Allow multiple managers per user - CLI part

Added commands:
* user-add-manager
* user-remove-manager
* stageuser-add-manager
* stageuser-remove-manager

Commit contains override of convert_attribute_members method in baseuser
class that ensures the managers will be returned in 'manager' attribute
due to backward compatibility instead of 'manager_user' as would be
expected.

https://fedorahosted.org/freeipa/ticket/5344

This patch also fixes: https://fedorahosted.org/freeipa/ticket/5387

Reviewed-By: David Kupka <dkupka@redhat.com>
Reviewed-By: Jan Cholasta <jcholast@redhat.com>
This commit is contained in:
Martin Basti 2015-11-05 17:11:23 +01:00
parent c56d45bc38
commit 457c974670
5 changed files with 113 additions and 31 deletions

44
API.txt
View File

@ -4248,6 +4248,17 @@ option: Str('version?', exclude='webui')
output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
output: PrimaryKey('value', None, None)
command: stageuser_add_manager
args: 1,5,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: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
option: Flag('no_members', autofill=True, default=False, exclude='webui')
option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
option: Str('user*', alwaysask=True, cli_name='users', csv=True)
option: Str('version?', exclude='webui')
output: Output('completed', <type 'int'>, None)
output: Output('failed', <type 'dict'>, None)
output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
command: stageuser_del
args: 1,2,3
arg: Str('uid', attribute=True, cli_name='login', maxlength=255, multivalue=True, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[a-zA-Z0-9_.$-]?$', primary_key=True, query=True, required=True)
@ -4367,6 +4378,17 @@ option: Str('version?', exclude='webui')
output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
output: PrimaryKey('value', None, None)
command: stageuser_remove_manager
args: 1,5,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: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
option: Flag('no_members', autofill=True, default=False, exclude='webui')
option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
option: Str('user*', alwaysask=True, cli_name='users', csv=True)
option: Str('version?', exclude='webui')
output: Output('completed', <type 'int'>, None)
output: Output('failed', <type 'dict'>, None)
output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
command: stageuser_show
args: 1,5,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)
@ -5208,6 +5230,17 @@ option: Str('version?', exclude='webui')
output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
output: PrimaryKey('value', None, None)
command: user_add_manager
args: 1,5,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: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
option: Flag('no_members', autofill=True, default=False, exclude='webui')
option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
option: Str('user*', alwaysask=True, cli_name='users', csv=True)
option: Str('version?', exclude='webui')
output: Output('completed', <type 'int'>, None)
output: Output('failed', <type 'dict'>, None)
output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
command: user_del
args: 1,4,3
arg: Str('uid', attribute=True, cli_name='login', maxlength=255, multivalue=True, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[a-zA-Z0-9_.$-]?$', primary_key=True, query=True, required=True)
@ -5358,6 +5391,17 @@ option: Str('version?', exclude='webui')
output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
output: PrimaryKey('value', None, None)
command: user_remove_manager
args: 1,5,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: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui')
option: Flag('no_members', autofill=True, default=False, exclude='webui')
option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui')
option: Str('user*', alwaysask=True, cli_name='users', csv=True)
option: Str('version?', exclude='webui')
output: Output('completed', <type 'int'>, None)
output: Output('failed', <type 'dict'>, None)
output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
command: user_show
args: 1,6,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)

View File

@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000
# #
########################################################
IPA_API_VERSION_MAJOR=2
IPA_API_VERSION_MINOR=157
# Last change: mbabinsk - hide segment direction from topology commands
IPA_API_VERSION_MINOR=158
# Last change: mbasti - allow multiple managers: (stage)user-{add|remove}-manager commands

View File

@ -27,8 +27,9 @@ import six
from ipalib import api, errors
from ipalib import Flag, Int, Password, Str, Bool, StrEnum, DateTime, Bytes
from ipalib.plugable import Registry
from ipalib.plugins.baseldap import DN, LDAPObject, \
LDAPCreate, LDAPUpdate, LDAPSearch, LDAPDelete, LDAPRetrieve
from ipalib.plugins.baseldap import (
DN, LDAPObject, LDAPCreate, LDAPUpdate, LDAPSearch, LDAPDelete,
LDAPRetrieve, LDAPAddMember, LDAPRemoveMember)
from ipalib.plugins.service import validate_certificate
from ipalib.plugins import baseldap
from ipalib.request import context
@ -201,6 +202,7 @@ class baseuser(LDAPObject):
]
uuid_attribute = 'ipauniqueid'
attribute_members = {
'manager': ['user'],
'memberof': ['group', 'netgroup', 'role', 'hbacrule', 'sudorule'],
'memberofindirect': ['group', 'netgroup', 'role', 'hbacrule', 'sudorule'],
}
@ -338,6 +340,7 @@ class baseuser(LDAPObject):
Str('title?',
label=_('Job Title'),
),
# keep backward compatibility using single value manager option
Str('manager?',
label=_('Manager'),
),
@ -428,6 +431,7 @@ class baseuser(LDAPObject):
if not isinstance(manager, list):
manager = [manager]
try:
container_dn = DN(container, api.env.basedn)
for i, mgr in enumerate(manager):
@ -443,17 +447,6 @@ class baseuser(LDAPObject):
return manager
def convert_manager(self, entry_attrs, **options):
"""
Convert a manager dn into a userid
"""
if options.get('raw', False):
return
if 'manager' in entry_attrs:
for i, mgr in enumerate(entry_attrs['manager']):
entry_attrs['manager'][i] = self.get_primary_key_from_dn(mgr)
def _user_status(self, user, container):
assert isinstance(user, DN)
return user.endswith(container)
@ -480,6 +473,26 @@ class baseuser(LDAPObject):
entry_attrs['usercertificate'] = entry_attrs.pop(
'usercertificate;binary')
def convert_attribute_members(self, entry_attrs, *keys, **options):
super(baseuser, self).convert_attribute_members(
entry_attrs, *keys, **options)
if options.get("raw", False):
return
# due the backward compatibility, managers have to be returned in
# 'manager' attribute instead of 'manager_user'
try:
entry_attrs['failed_manager'] = entry_attrs.pop('manager')
except KeyError:
pass
try:
entry_attrs['manager'] = entry_attrs.pop('manager_user')
except KeyError:
pass
class baseuser_add(LDAPCreate):
"""
Prototype command plugin to be implemented by real plugin
@ -578,7 +591,6 @@ class baseuser_mod(LDAPUpdate):
# if both randompassword and userpassword options were used
pass
convert_nsaccountlock(entry_attrs)
self.obj.convert_manager(entry_attrs, **options)
self.obj.get_password_attributes(ldap, dn, entry_attrs)
self.obj.convert_usercertificate_post(entry_attrs, **options)
convert_sshpubkey_post(ldap, dn, entry_attrs)
@ -609,7 +621,6 @@ class baseuser_find(LDAPSearch):
def post_common_callback(self, ldap, entries, lockout=False, **options):
for attrs in entries:
self.obj.convert_manager(attrs, **options)
self.obj.get_password_attributes(ldap, attrs.dn, attrs)
self.obj.convert_usercertificate_post(attrs, **options)
if (lockout):
@ -624,8 +635,15 @@ class baseuser_show(LDAPRetrieve):
"""
def post_common_callback(self, ldap, dn, entry_attrs, **options):
assert isinstance(dn, DN)
self.obj.convert_manager(entry_attrs, **options)
self.obj.get_password_attributes(ldap, dn, entry_attrs)
self.obj.convert_usercertificate_post(entry_attrs, **options)
convert_sshpubkey_post(ldap, dn, entry_attrs)
radius_dn2pk(self.api, entry_attrs)
class baseuser_add_manager(LDAPAddMember):
member_attributes = ['manager']
class baseuser_remove_manager(LDAPRemoveMember):
member_attributes = ['manager']

View File

@ -31,12 +31,12 @@ from ipalib import (Flag, Int, Password, Str, Bool, StrEnum, DateTime,
from ipalib.plugable import Registry
from ipalib.plugins.baseldap import LDAPCreate, LDAPQuery, LDAPSearch, DN, entry_to_dict, pkey_to_value
from ipalib.plugins import baseldap
from ipalib.plugins.baseuser import baseuser, baseuser_add, baseuser_del, \
baseuser_mod, baseuser_find, baseuser_show, \
NO_UPG_MAGIC, radius_dn2pk, \
baseuser_pwdchars, fix_addressbook_permission_bindrule, normalize_principal, validate_principal, \
baseuser_output_params, status_baseuser_output_params
from ipalib.plugins.baseuser import (
baseuser, baseuser_add, baseuser_del, baseuser_mod, baseuser_find,
baseuser_show, NO_UPG_MAGIC, radius_dn2pk, baseuser_pwdchars,
fix_addressbook_permission_bindrule, normalize_principal,
validate_principal, baseuser_output_params, status_baseuser_output_params,
baseuser_add_manager, baseuser_remove_manager)
from ipalib.request import context
from ipalib import _, ngettext
from ipalib import output
@ -716,3 +716,13 @@ class stageuser_activate(LDAPQuery):
return dict(result=result_entry,
summary=unicode(_('Stage user %s activated' % staging_dn[0].value)),
value=pkey_to_value(args[-1], options))
@register()
class stageuser_add_manager(baseuser_add_manager):
__doc__ = _("Add a manager to the stage user entry")
@register()
class stageuser_remove_manager(baseuser_remove_manager):
__doc__ = _("Remove a manager to the stage user entry")

View File

@ -27,12 +27,13 @@ import six
from ipalib import api, errors, util
from ipalib import Flag, Int, Password, Str, Bool, StrEnum, DateTime
from ipalib.plugins.baseuser import baseuser, baseuser_add, baseuser_del, \
baseuser_mod, baseuser_find, baseuser_show, \
NO_UPG_MAGIC, UPG_DEFINITION_DN, baseuser_output_params, \
status_baseuser_output_params, baseuser_pwdchars, \
validate_nsaccountlock, radius_dn2pk, convert_nsaccountlock, split_principal, validate_principal, \
normalize_principal, fix_addressbook_permission_bindrule
from ipalib.plugins.baseuser import (
baseuser, baseuser_add, baseuser_del, baseuser_mod, baseuser_find,
baseuser_show, NO_UPG_MAGIC, UPG_DEFINITION_DN, baseuser_output_params,
status_baseuser_output_params, baseuser_pwdchars, validate_nsaccountlock,
radius_dn2pk, convert_nsaccountlock, split_principal, validate_principal,
normalize_principal, fix_addressbook_permission_bindrule,
baseuser_add_manager, baseuser_remove_manager)
from ipalib.plugins.idviews import remove_ipaobject_overrides
from ipalib.plugable import Registry
from ipalib.plugins.baseldap import *
@ -542,7 +543,6 @@ class user_add(baseuser_add):
except errors.AlreadyGroupMember:
pass
self.obj.convert_manager(entry_attrs, **options)
# delete description attribute NO_UPG_MAGIC if present
if options.get('noprivate', False):
if not options.get('all', False):
@ -1157,3 +1157,13 @@ class user_remove_cert(LDAPRemoveAttribute):
self.obj.convert_usercertificate_post(entry_attrs, **options)
return dn
@register()
class user_add_manager(baseuser_add_manager):
__doc__ = _("Add a manager to the user entry")
@register()
class user_remove_manager(baseuser_remove_manager):
__doc__ = _("Remove a manager to the user entry")