mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
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
This commit is contained in:
committed by
Martin Kosek
parent
37836a2e6c
commit
a1430dcb2c
6
API.txt
6
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)
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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'
|
||||
|
||||
|
||||
@@ -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),
|
||||
),
|
||||
|
||||
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user