diff options
author | Rob Crittenden <rcritten@redhat.com> | 2007-12-04 13:18:37 -0500 |
---|---|---|
committer | Rob Crittenden <rcritten@redhat.com> | 2007-12-04 13:18:37 -0500 |
commit | 2fbe5cbf492597a87427b61f1e470052b77465b2 (patch) | |
tree | 0a4bdf0cbd8068f7d2e33a9be7037b178ee7f378 | |
parent | 69765f52ce54eacb704b7ff1ee4287a3ed787371 (diff) | |
download | freeipa-2fbe5cbf492597a87427b61f1e470052b77465b2.tar.gz freeipa-2fbe5cbf492597a87427b61f1e470052b77465b2.tar.xz freeipa-2fbe5cbf492597a87427b61f1e470052b77465b2.zip |
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.
-rw-r--r-- | ipa-python/ipaerror.py | 5 | ||||
-rw-r--r-- | ipa-server/ipa-gui/ipagui/forms/ipapolicy.py | 8 | ||||
-rw-r--r-- | ipa-server/ipa-gui/ipagui/helpers/ipahelper.py | 31 | ||||
-rw-r--r-- | ipa-server/ipa-gui/ipagui/subcontrollers/ipapolicy.py | 20 | ||||
-rw-r--r-- | ipa-server/ipa-gui/ipagui/subcontrollers/user.py | 77 | ||||
-rw-r--r-- | ipa-server/ipa-gui/ipagui/templates/ipapolicyeditform.kid | 75 | ||||
-rw-r--r-- | ipa-server/ipa-gui/ipagui/templates/ipapolicyshow.kid | 40 | ||||
-rw-r--r-- | ipa-server/ipa-install/share/60ipaconfig.ldif | 8 | ||||
-rw-r--r-- | ipa-server/xmlrpc-server/funcs.py | 39 |
9 files changed, 248 insertions, 55 deletions
diff --git a/ipa-python/ipaerror.py b/ipa-python/ipaerror.py index 2f9a98363..e34963365 100644 --- a/ipa-python/ipaerror.py +++ b/ipa-python/ipaerror.py @@ -177,3 +177,8 @@ CONFIG_DEFAULT_GROUP = gen_error_code( CONFIGURATION_CATEGORY, 0x0002, "You cannot remove the default users group.") + +CONFIG_INVALID_OC = gen_error_code( + CONFIGURATION_CATEGORY, + 0x0003, + "Invalid object class.") diff --git a/ipa-server/ipa-gui/ipagui/forms/ipapolicy.py b/ipa-server/ipa-gui/ipagui/forms/ipapolicy.py index 78acac664..1d48f8f33 100644 --- a/ipa-server/ipa-gui/ipagui/forms/ipapolicy.py +++ b/ipa-server/ipa-gui/ipagui/forms/ipapolicy.py @@ -1,5 +1,6 @@ import turbogears from turbogears import validators, widgets +from tg_expanding_form_widget.tg_expanding_form_widget import ExpandingForm class IPAPolicyFields(object): # From cn=ipaConfig @@ -12,6 +13,10 @@ class IPAPolicyFields(object): ipadefaultprimarygroup = widgets.TextField(name="ipadefaultprimarygroup", label="Default Users group") 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)) + 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") @@ -34,6 +39,9 @@ class IPAPolicyValidator(validators.Schema): ipahomesrootdir = validators.String(not_empty=True) ipadefaultloginshell = 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) krbminpwdlife = validators.Number(not_empty=True) krbpwdmindiffchars = validators.Number(not_empty=True) diff --git a/ipa-server/ipa-gui/ipagui/helpers/ipahelper.py b/ipa-server/ipa-gui/ipagui/helpers/ipahelper.py index 9ea6b48ab..e5c2bd378 100644 --- a/ipa-server/ipa-gui/ipagui/helpers/ipahelper.py +++ b/ipa-server/ipa-gui/ipagui/helpers/ipahelper.py @@ -7,3 +7,34 @@ def javascript_string_escape(input): return re.sub(r'[\'\"\\]', lambda match: "\\%s" % match.group(), 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 diff --git a/ipa-server/ipa-gui/ipagui/subcontrollers/ipapolicy.py b/ipa-server/ipa-gui/ipagui/subcontrollers/ipapolicy.py index a82b98888..d8237331b 100644 --- a/ipa-server/ipa-gui/ipagui/subcontrollers/ipapolicy.py +++ b/ipa-server/ipa-gui/ipagui/subcontrollers/ipapolicy.py @@ -17,6 +17,7 @@ from ipa.entity import utf8_encode_values from ipa import ipaerror import ipa.entity import ipagui.forms.ipapolicy +from ipagui.helpers import ipahelper import ldap.dn @@ -71,6 +72,15 @@ class IPAPolicyController(IPAController): # Combine the 2 dicts to make the form easier 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) except ipaerror.IPAError, e: turbogears.flash("IPA Policy edit failed: " + str(e) + "<br/>" + str(e.detail)) @@ -88,6 +98,10 @@ class IPAPolicyController(IPAController): turbogears.flash("Edit policy cancelled") 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) if tg_errors: turbogears.flash("There were validation errors.<br/>" + @@ -132,6 +146,12 @@ class IPAPolicyController(IPAController): if new_ipapolicy.ipadefaultprimarygroup != kw.get('ipadefaultprimarygroup'): policy_modified = True 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: rv = client.update_ipa_config(new_ipapolicy) diff --git a/ipa-server/ipa-gui/ipagui/subcontrollers/user.py b/ipa-server/ipa-gui/ipagui/subcontrollers/user.py index 39343b595..eda0966bb 100644 --- a/ipa-server/ipa-gui/ipagui/subcontrollers/user.py +++ b/ipa-server/ipa-gui/ipagui/subcontrollers/user.py @@ -18,6 +18,7 @@ from ipa.entity import utf8_encode_values from ipa import ipaerror import ipagui.forms.user import ipa.config +from ipagui.helpers import ipahelper log = logging.getLogger(__name__) @@ -83,36 +84,6 @@ class UserController(IPAController): user_new_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() def index(self): raise turbogears.redirect("/user/list") @@ -142,12 +113,12 @@ class UserController(IPAController): tg_errors, kw = self.usercreatevalidate(**kw) # Fix incoming multi-valued fields we created for the form - kw = self.fix_incoming_fields(kw, 'cn', 'cns') - kw = self.fix_incoming_fields(kw, 'telephonenumber', 'telephonenumbers') - kw = self.fix_incoming_fields(kw, 'facsimiletelephonenumber', 'facsimiletelephonenumbers') - kw = self.fix_incoming_fields(kw, 'mobile', 'mobiles') - kw = self.fix_incoming_fields(kw, 'pager', 'pagers') - kw = self.fix_incoming_fields(kw, 'homephone', 'homephones') + kw = ipahelper.fix_incoming_fields(kw, 'cn', 'cns') + kw = ipahelper.fix_incoming_fields(kw, 'telephonenumber', 'telephonenumbers') + kw = ipahelper.fix_incoming_fields(kw, 'facsimiletelephonenumber', 'facsimiletelephonenumbers') + kw = ipahelper.fix_incoming_fields(kw, 'mobile', 'mobiles') + kw = ipahelper.fix_incoming_fields(kw, 'pager', 'pagers') + kw = ipahelper.fix_incoming_fields(kw, 'homephone', 'homephones') if tg_errors: turbogears.flash("There were validation errors.<br/>" + @@ -325,27 +296,27 @@ class UserController(IPAController): # Load potential multi-valued fields if isinstance(user_dict['cn'], str): 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): - user_dict['telephonenumber'] = [user_dict.get('telephonenumber'),''] - user_dict['telephonenumbers'] = self.setup_mv_fields(user_dict.get('telephonenumber'), 'telephonenumber') + user_dict['telephonenumber'] = [user_dict.get('telephonenumber')] + user_dict['telephonenumbers'] = ipahelper.setup_mv_fields(user_dict.get('telephonenumber'), 'telephonenumber') if isinstance(user_dict.get('facsimiletelephonenumber',''), str): - user_dict['facsimiletelephonenumber'] = [user_dict.get('facsimiletelephonenumber'),''] - user_dict['facsimiletelephonenumbers'] = self.setup_mv_fields(user_dict.get('facsimiletelephonenumber'), 'facsimiletelephonenumber') + user_dict['facsimiletelephonenumber'] = [user_dict.get('facsimiletelephonenumber')] + user_dict['facsimiletelephonenumbers'] = ipahelper.setup_mv_fields(user_dict.get('facsimiletelephonenumber'), 'facsimiletelephonenumber') if isinstance(user_dict.get('mobile',''), str): - user_dict['mobile'] = [user_dict.get('mobile'),''] - user_dict['mobiles'] = self.setup_mv_fields(user_dict.get('mobile'), 'mobile') + user_dict['mobile'] = [user_dict.get('mobile')] + user_dict['mobiles'] = ipahelper.setup_mv_fields(user_dict.get('mobile'), 'mobile') if isinstance(user_dict.get('pager',''), str): - user_dict['pager'] = [user_dict.get('pager'),''] - user_dict['pagers'] = self.setup_mv_fields(user_dict.get('pager'), 'pager') + user_dict['pager'] = [user_dict.get('pager')] + user_dict['pagers'] = ipahelper.setup_mv_fields(user_dict.get('pager'), 'pager') if isinstance(user_dict.get('homephone',''), str): - user_dict['homephone'] = [user_dict.get('homephone'),''] - user_dict['homephones'] = self.setup_mv_fields(user_dict.get('homephone'), 'homephone') + user_dict['homephone'] = [user_dict.get('homephone')] + user_dict['homephones'] = ipahelper.setup_mv_fields(user_dict.get('homephone'), 'homephone') # Edit shouldn't fill in the password field. if user_dict.has_key('userpassword'): @@ -403,12 +374,12 @@ class UserController(IPAController): raise turbogears.redirect('/user/show', uid=kw.get('uid')) # Fix incoming multi-valued fields we created for the form - kw = self.fix_incoming_fields(kw, 'cn', 'cns') - kw = self.fix_incoming_fields(kw, 'telephonenumber', 'telephonenumbers') - kw = self.fix_incoming_fields(kw, 'facsimiletelephonenumber', 'facsimiletelephonenumbers') - kw = self.fix_incoming_fields(kw, 'mobile', 'mobiles') - kw = self.fix_incoming_fields(kw, 'pager', 'pagers') - kw = self.fix_incoming_fields(kw, 'homephone', 'homephones') + kw = ipahelper.fix_incoming_fields(kw, 'cn', 'cns') + kw = ipahelper.fix_incoming_fields(kw, 'telephonenumber', 'telephonenumbers') + kw = ipahelper.fix_incoming_fields(kw, 'facsimiletelephonenumber', 'facsimiletelephonenumbers') + kw = ipahelper.fix_incoming_fields(kw, 'mobile', 'mobiles') + kw = ipahelper.fix_incoming_fields(kw, 'pager', 'pagers') + kw = ipahelper.fix_incoming_fields(kw, 'homephone', 'homephones') # admins and editors can update anybody. A user can only update # themselves. We need this check because it is very easy to guess diff --git a/ipa-server/ipa-gui/ipagui/templates/ipapolicyeditform.kid b/ipa-server/ipa-gui/ipagui/templates/ipapolicyeditform.kid index 106657636..9584e4457 100644 --- a/ipa-server/ipa-gui/ipagui/templates/ipapolicyeditform.kid +++ b/ipa-server/ipa-gui/ipagui/templates/ipapolicyeditform.kid @@ -15,6 +15,8 @@ from ipagui.helpers import ipahelper <script type="text/javascript" charset="utf-8" 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" 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')" /> </td> </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> + + <hr/> + + <input type="submit" class="submitbutton" name="submit" + value="Update Policy"/> + <input type="submit" class="submitbutton" name="submit" + value="Cancel Edit" /> </form> </div> diff --git a/ipa-server/ipa-gui/ipagui/templates/ipapolicyshow.kid b/ipa-server/ipa-gui/ipagui/templates/ipapolicyshow.kid index 089fb494e..6e49e5556 100644 --- a/ipa-server/ipa-gui/ipagui/templates/ipapolicyshow.kid +++ b/ipa-server/ipa-gui/ipagui/templates/ipapolicyshow.kid @@ -109,6 +109,46 @@ edit_url = tg.url('/ipapolicy/edit') </th> <td>${ipapolicy.get("ipadefaultprimarygroup")}</td> </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> <hr /> <input class="submitbutton" type="button" diff --git a/ipa-server/ipa-install/share/60ipaconfig.ldif b/ipa-server/ipa-install/share/60ipaconfig.ldif index e15d4a417..b9371e779 100644 --- a/ipa-server/ipa-install/share/60ipaconfig.ldif +++ b/ipa-server/ipa-install/share/60ipaconfig.ldif @@ -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) ## 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) -## 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) +# 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 ## ## 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) ) diff --git a/ipa-server/xmlrpc-server/funcs.py b/ipa-server/xmlrpc-server/funcs.py index 12131c26b..9e9ad27a6 100644 --- a/ipa-server/xmlrpc-server/funcs.py +++ b/ipa-server/xmlrpc-server/funcs.py @@ -329,6 +329,32 @@ class IPAServer: 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 def get_aci_entry(self, sattrs, opts=None): @@ -1397,6 +1423,19 @@ class IPAServer: except: 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) def get_password_policy(self, opts=None): |