mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Merge upstream and fix bad suffix in default-aci
This commit is contained in:
commit
d5c269c8eb
@ -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()
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
#
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
|
@ -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) + "<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())
|
||||
|
@ -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)
|
||||
|
@ -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.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.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.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>
|
||||
|
@ -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("passwordnotif")}</td>
|
||||
<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>${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 />
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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();"
|
||||
/>
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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) > 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>
|
||||
|
@ -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
|
||||
|
@ -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";)
|
||||
|
@ -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 {
|
||||
|
@ -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."""
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user