mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Phase 1 of allowing admins to set the default object classes for users & groups
This adds the UI and does error checking of the selected object classes but it doesn't actually use the values yet. It also generalizes some functions for doing multi-valued fields.
This commit is contained in:
@@ -177,3 +177,8 @@ CONFIG_DEFAULT_GROUP = gen_error_code(
|
|||||||
CONFIGURATION_CATEGORY,
|
CONFIGURATION_CATEGORY,
|
||||||
0x0002,
|
0x0002,
|
||||||
"You cannot remove the default users group.")
|
"You cannot remove the default users group.")
|
||||||
|
|
||||||
|
CONFIG_INVALID_OC = gen_error_code(
|
||||||
|
CONFIGURATION_CATEGORY,
|
||||||
|
0x0003,
|
||||||
|
"Invalid object class.")
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import turbogears
|
import turbogears
|
||||||
from turbogears import validators, widgets
|
from turbogears import validators, widgets
|
||||||
|
from tg_expanding_form_widget.tg_expanding_form_widget import ExpandingForm
|
||||||
|
|
||||||
class IPAPolicyFields(object):
|
class IPAPolicyFields(object):
|
||||||
# From cn=ipaConfig
|
# From cn=ipaConfig
|
||||||
@@ -12,6 +13,10 @@ class IPAPolicyFields(object):
|
|||||||
ipadefaultprimarygroup = widgets.TextField(name="ipadefaultprimarygroup", label="Default Users group")
|
ipadefaultprimarygroup = widgets.TextField(name="ipadefaultprimarygroup", label="Default Users group")
|
||||||
ipamaxusernamelength = widgets.TextField(name="ipamaxusernamelength", label="Max. Username Length", attrs=dict(size=3,maxlength=3))
|
ipamaxusernamelength = widgets.TextField(name="ipamaxusernamelength", label="Max. Username Length", attrs=dict(size=3,maxlength=3))
|
||||||
ipapwdexpadvnotify = widgets.TextField(name="ipapwdexpadvnotify", label="Password Expiration Notification (days)", attrs=dict(size=3,maxlength=3))
|
ipapwdexpadvnotify = widgets.TextField(name="ipapwdexpadvnotify", label="Password Expiration Notification (days)", attrs=dict(size=3,maxlength=3))
|
||||||
|
ipauserobjectclasses = widgets.TextField(name="ipauserobjectclasses", label="Default User Object Classes", attrs=dict(size=50))
|
||||||
|
userobjectclasses = ExpandingForm(name="userobjectclasses", label="Default User Object Classes", fields=[ipauserobjectclasses])
|
||||||
|
ipagroupobjectclasses = widgets.TextField(name="ipagroupobjectclasses", label="Default Group Object Classes", attrs=dict(size=50))
|
||||||
|
groupobjectclasses = ExpandingForm(name="groupobjectclasses", label="Default User Object Classes", fields=[ipagroupobjectclasses])
|
||||||
|
|
||||||
ipapolicy_orig = widgets.HiddenField(name="ipapolicy_orig")
|
ipapolicy_orig = widgets.HiddenField(name="ipapolicy_orig")
|
||||||
|
|
||||||
@@ -34,6 +39,9 @@ class IPAPolicyValidator(validators.Schema):
|
|||||||
ipahomesrootdir = validators.String(not_empty=True)
|
ipahomesrootdir = validators.String(not_empty=True)
|
||||||
ipadefaultloginshell = validators.String(not_empty=True)
|
ipadefaultloginshell = validators.String(not_empty=True)
|
||||||
ipadefaultprimarygroup = validators.String(not_empty=True)
|
ipadefaultprimarygroup = validators.String(not_empty=True)
|
||||||
|
ipauserobjectclasses = validators.ForEach(validators.String(not_empty=True))
|
||||||
|
ipagroupobjectclasses = validators.ForEach(validators.String(not_empty=True))
|
||||||
|
|
||||||
krbmaxpwdlife = validators.Number(not_empty=True)
|
krbmaxpwdlife = validators.Number(not_empty=True)
|
||||||
krbminpwdlife = validators.Number(not_empty=True)
|
krbminpwdlife = validators.Number(not_empty=True)
|
||||||
krbpwdmindiffchars = validators.Number(not_empty=True)
|
krbpwdmindiffchars = validators.Number(not_empty=True)
|
||||||
|
|||||||
@@ -7,3 +7,34 @@ def javascript_string_escape(input):
|
|||||||
return re.sub(r'[\'\"\\]',
|
return re.sub(r'[\'\"\\]',
|
||||||
lambda match: "\\%s" % match.group(),
|
lambda match: "\\%s" % match.group(),
|
||||||
input)
|
input)
|
||||||
|
|
||||||
|
def setup_mv_fields(field, fieldname):
|
||||||
|
"""Given a field (must be a list) and field name, convert that
|
||||||
|
field into a list of dictionaries of the form:
|
||||||
|
[ { fieldname : v1}, { fieldname : v2 }, .. ]
|
||||||
|
|
||||||
|
This is how we pre-fill values for multi-valued fields.
|
||||||
|
"""
|
||||||
|
mvlist = []
|
||||||
|
if field:
|
||||||
|
for v in field:
|
||||||
|
if v:
|
||||||
|
mvlist.append({ fieldname : v } )
|
||||||
|
if len(mvlist) == 0:
|
||||||
|
# We need to return an empty value so something can be
|
||||||
|
# displayed on the edit page. Otherwise only an Add link
|
||||||
|
# will show, not an empty field.
|
||||||
|
mvlist.append({ fieldname : '' } )
|
||||||
|
return mvlist
|
||||||
|
|
||||||
|
def fix_incoming_fields(fields, fieldname, multifieldname):
|
||||||
|
"""This is called by the update() function. It takes the incoming
|
||||||
|
list of dictionaries and converts it into back into the original
|
||||||
|
field, then removes the multiple field.
|
||||||
|
"""
|
||||||
|
fields[fieldname] = []
|
||||||
|
for i in range(len(fields[multifieldname])):
|
||||||
|
fields[fieldname].append(fields[multifieldname][i][fieldname])
|
||||||
|
del(fields[multifieldname])
|
||||||
|
|
||||||
|
return fields
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ from ipa.entity import utf8_encode_values
|
|||||||
from ipa import ipaerror
|
from ipa import ipaerror
|
||||||
import ipa.entity
|
import ipa.entity
|
||||||
import ipagui.forms.ipapolicy
|
import ipagui.forms.ipapolicy
|
||||||
|
from ipagui.helpers import ipahelper
|
||||||
|
|
||||||
import ldap.dn
|
import ldap.dn
|
||||||
|
|
||||||
@@ -71,6 +72,15 @@ class IPAPolicyController(IPAController):
|
|||||||
# Combine the 2 dicts to make the form easier
|
# Combine the 2 dicts to make the form easier
|
||||||
ipapolicy_dict.update(password_dict)
|
ipapolicy_dict.update(password_dict)
|
||||||
|
|
||||||
|
# Load potential multi-valued fields
|
||||||
|
if isinstance(ipapolicy_dict.get('ipauserobjectclasses',''), str):
|
||||||
|
ipapolicy_dict['ipauserobjectclasses'] = [ipapolicy_dict.get('ipauserobjectclasses')]
|
||||||
|
ipapolicy_dict['userobjectclasses'] = ipahelper.setup_mv_fields(ipapolicy_dict.get('ipauserobjectclasses'), 'ipauserobjectclasses')
|
||||||
|
|
||||||
|
if isinstance(ipapolicy_dict.get('ipagroupobjectclasses',''), str):
|
||||||
|
ipapolicy_dict['ipagroupobjectclasses'] = [ipapolicy_dict.get('ipagroupobjectclasses')]
|
||||||
|
ipapolicy_dict['groupobjectclasses'] = ipahelper.setup_mv_fields(ipapolicy_dict.get('ipagroupobjectclasses'), 'ipagroupobjectclasses')
|
||||||
|
|
||||||
return dict(form=ipapolicy_edit_form, ipapolicy=ipapolicy_dict)
|
return dict(form=ipapolicy_edit_form, ipapolicy=ipapolicy_dict)
|
||||||
except ipaerror.IPAError, e:
|
except ipaerror.IPAError, e:
|
||||||
turbogears.flash("IPA Policy edit failed: " + str(e) + "<br/>" + str(e.detail))
|
turbogears.flash("IPA Policy edit failed: " + str(e) + "<br/>" + str(e.detail))
|
||||||
@@ -88,6 +98,10 @@ class IPAPolicyController(IPAController):
|
|||||||
turbogears.flash("Edit policy cancelled")
|
turbogears.flash("Edit policy cancelled")
|
||||||
raise turbogears.redirect('/ipapolicy/show')
|
raise turbogears.redirect('/ipapolicy/show')
|
||||||
|
|
||||||
|
# Fix incoming multi-valued fields we created for the form
|
||||||
|
kw = ipahelper.fix_incoming_fields(kw, 'ipauserobjectclasses', 'userobjectclasses')
|
||||||
|
kw = ipahelper.fix_incoming_fields(kw, 'ipagroupobjectclasses', 'groupobjectclasses')
|
||||||
|
|
||||||
tg_errors, kw = self.ipapolicyupdatevalidate(**kw)
|
tg_errors, kw = self.ipapolicyupdatevalidate(**kw)
|
||||||
if tg_errors:
|
if tg_errors:
|
||||||
turbogears.flash("There were validation errors.<br/>" +
|
turbogears.flash("There were validation errors.<br/>" +
|
||||||
@@ -132,6 +146,12 @@ class IPAPolicyController(IPAController):
|
|||||||
if new_ipapolicy.ipadefaultprimarygroup != kw.get('ipadefaultprimarygroup'):
|
if new_ipapolicy.ipadefaultprimarygroup != kw.get('ipadefaultprimarygroup'):
|
||||||
policy_modified = True
|
policy_modified = True
|
||||||
new_ipapolicy.setValue('ipadefaultprimarygroup', kw.get('ipadefaultprimarygroup'))
|
new_ipapolicy.setValue('ipadefaultprimarygroup', kw.get('ipadefaultprimarygroup'))
|
||||||
|
if new_ipapolicy.ipauserobjectclasses != kw.get('ipauserobjectclasses'):
|
||||||
|
policy_modified = True
|
||||||
|
new_ipapolicy.setValue('ipauserobjectclasses', kw.get('ipauserobjectclasses'))
|
||||||
|
if new_ipapolicy.ipagroupobjectclasses != kw.get('ipagroupobjectclasses'):
|
||||||
|
policy_modified = True
|
||||||
|
new_ipapolicy.setValue('ipagroupobjectclasses', kw.get('ipagroupobjectclasses'))
|
||||||
|
|
||||||
if policy_modified:
|
if policy_modified:
|
||||||
rv = client.update_ipa_config(new_ipapolicy)
|
rv = client.update_ipa_config(new_ipapolicy)
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ from ipa.entity import utf8_encode_values
|
|||||||
from ipa import ipaerror
|
from ipa import ipaerror
|
||||||
import ipagui.forms.user
|
import ipagui.forms.user
|
||||||
import ipa.config
|
import ipa.config
|
||||||
|
from ipagui.helpers import ipahelper
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -83,36 +84,6 @@ class UserController(IPAController):
|
|||||||
user_new_form.validator.add_field(s['field'], validator)
|
user_new_form.validator.add_field(s['field'], validator)
|
||||||
user_edit_form.validator.add_field(s['field'], validator)
|
user_edit_form.validator.add_field(s['field'], validator)
|
||||||
|
|
||||||
def setup_mv_fields(self, field, fieldname):
|
|
||||||
"""Given a field (must be a list) and field name, convert that
|
|
||||||
field into a list of dictionaries of the form:
|
|
||||||
[ { fieldname : v1}, { fieldname : v2 }, .. ]
|
|
||||||
|
|
||||||
This is how we pre-fill values for multi-valued fields.
|
|
||||||
"""
|
|
||||||
mvlist = []
|
|
||||||
if field is not None:
|
|
||||||
for v in field:
|
|
||||||
mvlist.append({ fieldname : v } )
|
|
||||||
else:
|
|
||||||
# We need to return an empty value so something can be
|
|
||||||
# displayed on the edit page. Otherwise only an Add link
|
|
||||||
# will show, not an empty field.
|
|
||||||
mvlist.append({ fieldname : '' } )
|
|
||||||
return mvlist
|
|
||||||
|
|
||||||
def fix_incoming_fields(self, fields, fieldname, multifieldname):
|
|
||||||
"""This is called by the update() function. It takes the incoming
|
|
||||||
list of dictionaries and converts it into back into the original
|
|
||||||
field, then removes the multiple field.
|
|
||||||
"""
|
|
||||||
fields[fieldname] = []
|
|
||||||
for i in range(len(fields[multifieldname])):
|
|
||||||
fields[fieldname].append(fields[multifieldname][i][fieldname])
|
|
||||||
del(fields[multifieldname])
|
|
||||||
|
|
||||||
return fields
|
|
||||||
|
|
||||||
@expose()
|
@expose()
|
||||||
def index(self):
|
def index(self):
|
||||||
raise turbogears.redirect("/user/list")
|
raise turbogears.redirect("/user/list")
|
||||||
@@ -142,12 +113,12 @@ class UserController(IPAController):
|
|||||||
tg_errors, kw = self.usercreatevalidate(**kw)
|
tg_errors, kw = self.usercreatevalidate(**kw)
|
||||||
|
|
||||||
# Fix incoming multi-valued fields we created for the form
|
# Fix incoming multi-valued fields we created for the form
|
||||||
kw = self.fix_incoming_fields(kw, 'cn', 'cns')
|
kw = ipahelper.fix_incoming_fields(kw, 'cn', 'cns')
|
||||||
kw = self.fix_incoming_fields(kw, 'telephonenumber', 'telephonenumbers')
|
kw = ipahelper.fix_incoming_fields(kw, 'telephonenumber', 'telephonenumbers')
|
||||||
kw = self.fix_incoming_fields(kw, 'facsimiletelephonenumber', 'facsimiletelephonenumbers')
|
kw = ipahelper.fix_incoming_fields(kw, 'facsimiletelephonenumber', 'facsimiletelephonenumbers')
|
||||||
kw = self.fix_incoming_fields(kw, 'mobile', 'mobiles')
|
kw = ipahelper.fix_incoming_fields(kw, 'mobile', 'mobiles')
|
||||||
kw = self.fix_incoming_fields(kw, 'pager', 'pagers')
|
kw = ipahelper.fix_incoming_fields(kw, 'pager', 'pagers')
|
||||||
kw = self.fix_incoming_fields(kw, 'homephone', 'homephones')
|
kw = ipahelper.fix_incoming_fields(kw, 'homephone', 'homephones')
|
||||||
|
|
||||||
if tg_errors:
|
if tg_errors:
|
||||||
turbogears.flash("There were validation errors.<br/>" +
|
turbogears.flash("There were validation errors.<br/>" +
|
||||||
@@ -325,27 +296,27 @@ class UserController(IPAController):
|
|||||||
# Load potential multi-valued fields
|
# Load potential multi-valued fields
|
||||||
if isinstance(user_dict['cn'], str):
|
if isinstance(user_dict['cn'], str):
|
||||||
user_dict['cn'] = [user_dict['cn']]
|
user_dict['cn'] = [user_dict['cn']]
|
||||||
user_dict['cns'] = self.setup_mv_fields(user_dict['cn'], 'cn')
|
user_dict['cns'] = ipahelper.setup_mv_fields(user_dict['cn'], 'cn')
|
||||||
|
|
||||||
if isinstance(user_dict.get('telephonenumber',''), str):
|
if isinstance(user_dict.get('telephonenumber',''), str):
|
||||||
user_dict['telephonenumber'] = [user_dict.get('telephonenumber'),'']
|
user_dict['telephonenumber'] = [user_dict.get('telephonenumber')]
|
||||||
user_dict['telephonenumbers'] = self.setup_mv_fields(user_dict.get('telephonenumber'), 'telephonenumber')
|
user_dict['telephonenumbers'] = ipahelper.setup_mv_fields(user_dict.get('telephonenumber'), 'telephonenumber')
|
||||||
|
|
||||||
if isinstance(user_dict.get('facsimiletelephonenumber',''), str):
|
if isinstance(user_dict.get('facsimiletelephonenumber',''), str):
|
||||||
user_dict['facsimiletelephonenumber'] = [user_dict.get('facsimiletelephonenumber'),'']
|
user_dict['facsimiletelephonenumber'] = [user_dict.get('facsimiletelephonenumber')]
|
||||||
user_dict['facsimiletelephonenumbers'] = self.setup_mv_fields(user_dict.get('facsimiletelephonenumber'), 'facsimiletelephonenumber')
|
user_dict['facsimiletelephonenumbers'] = ipahelper.setup_mv_fields(user_dict.get('facsimiletelephonenumber'), 'facsimiletelephonenumber')
|
||||||
|
|
||||||
if isinstance(user_dict.get('mobile',''), str):
|
if isinstance(user_dict.get('mobile',''), str):
|
||||||
user_dict['mobile'] = [user_dict.get('mobile'),'']
|
user_dict['mobile'] = [user_dict.get('mobile')]
|
||||||
user_dict['mobiles'] = self.setup_mv_fields(user_dict.get('mobile'), 'mobile')
|
user_dict['mobiles'] = ipahelper.setup_mv_fields(user_dict.get('mobile'), 'mobile')
|
||||||
|
|
||||||
if isinstance(user_dict.get('pager',''), str):
|
if isinstance(user_dict.get('pager',''), str):
|
||||||
user_dict['pager'] = [user_dict.get('pager'),'']
|
user_dict['pager'] = [user_dict.get('pager')]
|
||||||
user_dict['pagers'] = self.setup_mv_fields(user_dict.get('pager'), 'pager')
|
user_dict['pagers'] = ipahelper.setup_mv_fields(user_dict.get('pager'), 'pager')
|
||||||
|
|
||||||
if isinstance(user_dict.get('homephone',''), str):
|
if isinstance(user_dict.get('homephone',''), str):
|
||||||
user_dict['homephone'] = [user_dict.get('homephone'),'']
|
user_dict['homephone'] = [user_dict.get('homephone')]
|
||||||
user_dict['homephones'] = self.setup_mv_fields(user_dict.get('homephone'), 'homephone')
|
user_dict['homephones'] = ipahelper.setup_mv_fields(user_dict.get('homephone'), 'homephone')
|
||||||
|
|
||||||
# Edit shouldn't fill in the password field.
|
# Edit shouldn't fill in the password field.
|
||||||
if user_dict.has_key('userpassword'):
|
if user_dict.has_key('userpassword'):
|
||||||
@@ -403,12 +374,12 @@ class UserController(IPAController):
|
|||||||
raise turbogears.redirect('/user/show', uid=kw.get('uid'))
|
raise turbogears.redirect('/user/show', uid=kw.get('uid'))
|
||||||
|
|
||||||
# Fix incoming multi-valued fields we created for the form
|
# Fix incoming multi-valued fields we created for the form
|
||||||
kw = self.fix_incoming_fields(kw, 'cn', 'cns')
|
kw = ipahelper.fix_incoming_fields(kw, 'cn', 'cns')
|
||||||
kw = self.fix_incoming_fields(kw, 'telephonenumber', 'telephonenumbers')
|
kw = ipahelper.fix_incoming_fields(kw, 'telephonenumber', 'telephonenumbers')
|
||||||
kw = self.fix_incoming_fields(kw, 'facsimiletelephonenumber', 'facsimiletelephonenumbers')
|
kw = ipahelper.fix_incoming_fields(kw, 'facsimiletelephonenumber', 'facsimiletelephonenumbers')
|
||||||
kw = self.fix_incoming_fields(kw, 'mobile', 'mobiles')
|
kw = ipahelper.fix_incoming_fields(kw, 'mobile', 'mobiles')
|
||||||
kw = self.fix_incoming_fields(kw, 'pager', 'pagers')
|
kw = ipahelper.fix_incoming_fields(kw, 'pager', 'pagers')
|
||||||
kw = self.fix_incoming_fields(kw, 'homephone', 'homephones')
|
kw = ipahelper.fix_incoming_fields(kw, 'homephone', 'homephones')
|
||||||
|
|
||||||
# admins and editors can update anybody. A user can only update
|
# admins and editors can update anybody. A user can only update
|
||||||
# themselves. We need this check because it is very easy to guess
|
# themselves. We need this check because it is very easy to guess
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ from ipagui.helpers import ipahelper
|
|||||||
|
|
||||||
<script type="text/javascript" charset="utf-8"
|
<script type="text/javascript" charset="utf-8"
|
||||||
src="${tg.url('/static/javascript/dynamicedit.js')}"></script>
|
src="${tg.url('/static/javascript/dynamicedit.js')}"></script>
|
||||||
|
<script type="text/javascript" charset="utf-8"
|
||||||
|
src="${tg.url('/tg_widgets/tg_expanding_form_widget/javascript/expanding_form.js')}"></script>
|
||||||
|
|
||||||
<div py:for="field in hidden_fields"
|
<div py:for="field in hidden_fields"
|
||||||
py:replace="field.display(value_for(field), **params_for(field))"
|
py:replace="field.display(value_for(field), **params_for(field))"
|
||||||
@@ -170,7 +172,80 @@ from ipagui.helpers import ipahelper
|
|||||||
py:content="tg.errors.get('ipadefaultprimarygroup')" />
|
py:content="tg.errors.get('ipadefaultprimarygroup')" />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<label class="fieldlabel" for="${ipapolicy_fields.userobjectclasses.field_id}"
|
||||||
|
py:content="ipapolicy_fields.userobjectclasses.label" />:
|
||||||
|
</th>
|
||||||
|
<td colspan="3">
|
||||||
|
<table class="formtable" cellpadding="2" cellspacing="0" border="0" id="${ipapolicy_fields.userobjectclasses.field_id}">
|
||||||
|
<tbody>
|
||||||
|
<?python repetition = 0
|
||||||
|
fld_index = 0
|
||||||
|
fld_error = tg.errors.get('ipauserobjectclasses')
|
||||||
|
?>
|
||||||
|
<tr py:for="fld in value_for(ipapolicy_fields.ipauserobjectclasses)"
|
||||||
|
id="${ipapolicy_fields.userobjectclasses.field_id}_${repetition}"
|
||||||
|
class="${ipapolicy_fields.userobjectclasses.field_class}">
|
||||||
|
|
||||||
|
<td py:for="field in ipapolicy_fields.userobjectclasses.fields">
|
||||||
|
<span><input class="textfield" type="text" id="${ipapolicy_fields.userobjectclasses.field_id}_${repetition}_ipauserobjectclasses" name="userobjectclasses-${repetition}.ipauserobjectclasses" value="${fld}"/></span>
|
||||||
|
<span py:if="fld_error and fld_error[fld_index]" class="fielderror"
|
||||||
|
py:content="tg.errors.get('ipauserobjectclasses')" />
|
||||||
|
</td>
|
||||||
|
<?python fld_index = fld_index + 1 ?>
|
||||||
|
<td>
|
||||||
|
<a
|
||||||
|
href="javascript:ExpandingForm.removeItem('${ipapolicy_fields.userobjectclasses.field_id}_${repetition}')">Remove</a>
|
||||||
|
</td>
|
||||||
|
<?python repetition = repetition + 1?>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<a id="${ipapolicy_fields.userobjectclasses.field_id}_doclink" href="javascript:ExpandingForm.addItem('${ipapolicy_fields.userobjectclasses.field_id}');">Add User Object Class</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<label class="fieldlabel" for="${ipapolicy_fields.groupobjectclasses.field_id}"
|
||||||
|
py:content="ipapolicy_fields.groupobjectclasses.label" />:
|
||||||
|
</th>
|
||||||
|
<td colspan="3">
|
||||||
|
<table class="formtable" cellpadding="2" cellspacing="0" border="0" id="${ipapolicy_fields.groupobjectclasses.field_id}">
|
||||||
|
<tbody>
|
||||||
|
<?python repetition = 0
|
||||||
|
fld_index = 0
|
||||||
|
fld_error = tg.errors.get('ipagroupobjectclasses')
|
||||||
|
?>
|
||||||
|
<tr py:for="fld in value_for(ipapolicy_fields.ipagroupobjectclasses)"
|
||||||
|
id="${ipapolicy_fields.groupobjectclasses.field_id}_${repetition}"
|
||||||
|
class="${ipapolicy_fields.groupobjectclasses.field_class}">
|
||||||
|
|
||||||
|
<td py:for="field in ipapolicy_fields.groupobjectclasses.fields">
|
||||||
|
<span><input class="textfield" type="text" id="${ipapolicy_fields.groupobjectclasses.field_id}_${repetition}_ipagroupobjectclasses" name="groupobjectclasses-${repetition}.ipagroupobjectclasses" value="${fld}"/></span>
|
||||||
|
<span py:if="fld_error and fld_error[fld_index]" class="fielderror"
|
||||||
|
py:content="tg.errors.get('ipagroupobjectclasses')" />
|
||||||
|
</td>
|
||||||
|
<?python fld_index = fld_index + 1 ?>
|
||||||
|
<td>
|
||||||
|
<a
|
||||||
|
href="javascript:ExpandingForm.removeItem('${ipapolicy_fields.groupobjectclasses.field_id}_${repetition}')">Remove</a>
|
||||||
|
</td>
|
||||||
|
<?python repetition = repetition + 1?>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<a id="${ipapolicy_fields.groupobjectclasses.field_id}_doclink" href="javascript:ExpandingForm.addItem('${ipapolicy_fields.groupobjectclasses.field_id}');">Add Group Object Class</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<hr/>
|
||||||
|
|
||||||
|
<input type="submit" class="submitbutton" name="submit"
|
||||||
|
value="Update Policy"/>
|
||||||
|
<input type="submit" class="submitbutton" name="submit"
|
||||||
|
value="Cancel Edit" />
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -109,6 +109,46 @@ edit_url = tg.url('/ipapolicy/edit')
|
|||||||
</th>
|
</th>
|
||||||
<td>${ipapolicy.get("ipadefaultprimarygroup")}</td>
|
<td>${ipapolicy.get("ipadefaultprimarygroup")}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<label class="fieldlabel" py:content="fields.ipauserobjectclasses.label" />:
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<table cellpadding="2" cellspacing="0" border="0">
|
||||||
|
<tbody>
|
||||||
|
<?python
|
||||||
|
index = 0
|
||||||
|
values = ipapolicy.get("ipauserobjectclasses", '')
|
||||||
|
if isinstance(values, str):
|
||||||
|
values = [values]
|
||||||
|
?>
|
||||||
|
<tr py:for="index in range(len(values))">
|
||||||
|
<td>${values[index]}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<label class="fieldlabel" py:content="fields.ipagroupobjectclasses.label" />:
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<table cellpadding="2" cellspacing="0" border="0">
|
||||||
|
<tbody>
|
||||||
|
<?python
|
||||||
|
index = 0
|
||||||
|
values = ipapolicy.get("ipagroupobjectclasses", '')
|
||||||
|
if isinstance(values, str):
|
||||||
|
values = [values]
|
||||||
|
?>
|
||||||
|
<tr py:for="index in range(len(values))">
|
||||||
|
<td>${values[index]}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<hr />
|
<hr />
|
||||||
<input class="submitbutton" type="button"
|
<input class="submitbutton" type="button"
|
||||||
|
|||||||
@@ -27,11 +27,15 @@ attributetypes: ( 2.16.840.1.113730.3.8.1.7 NAME 'ipaDefaultLoginShell' EQUALITY
|
|||||||
attributetypes: ( 2.16.840.1.113730.3.8.1.8 NAME 'ipaDefaultPrimaryGroup' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE)
|
attributetypes: ( 2.16.840.1.113730.3.8.1.8 NAME 'ipaDefaultPrimaryGroup' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE)
|
||||||
## ipaMaxUsernameLength - maximum username length to allow in the UI
|
## ipaMaxUsernameLength - maximum username length to allow in the UI
|
||||||
attributetypes: ( 2.16.840.1.113730.3.8.1.9 NAME 'ipaMaxUsernameLength' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE)
|
attributetypes: ( 2.16.840.1.113730.3.8.1.9 NAME 'ipaMaxUsernameLength' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE)
|
||||||
## ipaPwdExpAdvNotify - time in days to send out paswwrod expiration notification before passwpord actually expires
|
## ipaPwdExpAdvNotify - time in days to send out paswword expiration notification before passwpord actually expires
|
||||||
attributetypes: ( 2.16.840.1.113730.3.8.1.10 NAME 'ipaPwdExpAdvNotify' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE)
|
attributetypes: ( 2.16.840.1.113730.3.8.1.10 NAME 'ipaPwdExpAdvNotify' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE)
|
||||||
|
# ipaUserObjectClasses - required objectclasses for users
|
||||||
|
attributetypes: ( 2.16.840.1.113730.3.8.1.11 NAME 'ipaUserObjectClasses' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27)
|
||||||
|
# ipaGroupObjectClasses - required objectclasses for groups
|
||||||
|
attributetypes: ( 2.16.840.1.113730.3.8.1.12 NAME 'ipaGroupObjectClasses' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27)
|
||||||
###############################################
|
###############################################
|
||||||
##
|
##
|
||||||
## ObjectClasses
|
## ObjectClasses
|
||||||
##
|
##
|
||||||
## ipaGuiConfig - GUI config parameters objectclass
|
## ipaGuiConfig - GUI config parameters objectclass
|
||||||
objectClasses: ( 2.16.840.1.113730.3.8.2.1 NAME 'ipaGuiConfig' AUXILIARY MAY ( ipaUserSearchFields $ ipaGroupSearchFields $ ipaSearchTimeLimit $ ipaSearchRecordsLimit $ ipaCustomFields $ ipaHomesRootDir $ ipaDefaultLoginShell $ ipaDefaultPrimaryGroup $ ipaMaxUsernameLength $ ipaPwdExpAdvNotify ) )
|
objectClasses: ( 2.16.840.1.113730.3.8.2.1 NAME 'ipaGuiConfig' AUXILIARY MAY ( ipaUserSearchFields $ ipaGroupSearchFields $ ipaSearchTimeLimit $ ipaSearchRecordsLimit $ ipaCustomFields $ ipaHomesRootDir $ ipaDefaultLoginShell $ ipaDefaultPrimaryGroup $ ipaMaxUsernameLength $ ipaPwdExpAdvNotify $ ipaUserObjectClasses $ ipaGroupObjectClasses) )
|
||||||
|
|||||||
@@ -329,6 +329,32 @@ class IPAServer:
|
|||||||
|
|
||||||
return (exact_match_filter, partial_match_filter)
|
return (exact_match_filter, partial_match_filter)
|
||||||
|
|
||||||
|
def __get_schema(self, opts=None):
|
||||||
|
"""Retrieves the current LDAP schema from the LDAP server."""
|
||||||
|
|
||||||
|
schema_entry = self.__get_base_entry("", "objectclass=*", ['dn','subschemasubentry'], opts)
|
||||||
|
schema_cn = schema_entry.get('subschemasubentry')
|
||||||
|
schema = self.__get_base_entry(schema_cn, "objectclass=*", ['*'], opts)
|
||||||
|
|
||||||
|
return schema
|
||||||
|
|
||||||
|
def __get_objectclasses(self, opts=None):
|
||||||
|
"""Returns a list of available objectclasses that the LDAP
|
||||||
|
server supports. This parses out the syntax, attributes, etc
|
||||||
|
and JUST returns a lower-case list of the names."""
|
||||||
|
|
||||||
|
schema = self.__get_schema(opts)
|
||||||
|
|
||||||
|
objectclasses = schema.get('objectclasses')
|
||||||
|
|
||||||
|
# Convert this list into something more readable
|
||||||
|
result = []
|
||||||
|
for i in range(len(objectclasses)):
|
||||||
|
oc = objectclasses[i].lower().split(" ")
|
||||||
|
result.append(oc[3].replace("'",""))
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
# Higher-level API
|
# Higher-level API
|
||||||
|
|
||||||
def get_aci_entry(self, sattrs, opts=None):
|
def get_aci_entry(self, sattrs, opts=None):
|
||||||
@@ -1397,6 +1423,19 @@ class IPAServer:
|
|||||||
except:
|
except:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
# Run through the list of User and Group object classes to make
|
||||||
|
# sure they are all valid. This doesn't handle dependencies but it
|
||||||
|
# will at least catch typos.
|
||||||
|
classes = self.__get_objectclasses(opts)
|
||||||
|
oc = newconfig['ipauserobjectclasses']
|
||||||
|
for i in range(len(oc)):
|
||||||
|
if not oc[i].lower() in classes:
|
||||||
|
raise ipaerror.gen_exception(ipaerror.CONFIG_INVALID_OC)
|
||||||
|
oc = newconfig['ipagroupobjectclasses']
|
||||||
|
for i in range(len(oc)):
|
||||||
|
if not oc[i].lower() in classes:
|
||||||
|
raise ipaerror.gen_exception(ipaerror.CONFIG_INVALID_OC)
|
||||||
|
|
||||||
return self.update_entry(oldconfig, newconfig, opts)
|
return self.update_entry(oldconfig, newconfig, opts)
|
||||||
|
|
||||||
def get_password_policy(self, opts=None):
|
def get_password_policy(self, opts=None):
|
||||||
|
|||||||
Reference in New Issue
Block a user