summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--API.txt9
-rw-r--r--VERSION2
-rw-r--r--install/share/60basev3.ldif1
-rw-r--r--ipalib/plugins/user.py22
-rw-r--r--ipatests/test_xmlrpc/test_user_plugin.py48
5 files changed, 71 insertions, 11 deletions
diff --git a/API.txt b/API.txt
index b3b3a7e3..c29efad3 100644
--- a/API.txt
+++ b/API.txt
@@ -3596,7 +3596,7 @@ output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDA
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
output: Output('value', <type 'unicode'>, None)
command: user_add
-args: 1,36,3
+args: 1,37,3
arg: Str('uid', attribute=True, cli_name='login', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[a-zA-Z0-9_.$-]?$', primary_key=True, required=True)
option: Str('addattr*', cli_name='addattr', exclude='webui')
option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
@@ -3632,6 +3632,7 @@ option: Str('street', attribute=True, cli_name='street', multivalue=False, requi
option: Str('telephonenumber', attribute=True, cli_name='phone', multivalue=True, required=False)
option: Str('title', attribute=True, cli_name='title', multivalue=False, required=False)
option: Int('uidnumber', attribute=True, cli_name='uid', minvalue=1, multivalue=False, required=False)
+option: Str('userclass', attribute=True, cli_name='class', multivalue=True, required=False)
option: Password('userpassword', attribute=True, cli_name='password', exclude='webui', multivalue=False, required=False)
option: Str('version?', exclude='webui')
output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
@@ -3660,7 +3661,7 @@ output: Output('result', <type 'bool'>, None)
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
output: Output('value', <type 'unicode'>, None)
command: user_find
-args: 1,46,4
+args: 1,47,4
arg: Str('criteria?', noextrawhitespace=False)
option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
option: Str('carlicense', attribute=True, autofill=False, cli_name='carlicense', multivalue=False, query=True, required=False)
@@ -3705,6 +3706,7 @@ option: Int('timelimit?', autofill=False, minvalue=0)
option: Str('title', attribute=True, autofill=False, cli_name='title', multivalue=False, query=True, required=False)
option: Str('uid', attribute=True, autofill=False, cli_name='login', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[a-zA-Z0-9_.$-]?$', primary_key=True, query=True, required=False)
option: Int('uidnumber', attribute=True, autofill=False, cli_name='uid', minvalue=1, multivalue=False, query=True, required=False)
+option: Str('userclass', attribute=True, autofill=False, cli_name='class', multivalue=True, query=True, required=False)
option: Password('userpassword', attribute=True, autofill=False, cli_name='password', exclude='webui', multivalue=False, query=True, required=False)
option: Str('version?', exclude='webui')
option: Flag('whoami', autofill=True, default=False)
@@ -3713,7 +3715,7 @@ output: ListOfEntries('result', (<type 'list'>, <type 'tuple'>), Gettext('A list
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
output: Output('truncated', <type 'bool'>, None)
command: user_mod
-args: 1,37,3
+args: 1,38,3
arg: Str('uid', attribute=True, cli_name='login', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[a-zA-Z0-9_.$-]?$', primary_key=True, query=True, required=True)
option: Str('addattr*', cli_name='addattr', exclude='webui')
option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
@@ -3750,6 +3752,7 @@ option: Str('street', attribute=True, autofill=False, cli_name='street', multiva
option: Str('telephonenumber', attribute=True, autofill=False, cli_name='phone', multivalue=True, required=False)
option: Str('title', attribute=True, autofill=False, cli_name='title', multivalue=False, required=False)
option: Int('uidnumber', attribute=True, autofill=False, cli_name='uid', minvalue=1, multivalue=False, required=False)
+option: Str('userclass', attribute=True, autofill=False, cli_name='class', multivalue=True, required=False)
option: Password('userpassword', attribute=True, autofill=False, cli_name='password', exclude='webui', multivalue=False, required=False)
option: Str('version?', exclude='webui')
output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
diff --git a/VERSION b/VERSION
index 0dacb970..c036dc56 100644
--- a/VERSION
+++ b/VERSION
@@ -89,4 +89,4 @@ IPA_DATA_VERSION=20100614120000
# #
########################################################
IPA_API_VERSION_MAJOR=2
-IPA_API_VERSION_MINOR=67
+IPA_API_VERSION_MINOR=68
diff --git a/install/share/60basev3.ldif b/install/share/60basev3.ldif
index dbb6a2de..1d913542 100644
--- a/install/share/60basev3.ldif
+++ b/install/share/60basev3.ldif
@@ -54,3 +54,4 @@ objectClasses: (2.16.840.1.113730.3.8.12.15 NAME 'ipaIDrange' ABSTRACT MUST ( cn
objectClasses: (2.16.840.1.113730.3.8.12.16 NAME 'ipaDomainIDRange' SUP ipaIDrange STRUCTURAL MAY ( ipaBaseRID $ ipaSecondaryBaseRID ) X-ORIGIN 'IPA v3' )
objectClasses: (2.16.840.1.113730.3.8.12.17 NAME 'ipaTrustedADDomainRange' SUP ipaIDrange STRUCTURAL MUST ( ipaBaseRID $ ipaNTTrustedDomainSID ) X-ORIGIN 'IPA v3' )
objectClasses: (2.16.840.1.113730.3.8.12.19 NAME 'ipaUserAuthTypeClass' SUP top AUXILIARY DESC 'Class for authentication methods definition' MAY ipaUserAuthType X-ORIGIN 'IPA v3')
+objectClasses: (2.16.840.1.113730.3.8.12.20 NAME 'ipaUser' AUXILIARY MUST ( uid ) MAY ( userClass ) X-ORIGIN 'IPA v3' )
diff --git a/ipalib/plugins/user.py b/ipalib/plugins/user.py
index 54d11c22..a7005faf 100644
--- a/ipalib/plugins/user.py
+++ b/ipalib/plugins/user.py
@@ -198,14 +198,16 @@ class user(LDAPObject):
object_name_plural = _('users')
object_class = ['posixaccount']
object_class_config = 'ipauserobjectclasses'
- possible_objectclasses = ['meporiginentry', 'ipauserauthtypeclass']
+ possible_objectclasses = [
+ 'meporiginentry', 'ipauserauthtypeclass', 'ipauser'
+ ]
disallow_object_classes = ['krbticketpolicyaux']
search_attributes_config = 'ipausersearchfields'
default_attributes = [
'uid', 'givenname', 'sn', 'homedirectory', 'loginshell',
'uidnumber', 'gidnumber', 'mail', 'ou',
'telephonenumber', 'title', 'memberof', 'nsaccountlock',
- 'memberofindirect', 'ipauserauthtype'
+ 'memberofindirect', 'ipauserauthtype', 'userclass'
]
search_display_attributes = [
'uid', 'givenname', 'sn', 'homedirectory', 'loginshell',
@@ -372,6 +374,12 @@ class user(LDAPObject):
values=(u'password',),
csv=True,
),
+ Str('userclass*',
+ cli_name='class',
+ label=_('Class'),
+ doc=_('User category (semantics placed on this attribute are for '
+ 'local interpretation)'),
+ ),
)
def _normalize_and_validate_email(self, email, config=None):
@@ -547,6 +555,11 @@ class user_add(LDAPCreate):
if 'manager' in entry_attrs:
entry_attrs['manager'] = self.obj._normalize_manager(entry_attrs['manager'])
+ if ('objectclass' in entry_attrs
+ and 'userclass' in entry_attrs
+ and 'ipauser' not in entry_attrs['objectclass']):
+ entry_attrs['objectclass'].append('ipauser')
+
return dn
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
@@ -640,7 +653,8 @@ class user_mod(LDAPUpdate):
entry_attrs['userpassword'] = ipa_generate_password(user_pwdchars)
# save the password so it can be displayed in post_callback
setattr(context, 'randompassword', entry_attrs['userpassword'])
- if 'ipasshpubkey' in entry_attrs or 'ipauserauthtype' in entry_attrs:
+ if ('ipasshpubkey' in entry_attrs or 'ipauserauthtype' in entry_attrs
+ or 'userclass' in entry_attrs):
if 'objectclass' in entry_attrs:
obj_classes = entry_attrs['objectclass']
else:
@@ -650,6 +664,8 @@ class user_mod(LDAPUpdate):
obj_classes.append('ipasshuser')
if 'ipauserauthtype' in entry_attrs and 'ipauserauthtype' not in obj_classes:
obj_classes.append('ipauserauthtypeclass')
+ if 'userclass' in entry_attrs and 'ipauser' not in obj_classes:
+ obj_classes.append('ipauser')
return dn
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
diff --git a/ipatests/test_xmlrpc/test_user_plugin.py b/ipatests/test_xmlrpc/test_user_plugin.py
index 4f30ec61..2f07e149 100644
--- a/ipatests/test_xmlrpc/test_user_plugin.py
+++ b/ipatests/test_xmlrpc/test_user_plugin.py
@@ -188,12 +188,28 @@ class test_user(Declarative):
dict(
desc='Create "%s"' % user1,
command=(
- 'user_add', [user1], dict(givenname=u'Test', sn=u'User1')
+ 'user_add',
+ [user1],
+ dict(
+ givenname=u'Test',
+ sn=u'User1',
+ userclass=u'testusers'
+ )
),
expected=dict(
value=user1,
summary=u'Added user "%s"' % user1,
- result=get_user_result(user1, u'Test', u'User1', 'add'),
+ result=get_user_result(
+ user1,
+ u'Test',
+ u'User1',
+ 'add',
+ userclass=[u'testusers'],
+ objectclass=add_oc(
+ objectclasses.user,
+ u'ipantuserattrs'
+ ) + [u'ipauser']
+ ),
),
extra_check = upg_check,
),
@@ -215,12 +231,27 @@ class test_user(Declarative):
'user_show', [user1], {}
),
expected=dict(
- result=get_user_result(user1, u'Test', u'User1', 'show'),
+ result=get_user_result(
+ user1,
+ u'Test',
+ u'User1',
+ 'show',
+ userclass=[u'testusers']
+ ),
value=user1,
summary=None,
),
),
+ dict(
+ desc='Remove userclass for user "%s"' % user1,
+ command=('user_mod', [user1], dict(userclass=u'')),
+ expected=dict(
+ result=get_user_result(user1, u'Test', u'User1', 'mod'),
+ value=user1,
+ summary=u'Modified user "%s"' % user1,
+ ),
+ ),
dict(
desc='Search for "%s" with all=True' % user1,
@@ -229,7 +260,16 @@ class test_user(Declarative):
),
expected=dict(
result=[
- get_user_result(user1, u'Test', u'User1', 'show-all'),
+ get_user_result(
+ user1,
+ u'Test',
+ u'User1',
+ 'show-all',
+ objectclass=add_oc(
+ objectclasses.user,
+ u'ipantuserattrs'
+ ) + [u'ipauser']
+ ),
],
summary=u'1 user matched',
count=1, truncated=False,