On 18.11.2015 16:10, Martin Basti wrote:
On 12.11.2015 12:39, Martin Basti wrote:
On 27.10.2015 14:59, Martin Basti wrote:
On 20.10.2015 18:46, Martin Basti wrote:
On 20.10.2015 16:07, Martin Basti wrote:
On 20.10.2015 15:57, Martin Basti wrote:
https://fedorahosted.org/freeipa/ticket/5344
Patch attached.
Test are failing, a fix in UserTracker has to be done (partially
in my patch 329)
SelfNACK, I forgot to add stageuser tests
Updated patch attached.
I extracted tests to the separate patch, tests do not work, I had
issues with user and stageuser trackers.
Patch to fix issues with --addattr and managers added and attached.
The new one patch 0331 attached, patch 0337 is not needed anymore.
This patch also fixes https://fedorahosted.org/freeipa/ticket/5387
updated patch attached.
updated patch attached
From 05e586484da12e136f86f7b5e50cb4703ea38333 Mon Sep 17 00:00:00 2001
From: Martin Basti <mba...@redhat.com>
Date: Thu, 5 Nov 2015 17:11:23 +0100
Subject: [PATCH] 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
---
API.txt | 44 +++++++++++++++++++++++++++++++++++++++
VERSION | 4 ++--
ipalib/plugins/baseuser.py | 50 ++++++++++++++++++++++++++++++---------------
ipalib/plugins/stageuser.py | 22 ++++++++++++++------
ipalib/plugins/user.py | 24 +++++++++++++++-------
5 files changed, 113 insertions(+), 31 deletions(-)
diff --git a/API.txt b/API.txt
index 873c6d54221a0c1657b5457bd9dceedb4adf06b3..0976c97213775d79da43ee382a0badbe029b7960 100644
--- a/API.txt
+++ b/API.txt
@@ -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)
diff --git a/VERSION b/VERSION
index cdda198c6ce3148dcf785149dc3ce050782e8caa..064e98cb46a084b9f87f4fb52c8cd6033be171a4 100644
--- a/VERSION
+++ b/VERSION
@@ -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
diff --git a/ipalib/plugins/baseuser.py b/ipalib/plugins/baseuser.py
index cf0fd88d9b9ee83ee046852e0e4709362947b291..e2572930ecb88154fb3ed4974605f7f7635e4046 100644
--- a/ipalib/plugins/baseuser.py
+++ b/ipalib/plugins/baseuser.py
@@ -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']
diff --git a/ipalib/plugins/stageuser.py b/ipalib/plugins/stageuser.py
index 47c96bb715fcf8293f4ce257566ab914644fa489..995f679235a4ceaa398fb7ee0f7ffcd98f833058 100644
--- a/ipalib/plugins/stageuser.py
+++ b/ipalib/plugins/stageuser.py
@@ -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")
diff --git a/ipalib/plugins/user.py b/ipalib/plugins/user.py
index 81a7070359253262f30e65298c42759cd055e67d..2b792af6289bae3644e627afff8e8ddc662068b2 100644
--- a/ipalib/plugins/user.py
+++ b/ipalib/plugins/user.py
@@ -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")
--
2.5.0
--
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code