diff --git a/ipa-admintools/ipa-adduser b/ipa-admintools/ipa-adduser index bb97a0d67..e993bee5e 100644 --- a/ipa-admintools/ipa-adduser +++ b/ipa-admintools/ipa-adduser @@ -205,8 +205,6 @@ def main(): user.setValue('homedirectory', directory) if shell: user.setValue('loginshell', shell) - else: - user.setValue('loginshell', "/bin/sh") try: client = ipaclient.IPAClient() diff --git a/ipa-admintools/ipa-findgroup b/ipa-admintools/ipa-findgroup index 6953d4fd3..9f809aa0b 100644 --- a/ipa-admintools/ipa-findgroup +++ b/ipa-admintools/ipa-findgroup @@ -35,6 +35,12 @@ def usage(): def parse_options(): parser = OptionParser() + parser.add_option("-a", "--all", action="store_true", dest="all", + help="Show all group attributes") + parser.add_option("-n", "--notranslate", action="store_true", + dest="notranslate", + help="Don't translate LDAP attributes into readable labels") + args = ipa.config.init_config(sys.argv) options, args = parser.parse_args(args) @@ -49,7 +55,10 @@ def main(): try: client = ipaclient.IPAClient() - groups = client.find_groups(args[1], ['cn','description','gidnumber']) + if options.all is None: + groups = client.find_groups(args[1], ['cn','description','gidnumber','nsAccountLock']) + else: + groups = client.find_groups(args[1], sattrs=['*','nsAccountLock']) counter = groups[0] groups = groups[1:] @@ -65,15 +74,21 @@ def main(): print str(e) continue attr = ent.attrList() + if options.notranslate: + labels = {} + for a in attr: + labels[a] = a + else: + labels = client.attrs_to_labels(attr) print "dn: " + ent.dn for a in attr: value = ent.getValues(a) if isinstance(value,str): - print a + ": " + value + print labels[a] + ": " + value else: - print a + ": " + print labels[a] + ": " for l in value: print "\t" + l diff --git a/ipa-admintools/ipa-finduser b/ipa-admintools/ipa-finduser index a6f052f1d..6dc4d56c8 100644 --- a/ipa-admintools/ipa-finduser +++ b/ipa-admintools/ipa-finduser @@ -39,6 +39,9 @@ def parse_options(): parser.add_option("-a", "--all", action="store_true", dest="all", help="Set user's e-mail address") + parser.add_option("-n", "--notranslate", action="store_true", + dest="notranslate", + help="Don't translate LDAP attributes into readable labels") parser.add_option("--usage", action="store_true", help="Program usage") @@ -91,6 +94,12 @@ def main(): for ent in users: attr = ent.attrList() attr.sort() + if options.notranslate: + labels = {} + for a in attr: + labels[a] = a + else: + labels = client.attrs_to_labels(attr) if options.all is True: print "dn: " + ent.dn @@ -98,9 +107,9 @@ def main(): for a in attr: value = ent.getValues(a) if isinstance(value,str): - print a + ": " + str(wrap_binary_data(value)).rstrip() + print labels[a] + ": " + str(wrap_binary_data(value)).rstrip() else: - print a + ": " + print labels[a] + ": " for l in value: print "\t" + wrap_binary_data(l) # blank line between results diff --git a/ipa-admintools/ipa-groupmod b/ipa-admintools/ipa-groupmod index 1e07e609f..c7e6e1fa0 100644 --- a/ipa-admintools/ipa-groupmod +++ b/ipa-admintools/ipa-groupmod @@ -67,9 +67,18 @@ def parse_options(): return options, args -def get_group(client, group_cn): +def get_group(client, options, group_cn): try: - group = client.get_entry_by_cn(group_cn) + attrs = ['*'] + + # in case any attributes being modified are operational such as + # nsaccountlock. Any attribute to be deleted needs to be included + # in the original record so it can be seen as being removed. + if options.delattr: + for d in options.delattr: + attrs.append(d) + group = client.get_entry_by_cn(group_cn, sattrs=attrs) + except ipa.ipaerror.IPAError, e: print "%s" % e.message return None @@ -88,7 +97,7 @@ def main(): try: client = ipaclient.IPAClient() if options.add: - group = get_group(client, args[2]) + group = get_group(client, options, args[2]) if group is None: return 1 users = args[1].split(',') @@ -96,7 +105,7 @@ def main(): client.add_user_to_group(user, group.dn) print user + " successfully added to " + args[2] elif options.remove: - group = get_group(client, args[2]) + group = get_group(client, options, args[2]) if group is None: return 1 users = args[1].split(',') @@ -104,7 +113,7 @@ def main(): client.remove_user_from_group(user, group.dn) print user + " successfully removed" else: - group = get_group(client, args[1]) + group = get_group(client, options, args[1]) if group is None: return 1 @@ -113,8 +122,7 @@ def main(): if options.delattr: for d in options.delattr: - # doesn't truly delete the attribute but does null out the value - group.setValue(d, '') + group.delValue(d) if options.setattr: for s in options.setattr: diff --git a/ipa-admintools/ipa-usermod b/ipa-admintools/ipa-usermod index 4623d7448..9ebddd2c6 100644 --- a/ipa-admintools/ipa-usermod +++ b/ipa-admintools/ipa-usermod @@ -91,7 +91,15 @@ def main(): client = ipaclient.IPAClient() try: - user = client.get_user_by_uid(username) + attrs = ['*'] + + # in case any attributes being modified are operational such as + # nsaccountlock. Any attribute to be deleted needs to be included + # in the original record so it can be seen as being removed. + if options.delattr: + for d in options.delattr: + attrs.append(d) + user = client.get_user_by_uid(username, sattrs=attrs) except ipa.ipaerror.exception_for(ipa.ipaerror.LDAP_NOT_FOUND): print "User %s not found" % username return 1 @@ -203,8 +211,7 @@ def main(): if options.delattr: for d in options.delattr: - # doesn't truly delete the attribute but does null out the value - user.setValue(d, '') + user.delValue(d) if options.setattr: for s in options.setattr: diff --git a/ipa-python/ipaclient.py b/ipa-python/ipaclient.py index 659ff995d..f8c70974a 100644 --- a/ipa-python/ipaclient.py +++ b/ipa-python/ipaclient.py @@ -134,10 +134,14 @@ class IPAClient: return all_users - def get_add_schema(self): - """Prototype for the GUI. Specify in the directory fields to - be displayed and what data to get for new users.""" - result = self.transport.get_add_schema() + def get_custom_fields(self): + """Get custom user fields""" + result = self.transport.get_custom_fields() + return result + + def set_custom_fields(self, schema): + """Set custom user fields""" + result = self.transport.set_custom_fields(schema) return result def find_users(self, criteria, sattrs=None, searchlimit=0, timelimit=-1): @@ -331,3 +335,29 @@ class IPAClient: entries.append(user.User(e)) return entries + + def get_ipa_config(self): + """Get the IPA configuration""" + result = self.transport.get_ipa_config() + return entity.Entity(result) + + def update_ipa_config(self, config): + """Updates the IPA configuration. + + config is an Entity object. + """ + result = self.transport.update_ipa_config(config.origDataDict(), config.toDict()) + return result + + def get_password_policy(self): + """Get the IPA password policy""" + result = self.transport.get_password_policy() + return entity.Entity(result) + + def update_password_policy(self, policy): + """Updates the IPA password policy. + + policy is an Entity object. + """ + result = self.transport.update_password_policy(policy.origDataDict(), policy.toDict()) + return result diff --git a/ipa-python/ipaerror.py b/ipa-python/ipaerror.py index f583322e6..5391b3fd4 100644 --- a/ipa-python/ipaerror.py +++ b/ipa-python/ipaerror.py @@ -123,6 +123,11 @@ LDAP_EMPTY_MODLIST = gen_error_code( 0x0006, "No modifications to be performed") +LDAP_NO_CONFIG = gen_error_code( + LDAP_CATEGORY, + 0x0007, + "IPA configuration not found") + # # Input errors (sample - replace me) # diff --git a/ipa-python/rpcclient.py b/ipa-python/rpcclient.py index 871c37254..c4ca2ff3e 100644 --- a/ipa-python/rpcclient.py +++ b/ipa-python/rpcclient.py @@ -218,23 +218,32 @@ class RPCClient: return ipautil.unwrap_binary_data(result) - def get_add_schema(self): - """Get the list of attributes we need to ask when adding a new - user. - """ + def get_custom_fields(self): + """Get custom user fields.""" server = self.setup_server() - # FIXME: Hardcoded and designed for the TurboGears GUI. Do we want - # this for the CLI as well? try: - result = server.get_add_schema() + result = server.get_custom_fields() except xmlrpclib.Fault, fault: raise ipaerror.gen_exception(fault.faultCode, fault.faultString) except socket.error, (value, msg): raise xmlrpclib.Fault(value, msg) return ipautil.unwrap_binary_data(result) - + + def set_custom_fields(self, schema): + """Set custom user fields.""" + server = self.setup_server() + + try: + result = server.set_custom_fields(schema) + except xmlrpclib.Fault, fault: + raise ipaerror.gen_exception(fault.faultCode, fault.faultString) + except socket.error, (value, msg): + raise xmlrpclib.Fault(value, msg) + + return ipautil.unwrap_binary_data(result) + def get_all_users (self): """Return a list containing a User object for each existing user.""" @@ -591,3 +600,51 @@ class RPCClient: raise xmlrpclib.Fault(value, msg) return ipautil.unwrap_binary_data(result) + + def get_ipa_config(self): + """Get the IPA configuration""" + server = self.setup_server() + try: + result = server.get_ipa_config() + except xmlrpclib.Fault, fault: + raise ipaerror.gen_exception(fault.faultCode, fault.faultString) + except socket.error, (value, msg): + raise xmlrpclib.Fault(value, msg) + + return ipautil.unwrap_binary_data(result) + + def update_ipa_config(self, oldconfig, newconfig): + """Update the IPA configuration""" + server = self.setup_server() + try: + result = server.update_ipa_config(oldconfig, newconfig) + except xmlrpclib.Fault, fault: + raise ipaerror.gen_exception(fault.faultCode, fault.faultString) + except socket.error, (value, msg): + raise xmlrpclib.Fault(value, msg) + + return ipautil.unwrap_binary_data(result) + + def get_password_policy(self): + """Get the IPA password policy""" + server = self.setup_server() + try: + result = server.get_password_policy() + except xmlrpclib.Fault, fault: + raise ipaerror.gen_exception(fault.faultCode, fault.faultString) + except socket.error, (value, msg): + raise xmlrpclib.Fault(value, msg) + + return ipautil.unwrap_binary_data(result) + + def update_password_policy(self, oldpolicy, newpolicy): + """Update the IPA password policy""" + server = self.setup_server() + try: + result = server.update_password_policy(oldpolicy, newpolicy) + except xmlrpclib.Fault, fault: + raise ipaerror.gen_exception(fault.faultCode, fault.faultString) + except socket.error, (value, msg): + raise xmlrpclib.Fault(value, msg) + + return ipautil.unwrap_binary_data(result) diff --git a/ipa-server/ipa-gui/ipagui/forms/ipapolicy.py b/ipa-server/ipa-gui/ipagui/forms/ipapolicy.py index 660a34b68..ec0e8c6f8 100644 --- a/ipa-server/ipa-gui/ipagui/forms/ipapolicy.py +++ b/ipa-server/ipa-gui/ipagui/forms/ipapolicy.py @@ -2,25 +2,49 @@ import turbogears from turbogears import validators, widgets class IPAPolicyFields(): - searchlimit = widgets.TextField(name="searchlimit", label="Search Time Limit (sec.)", attrs=dict(size=6,maxlength=6)) - maxuidlength = widgets.TextField(name="maxuidlength", label="Max. UID Length", attrs=dict(size=3,maxlength=3)) - passwordnotif = widgets.TextField(name="passwordnotif", label="Password Expiration Notification (days)", attrs=dict(size=3,maxlength=3)) - homedir = widgets.TextField(name="homedir", label="Root for Home Directories") - defaultshell = widgets.TextField(name="defaultshell", label="Default shell") - defaultgroup = widgets.TextField(name="defaultgroup", label="Default Users group") + # From cn=ipaConfig + ipausersearchfields = widgets.TextField(name="ipausersearchfields", label="User Search Fields") + ipagroupsearchfields = widgets.TextField(name="ipagroupsearchfields", label="Group Search Fields") + ipasearchtimelimit = widgets.TextField(name="ipasearchtimelimit", label="Search Time Limit (sec.)", attrs=dict(size=6,maxlength=6)) + ipasearchrecordslimit = widgets.TextField(name="ipasearchrecordslimit", label="Search Records Limit", attrs=dict(size=6,maxlength=6)) + ipahomesrootdir = widgets.TextField(name="ipahomesrootdir", label="Root for Home Directories") + ipadefaultloginshell = widgets.TextField(name="ipadefaultloginshell", label="Default shell") + 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)) + + ipapolicy_orig = widgets.HiddenField(name="ipapolicy_orig") + + # From cn=accounts + krbmaxpwdlife = widgets.TextField(name="krbmaxpwdlife", label="Max. Password Lifetime", attrs=dict(size=3,maxlength=3)) + krbminpwdlife = widgets.TextField(name="krbminpwdlife", label="Min. Password Lifetime", attrs=dict(size=3,maxlength=3)) + krbpwdmindiffchars = widgets.TextField(name="krbpwdmindiffchars", label="Min. number of character classes", attrs=dict(size=3,maxlength=3)) + krbpwdminlength = widgets.TextField(name="krbpwdminlength", label="Min. Length of password", attrs=dict(size=3,maxlength=3)) + krbpwdhistorylength = widgets.TextField(name="krbpwdhistorylength", label="Password History size", attrs=dict(size=3,maxlength=3)) + + password_orig = widgets.HiddenField(name="password_orig") class IPAPolicyValidator(validators.Schema): - searchlimit = validators.Number(not_empty=True) - maxuidlength = validators.Number(not_empty=True) - passwordnotif = validators.Number(not_empty=True) - homedir = validators.String(not_empty=True) - defaultshell = validators.String(not_empty=True) - defaultgroup = validators.String(not_empty=True) + ipausersearchfields = validators.String(not_empty=True) + ipagroupsearchfields = validators.String(not_empty=True) + ipasearchtimelimit = validators.Number(not_empty=True) + ipasearchrecordslimit = validators.Number(not_empty=True) + ipamaxusernamelength = validators.Number(not_empty=True) + ipapwdexpadvnotify = validators.Number(not_empty=True) + ipahomesrootdir = validators.String(not_empty=True) + ipadefaultloginshell = validators.String(not_empty=True) + ipadefaultprimarygroup = validators.String(not_empty=True) + krbmaxpwdlife = validators.Number(not_empty=True) + krbminpwdlife = validators.Number(not_empty=True) + krbpwdmindiffchars = validators.Number(not_empty=True) + krbpwdminlength = validators.Number(not_empty=True) + krbpwdhistorylength = validators.Number(not_empty=True) class IPAPolicyForm(widgets.Form): params = ['ipapolicy_fields'] hidden_fields = [ + IPAPolicyFields.ipapolicy_orig, IPAPolicyFields.password_orig ] validator = IPAPolicyValidator() diff --git a/ipa-server/ipa-gui/ipagui/subcontrollers/ipapolicy.py b/ipa-server/ipa-gui/ipagui/subcontrollers/ipapolicy.py index 5d9024275..781ca35d4 100644 --- a/ipa-server/ipa-gui/ipagui/subcontrollers/ipapolicy.py +++ b/ipa-server/ipa-gui/ipagui/subcontrollers/ipapolicy.py @@ -15,6 +15,7 @@ from turbogears import identity from ipacontroller import IPAController from ipa.entity import utf8_encode_values from ipa import ipaerror +import ipa.entity import ipagui.forms.ipapolicy import ldap.dn @@ -34,16 +35,14 @@ class IPAPolicyController(IPAController): @identity.require(identity.in_group("admins")) def show(self, tg_errors=None): """Displays the one policy page""" + client = self.get_ipaclient() + config = client.get_ipa_config() + ipapolicy = config.toDict() - # TODO: Get this dict from LDAP - ipapolicy = {} - ipapolicy['searchlimit'] = 2 - ipapolicy['maxuidlength'] = 3 - ipapolicy['passwordnotif'] = 4 - ipapolicy['homedir'] = "/home" - ipapolicy['defaultgroup'] = "ipausers" - ipapolicy['defaultshell'] = "/bin/bash" - return dict(ipapolicy=ipapolicy,fields=ipagui.forms.ipapolicy.IPAPolicyFields()) + ppolicy = client.get_password_policy() + password = ppolicy.toDict() + + return dict(ipapolicy=ipapolicy,password=password,fields=ipagui.forms.ipapolicy.IPAPolicyFields()) @expose("ipagui.templates.ipapolicyedit") @identity.require(identity.in_group("admins")) @@ -54,18 +53,28 @@ class IPAPolicyController(IPAController): "Please see the messages below for details.") try: - # TODO: Get this dict from LDAP - ipapolicy_dict = {} - ipapolicy_dict['searchlimit'] = 2 - ipapolicy_dict['maxuidlength'] = 3 - ipapolicy_dict['passwordnotif'] = 4 - ipapolicy_dict['homedir'] = "/home" - ipapolicy_dict['defaultgroup'] = "ipausers" - ipapolicy_dict['defaultshell'] = "/bin/bash" + client = self.get_ipaclient() + config = client.get_ipa_config() + ipapolicy_dict = config.toDict() + + ppolicy = client.get_password_policy() + password_dict = ppolicy.toDict() + + # store a copy of the original policy for the update later + ipapolicy_data = b64encode(dumps(ipapolicy_dict)) + ipapolicy_dict['ipapolicy_orig'] = ipapolicy_data + + # store a copy of the original policy for the update later + password_data = b64encode(dumps(password_dict)) + password_dict['password_orig'] = password_data + + # Combine the 2 dicts to make the form easier + ipapolicy_dict.update(password_dict) + return dict(form=ipapolicy_edit_form, ipapolicy=ipapolicy_dict) except ipaerror.IPAError, e: turbogears.flash("IPA Policy edit failed: " + str(e) + "
" + str(e.detail)) - raise turbogears.redirect('/group/show', uid=cn) + raise turbogears.redirect('/ipapolicy/show') @expose() @@ -86,16 +95,72 @@ class IPAPolicyController(IPAController): return dict(form=ipapolicy_edit_form, ipapolicy=kw, tg_template='ipagui.templates.ipapolicyedit') - try: + policy_modified = False + password_modified = False - # TODO: Actually save the data + try: + orig_ipapolicy_dict = loads(b64decode(kw.get('ipapolicy_orig'))) + orig_password_dict = loads(b64decode(kw.get('password_orig'))) + + new_ipapolicy = ipa.entity.Entity(orig_ipapolicy_dict) + new_password = ipa.entity.Entity(orig_password_dict) + + if str(new_ipapolicy.ipasearchtimelimit) != str(kw.get('ipasearchtimelimit')): + policy_modified = True + new_ipapolicy.setValue('ipasearchtimelimit', kw.get('ipasearchtimelimit')) + if str(new_ipapolicy.ipasearchrecordslimit) != str(kw.get('ipasearchrecordslimit')): + policy_modified = True + new_ipapolicy.setValue('ipasearchrecordslimit', kw.get('ipasearchrecordslimit')) + if new_ipapolicy.ipausersearchfields != kw.get('ipausersearchfields'): + policy_modified = True + new_ipapolicy.setValue('ipausersearchfields', kw.get('ipausersearchfields')) + if new_ipapolicy.ipagroupsearchfields != kw.get('ipagroupsearchfields'): + policy_modified = True + new_ipapolicy.setValue('ipagroupsearchfields', kw.get('ipagroupsearchfields')) + if str(new_ipapolicy.ipapwdexpadvnotify) != str(kw.get('ipapwdexpadvnotify')): + policy_modified = True + new_ipapolicy.setValue('ipapwdexpadvnotify', kw.get('ipapwdexpadvnotify')) + if str(new_ipapolicy.ipamaxusernamelength) != str(kw.get('ipamaxusernamelength')): + policy_modified = True + new_ipapolicy.setValue('ipamaxusernamelength', kw.get('ipamaxusernamelength')) + if new_ipapolicy.ipahomesrootdir != kw.get('ipahomesrootdir'): + policy_modified = True + new_ipapolicy.setValue('ipahomesrootdir', kw.get('ipahomesrootdir')) + if new_ipapolicy.ipadefaultloginshell != kw.get('ipadefaultloginshell'): + policy_modified = True + new_ipapolicy.setValue('ipadefaultloginshell', kw.get('ipadefaultloginshell')) + if new_ipapolicy.ipadefaultprimarygroup != kw.get('ipadefaultprimarygroup'): + policy_modified = True + new_ipapolicy.setValue('ipadefaultprimarygroup', kw.get('ipadefaultprimarygroup')) + + if policy_modified: + rv = client.update_ipa_config(new_ipapolicy) + + # Now check the password policy for updates + if str(new_password.krbmaxpwdlife) != str(kw.get('krbmaxpwdlife')): + password_modified = True + new_password.setValue('krbmaxpwdlife', str(kw.get('krbmaxpwdlife'))) + if str(new_password.krbminpwdlife) != str(kw.get('krbminpwdlife')): + password_modified = True + new_password.setValue('krbminpwdlife', str(kw.get('krbminpwdlife'))) + if str(new_password.krbpwdhistorylength) != str(kw.get('krbpwdhistorylength')): + password_modified = True + new_password.setValue('krbpwdhistorylength', str(kw.get('krbpwdhistorylength'))) + if str(new_password.krbpwdmindiffchars) != str(kw.get('krbpwdmindiffchars')): + password_modified = True + new_password.setValue('krbpwdmindiffchars', str(kw.get('krbpwdmindiffchars'))) + if str(new_password.krbpwdminlength) != str(kw.get('krbpwdminlength')): + password_modified = True + new_password.setValue('krbpwdminlength', str(kw.get('krbpwdminlength'))) + if password_modified: + rv = client.update_password_policy(new_password) turbogears.flash("IPA Policy updated") raise turbogears.redirect('/ipapolicy/show') - except (SyntaxError, ipaerror.IPAError), e: - turbogears.flash("Policy update failed: " + str(e)) - return dict(form=policy_form, policy=kw, - tg_template='ipagui.templates.policyindex') + except ipaerror.IPAError, e: + turbogears.flash("Policy update failed: " + str(e) + e.detail[0]['desc']) + return dict(form=ipapolicy_edit_form, ipapolicy=kw, + tg_template='ipagui.templates.ipapolicyedit') @validate(form=ipapolicy_edit_form) @identity.require(identity.not_anonymous()) diff --git a/ipa-server/ipa-gui/ipagui/subcontrollers/user.py b/ipa-server/ipa-gui/ipagui/subcontrollers/user.py index 290ad25cb..579379c43 100644 --- a/ipa-server/ipa-gui/ipagui/subcontrollers/user.py +++ b/ipa-server/ipa-gui/ipagui/subcontrollers/user.py @@ -34,26 +34,48 @@ class UserController(IPAController): def __init__(self, *args, **kw): super(UserController,self).__init__(*args, **kw) - self.load_custom_fields() +# self.load_custom_fields() def load_custom_fields(self): - # client = self.get_ipaclient() - # schema = client.get_user_custom_schema() - schema = [ - { 'label': 'See Also', - 'field': 'seeAlso', - 'required': 'true', } , - { 'label': 'O O O', - 'field': 'o', - 'required': 'false', } , - ] + + client = self.get_ipaclient() + schema = client.get_custom_fields() + + # FIXME: Don't load from LDAP every single time it is called + + # FIXME: Is removing the attributes on the fly thread-safe? Do we + # need to lock here? for s in schema: required=False - if (s['required'] == "true"): + if (s['required'].lower() == "true"): required=True field = widgets.TextField(name=s['field'],label=s['label']) validator = validators.String(not_empty=required) + # Don't allow dupes on the new form + try: + for i in range(len(user_new_form.custom_fields)): + if user_new_form.custom_fields[i].name == s['field']: + user_new_form.custom_fields.pop(i) + except: + pass + + # Don't allow dupes on the edit form + try: + for i in range(len(user_edit_form.custom_fields)): + if user_edit_form.custom_fields[i].name == s['field']: + user_edit_form.custom_fields.pop(i) + except: + pass + + # Don't allow dupes in the list of user fields + try: + for i in range(len(ipagui.forms.user.UserFields.custom_fields)): + if ipagui.forms.user.UserFields.custom_fields[i].name == s['field']: + ipagui.forms.user.UserFields.custom_fields.pop(i) + except: + pass + ipagui.forms.user.UserFields.custom_fields.append(field) user_new_form.custom_fields.append(field) user_edit_form.custom_fields.append(field) @@ -99,6 +121,7 @@ class UserController(IPAController): @identity.require(identity.in_any_group("admins","editors")) def new(self, tg_errors=None): """Displays the new user form""" + self.load_custom_fields() if tg_errors: turbogears.flash("There were validation errors.
" + "Please see the messages below for details.") @@ -183,7 +206,7 @@ class UserController(IPAController): rv = client.add_user(new_user) except ipaerror.exception_for(ipaerror.LDAP_DUPLICATE): - turbogears.flash("Person with login '%s' already exists" % + turbogears.flash("User with login '%s' already exists" % kw.get('uid')) return dict(form=user_new_form, user=kw, tg_template='ipagui.templates.usernew') @@ -219,7 +242,7 @@ class UserController(IPAController): try: client.modifyPassword(user_dict['krbprincipalname'], "", kw.get('userpassword')) except ipaerror.IPAError, e: - message = "Person successfully created.
" + message = "User successfully created.
" message += "There was an error setting the password.
" turbogears.flash(message) return dict(form=user_edit_form, user=user_dict, @@ -242,7 +265,7 @@ class UserController(IPAController): failed_adds = dnadds if len(failed_adds) > 0: - message = "Person successfully created.
" + message = "User successfully created.
" message += "There was an error adding groups.
" message += "Failures have been preserved in the add/remove lists." turbogears.flash(message) @@ -281,6 +304,7 @@ class UserController(IPAController): @identity.require(identity.not_anonymous()) def edit(self, uid=None, principal=None, tg_errors=None): """Displays the edit user form""" + self.load_custom_fields() if tg_errors: turbogears.flash("There were validation errors.
" + "Please see the messages below for details.") @@ -581,6 +605,7 @@ class UserController(IPAController): def show(self, uid): """Retrieve a single user for display""" client = self.get_ipaclient() + self.load_custom_fields() try: user = client.get_user_by_uid(uid, user_fields) diff --git a/ipa-server/ipa-gui/ipagui/templates/ipapolicyeditform.kid b/ipa-server/ipa-gui/ipagui/templates/ipapolicyeditform.kid index bcdef8c27..106657636 100644 --- a/ipa-server/ipa-gui/ipagui/templates/ipapolicyeditform.kid +++ b/ipa-server/ipa-gui/ipagui/templates/ipapolicyeditform.kid @@ -24,12 +24,42 @@ from ipagui.helpers import ipahelper + + + + + + + + + + + +
- - - + + +
+ + + +
+ + + +
+ + +
@@ -38,56 +68,106 @@ from ipagui.helpers import ipahelper + + + + + + + + + + + + + + + + + + + +
- - - + + +
+ + + +
+ + + +
+ + + +
+ + + +
+ + +
-

Password Policy

+

User Settings

- - - + +
- - - + +
- - - + +
- - - + +
diff --git a/ipa-server/ipa-gui/ipagui/templates/ipapolicyshow.kid b/ipa-server/ipa-gui/ipagui/templates/ipapolicyshow.kid index e14485f2a..089fb494e 100644 --- a/ipa-server/ipa-gui/ipagui/templates/ipapolicyshow.kid +++ b/ipa-server/ipa-gui/ipagui/templates/ipapolicyshow.kid @@ -20,9 +20,27 @@ edit_url = tg.url('/ipapolicy/edit') - + + + + + + + + + + + + +
- ${ipapolicy.get("searchlimit")}${ipapolicy.get("ipasearchtimelimit")}
+ ${ipapolicy.get("ipasearchrecordslimit")}
+ ${ipapolicy.get("ipausersearchfields")}
+ ${ipapolicy.get("ipagroupsearchfields")}
@@ -30,36 +48,66 @@ edit_url = tg.url('/ipapolicy/edit') - + + + + + + + + + + + + + + + + + + + + +
- ${ipapolicy.get("passwordnotif")}${ipapolicy.get("ipapwdexpadvnotify")}
+ ${password.get("krbminpwdlife")}
+ ${password.get("krbmaxpwdlife")}
+ ${password.get("krbpwdmindiffchars")}
+ ${password.get("krbpwdminlength")}
+ ${password.get("krbpwdhistorylength")}

User Settings

- + - + - + - +
- ${ipapolicy.get("maxuidlength")}${ipapolicy.get("ipamaxusernamelength")}
- ${ipapolicy.get("homedir")}${ipapolicy.get("ipahomesrootdir")}
- ${ipapolicy.get("defaultshell")}${ipapolicy.get("ipadefaultloginshell")}
- ${ipapolicy.get("defaultgroup")}${ipapolicy.get("ipadefaultprimarygroup")}

diff --git a/ipa-server/ipa-gui/ipagui/templates/master.kid b/ipa-server/ipa-gui/ipagui/templates/master.kid index 6b97c73fd..12e54fa1d 100644 --- a/ipa-server/ipa-gui/ipagui/templates/master.kid +++ b/ipa-server/ipa-gui/ipagui/templates/master.kid @@ -70,8 +70,8 @@ -

Edit Person

+

Edit User

+ value="Update User"/> @@ -847,11 +847,11 @@ from ipagui.helpers import ipahelper
+ value="Update User"/> diff --git a/ipa-server/ipa-gui/ipagui/templates/userlayout.kid b/ipa-server/ipa-gui/ipagui/templates/userlayout.kid index bbeb81399..c4e8104e6 100644 --- a/ipa-server/ipa-gui/ipagui/templates/userlayout.kid +++ b/ipa-server/ipa-gui/ipagui/templates/userlayout.kid @@ -15,8 +15,8 @@ diff --git a/ipa-server/ipa-gui/ipagui/templates/userlist.kid b/ipa-server/ipa-gui/ipagui/templates/userlist.kid index fdeeb3169..9ca3753d0 100644 --- a/ipa-server/ipa-gui/ipagui/templates/userlist.kid +++ b/ipa-server/ipa-gui/ipagui/templates/userlist.kid @@ -3,15 +3,15 @@ py:extends="'userlayout.kid'"> -Find People +Find Users -

Find People

+

Find Users