summaryrefslogtreecommitdiffstats
path: root/ipa-server
diff options
context:
space:
mode:
authorSimo Sorce <ssorce@redhat.com>2007-11-18 14:27:25 -0500
committerSimo Sorce <ssorce@redhat.com>2007-11-18 14:27:25 -0500
commitd5c269c8ebf21281348f69840bf60259bbd37cbf (patch)
treed06d52e06e82d9f57874576705960fa32f728085 /ipa-server
parentb51f4b28ec86360d27cfb6f529a8e2def500e91f (diff)
parentde5a54ef75473764b91e9e69cbe82c35fac89028 (diff)
downloadfreeipa-d5c269c8ebf21281348f69840bf60259bbd37cbf.tar.gz
freeipa-d5c269c8ebf21281348f69840bf60259bbd37cbf.tar.xz
freeipa-d5c269c8ebf21281348f69840bf60259bbd37cbf.zip
Merge upstream and fix bad suffix in default-aci
Diffstat (limited to 'ipa-server')
-rw-r--r--ipa-server/ipa-gui/ipagui/forms/ipapolicy.py48
-rw-r--r--ipa-server/ipa-gui/ipagui/subcontrollers/ipapolicy.py113
-rw-r--r--ipa-server/ipa-gui/ipagui/subcontrollers/user.py55
-rw-r--r--ipa-server/ipa-gui/ipagui/templates/ipapolicyeditform.kid130
-rw-r--r--ipa-server/ipa-gui/ipagui/templates/ipapolicyshow.kid72
-rw-r--r--ipa-server/ipa-gui/ipagui/templates/master.kid4
-rw-r--r--ipa-server/ipa-gui/ipagui/templates/useredit.kid4
-rw-r--r--ipa-server/ipa-gui/ipagui/templates/usereditform.kid8
-rw-r--r--ipa-server/ipa-gui/ipagui/templates/userlayout.kid4
-rw-r--r--ipa-server/ipa-gui/ipagui/templates/userlist.kid8
-rw-r--r--ipa-server/ipa-gui/ipagui/templates/usernew.kid4
-rw-r--r--ipa-server/ipa-gui/ipagui/templates/usernewform.kid4
-rw-r--r--ipa-server/ipa-gui/ipagui/templates/usershow.kid10
-rw-r--r--ipa-server/ipa-install/share/bootstrap-template.ldif21
-rw-r--r--ipa-server/ipa-install/share/default-aci.ldif11
-rw-r--r--ipa-server/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c2
-rw-r--r--ipa-server/xmlrpc-server/funcs.py195
-rw-r--r--ipa-server/xmlrpc-server/ipaxmlrpc.py7
18 files changed, 532 insertions, 168 deletions
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()
+
+ ppolicy = client.get_password_policy()
+ password = ppolicy.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())
+ 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) + "<br/>" + 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.<br/>" +
"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.<br />"
+ message = "User successfully created.<br />"
message += "There was an error setting the password.<br />"
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.<br />"
+ message = "User successfully created.<br />"
message += "There was an error adding groups.<br />"
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.<br/>" +
"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
<table class="formtable" cellpadding="2" cellspacing="0" border="0">
<tr>
<th>
- <label class="fieldlabel" py:content="ipapolicy_fields.searchlimit.label" />:
+ <label class="fieldlabel" py:content="ipapolicy_fields.ipasearchtimelimit.label" />:
</th>
<td>
- <span py:replace="ipapolicy_fields.searchlimit.display(value_for(ipapolicy_fields.searchlimit))" />
- <span py:if="tg.errors.get('searchlimit')" class="fielderror"
- py:content="tg.errors.get('searchlimit')" />
+ <span py:replace="ipapolicy_fields.ipasearchtimelimit.display(value_for(ipapolicy_fields.ipasearchtimelimit))" />
+ <span py:if="tg.errors.get('ipasearchtimelimit')" class="fielderror"
+ py:content="tg.errors.get('ipasearchtimelimit')" />
+ </td>
+ </tr>
+ <tr>
+ <th>
+ <label class="fieldlabel" py:content="ipapolicy_fields.ipasearchrecordslimit.label" />:
+ </th>
+ <td>
+ <span py:replace="ipapolicy_fields.ipasearchrecordslimit.display(value_for(ipapolicy_fields.ipasearchrecordslimit))" />
+ <span py:if="tg.errors.get('ipasearchrecordslimit')" class="fielderror"
+ py:content="tg.errors.get('ipasearchrecordslimit')" />
+ </td>
+ </tr>
+ <tr>
+ <th>
+ <label class="fieldlabel" py:content="ipapolicy_fields.ipausersearchfields.label" />:
+ </th>
+ <td>
+ <span py:replace="ipapolicy_fields.ipausersearchfields.display(value_for(ipapolicy_fields.ipausersearchfields))" />
+ <span py:if="tg.errors.get('ipausersearchfields')" class="fielderror"
+ py:content="tg.errors.get('ipausersearchfields')" />
+ </td>
+ </tr>
+ <tr>
+ <th>
+ <label class="fieldlabel" py:content="ipapolicy_fields.ipagroupsearchfields.label" />:
+ </th>
+ <td>
+ <span py:replace="ipapolicy_fields.ipagroupsearchfields.display(value_for(ipapolicy_fields.ipagroupsearchfields))" />
+ <span py:if="tg.errors.get('ipagroupsearchfields')" class="fielderror"
+ py:content="tg.errors.get('ipagroupsearchfields')" />
</td>
</tr>
</table>
@@ -38,56 +68,106 @@ from ipagui.helpers import ipahelper
<table class="formtable" cellpadding="2" cellspacing="0" border="0">
<tr>
<th>
- <label class="fieldlabel" py:content="ipapolicy_fields.passwordnotif.label" />:
+ <label class="fieldlabel" py:content="ipapolicy_fields.ipapwdexpadvnotify.label" />:
+ </th>
+ <td>
+ <span py:replace="ipapolicy_fields.ipapwdexpadvnotify.display(value_for(ipapolicy_fields.ipapwdexpadvnotify))" />
+ <span py:if="tg.errors.get('ipapwdexpadvnotify')" class="fielderror"
+ py:content="tg.errors.get('ipapwdexpadvnotify')" />
+ </td>
+ </tr>
+ <tr>
+ <th>
+ <label class="fieldlabel" py:content="ipapolicy_fields.krbminpwdlife.label" />:
</th>
<td>
- <span py:replace="ipapolicy_fields.passwordnotif.display(value_for(ipapolicy_fields.passwordnotif))" />
- <span py:if="tg.errors.get('passwordnotif')" class="fielderror"
- py:content="tg.errors.get('passwordnotif')" />
+ <span py:replace="ipapolicy_fields.krbminpwdlife.display(value_for(ipapolicy_fields.krbminpwdlife))" />
+ <span py:if="tg.errors.get('krbminpwdlife')" class="fielderror"
+ py:content="tg.errors.get('krbminpwdlife')" />
+ </td>
+ </tr>
+ <tr>
+ <th>
+ <label class="fieldlabel" py:content="ipapolicy_fields.krbmaxpwdlife.label" />:
+ </th>
+ <td>
+ <span py:replace="ipapolicy_fields.krbmaxpwdlife.display(value_for(ipapolicy_fields.krbmaxpwdlife))" />
+ <span py:if="tg.errors.get('krbmaxpwdlife')" class="fielderror"
+ py:content="tg.errors.get('krbmaxpwdlife')" />
+ </td>
+ </tr>
+ <tr>
+ <th>
+ <label class="fieldlabel" py:content="ipapolicy_fields.krbpwdmindiffchars.label" />:
+ </th>
+ <td>
+ <span py:replace="ipapolicy_fields.krbpwdmindiffchars.display(value_for(ipapolicy_fields.krbpwdmindiffchars))" />
+ <span py:if="tg.errors.get('krbpwdmindiffchars')" class="fielderror"
+ py:content="tg.errors.get('krbpwdmindiffchars')" />
+ </td>
+ </tr>
+ <tr>
+ <th>
+ <label class="fieldlabel" py:content="ipapolicy_fields.krbpwdminlength.label" />:
+ </th>
+ <td>
+ <span py:replace="ipapolicy_fields.krbpwdminlength.display(value_for(ipapolicy_fields.krbpwdminlength))" />
+ <span py:if="tg.errors.get('krbpwdminlength')" class="fielderror"
+ py:content="tg.errors.get('krbpwdminlength')" />
+ </td>
+ </tr>
+ <tr>
+ <th>
+ <label class="fieldlabel" py:content="ipapolicy_fields.krbpwdhistorylength.label" />:
+ </th>
+ <td>
+ <span py:replace="ipapolicy_fields.krbpwdhistorylength.display(value_for(ipapolicy_fields.krbpwdhistorylength))" />
+ <span py:if="tg.errors.get('krbpwdhistorylength')" class="fielderror"
+ py:content="tg.errors.get('krbpwdhistorylength')" />
</td>
</tr>
</table>
- <h2 class="formsection">Password Policy</h2>
+ <h2 class="formsection">User Settings</h2>
<table class="formtable" cellpadding="2" cellspacing="0" border="0">
<tr>
<th>
- <label class="fieldlabel" py:content="ipapolicy_fields.maxuidlength.label" />:
+ <label class="fieldlabel" py:content="ipapolicy_fields.ipamaxusernamelength.label" />:
</th>
<td>
- <span py:replace="ipapolicy_fields.maxuidlength.display(value_for(ipapolicy_fields.maxuidlength))" />
- <span py:if="tg.errors.get('maxuidlength')" class="fielderror"
- py:content="tg.errors.get('maxuidlength')" />
+ <span py:replace="ipapolicy_fields.ipamaxusernamelength.display(value_for(ipapolicy_fields.ipamaxusernamelength))" />
+ <span py:if="tg.errors.get('ipamaxusernamelength')" class="fielderror"
+ py:content="tg.errors.get('ipamaxusernamelength')" />
</td>
</tr>
<tr>
<th>
- <label class="fieldlabel" py:content="ipapolicy_fields.homedir.label" />:
+ <label class="fieldlabel" py:content="ipapolicy_fields.ipahomesrootdir.label" />:
</th>
<td>
- <span py:replace="ipapolicy_fields.homedir.display(value_for(ipapolicy_fields.homedir))" />
- <span py:if="tg.errors.get('homedir')" class="fielderror"
- py:content="tg.errors.get('homedir')" />
+ <span py:replace="ipapolicy_fields.ipahomesrootdir.display(value_for(ipapolicy_fields.ipahomesrootdir))" />
+ <span py:if="tg.errors.get('ipahomesrootdir')" class="fielderror"
+ py:content="tg.errors.get('ipahomesrootdir')" />
</td>
</tr>
<tr>
<th>
- <label class="fieldlabel" py:content="ipapolicy_fields.defaultshell.label" />:
+ <label class="fieldlabel" py:content="ipapolicy_fields.ipadefaultloginshell.label" />:
</th>
<td>
- <span py:replace="ipapolicy_fields.defaultshell.display(value_for(ipapolicy_fields.defaultshell))" />
- <span py:if="tg.errors.get('defaultshell')" class="fielderror"
- py:content="tg.errors.get('defaultshell')" />
+ <span py:replace="ipapolicy_fields.ipadefaultloginshell.display(value_for(ipapolicy_fields.ipadefaultloginshell))" />
+ <span py:if="tg.errors.get('ipadefaultloginshell')" class="fielderror"
+ py:content="tg.errors.get('ipadefaultloginshell')" />
</td>
</tr>
<tr>
<th>
- <label class="fieldlabel" py:content="ipapolicy_fields.defaultgroup.label" />:
+ <label class="fieldlabel" py:content="ipapolicy_fields.ipadefaultprimarygroup.label" />:
</th>
<td>
- <span py:replace="ipapolicy_fields.defaultgroup.display(value_for(ipapolicy_fields.defaultgroup))" />
- <span py:if="tg.errors.get('defaultgroup')" class="fielderror"
- py:content="tg.errors.get('defaultgroup')" />
+ <span py:replace="ipapolicy_fields.ipadefaultprimarygroup.display(value_for(ipapolicy_fields.ipadefaultprimarygroup))" />
+ <span py:if="tg.errors.get('ipadefaultprimarygroup')" class="fielderror"
+ py:content="tg.errors.get('ipadefaultprimarygroup')" />
</td>
</tr>
</table>
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')
<table class="formtable" cellpadding="2" cellspacing="0" border="0">
<tr>
<th>
- <label class="fieldlabel" py:content="fields.searchlimit.label" />:
+ <label class="fieldlabel" py:content="fields.ipasearchtimelimit.label" />:
</th>
- <td>${ipapolicy.get("searchlimit")}</td>
+ <td>${ipapolicy.get("ipasearchtimelimit")}</td>
+ </tr>
+ <tr>
+ <th>
+ <label class="fieldlabel" py:content="fields.ipasearchrecordslimit.label" />:
+ </th>
+ <td>${ipapolicy.get("ipasearchrecordslimit")}</td>
+ </tr>
+ <tr>
+ <th>
+ <label class="fieldlabel" py:content="fields.ipausersearchfields.label" />:
+ </th>
+ <td>${ipapolicy.get("ipausersearchfields")}</td>
+ </tr>
+ <tr>
+ <th>
+ <label class="fieldlabel" py:content="fields.ipagroupsearchfields.label" />:
+ </th>
+ <td>${ipapolicy.get("ipagroupsearchfields")}</td>
</tr>
</table>
@@ -30,36 +48,66 @@ edit_url = tg.url('/ipapolicy/edit')
<table class="formtable" cellpadding="2" cellspacing="0" border="0">
<tr>
<th>
- <label class="fieldlabel" py:content="fields.passwordnotif.label" />:
+ <label class="fieldlabel" py:content="fields.ipapwdexpadvnotify.label" />:
+ </th>
+ <td>${ipapolicy.get("ipapwdexpadvnotify")}</td>
+ </tr>
+ <tr>
+ <th>
+ <label class="fieldlabel" py:content="fields.krbminpwdlife.label" />:
+ </th>
+ <td>${password.get("krbminpwdlife")}</td>
+ </tr>
+ <tr>
+ <th>
+ <label class="fieldlabel" py:content="fields.krbmaxpwdlife.label" />:
+ </th>
+ <td>${password.get("krbmaxpwdlife")}</td>
+ </tr>
+ <tr>
+ <th>
+ <label class="fieldlabel" py:content="fields.krbpwdmindiffchars.label" />:
+ </th>
+ <td>${password.get("krbpwdmindiffchars")}</td>
+ </tr>
+ <tr>
+ <th>
+ <label class="fieldlabel" py:content="fields.krbpwdminlength.label" />:
+ </th>
+ <td>${password.get("krbpwdminlength")}</td>
+ </tr>
+ <tr>
+ <th>
+ <label class="fieldlabel" py:content="fields.krbpwdhistorylength.label" />:
</th>
- <td>${ipapolicy.get("passwordnotif")}</td>
+ <td>${password.get("krbpwdhistorylength")}</td>
</tr>
</table>
<h2 class="formsection">User Settings</h2>
<table class="formtable" cellpadding="2" cellspacing="0" border="0">
<tr>
<th>
- <label class="fieldlabel" py:content="fields.maxuidlength.label" />:
+ <label class="fieldlabel" py:content="fields.ipamaxusernamelength.label" />:
</th>
- <td>${ipapolicy.get("maxuidlength")}</td>
+ <td>${ipapolicy.get("ipamaxusernamelength")}</td>
</tr>
<tr>
<th>
- <label class="fieldlabel" py:content="fields.homedir.label" />:
+ <label class="fieldlabel" py:content="fields.ipahomesrootdir.label" />:
</th>
- <td>${ipapolicy.get("homedir")}</td>
+ <td>${ipapolicy.get("ipahomesrootdir")}</td>
</tr>
<tr>
<th>
- <label class="fieldlabel" py:content="fields.defaultshell.label" />:
+ <label class="fieldlabel" py:content="fields.ipadefaultloginshell.label" />:
</th>
- <td>${ipapolicy.get("defaultshell")}</td>
+ <td>${ipapolicy.get("ipadefaultloginshell")}</td>
</tr>
<tr>
<th>
- <label class="fieldlabel" py:content="fields.defaultgroup.label" />:
+ <label class="fieldlabel" py:content="fields.ipadefaultprimarygroup.label" />:
</th>
- <td>${ipapolicy.get("defaultgroup")}</td>
+ <td>${ipapolicy.get("ipadefaultprimarygroup")}</td>
</tr>
</table>
<hr />
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 @@
<div id="sidebar">
<h2>Tasks</h2>
<ul>
- <li py:if="'admins' in tg.identity.groups"><a href="${tg.url('/user/new')}">Add Person</a></li>
- <li><a href="${tg.url('/user/list')}">Find People</a></li>
+ <li py:if="'admins' in tg.identity.groups"><a href="${tg.url('/user/new')}">Add User</a></li>
+ <li><a href="${tg.url('/user/list')}">Find Users</a></li>
</ul>
<ul>
<li py:if="'admins' in tg.identity.groups"><a href="${tg.url('/group/new')}">Add Group</a></li>
diff --git a/ipa-server/ipa-gui/ipagui/templates/useredit.kid b/ipa-server/ipa-gui/ipagui/templates/useredit.kid
index 3f9482a3d..f5cb1b02e 100644
--- a/ipa-server/ipa-gui/ipagui/templates/useredit.kid
+++ b/ipa-server/ipa-gui/ipagui/templates/useredit.kid
@@ -3,7 +3,7 @@
py:extends="'userlayout.kid'">
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" py:replace="''"/>
-<title>Edit Person</title>
+<title>Edit User</title>
</head>
<body>
@@ -14,7 +14,7 @@
<span class="small">edit protected fields</span>
</input>
</div>
- <h1>Edit Person</h1>
+ <h1>Edit User</h1>
</div>
<?python
diff --git a/ipa-server/ipa-gui/ipagui/templates/usereditform.kid b/ipa-server/ipa-gui/ipagui/templates/usereditform.kid
index 5afb0d055..c95b36e39 100644
--- a/ipa-server/ipa-gui/ipagui/templates/usereditform.kid
+++ b/ipa-server/ipa-gui/ipagui/templates/usereditform.kid
@@ -10,11 +10,11 @@
onsubmit="preSubmit()">
<input type="submit" class="submitbutton" name="submit"
- value="Update Person"/>
+ value="Update User"/>
<input type="submit" class="submitbutton" name="submit"
value="Cancel Edit" />
<input type="button" class="submitbutton"
- value="Delete Person"
+ value="Delete User"
onclick="return confirmDelete();"
/>
@@ -847,11 +847,11 @@ from ipagui.helpers import ipahelper
<hr/>
<input type="submit" class="submitbutton" name="submit"
- value="Update Person"/>
+ value="Update User"/>
<input type="submit" class="submitbutton" name="submit"
value="Cancel Edit" />
<input type="button" class="submitbutton"
- value="Delete Person"
+ value="Delete User"
onclick="return confirmDelete();"
/>
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 @@
<!-- <div id="sidebar">
<h2>Tools</h2>
- <a href="${tg.url('/user/new')}">Add Person</a><br/>
- <a href="${tg.url('/user/list')}">Find People</a><br/>
+ <a href="${tg.url('/user/new')}">Add User</a><br/>
+ <a href="${tg.url('/user/list')}">Find Users</a><br/>
</div> -->
</div>
</body>
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'">
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" py:replace="''"/>
-<title>Find People</title>
+<title>Find Users</title>
</head>
<body>
- <h1>Find People</h1>
+ <h1>Find Users</h1>
<script type="text/javascript" charset="utf-8" src="${tg.url('/static/javascript/tablekit.js')}"></script>
<div id="search">
<form action="${tg.url('/user/list')}" method="get">
<input id="uid" type="text" name="uid" value="${uid}" />
- <input class="searchbutton" type="submit" value="Find People"/>
+ <input class="searchbutton" type="submit" value="Find Users"/>
</form>
<script type="text/javascript">
document.getElementById("uid").focus();
@@ -23,7 +23,7 @@
<thead>
<tr>
<th>
- Person
+ User
</th>
<th>
Phone
diff --git a/ipa-server/ipa-gui/ipagui/templates/usernew.kid b/ipa-server/ipa-gui/ipagui/templates/usernew.kid
index 16f0e66b9..b740bca22 100644
--- a/ipa-server/ipa-gui/ipagui/templates/usernew.kid
+++ b/ipa-server/ipa-gui/ipagui/templates/usernew.kid
@@ -3,10 +3,10 @@
py:extends="'userlayout.kid'">
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" py:replace="''"/>
- <title>Add Person</title>
+ <title>Add User</title>
</head>
<body>
- <h1>Add Person</h1>
+ <h1>Add User</h1>
${form.display(action=tg.url("/user/create"), value=user)}
</body>
diff --git a/ipa-server/ipa-gui/ipagui/templates/usernewform.kid b/ipa-server/ipa-gui/ipagui/templates/usernewform.kid
index 51d1711e7..97be52732 100644
--- a/ipa-server/ipa-gui/ipagui/templates/usernewform.kid
+++ b/ipa-server/ipa-gui/ipagui/templates/usernewform.kid
@@ -3,7 +3,7 @@
<form action="${action}" name="${name}" method="${method}" class="tableform"
onsubmit="preSubmit()">
-<input type="submit" class="submitbutton" name="submit" value="Add Person"/>
+<input type="submit" class="submitbutton" name="submit" value="Add User"/>
<?python
from ipagui.helpers import ipahelper
@@ -786,7 +786,7 @@ from ipagui.helpers import ipahelper
</div>
<hr />
-<input type="submit" class="submitbutton" name="submit" value="Add Person"/>
+<input type="submit" class="submitbutton" name="submit" value="Add User"/>
</form>
diff --git a/ipa-server/ipa-gui/ipagui/templates/usershow.kid b/ipa-server/ipa-gui/ipagui/templates/usershow.kid
index 65c2bc35c..8cc356b89 100644
--- a/ipa-server/ipa-gui/ipagui/templates/usershow.kid
+++ b/ipa-server/ipa-gui/ipagui/templates/usershow.kid
@@ -3,18 +3,18 @@
py:extends="'userlayout.kid'">
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" py:replace="''"/>
- <title>View Person</title>
+ <title>View User</title>
</head>
<body>
<?python
edit_url = tg.url('/user/edit', uid=user.get('uid'))
?>
- <h1>View Person</h1>
+ <h1>View User</h1>
<input py:if="'editors' in tg.identity.groups or 'admins' in tg.identity.groups"
class="submitbutton" type="button"
onclick="document.location.href='${edit_url}'"
- value="Edit Person" />
+ value="Edit User" />
<?python
from ipagui.helpers import userhelper
@@ -345,7 +345,7 @@ else:
</table>
<div py:if='len(fields.custom_fields) &gt; 0'>
- <div class="formsection" >Custom Fields</div>
+ <h2 class="formsection">Custom Fields</h2>
<table class="formtable" cellpadding="2" cellspacing="0" border="0">
<tr py:for='custom_field in fields.custom_fields'>
<th>
@@ -377,6 +377,6 @@ else:
<input py:if="'editors' in tg.identity.groups or 'admins' in tg.identity.groups"
class="submitbutton" type="button"
onclick="document.location.href='${edit_url}'"
- value="Edit Person" />
+ value="Edit User" />
</body>
</html>
diff --git a/ipa-server/ipa-install/share/bootstrap-template.ldif b/ipa-server/ipa-install/share/bootstrap-template.ldif
index 8eb42b332..30f6fe8a0 100644
--- a/ipa-server/ipa-install/share/bootstrap-template.ldif
+++ b/ipa-server/ipa-install/share/bootstrap-template.ldif
@@ -9,6 +9,11 @@ changetype: add
objectClass: top
objectClass: nsContainer
cn: accounts
+krbMinPwdLife: 3600
+krbPwdMinDiffChars: 0
+krbPwdMinLength: 8
+krbPwdHistoryLength: 0
+krbMaxPwdLife: 864000
dn: cn=users,cn=accounts,$SUFFIX
changetype: add
@@ -95,3 +100,19 @@ objectClass: posixGroup
gidNumber: 1003
description: Limited admins who can edit other users
cn: editors
+
+dn: cn=ipaConfig,cn=etc,dc=greyoak,dc=com
+changetype: add
+objectClass: nsContainer
+objectClass: top
+objectClass: ipaGuiConfig
+ipaUserSearchFields: uid,givenName,sn,telephoneNumber,ou,title
+ipaGroupSearchFields: cn,description
+ipaSearchTimeLimit: 2
+ipaSearchRecordsLimit: 0
+ipaCustomFields:
+ipaHomesRootDir: /home
+ipaDefaultLoginShell: /bin/sh
+ipaDefaultPrimaryGroup: ipausers
+ipaMaxUsernameLength: 8
+ipaPwdExpAdvNotify: 4
diff --git a/ipa-server/ipa-install/share/default-aci.ldif b/ipa-server/ipa-install/share/default-aci.ldif
index 8d3182191..29792ea9a 100644
--- a/ipa-server/ipa-install/share/default-aci.ldif
+++ b/ipa-server/ipa-install/share/default-aci.ldif
@@ -9,3 +9,14 @@ aci: (targetattr="krbLastSuccessfulAuth || krbLastFailedAuth || krbLoginFailedCo
aci: (targetattr="userPassword || krbPrincipalKey ||sambaLMPassword || sambaNTPassword || krbPasswordExpiration || krbPwdHistory || krbLastPwdChange")(version 3.0; acl "Kpasswd access to passowrd hashes for passowrd changes"; allow (read, write) userdn="ldap:///krbprincipalname=kadmin/changepw@$REALM,cn=$REALM,cn=kerberos,$SUFFIX";)
aci: (targetfilter="(|(objectClass=person)(objectClass=krbPrincipalAux)(objectClass=posixAccount)(objectClass=groupOfUniqueNames)(objectClass=posixGroup))")(targetattr="*")(version 3.0; acl "Account Admins can manage Users and Groups"; allow (add,delete,read,write) groupdn="ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";)
aci: (targetattr = "givenName || sn || cn || displayName || initials || loginShell || homePhone || mobile || pager || facsimileTelephoneNumber || telephoneNumber || street || roomNumber || l || st || postalCode || manager || description || carLicense || labeledURI || inetUserHTTPURL || seeAlso || userPassword")(version 3.0;acl "Self service";allow (write) userdn="ldap:///self";)
+
+dn: cn=ipaConfig,cn=etc,$SUFFIX
+changetype: modify
+add: aci
+aci: (targetattr = "ipaUserSearchFields || ipaGroupSearchFields || ipaSearchTimeLimit || ipaSearchRecordsLimit || ipaCustomFields || ipaHomesRootDir || ipaDefaultLoginShell || ipaDefaultPrimaryGroup || ipaMaxUsernameLength || ipaPwdExpAdvNotify")(version 3.0;acl "Admins can write IPA policy"; allow (write) groupdn="ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";)
+replace: aci
+
+dn: cn=accounts,$SUFFIX
+changetype: modify
+add: aci
+aci: (targetattr = "krbMaxPwdLife || krbMinPwdLife || krbPwdMinDiffChars || krbPwdMinLength || krbPwdHistoryLength")(version 3.0;acl "Admins can write password policy"; allow (write) groupdn="ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";)
diff --git a/ipa-server/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c b/ipa-server/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c
index 988b0a32e..c629e018b 100644
--- a/ipa-server/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c
+++ b/ipa-server/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c
@@ -263,7 +263,7 @@ static Slapi_Value **encrypt_encode_key(krb5_context krbctx, struct ipapwd_data
kbvals = (struct kbvals *)calloc(count, sizeof(struct kbvals));
}
n = 0;
- for (i = 0i, idx = 0; count > 0 && i < count; i++) {
+ for (i = 0, idx = 0; count > 0 && i < count; i++) {
if (i == 0) {
idx = slapi_valueset_first_value(svs, &sv);
} else {
diff --git a/ipa-server/xmlrpc-server/funcs.py b/ipa-server/xmlrpc-server/funcs.py
index 82c84855e..85d22993a 100644
--- a/ipa-server/xmlrpc-server/funcs.py
+++ b/ipa-server/xmlrpc-server/funcs.py
@@ -30,6 +30,7 @@ import xmlrpclib
import copy
import attrs
from ipa import ipaerror
+from urllib import quote,unquote
import string
from types import *
@@ -420,17 +421,23 @@ class IPAServer:
# FIXME: This should be dynamic and can include just about anything
+ # Get our configuration
+ config = self.get_ipa_config(opts)
+
# Let us add in some missing attributes
if user.get('homedirectory') is None:
- user['homedirectory'] = '/home/%s' % user.get('uid')
+ user['homedirectory'] = '%s/%s' % (config.get('ipahomesrootdir'), user.get('uid'))
+ user['homedirectory'] = user['homedirectory'].replace('//', '/')
+ user['homedirectory'] = user['homedirectory'].rstrip('/')
+ if user.get('loginshell') is None:
+ user['loginshell'] = config.get('ipadefaultloginshell')
if user.get('gecos') is None:
user['gecos'] = user['uid']
# If uidnumber is blank the the FDS dna_plugin will automatically
# assign the next value. So we don't have to do anything with it.
- # FIXME: put the default group in a config file
- group_dn="cn=%s,%s,%s" % ("ipausers", DefaultGroupContainer, self.basedn)
+ group_dn="cn=%s,%s,%s" % (config.get('ipadefaultprimarygroup'), DefaultGroupContainer, self.basedn)
try:
default_group = self.get_entry_by_dn(group_dn, ['dn','gidNumber'], opts)
if default_group:
@@ -467,50 +474,67 @@ class IPAServer:
self.releaseConnection(conn)
return res
- def get_add_schema (self):
- """Get the list of fields to be used when adding users in the GUI."""
-
- # FIXME: this needs to be pulled from LDAP
- fields = []
-
- field1 = {
- "name": "uid" ,
- "label": "Login:",
- "type": "text",
- "validator": "text",
- "required": "true"
- }
- fields.append(field1)
-
- field1 = {
- "name": "givenName" ,
- "label": "First name:",
- "type": "text",
- "validator": "string",
- "required": "true"
- }
- fields.append(field1)
-
- field1 = {
- "name": "sn" ,
- "label": "Last name:",
- "type": "text",
- "validator": "string",
- "required": "true"
- }
- fields.append(field1)
-
- field1 = {
- "name": "mail" ,
- "label": "E-mail address:",
- "type": "text",
- "validator": "email",
- "required": "false"
- }
- fields.append(field1)
-
- return fields
+ def get_custom_fields (self, opts=None):
+ """Get the list of custom user fields.
+
+ A schema is a list of dict's of the form:
+ label: The label dispayed to the user
+ field: the attribute name
+ required: true/false
+
+ It is displayed to the user in the order of the list.
+ """
+
+ config = self.get_ipa_config(opts)
+
+ fields = config.get('ipacustomfields')
+
+ if fields is None or fields == '':
+ return []
+
+ fl = fields.split('$')
+ schema = []
+ for x in range(len(fl)):
+ vals = fl[x].split(',')
+ if len(vals) != 3:
+ # Raise?
+ print "Invalid field, skipping"
+ d = dict(label=unquote(vals[0]), field=unquote(vals[1]), required=unquote(vals[2]))
+ schema.append(d)
+
+ return schema
+ def set_custom_fields (self, schema, opts=None):
+ """Set the list of custom user fields.
+
+ A schema is a list of dict's of the form:
+ label: The label dispayed to the user
+ field: the attribute name
+ required: true/false
+
+ It is displayed to the user in the order of the list.
+ """
+ config = self.get_ipa_config(opts)
+
+ # The schema is stored as:
+ # label,field,required$label,field,required$...
+ # quote() from urilib is used to ensure that it is easy to unparse
+
+ stored_schema = ""
+ for i in range(len(schema)):
+ entry = schema[i]
+ entry = quote(entry.get('label')) + "," + quote(entry.get('field')) + "," + quote(entry.get('required'))
+
+ if stored_schema != "":
+ stored_schema = stored_schema + "$" + entry
+ else:
+ stored_schema = entry
+
+ new_config = copy.deepcopy(config)
+ new_config['ipacustomfields'] = stored_schema
+
+ return self.update_entry(config, new_config, opts)
+
def get_all_users (self, args=None, opts=None):
"""Return a list containing a User object for each
existing user.
@@ -529,18 +553,21 @@ class IPAServer:
return users
- def find_users (self, criteria, sattrs=None, searchlimit=0, timelimit=-1,
+ def find_users (self, criteria, sattrs=None, searchlimit=-1, timelimit=-1,
opts=None):
"""Returns a list: counter followed by the results.
If the results are truncated, counter will be set to -1."""
- # TODO - retrieve from config
- timelimit = 2
+ config = self.get_ipa_config(opts)
+ if timelimit < 0:
+ timelimit = float(config.get('ipasearchtimelimit'))
+ if searchlimit < 0:
+ searchlimit = float(config.get('ipasearchrecordslimit'))
# Assume the list of fields to search will come from a central
# configuration repository. A good format for that would be
# a comma-separated list of fields
- search_fields_conf_str = "uid,givenName,sn,telephoneNumber,ou,title"
+ search_fields_conf_str = config.get('ipausersearchfields')
search_fields = string.split(search_fields_conf_str, ",")
criteria = self.__safe_filter(criteria)
@@ -763,16 +790,22 @@ class IPAServer:
finally:
self.releaseConnection(conn)
- def find_groups (self, criteria, sattrs=None, searchlimit=0, timelimit=-1,
+ def find_groups (self, criteria, sattrs=None, searchlimit=-1, timelimit=-1,
opts=None):
"""Return a list containing a User object for each
existing group that matches the criteria.
"""
+ config = self.get_ipa_config(opts)
+ if timelimit < 0:
+ timelimit = float(config.get('ipasearchtimelimit'))
+ if searchlimit < 0:
+ searchlimit = float(config.get('ipasearchrecordslimit'))
+
# Assume the list of fields to search will come from a central
# configuration repository. A good format for that would be
# a comma-separated list of fields
- search_fields_conf_str = "cn,description"
+ search_fields_conf_str = config.get('ipagroupsearchfields')
search_fields = string.split(search_fields_conf_str, ",")
criteria = self.__safe_filter(criteria)
@@ -1155,10 +1188,10 @@ class IPAServer:
"""Do a memberOf search of groupdn and return the attributes in
attr_list (an empty list returns everything)."""
- # TODO - retrieve from config
- timelimit = 2
+ config = self.get_ipa_config(opts)
+ timelimit = float(config.get('ipasearchtimelimit'))
- searchlimit = 0
+ searchlimit = float(config.get('ipasearchrecordslimit'))
groupdn = self.__safe_filter(groupdn)
filter = "(memberOf=%s)" % groupdn
@@ -1182,6 +1215,58 @@ class IPAServer:
return entries
+# Configuration support
+ def get_ipa_config(self, opts=None):
+ """Retrieve the IPA configuration"""
+ try:
+ config = self.get_entry_by_cn("ipaconfig", None, opts)
+ except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
+ raise ipaerror.gen_exception(ipaerror.LDAP_NO_CONFIG)
+
+ return config
+
+ def update_ipa_config(self, oldconfig, newconfig, opts=None):
+ """Update the IPA configuration"""
+
+ # The LDAP routines want strings, not ints, so convert a few
+ # things. Otherwise it sees a string -> int conversion as a change.
+ try:
+ newconfig['krbmaxpwdlife'] = str(newconfig.get('krbmaxpwdlife'))
+ newconfig['krbminpwdlife'] = str(newconfig.get('krbminpwdlife'))
+ newconfig['krbpwdmindiffchars'] = str(newconfig.get('krbpwdmindiffchars'))
+ newconfig['krbpwdminlength'] = str(newconfig.get('krbpwdminlength'))
+ newconfig['krbpwdhistorylength'] = str(newconfig.get('krbpwdhistorylength'))
+ except KeyError:
+ # These should all be there but if not, let things proceed
+ pass
+ return self.update_entry(oldconfig, newconfig, opts)
+
+ def get_password_policy(self, opts=None):
+ """Retrieve the IPA password policy"""
+ try:
+ policy = self.get_entry_by_cn("accounts", None, opts)
+ except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
+ raise ipaerror.gen_exception(ipaerror.LDAP_NO_CONFIG)
+
+ return policy
+
+ def update_password_policy(self, oldpolicy, newpolicy, opts=None):
+ """Update the IPA configuration"""
+
+ # The LDAP routines want strings, not ints, so convert a few
+ # things. Otherwise it sees a string -> int conversion as a change.
+ try:
+ newpolicy['krbmaxpwdlife'] = str(newpolicy.get('krbmaxpwdlife'))
+ newpolicy['krbminpwdlife'] = str(newpolicy.get('krbminpwdlife'))
+ newpolicy['krbpwdhistorylength'] = str(newpolicy.get('krbpwdhistorylength'))
+ newpolicy['krbpwdmindiffchars'] = str(newpolicy.get('krbpwdmindiffchars'))
+ newpolicy['krbpwdminlength'] = str(newpolicy.get('krbpwdminlength'))
+ except KeyError:
+ # These should all be there but if not, let things proceed
+ pass
+
+ return self.update_entry(oldpolicy, newpolicy, opts)
+
def ldap_search_escape(match):
"""Escapes out nasty characters from the ldap search.
See RFC 2254."""
diff --git a/ipa-server/xmlrpc-server/ipaxmlrpc.py b/ipa-server/xmlrpc-server/ipaxmlrpc.py
index 86f5fda02..23bdcec1e 100644
--- a/ipa-server/xmlrpc-server/ipaxmlrpc.py
+++ b/ipa-server/xmlrpc-server/ipaxmlrpc.py
@@ -326,7 +326,8 @@ def handler(req, profiling=False):
h.register_function(f.get_user_by_email)
h.register_function(f.get_users_by_manager)
h.register_function(f.add_user)
- h.register_function(f.get_add_schema)
+ h.register_function(f.get_custom_fields)
+ h.register_function(f.set_custom_fields)
h.register_function(f.get_all_users)
h.register_function(f.find_users)
h.register_function(f.update_user)
@@ -351,6 +352,10 @@ def handler(req, profiling=False):
h.register_function(f.delete_group)
h.register_function(f.attrs_to_labels)
h.register_function(f.group_members)
+ h.register_function(f.get_ipa_config)
+ h.register_function(f.update_ipa_config)
+ h.register_function(f.get_password_policy)
+ h.register_function(f.update_password_policy)
h.handle_request(req)
finally:
pass