summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRob Crittenden <rcritten@redhat.com>2011-09-16 09:35:48 -0400
committerMartin Kosek <mkosek@redhat.com>2011-09-22 15:41:19 +0200
commita1430dcb2c8e63e3077d00878431c0698944a07d (patch)
tree7843a84ec320eeff7e6951e5eebf9765b76bc11d
parent37836a2e6c07550d504a1075ea5626f160f13342 (diff)
downloadfreeipa-a1430dcb2c8e63e3077d00878431c0698944a07d.tar.gz
freeipa-a1430dcb2c8e63e3077d00878431c0698944a07d.tar.xz
freeipa-a1430dcb2c8e63e3077d00878431c0698944a07d.zip
Normalize uid in user principal to lower-case and do validation
Use same normalization and validation in passwd plugin and add some tests for invalid principals https://fedorahosted.org/freeipa/ticket/1778
-rw-r--r--API.txt6
-rw-r--r--ipalib/plugins/passwd.py11
-rw-r--r--ipalib/plugins/user.py47
-rw-r--r--tests/test_xmlrpc/test_hbactest_plugin.py4
-rw-r--r--tests/test_xmlrpc/test_user_plugin.py62
5 files changed, 114 insertions, 16 deletions
diff --git a/API.txt b/API.txt
index ba573a7a..73652fec 100644
--- a/API.txt
+++ b/API.txt
@@ -1830,7 +1830,7 @@ output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDA
output: Output('value', <type 'unicode'>, "The primary_key value of the entry, e.g. 'jdoe' for a user")
command: passwd
args: 2,0,3
-arg: Str('principal', autofill=True, cli_name='user', create_default=<lambda>, label=Gettext('User name', domain='ipa', localedir=None), primary_key=True)
+arg: Str('principal', validate_principal, autofill=True, cli_name='user', create_default=<lambda>, label=Gettext('User name', domain='ipa', localedir=None), normalizer=<lambda>, primary_key=True)
arg: Password('password', label=Gettext('Password', domain='ipa', localedir=None))
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), 'User-friendly description of action performed')
output: Output('result', <type 'bool'>, 'True means the operation was successful')
@@ -2729,7 +2729,7 @@ option: Str('initials', attribute=True, autofill=True, cli_name='initials', defa
option: Str('homedirectory', attribute=True, cli_name='homedir', default_from=DefaultFrom(<lambda>, 'uid'), label=Gettext('Home directory', domain='ipa', localedir=None), multivalue=False, required=False)
option: Str('gecos', attribute=True, autofill=True, cli_name='gecos', default_from=DefaultFrom(<lambda>, 'givenname', 'sn'), label=Gettext('GECOS field', domain='ipa', localedir=None), multivalue=False, required=False)
option: Str('loginshell', attribute=True, cli_name='shell', default=u'/bin/sh', label=Gettext('Login shell', domain='ipa', localedir=None), multivalue=False, required=False)
-option: Str('krbprincipalname', attribute=True, autofill=True, cli_name='principal', default_from=DefaultFrom(<lambda>, 'uid'), flags=['no_update'], label=Gettext('Kerberos principal', domain='ipa', localedir=None), multivalue=False, required=False)
+option: Str('krbprincipalname', validate_principal, attribute=True, autofill=True, cli_name='principal', default_from=DefaultFrom(<lambda>, 'uid'), flags=['no_update'], label=Gettext('Kerberos principal', domain='ipa', localedir=None), multivalue=False, normalizer=<lambda>, required=False)
option: Str('mail', attribute=True, cli_name='email', label=Gettext('Email address', domain='ipa', localedir=None), multivalue=True, required=False)
option: Password('userpassword', attribute=True, cli_name='password', exclude='webui', label=Gettext('Password', domain='ipa', localedir=None), multivalue=False, required=False)
option: Int('uidnumber', attribute=True, autofill=True, cli_name='uid', default=999, label=Gettext('UID', domain='ipa', localedir=None), minvalue=1, multivalue=False, required=False)
@@ -2786,7 +2786,7 @@ option: Str('initials', attribute=True, autofill=False, cli_name='initials', def
option: Str('homedirectory', attribute=True, autofill=False, cli_name='homedir', default_from=DefaultFrom(<lambda>, 'uid'), label=Gettext('Home directory', domain='ipa', localedir=None), multivalue=False, query=True, required=False)
option: Str('gecos', attribute=True, autofill=False, cli_name='gecos', default_from=DefaultFrom(<lambda>, 'givenname', 'sn'), label=Gettext('GECOS field', domain='ipa', localedir=None), multivalue=False, query=True, required=False)
option: Str('loginshell', attribute=True, autofill=False, cli_name='shell', default=u'/bin/sh', label=Gettext('Login shell', domain='ipa', localedir=None), multivalue=False, query=True, required=False)
-option: Str('krbprincipalname', attribute=True, autofill=False, cli_name='principal', default_from=DefaultFrom(<lambda>, 'uid'), flags=['no_update'], label=Gettext('Kerberos principal', domain='ipa', localedir=None), multivalue=False, query=True, required=False)
+option: Str('krbprincipalname', validate_principal, attribute=True, autofill=False, cli_name='principal', default_from=DefaultFrom(<lambda>, 'uid'), flags=['no_update'], label=Gettext('Kerberos principal', domain='ipa', localedir=None), multivalue=False, normalizer=<lambda>, query=True, required=False)
option: Str('mail', attribute=True, autofill=False, cli_name='email', label=Gettext('Email address', domain='ipa', localedir=None), multivalue=True, query=True, required=False)
option: Password('userpassword', attribute=True, autofill=False, cli_name='password', exclude='webui', label=Gettext('Password', domain='ipa', localedir=None), multivalue=False, query=True, required=False)
option: Int('uidnumber', attribute=True, autofill=False, cli_name='uid', default=999, label=Gettext('UID', domain='ipa', localedir=None), minvalue=1, multivalue=False, query=True, required=False)
diff --git a/ipalib/plugins/passwd.py b/ipalib/plugins/passwd.py
index 901a56f2..b7d82f35 100644
--- a/ipalib/plugins/passwd.py
+++ b/ipalib/plugins/passwd.py
@@ -22,6 +22,7 @@ from ipalib import Command
from ipalib import Str, Password
from ipalib import _
from ipalib import output
+from ipalib.plugins.user import split_principal, validate_principal, normalize_principal
__doc__ = _("""
Set a user's password
@@ -46,12 +47,13 @@ class passwd(Command):
__doc__ = _("Set a user's password.")
takes_args = (
- Str('principal',
+ Str('principal', validate_principal,
cli_name='user',
label=_('User name'),
primary_key=True,
autofill=True,
create_default=lambda **kw: util.get_current_principal(),
+ normalizer=lambda value: normalize_principal(value),
),
Password('password',
label=_('Password'),
@@ -75,13 +77,6 @@ class passwd(Command):
"""
ldap = self.api.Backend.ldap2
- if principal.find('@') != -1:
- principal_parts = principal.split('@')
- if len(principal_parts) > 2:
- raise errors.MalformedUserPrincipal(principal=principal)
- else:
- principal = '%s@%s' % (principal, self.api.env.realm)
-
(dn, entry_attrs) = ldap.find_entry_by_attr(
'krbprincipalname', principal, 'posixaccount', [''],
",".join([api.env.container_user, api.env.basedn])
diff --git a/ipalib/plugins/user.py b/ipalib/plugins/user.py
index 92a026d0..35866d6e 100644
--- a/ipalib/plugins/user.py
+++ b/ipalib/plugins/user.py
@@ -84,6 +84,48 @@ def convert_nsaccountlock(entry_attrs):
nsaccountlock = Bool('temp')
entry_attrs['nsaccountlock'] = nsaccountlock.convert(entry_attrs['nsaccountlock'][0])
+def split_principal(principal):
+ """
+ Split the principal into its components and do some basic validation.
+
+ Automatically append our realm if it wasn't provided.
+ """
+ realm = None
+ parts = principal.split('@')
+ user = parts[0].lower()
+ if len(parts) > 2:
+ raise errors.MalformedUserPrincipal(
+ principal=principal
+ )
+
+ if len(parts) == 2:
+ realm = parts[1].upper()
+ # At some point we'll support multiple realms
+ if realm != api.env.realm:
+ raise errors.RealmMismatch()
+ else:
+ realm = api.env.realm
+
+ return (user, realm)
+
+def validate_principal(ugettext, principal):
+ """
+ All the real work is done in split_principal.
+ """
+ (user, realm) = split_principal(principal)
+ return None
+
+def normalize_principal(principal):
+ """
+ Ensure that the name in the principal is lower-case. The realm is
+ upper-case by convention but it isn't required.
+
+ The principal is validated at this point.
+ """
+ (user, realm) = split_principal(principal)
+ return unicode('%s@%s' % (user, realm))
+
+
class user(LDAPObject):
"""
User object.
@@ -169,12 +211,13 @@ class user(LDAPObject):
label=_('Login shell'),
default=u'/bin/sh',
),
- Str('krbprincipalname?',
+ Str('krbprincipalname?', validate_principal,
cli_name='principal',
label=_('Kerberos principal'),
- default_from=lambda uid: '%s@%s' % (uid, api.env.realm),
+ default_from=lambda uid: '%s@%s' % (uid.lower(), api.env.realm),
autofill=True,
flags=['no_update'],
+ normalizer=lambda value: normalize_principal(value),
),
Str('mail*',
cli_name='email',
diff --git a/tests/test_xmlrpc/test_hbactest_plugin.py b/tests/test_xmlrpc/test_hbactest_plugin.py
index 37e3ad80..7e4607c8 100644
--- a/tests/test_xmlrpc/test_hbactest_plugin.py
+++ b/tests/test_xmlrpc/test_hbactest_plugin.py
@@ -42,9 +42,9 @@ class test_hbactest(XMLRPC_test):
test_user = u'hbacrule_test_user'
test_group = u'hbacrule_test_group'
- test_host = u'hbacrule._test_host'
+ test_host = u'hbacrule.test-host'
test_hostgroup = u'hbacrule_test_hostgroup'
- test_sourcehost = u'hbacrule._test_src_host'
+ test_sourcehost = u'hbacrule.test-src-host'
test_sourcehostgroup = u'hbacrule_test_src_hostgroup'
test_service = u'ssh'
diff --git a/tests/test_xmlrpc/test_user_plugin.py b/tests/test_xmlrpc/test_user_plugin.py
index 9392742e..7a2489ee 100644
--- a/tests/test_xmlrpc/test_user_plugin.py
+++ b/tests/test_xmlrpc/test_user_plugin.py
@@ -466,7 +466,6 @@ class test_user(Declarative):
),
-
dict(
desc='Create %r' % user1,
command=(
@@ -704,4 +703,65 @@ class test_user(Declarative):
),
+ dict(
+ desc='Create user %r with upper-case principal' % user1,
+ command=(
+ 'user_add', [user1], dict(givenname=u'Test', sn=u'User1',
+ krbprincipalname=user1.upper())
+ ),
+ expected=dict(
+ value=user1,
+ summary=u'Added user "tuser1"',
+ result=dict(
+ gecos=[u'Test User1'],
+ givenname=[u'Test'],
+ homedirectory=[u'/home/tuser1'],
+ krbprincipalname=[u'tuser1@' + api.env.realm],
+ loginshell=[u'/bin/sh'],
+ objectclass=objectclasses.user,
+ sn=[u'User1'],
+ uid=[user1],
+ uidnumber=[fuzzy_digits],
+ gidnumber=[fuzzy_digits],
+ displayname=[u'Test User1'],
+ cn=[u'Test User1'],
+ initials=[u'TU'],
+ ipauniqueid=[fuzzy_uuid],
+ krbpwdpolicyreference=lambda x: [DN(i) for i in x] == \
+ [DN(('cn','global_policy'),('cn',api.env.realm),
+ ('cn','kerberos'),api.env.basedn)],
+ mepmanagedentry=lambda x: [DN(i) for i in x] == \
+ [DN(('cn',user1),('cn','groups'),('cn','accounts'),
+ api.env.basedn)],
+ memberof_group=[u'ipausers'],
+ has_keytab=False,
+ has_password=False,
+ dn=lambda x: DN(x) == \
+ DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
+ api.env.basedn),
+ ),
+ ),
+ ),
+
+
+ dict(
+ desc='Create user %r with bad realm in principal' % user1,
+ command=(
+ 'user_add', [user1], dict(givenname=u'Test', sn=u'User1',
+ krbprincipalname='%s@NOTFOUND.ORG' % user1)
+ ),
+ expected=errors.RealmMismatch()
+ ),
+
+
+ dict(
+ desc='Create user %r with malformed principal' % user1,
+ command=(
+ 'user_add', [user1], dict(givenname=u'Test', sn=u'User1',
+ krbprincipalname='%s@BAD@NOTFOUND.ORG' % user1)
+ ),
+ expected=errors.MalformedUserPrincipal(principal='%s@BAD@NOTFOUND.ORG' % user1),
+ ),
+
+
]