On 08/20/2012 01:37 PM, Petr Viktorin wrote:
(Sorry if you're getting this twice; I didn't send it to the list)

On 08/16/2012 08:38 PM, John Dennis wrote:

--
John Dennis <jden...@redhat.com>

Looking to carve out IT costs?
www.redhat.com/carveoutcosts/

freeipa-jdennis-0078-Ticket-2979-prevent-last-admin-from-being-disabled.patch


>From c47109c63530e188db76986fdda48c76bf681d10 Mon Sep 17 00:00:00 2001
From: John Dennis<jden...@redhat.com>
Date: Thu, 16 Aug 2012 20:28:44 -0400
Subject: [PATCH 78] Ticket #2979 - prevent last admin from being disabled
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 8bit

We prevent the last member of the admin group from being deleted. The
same check needs to be performed when disabling a user.

Moved the code in del_user to a common subroutine and call it from
both user_del and user_disable. Note, unlike user_del user_disable
does not have a 'pre' callback therefore the check function is called
in user_disable's execute routine.

This should also prevent disabling all admins if there's more than one:

# ipa user-add admin2 --first=a --last=b
-------------------
Added user "admin2"
-------------------
...
# ipa group-add-member admins --user=admin2
-------------------------
Number of members added 1
-------------------------
# ipa user-disable admin2
------------------------------
Disabled user account "admin2"
------------------------------
# ipa user-disable admin
------------------------------
Disabled user account "admin"
------------------------------
# ipa ping
ipa: ERROR: Server is unwilling to perform: Account inactivated. Contact
system administrator.

Also with one enabled and one disabled admin, it shouldn't be possible
to delete the enabled one.


Please add some tests; you can extend the ones added in commit f8e7b51.

Good catch with respect to disabled users, thank you.

Reworked patch attached, see patch comments.




--
John Dennis <jden...@redhat.com>

Looking to carve out IT costs?
www.redhat.com/carveoutcosts/
>From c635ac107de3b0a3965c596224b0f8c73c9139ac Mon Sep 17 00:00:00 2001
From: John Dennis <jden...@redhat.com>
Date: Thu, 16 Aug 2012 20:28:44 -0400
Subject: [PATCH 78-1] Ticket #2979 - prevent last admin from being disabled
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: 8bit

Ticket #2979 - prevent last admin from being disabled

We prevent the last member of the admin group from being deleted. The
same check needs to be performed when disabling a user.

* Moved the code in del_user to the common subroutine
  check_protected_member() and call it from both user_del and
  user_disable. Note, unlike user_del user_disable does not have a
  'pre' callback therefore the check function is called in
  user_disable's execute routine.

* Make check_protected_member() aware of disabled members. It's not
  sufficient to check which members of the protected group are
  present, one must only consider those members which are enabled.

* Add tests to test_user_plugin.py.

  - verify you cannot delete nor disable the last member of the admin
    group

  - verify when the admin group contains disabled users in addition to
    enabled users only the enabled users are considered when
    determining if the last admin is about to be disabled or deleted.

* Replace duplicated hardcoded values in the tests with variables or
  subroutines, this makes the individual tests a bit more succinct and
  easier to copy/modify.
---
 ipalib/plugins/user.py                |  27 ++-
 tests/test_xmlrpc/test_user_plugin.py | 443 +++++++++++++++++++++-------------
 2 files changed, 300 insertions(+), 170 deletions(-)

diff --git a/ipalib/plugins/user.py b/ipalib/plugins/user.py
index 529699f..d0f7da2 100644
--- a/ipalib/plugins/user.py
+++ b/ipalib/plugins/user.py
@@ -166,6 +166,24 @@ def normalize_principal(principal):
     return unicode('%s@%s' % (user, realm))
 
 
+def check_protected_member(user, protected_group_name=u'admins'):
+    '''
+    Ensure the last enabled member of a protected group cannot be deleted or
+    disabled by raising LastMemberError.
+    '''
+
+    # Get all users in the protected group
+    result = api.Command.user_find(in_group=protected_group_name)
+
+    # Build list of users in the protected group who are enabled
+    result = result['result']
+    enabled_users = [entry['uid'][0] for entry in result if not entry['nsaccountlock']]
+
+    # If the user is the last enabled user raise LastMemberError exception
+    if enabled_users == [user]:
+        raise errors.LastMemberError(key=user, label=_(u'group'),
+            container=protected_group_name)
+
 class user(LDAPObject):
     """
     User object.
@@ -550,11 +568,7 @@ class user_del(LDAPDelete):
 
     def pre_callback(self, ldap, dn, *keys, **options):
         assert isinstance(dn, DN)
-        protected_group_name = u'admins'
-        result = api.Command.group_show(protected_group_name)
-        if result['result'].get('member_user', []) == [keys[-1]]:
-            raise errors.LastMemberError(key=keys[-1], label=_(u'group'),
-                container=protected_group_name)
+        check_protected_member(keys[-1])
         return dn
 
 api.register(user_del)
@@ -679,8 +693,9 @@ class user_disable(LDAPQuery):
     def execute(self, *keys, **options):
         ldap = self.obj.backend
 
-        dn = self.obj.get_dn(*keys, **options)
+        check_protected_member(keys[-1])
 
+        dn = self.obj.get_dn(*keys, **options)
         ldap.deactivate_entry(dn)
 
         return dict(
diff --git a/tests/test_xmlrpc/test_user_plugin.py b/tests/test_xmlrpc/test_user_plugin.py
index 4a4c69c..5240c8c 100644
--- a/tests/test_xmlrpc/test_user_plugin.py
+++ b/tests/test_xmlrpc/test_user_plugin.py
@@ -2,6 +2,7 @@
 #   Rob Crittenden <rcrit...@redhat.com>
 #   Pavel Zuna <pz...@redhat.com>
 #   Jason Gerard DeRose <jder...@redhat.com>
+#   John Dennis <jden...@redhat.com>
 #
 # Copyright (C) 2008, 2009  Red Hat
 # see file 'COPYING' for use and warranty information
@@ -31,12 +32,21 @@ from ipapython.dn import DN
 
 user1=u'tuser1'
 user2=u'tuser2'
+admin1=u'admin'
+admin2=u'admin2'
 renameduser1=u'tuser'
 group1=u'group1'
+admins_group=u'admins'
 
 invaliduser1=u'+tuser1'
 invaliduser2=u'tuser1234567890123456789012345678901234567890'
 
+def get_user_dn(uid):
+    return DN(('uid', uid), api.env.container_user, api.env.basedn)
+
+def get_group_dn(cn):
+    return DN(('cn', cn), api.env.container_group, api.env.basedn)
+
 def upg_check(response):
     """Check that the user was assigned to the corresponding private group."""
     assert_equal(response['result']['uidnumber'],
@@ -52,48 +62,48 @@ def not_upg_check(response):
 class test_user(Declarative):
 
     cleanup_commands = [
-        ('user_del', [user1, user2, renameduser1], {}),
+        ('user_del', [user1, user2, renameduser1, admin2], {}),
         ('group_del', [group1], {}),
     ]
 
     tests = [
 
         dict(
-            desc='Try to retrieve non-existent %r' % user1,
+            desc='Try to retrieve non-existent "%s"' % user1,
             command=('user_show', [user1], {}),
             expected=errors.NotFound(reason=u'%s: user not found' % user1),
         ),
 
 
         dict(
-            desc='Try to update non-existent %r' % user1,
+            desc='Try to update non-existent "%s"' % user1,
             command=('user_mod', [user1], dict(givenname=u'Foo')),
             expected=errors.NotFound(reason=u'%s: user not found' % user1),
         ),
 
 
         dict(
-            desc='Try to delete non-existent %r' % user1,
+            desc='Try to delete non-existent "%s"' % user1,
             command=('user_del', [user1], {}),
             expected=errors.NotFound(reason=u'%s: user not found' % user1),
         ),
 
 
         dict(
-            desc='Try to rename non-existent %r' % user1,
+            desc='Try to rename non-existent "%s"' % user1,
             command=('user_mod', [user1], dict(setattr=u'uid=%s' % renameduser1)),
             expected=errors.NotFound(reason=u'%s: user not found' % user1),
         ),
 
 
         dict(
-            desc='Create %r' % user1,
+            desc='Create "%s"' % user1,
             command=(
                 'user_add', [user1], dict(givenname=u'Test', sn=u'User1')
             ),
             expected=dict(
                 value=user1,
-                summary=u'Added user "tuser1"',
+                summary=u'Added user "%s"' % user1,
                 result=dict(
                     gecos=[u'Test User1'],
                     givenname=[u'Test'],
@@ -111,13 +121,11 @@ class test_user(Declarative):
                     ipauniqueid=[fuzzy_uuid],
                     krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),
                                               ('cn','kerberos'),api.env.basedn)],
-                    mepmanagedentry=[DN(('cn',user1),('cn','groups'),('cn','accounts'),
-                                        api.env.basedn)],
+                    mepmanagedentry=[get_group_dn(user1)],
                     memberof_group=[u'ipausers'],
                     has_keytab=False,
                     has_password=False,
-                    dn=DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
-                          api.env.basedn),
+                    dn=get_user_dn(user1),
                 ),
             ),
             extra_check = upg_check,
@@ -125,7 +133,7 @@ class test_user(Declarative):
 
 
         dict(
-            desc='Try to create duplicate %r' % user1,
+            desc='Try to create duplicate "%s"' % user1,
             command=(
                 'user_add', [user1], dict(givenname=u'Test', sn=u'User1')
             ),
@@ -135,14 +143,13 @@ class test_user(Declarative):
 
 
         dict(
-            desc='Retrieve %r' % user1,
+            desc='Retrieve "%s"' % user1,
             command=(
                 'user_show', [user1], {}
             ),
             expected=dict(
                 result=dict(
-                    dn=DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
-                          api.env.basedn),
+                    dn=get_user_dn(user1),
                     givenname=[u'Test'],
                     homedirectory=[u'/home/tuser1'],
                     loginshell=[u'/bin/sh'],
@@ -162,15 +169,14 @@ class test_user(Declarative):
 
 
         dict(
-            desc='Search for %r with all=True' % user1,
+            desc='Search for "%s" with all=True' % user1,
             command=(
                 'user_find', [user1], {'all': True}
             ),
             expected=dict(
                 result=[
                     {
-                        'dn': DN(('uid','tuser1'),('cn','users'),
-                                 ('cn','accounts'),api.env.basedn),
+                        'dn': get_user_dn(user1),
                         'cn': [u'Test User1'],
                         'gecos': [u'Test User1'],
                         'givenname': [u'Test'],
@@ -184,8 +190,7 @@ class test_user(Declarative):
                         'uidnumber': [fuzzy_digits],
                         'gidnumber': [fuzzy_digits],
                         'ipauniqueid': [fuzzy_uuid],
-                        'mepmanagedentry': [DN(('cn',user1),('cn','groups'),('cn','accounts'),
-                                               api.env.basedn)],
+                        'mepmanagedentry': [get_group_dn(user1)],
                         'krbpwdpolicyreference': [DN(('cn','global_policy'),('cn',api.env.realm),
                                                      ('cn','kerberos'),api.env.basedn)],
                         'nsaccountlock': False,
@@ -203,15 +208,14 @@ class test_user(Declarative):
 
 
         dict(
-            desc='Search for %r with pkey-only=True' % user1,
+            desc='Search for "%s" with pkey-only=True' % user1,
             command=(
                 'user_find', [user1], {'pkey_only': True}
             ),
             expected=dict(
                 result=[
                     {
-                        'dn':DN(('uid',user1),('cn','users'),
-                                ('cn','accounts'),api.env.basedn),
+                        'dn': get_user_dn(user1),
                         'uid': [user1],
                     },
                 ],
@@ -222,15 +226,14 @@ class test_user(Declarative):
 
 
         dict(
-            desc='Search for %r with minimal attributes' % user1,
+            desc='Search for "%s" with minimal attributes' % user1,
             command=(
                 'user_find', [user1], {}
             ),
             expected=dict(
                 result=[
                     dict(
-                        dn=DN(('uid','tuser1'),('cn','users'),
-                              ('cn','accounts'),api.env.basedn),
+                        dn=get_user_dn(user1),
                         givenname=[u'Test'],
                         homedirectory=[u'/home/tuser1'],
                         loginshell=[u'/bin/sh'],
@@ -258,12 +261,11 @@ class test_user(Declarative):
             expected=dict(
                 result=[
                     dict(
-                        dn=DN(('uid','admin'),('cn','users'),('cn','accounts'),
-                              api.env.basedn),
+                        dn=get_user_dn(admin1),
                         homedirectory=[u'/home/admin'],
                         loginshell=[u'/bin/bash'],
                         sn=[u'Administrator'],
-                        uid=[u'admin'],
+                        uid=[admin1],
                         nsaccountlock=False,
                         has_keytab=True,
                         has_password=True,
@@ -271,8 +273,7 @@ class test_user(Declarative):
                         gidnumber=[fuzzy_digits],
                     ),
                     dict(
-                        dn=DN(('uid','tuser1'),('cn','users'),
-                              ('cn','accounts'),api.env.basedn),
+                        dn=get_user_dn(user1),
                         givenname=[u'Test'],
                         homedirectory=[u'/home/tuser1'],
                         loginshell=[u'/bin/sh'],
@@ -300,12 +301,11 @@ class test_user(Declarative):
             expected=dict(
                 result=[
                     dict(
-                        dn=DN(('uid','admin'),('cn','users'),('cn','accounts'),
-                              api.env.basedn),
+                        dn=get_user_dn(admin1),
                         homedirectory=[u'/home/admin'],
                         loginshell=[u'/bin/bash'],
                         sn=[u'Administrator'],
-                        uid=[u'admin'],
+                        uid=[admin1],
                         nsaccountlock=False,
                         has_keytab=True,
                         has_password=True,
@@ -321,14 +321,14 @@ class test_user(Declarative):
 
 
         dict(
-            desc='Disable %r' % user1,
+            desc='Disable "%s"' % user1,
             command=(
                 'user_disable', [user1], {}
             ),
             expected=dict(
                 result=True,
                 value=user1,
-                summary=u'Disabled user account "tuser1"',
+                summary=u'Disabled user account "%s"' % user1,
             ),
         ),
 
@@ -344,19 +344,19 @@ class test_user(Declarative):
         ),
 
         dict(
-            desc='Enable %r'  % user1,
+            desc='Enable "%s"'  % user1,
             command=(
                 'user_enable', [user1], {}
             ),
             expected=dict(
                 result=True,
                 value=user1,
-                summary=u'Enabled user account "tuser1"',
+                summary=u'Enabled user account "%s"' % user1,
             ),
         ),
 
         dict(
-            desc='Assert user is enabled',
+            desc='Assert user "%s" is enabled' % user1,
             command=('user_find', [user1], {}),
             expected=dict(
                 result=[lambda d: d['nsaccountlock'] == False],
@@ -367,54 +367,54 @@ class test_user(Declarative):
         ),
 
         dict(
-            desc='Disable %r using setattr' % user1,
+            desc='Disable "%s" using setattr' % user1,
             command=('user_mod', [user1], dict(setattr=u'nsaccountlock=True')),
             expected=dict(
                 result=lambda d: d['nsaccountlock'] == True,
                 value=user1,
-                summary=u'Modified user "tuser1"',
+                summary=u'Modified user "%s"' % user1,
             ),
         ),
 
         dict(
-            desc='Enable %r using setattr' % user1,
+            desc='Enable "%s" using setattr' % user1,
             command=('user_mod', [user1], dict(setattr=u'nsaccountlock=False')),
             expected=dict(
                 result=lambda d: d['nsaccountlock'] == False,
                 value=user1,
-                summary=u'Modified user "tuser1"',
+                summary=u'Modified user "%s"' % user1,
             ),
         ),
 
         dict(
-            desc='Disable %r using user_mod' % user1,
+            desc='Disable "%s" using user_mod' % user1,
             command=('user_mod', [user1], dict(nsaccountlock=True)),
             expected=dict(
                 result=lambda d: d['nsaccountlock'] == True,
                 value=user1,
-                summary=u'Modified user "tuser1"',
+                summary=u'Modified user "%s"' % user1,
             ),
         ),
 
         dict(
-            desc='Enable %r using user_mod' % user1,
+            desc='Enable "%s" using user_mod' % user1,
             command=('user_mod', [user1], dict(nsaccountlock=False)),
             expected=dict(
                 result=lambda d: d['nsaccountlock'] == False,
                 value=user1,
-                summary=u'Modified user "tuser1"',
+                summary=u'Modified user "%s"' % user1,
             ),
         ),
 
         dict(
-            desc='Try setting virtual attribute on %r using setattr' % user1,
+            desc='Try setting virtual attribute on "%s" using setattr' % user1,
             command=('user_mod', [user1], dict(setattr=u'random=xyz123')),
             expected=errors.ObjectclassViolation(
                 info='attribute "random" not allowed'),
         ),
 
         dict(
-            desc='Update %r' % user1,
+            desc='Update "%s"' % user1,
             command=(
                 'user_mod', [user1], dict(givenname=u'Finkle')
             ),
@@ -432,14 +432,14 @@ class test_user(Declarative):
                     has_keytab=False,
                     has_password=False,
                 ),
-                summary=u'Modified user "tuser1"',
+                summary=u'Modified user "%s"' % user1,
                 value=user1,
             ),
         ),
 
 
         dict(
-            desc='Try updating the krb ticket policy of %r' % user1,
+            desc='Try updating the krb ticket policy of "%s"' % user1,
             command=(
                 'user_mod', [user1], dict(setattr=u'krbmaxticketlife=88000')
             ),
@@ -449,12 +449,11 @@ class test_user(Declarative):
 
 
         dict(
-            desc='Retrieve %r to verify update' % user1,
+            desc='Retrieve "%s" to verify update' % user1,
             command=('user_show', [user1], {}),
             expected=dict(
                 result=dict(
-                    dn=DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
-                          api.env.basedn),
+                    dn=get_user_dn(user1),
                     givenname=[u'Finkle'],
                     homedirectory=[u'/home/tuser1'],
                     loginshell=[u'/bin/sh'],
@@ -475,7 +474,7 @@ class test_user(Declarative):
 
 
         dict(
-            desc='Rename %r' % user1,
+            desc='Rename "%s"' % user1,
             command=('user_mod', [user1], dict(setattr=u'uid=%s' % renameduser1)),
             expected=dict(
                 result=dict(
@@ -498,14 +497,14 @@ class test_user(Declarative):
 
 
         dict(
-            desc='Rename %r to same value' % renameduser1,
+            desc='Rename "%s" to same value' % renameduser1,
             command=('user_mod', [renameduser1], dict(setattr=u'uid=%s' % renameduser1)),
             expected=errors.EmptyModlist(),
         ),
 
 
         dict(
-            desc='Rename back %r' % renameduser1,
+            desc='Rename back "%s"' % renameduser1,
             command=('user_mod', [renameduser1], dict(setattr=u'uid=%s' % user1)),
             expected=dict(
                 result=dict(
@@ -528,25 +527,25 @@ class test_user(Declarative):
 
 
         dict(
-            desc='Delete %r' % user1,
+            desc='Delete "%s"' % user1,
             command=('user_del', [user1], {}),
             expected=dict(
                 result=dict(failed=u''),
-                summary=u'Deleted user "tuser1"',
+                summary=u'Deleted user "%s"' % user1,
                 value=user1,
             ),
         ),
 
 
         dict(
-            desc='Try to delete non-existent %r' % user1,
+            desc='Try to delete non-existent "%s"' % user1,
             command=('user_del', [user1], {}),
             expected=errors.NotFound(reason=u'tuser1: user not found'),
         ),
 
 
         dict(
-            desc='Create user %r with krb ticket policy' % user1,
+            desc='Create user "%s" with krb ticket policy' % user1,
             command=(
                 'user_add', [user1], dict(givenname=u'Test', sn=u'User1',
                 setattr=u'krbmaxticketlife=88000')
@@ -556,13 +555,13 @@ class test_user(Declarative):
 
 
         dict(
-            desc='Create %r' % user1,
+            desc='Create "%s"' % user1,
             command=(
                 'user_add', [user1], dict(givenname=u'Test', sn=u'User1')
             ),
             expected=dict(
                 value=user1,
-                summary=u'Added user "tuser1"',
+                summary=u'Added user "%s"' % user1,
                 result=dict(
                     gecos=[u'Test User1'],
                     givenname=[u'Test'],
@@ -580,13 +579,11 @@ class test_user(Declarative):
                     ipauniqueid=[fuzzy_uuid],
                     krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),
                                               ('cn','kerberos'),api.env.basedn)],
-                    mepmanagedentry=[DN(('cn',user1),('cn','groups'),('cn','accounts'),
-                                        api.env.basedn)],
+                    mepmanagedentry=[get_group_dn(user1)],
                     memberof_group=[u'ipausers'],
                     has_keytab=False,
                     has_password=False,
-                    dn=DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
-                          api.env.basedn),
+                    dn=get_user_dn(user1),
                 ),
             ),
             extra_check = upg_check,
@@ -594,13 +591,13 @@ class test_user(Declarative):
 
 
         dict(
-            desc='Create %r' % user2,
+            desc='Create "%s"' % user2,
             command=(
                 'user_add', [user2], dict(givenname=u'Test', sn=u'User2')
             ),
             expected=dict(
                 value=user2,
-                summary=u'Added user "tuser2"',
+                summary=u'Added user "%s"' % user2,
                 result=dict(
                     gecos=[u'Test User2'],
                     givenname=[u'Test'],
@@ -618,13 +615,11 @@ class test_user(Declarative):
                     ipauniqueid=[fuzzy_uuid],
                     krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),
                                               ('cn','kerberos'),api.env.basedn)],
-                    mepmanagedentry=[DN(('cn',user2),('cn','groups'),('cn','accounts'),
-                                        api.env.basedn)],
+                    mepmanagedentry=[get_group_dn(user2)],
                     memberof_group=[u'ipausers'],
                     has_keytab=False,
                     has_password=False,
-                    dn=DN(('uid','tuser2'),('cn','users'),('cn','accounts'),
-                          api.env.basedn),
+                    dn=get_user_dn(user2),
                 ),
             ),
             extra_check = upg_check,
@@ -632,7 +627,7 @@ class test_user(Declarative):
 
 
         dict(
-            desc='Make non-existent %r the manager of %r' % (renameduser1, user2),
+            desc='Make non-existent "%s" the manager of "%s"' % (renameduser1, user2),
             command=('user_mod', [user2], dict(manager=renameduser1)),
             expected=errors.NotFound(
                 reason=u'manager %s not found' % renameduser1),
@@ -640,7 +635,7 @@ class test_user(Declarative):
 
 
         dict(
-            desc='Make %r the manager of %r' % (user1, user2),
+            desc='Make "%s" the manager of "%s"' % (user1, user2),
             command=('user_mod', [user2], dict(manager=user1)),
             expected=dict(
                 result=dict(
@@ -664,7 +659,7 @@ class test_user(Declarative):
 
 
         dict(
-            desc='Delete %r and %r at the same time' % (user1, user2),
+            desc='Delete "%s" and "%s" at the same time' % (user1, user2),
             command=('user_del', [user1, user2], {}),
             expected=dict(
                 result=dict(failed=u''),
@@ -674,21 +669,21 @@ class test_user(Declarative):
         ),
 
         dict(
-            desc='Try to retrieve non-existent %r' % user1,
+            desc='Try to retrieve non-existent "%s"' % user1,
             command=('user_show', [user1], {}),
             expected=errors.NotFound(reason=u'%s: user not found' % user1),
         ),
 
 
         dict(
-            desc='Try to update non-existent %r' % user1,
+            desc='Try to update non-existent "%s"' % user1,
             command=('user_mod', [user1], dict(givenname=u'Foo')),
             expected=errors.NotFound(reason=u'%s: user not found' % user1),
         ),
 
 
         dict(
-            desc='Test an invalid login name %r' % invaliduser1,
+            desc='Test an invalid login name "%s"' % invaliduser1,
             command=('user_add', [invaliduser1], dict(givenname=u'Test', sn=u'User1')),
             expected=errors.ValidationError(name='login',
                 error=u'may only include letters, numbers, _, -, . and $'),
@@ -696,7 +691,7 @@ class test_user(Declarative):
 
 
         dict(
-            desc='Test a login name that is too long %r' % invaliduser2,
+            desc='Test a login name that is too long "%s"' % invaliduser2,
             command=('user_add', [invaliduser2],
                 dict(givenname=u'Test', sn=u'User1')),
             expected=errors.ValidationError(name='login',
@@ -735,7 +730,7 @@ class test_user(Declarative):
 
 
         dict(
-            desc='Try to rename to invalid username %r' % user1,
+            desc='Try to rename to invalid username "%s"' % user1,
             command=('user_mod', [user1], dict(rename=invaliduser1)),
             expected=errors.ValidationError(name='rename',
                 error=u'may only include letters, numbers, _, -, . and $'),
@@ -743,7 +738,7 @@ class test_user(Declarative):
 
 
         dict(
-            desc='Try to rename to a username that is too long %r' % user1,
+            desc='Try to rename to a username that is too long "%s"' % user1,
             command=('user_mod', [user1], dict(rename=invaliduser2)),
             expected=errors.ValidationError(name='login',
                 error='can be at most 32 characters'),
@@ -751,7 +746,7 @@ class test_user(Declarative):
 
 
         dict(
-            desc='Create %r' % group1,
+            desc='Create "%s"' % group1,
             command=(
                 'group_add', [group1], dict(description=u'Test desc')
             ),
@@ -764,15 +759,14 @@ class test_user(Declarative):
                     gidnumber=[fuzzy_digits],
                     objectclass=objectclasses.group + [u'posixgroup'],
                     ipauniqueid=[fuzzy_uuid],
-                    dn=DN(('cn',group1),('cn','groups'),('cn','accounts'),
-                          api.env.basedn),
+                    dn=get_group_dn(group1),
                 ),
             ),
         ),
 
 
         dict(
-            desc='Try to user %r where the managed group exists' % group1,
+            desc='Try to user "%s" where the managed group exists' % group1,
             command=(
                 'user_add', [group1], dict(givenname=u'Test', sn=u'User1')
             ),
@@ -781,7 +775,7 @@ class test_user(Declarative):
 
 
         dict(
-            desc='Create %r with a full address' % user1,
+            desc='Create "%s" with a full address' % user1,
             command=(
                 'user_add', [user1], dict(givenname=u'Test', sn=u'User1',
                 street=u'123 Maple Rd', l=u'Anytown', st=u'MD',
@@ -789,7 +783,7 @@ class test_user(Declarative):
             ),
             expected=dict(
                 value=user1,
-                summary=u'Added user "tuser1"',
+                summary=u'Added user "%s"' % user1,
                 result=dict(
                     gecos=[u'Test User1'],
                     givenname=[u'Test'],
@@ -812,36 +806,34 @@ class test_user(Declarative):
                     ipauniqueid=[fuzzy_uuid],
                     krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),
                                               ('cn','kerberos'),api.env.basedn)],
-                    mepmanagedentry=[DN(('cn',user1),('cn','groups'),('cn','accounts'),
-                                        api.env.basedn)],
+                    mepmanagedentry=[get_group_dn(user1)],
                     memberof_group=[u'ipausers'],
                     has_keytab=False,
                     has_password=False,
-                    dn=DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
-                          api.env.basedn),
+                    dn=get_user_dn(user1),
                 ),
             ),
         ),
 
 
         dict(
-            desc='Delete %r' % user1,
+            desc='Delete "%s"' % user1,
             command=('user_del', [user1], {}),
             expected=dict(
                 result=dict(failed=u''),
-                summary=u'Deleted user "tuser1"',
+                summary=u'Deleted user "%s"' % user1,
                 value=user1,
             ),
         ),
 
         dict(
-            desc='Create %r with random password' % user1,
+            desc='Create "%s" with random password' % user1,
             command=(
                 'user_add', [user1], dict(givenname=u'Test', sn=u'User1', random=True)
             ),
             expected=dict(
                 value=user1,
-                summary=u'Added user "tuser1"',
+                summary=u'Added user "%s"' % user1,
                 result=dict(
                     gecos=[u'Test User1'],
                     givenname=[u'Test'],
@@ -859,8 +851,7 @@ class test_user(Declarative):
                     ipauniqueid=[fuzzy_uuid],
                     krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),
                                               ('cn','kerberos'),api.env.basedn)],
-                    mepmanagedentry=[DN(('cn',user1),('cn','groups'),('cn','accounts'),
-                                        api.env.basedn)],
+                    mepmanagedentry=[get_group_dn(user1)],
                     memberof_group=[u'ipausers'],
                     has_keytab=True,
                     has_password=True,
@@ -868,30 +859,29 @@ class test_user(Declarative):
                     krbextradata=[fuzzy_string],
                     krbpasswordexpiration=[fuzzy_dergeneralizedtime],
                     krblastpwdchange=[fuzzy_dergeneralizedtime],
-                    dn=DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
-                          api.env.basedn),
+                    dn=get_user_dn(user1),
                 ),
             ),
         ),
 
         dict(
-            desc='Delete %r' % user1,
+            desc='Delete "%s"' % user1,
             command=('user_del', [user1], {}),
             expected=dict(
                 result=dict(failed=u''),
-                summary=u'Deleted user "tuser1"',
+                summary=u'Deleted user "%s"' % user1,
                 value=user1,
             ),
         ),
 
         dict(
-            desc='Create %r' % user2,
+            desc='Create "%s"' % user2,
             command=(
                 'user_add', [user2], dict(givenname=u'Test', sn=u'User2')
             ),
             expected=dict(
                 value=user2,
-                summary=u'Added user "tuser2"',
+                summary=u'Added user "%s"' % user2,
                 result=dict(
                     gecos=[u'Test User2'],
                     givenname=[u'Test'],
@@ -909,19 +899,17 @@ class test_user(Declarative):
                     ipauniqueid=[fuzzy_uuid],
                     krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),
                                               ('cn','kerberos'),api.env.basedn)],
-                    mepmanagedentry=[DN(('cn',user2),('cn','groups'),('cn','accounts'),
-                                        api.env.basedn)],
+                    mepmanagedentry=[get_group_dn(user2)],
                     memberof_group=[u'ipausers'],
                     has_keytab=False,
                     has_password=False,
-                    dn=DN(('uid','tuser2'),('cn','users'),('cn','accounts'),
-                          api.env.basedn),
+                    dn=get_user_dn(user2),
                 ),
             ),
         ),
 
         dict(
-            desc='Modify %r with random password' % user2,
+            desc='Modify "%s" with random password' % user2,
             command=(
                 'user_mod', [user2], dict(random=True)
             ),
@@ -940,30 +928,30 @@ class test_user(Declarative):
                     has_password=True,
                     randompassword=fuzzy_password,
                 ),
-                summary=u'Modified user "tuser2"',
+                summary=u'Modified user "%s"' % user2,
                 value=user2,
             ),
         ),
 
         dict(
-            desc='Delete %r' % user2,
+            desc='Delete "%s"' % user2,
             command=('user_del', [user2], {}),
             expected=dict(
                 result=dict(failed=u''),
-                summary=u'Deleted user "tuser2"',
+                summary=u'Deleted user "%s"' % user2,
                 value=user2,
             ),
         ),
 
         dict(
-            desc='Create user %r with upper-case principal' % user1,
+            desc='Create user "%s" 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"',
+                summary=u'Added user "%s"' % user1,
                 result=dict(
                     gecos=[u'Test User1'],
                     givenname=[u'Test'],
@@ -981,20 +969,18 @@ class test_user(Declarative):
                     ipauniqueid=[fuzzy_uuid],
                     krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),
                                               ('cn','kerberos'),api.env.basedn)],
-                    mepmanagedentry=[DN(('cn',user1),('cn','groups'),('cn','accounts'),
-                                        api.env.basedn)],
+                    mepmanagedentry=[get_group_dn(user1)],
                     memberof_group=[u'ipausers'],
                     has_keytab=False,
                     has_password=False,
-                    dn=DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
-                          api.env.basedn),
+                    dn=get_user_dn(user1),
                 ),
             ),
         ),
 
 
         dict(
-            desc='Create user %r with bad realm in principal' % user1,
+            desc='Create user "%s" with bad realm in principal' % user1,
             command=(
                 'user_add', [user1], dict(givenname=u'Test', sn=u'User1',
                 krbprincipalname='%s...@notfound.org' % user1)
@@ -1004,7 +990,7 @@ class test_user(Declarative):
 
 
         dict(
-            desc='Create user %r with malformed principal' % user1,
+            desc='Create user "%s" with malformed principal' % user1,
             command=(
                 'user_add', [user1], dict(givenname=u'Test', sn=u'User1',
                 krbprincipalname='%s@b...@notfound.org' % user1)
@@ -1013,11 +999,11 @@ class test_user(Declarative):
         ),
 
         dict(
-            desc='Delete %r' % user1,
+            desc='Delete "%s"' % user1,
             command=('user_del', [user1], {}),
             expected=dict(
                 result=dict(failed=u''),
-                summary=u'Deleted user "tuser1"',
+                summary=u'Deleted user "%s"' % user1,
                 value=user1,
             ),
         ),
@@ -1031,13 +1017,13 @@ class test_user(Declarative):
         ),
 
         dict(
-            desc='Create user %r with different default home directory' % user1,
+            desc='Create user "%s" with different default home directory' % user1,
             command=(
                 'user_add', [user1], dict(givenname=u'Test', sn=u'User1')
             ),
             expected=dict(
                 value=user1,
-                summary=u'Added user "tuser1"',
+                summary=u'Added user "%s"' % user1,
                 result=dict(
                     gecos=[u'Test User1'],
                     givenname=[u'Test'],
@@ -1055,13 +1041,11 @@ class test_user(Declarative):
                     ipauniqueid=[fuzzy_uuid],
                     krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),
                                               ('cn','kerberos'),api.env.basedn)],
-                    mepmanagedentry=[DN(('cn',user1),('cn','groups'),('cn','accounts'),
-                                        api.env.basedn)],
+                    mepmanagedentry=[get_group_dn(user1)],
                     memberof_group=[u'ipausers'],
                     has_keytab=False,
                     has_password=False,
-                    dn=DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
-                          api.env.basedn),
+                    dn=get_user_dn(user1),
                 ),
             ),
         ),
@@ -1076,7 +1060,7 @@ class test_user(Declarative):
         ),
 
         dict(
-            desc='Delete %r' % user1,
+            desc='Delete "%s"' % user1,
             command=('user_del', [user1], {}),
             expected=dict(
                 result=dict(failed=u''),
@@ -1094,13 +1078,13 @@ class test_user(Declarative):
         ),
 
         dict(
-            desc='Create user %r with different default login shell' % user1,
+            desc='Create user "%s" with different default login shell' % user1,
             command=(
                 'user_add', [user1], dict(givenname=u'Test', sn=u'User1')
             ),
             expected=dict(
                 value=user1,
-                summary=u'Added user "tuser1"',
+                summary=u'Added user "%s"' % user1,
                 result=dict(
                     gecos=[u'Test User1'],
                     givenname=[u'Test'],
@@ -1118,13 +1102,11 @@ class test_user(Declarative):
                     ipauniqueid=[fuzzy_uuid],
                     krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),
                                               ('cn','kerberos'),api.env.basedn)],
-                    mepmanagedentry=[DN(('cn',user1),('cn','groups'),('cn','accounts'),
-                                        api.env.basedn)],
+                    mepmanagedentry=[get_group_dn(user1)],
                     memberof_group=[u'ipausers'],
                     has_keytab=False,
                     has_password=False,
-                    dn=DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
-                          api.env.basedn),
+                    dn=get_user_dn(user1),
                 ),
             ),
         ),
@@ -1138,7 +1120,7 @@ class test_user(Declarative):
         ),
 
         dict(
-            desc='Delete %r' % user1,
+            desc='Delete "%s"' % user1,
             command=('user_del', [user1], {}),
             expected=dict(
                 result=dict(failed=u''),
@@ -1148,7 +1130,7 @@ class test_user(Declarative):
         ),
 
         dict(
-            desc='Create %r without UPG' % user1,
+            desc='Create "%s" without UPG' % user1,
             command=(
                 'user_add', [user1], dict(givenname=u'Test', sn=u'User1', noprivate=True)
             ),
@@ -1156,13 +1138,13 @@ class test_user(Declarative):
         ),
 
         dict(
-            desc='Create %r without UPG with GID explicitly set' % user2,
+            desc='Create "%s" without UPG with GID explicitly set' % user2,
             command=(
                 'user_add', [user2], dict(givenname=u'Test', sn=u'User2', noprivate=True, gidnumber=1000)
             ),
             expected=dict(
                 value=user2,
-                summary=u'Added user "tuser2"',
+                summary=u'Added user "%s"' % user2,
                 result=dict(
                     gecos=[u'Test User2'],
                     givenname=[u'Test'],
@@ -1184,14 +1166,13 @@ class test_user(Declarative):
                     memberof_group=[u'ipausers'],
                     has_keytab=False,
                     has_password=False,
-                    dn=DN(('uid','tuser2'),('cn','users'),('cn','accounts'),
-                          api.env.basedn),
+                    dn=get_user_dn(user2),
                 ),
             ),
         ),
 
         dict(
-            desc='Delete %r' % user2,
+            desc='Delete "%s"' % user2,
             command=('user_del', [user2], {}),
             expected=dict(
                 result=dict(failed=u''),
@@ -1209,13 +1190,13 @@ class test_user(Declarative):
         ),
 
         dict(
-            desc='Create %r without UPG' % user1,
+            desc='Create "%s" without UPG' % user1,
             command=(
                 'user_add', [user1], dict(givenname=u'Test', sn=u'User1', noprivate=True)
             ),
             expected=dict(
                 value=user1,
-                summary=u'Added user "tuser1"',
+                summary=u'Added user "%s"' % user1,
                 result=dict(
                     gecos=[u'Test User1'],
                     givenname=[u'Test'],
@@ -1237,21 +1218,20 @@ class test_user(Declarative):
                     memberof_group=[group1],
                     has_keytab=False,
                     has_password=False,
-                    dn=DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
-                          api.env.basedn),
+                    dn=get_user_dn(user1),
                 ),
             ),
             extra_check = not_upg_check,
         ),
 
         dict(
-            desc='Create %r without UPG with GID explicitly set' % user2,
+            desc='Create "%s" without UPG with GID explicitly set' % user2,
             command=(
                 'user_add', [user2], dict(givenname=u'Test', sn=u'User2', noprivate=True, gidnumber=1000)
             ),
             expected=dict(
                 value=user2,
-                summary=u'Added user "tuser2"',
+                summary=u'Added user "%s"' % user2,
                 result=dict(
                     gecos=[u'Test User2'],
                     givenname=[u'Test'],
@@ -1273,8 +1253,7 @@ class test_user(Declarative):
                     memberof_group=[group1],
                     has_keytab=False,
                     has_password=False,
-                    dn=DN(('uid','tuser2'),('cn','users'),('cn','accounts'),
-                          api.env.basedn),
+                    dn=get_user_dn(user2),
                 ),
             ),
         ),
@@ -1288,15 +1267,57 @@ class test_user(Declarative):
         ),
 
         dict(
-            desc='Try to remove the admin user',
-            command=('user_del', [u'admin'], {}),
-            expected=errors.LastMemberError(key=u'admin', label=u'group',
-                container='admins'),
+            desc='Try to remove the original admin user "%s"' % admin1,
+            command=('user_del', [admin1], {}),
+            expected=errors.LastMemberError(key=admin1, label=u'group',
+                container=admins_group),
+        ),
+
+        dict(
+            desc='Try to disable the original admin user "%s"' % admin1,
+            command=('user_disable', [admin1], {}),
+            expected=errors.LastMemberError(key=admin1, label=u'group',
+                container=admins_group),
+        ),
+
+
+        dict(
+            desc='Create 2nd admin user "%s"' % admin2,
+            command=(
+                'user_add', [admin2], dict(givenname=u'Second', sn=u'Admin')
+            ),
+            expected=dict(
+                value=admin2,
+                summary=u'Added user "%s"' % admin2,
+                result=dict(
+                    gecos=[u'Second Admin'],
+                    givenname=[u'Second'],
+                    homedirectory=[u'/home/admin2'],
+                    krbprincipalname=[u'admin2@' + api.env.realm],
+                    loginshell=[u'/bin/sh'],
+                    objectclass=objectclasses.user,
+                    sn=[u'Admin'],
+                    uid=[admin2],
+                    uidnumber=[fuzzy_digits],
+                    gidnumber=[fuzzy_digits],
+                    displayname=[u'Second Admin'],
+                    cn=[u'Second Admin'],
+                    initials=[u'SA'],
+                    ipauniqueid=[fuzzy_uuid],
+                    krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),
+                                              ('cn','kerberos'),api.env.basedn)],
+                    mepmanagedentry=[get_group_dn(admin2)],
+                    memberof_group=[u'ipausers'],
+                    has_keytab=False,
+                    has_password=False,
+                    dn=get_user_dn(admin2),
+                ),
+            ),
         ),
 
         dict(
-            desc='Add %r to the admins group' % user2,
-            command=('group_add_member', [u'admins'], dict(user=user2)),
+            desc='Add "%s" to the admins group "%s"' % (admin2, admins_group),
+            command=('group_add_member', [admins_group], dict(user=admin2)),
             expected=dict(
                 completed=1,
                 failed=dict(
@@ -1306,24 +1327,118 @@ class test_user(Declarative):
                     ),
                 ),
                 result={
-                        'dn': DN(('cn', 'admins'), ('cn', 'groups'),
-                                 ('cn', 'accounts'), api.env.basedn),
-                        'member_user': [u'admin', user2],
+                        'dn': get_group_dn(admins_group),
+                        'member_user': [admin1, admin2],
                         'gidnumber': [fuzzy_digits],
-                        'cn': [u'admins'],
+                        'cn': [admins_group],
                         'description': [u'Account administrators group'],
                 },
             ),
         ),
 
+
         dict(
-            desc='Delete %r' % user2,
-            command=('user_del', [user2], {}),
+            desc='Retrieve admins group "%s" to verify membership is "%s","%s"' % (admins_group, admin1, admin2),
+            command=('group_show', [admins_group], {}),
+            expected=dict(
+                value=admins_group,
+                result=dict(
+                    cn=[admins_group],
+                    gidnumber=[fuzzy_digits],
+                    description=[u'Account administrators group'],
+                    dn=get_group_dn(admins_group),
+                    member_user=[admin1, admin2],
+                ),
+                summary=None,
+            ),
+        ),
+
+        dict(
+            desc='Disable 2nd admin user "%s", admins group "%s" should also contain enabled "%s"' % (admin2, admins_group, admin1),
+            command=(
+                'user_disable', [admin2], {}
+            ),
+            expected=dict(
+                result=True,
+                value=admin2,
+                summary=u'Disabled user account "%s"' % admin2,
+            ),
+        ),
+
+        dict(
+            desc='Assert 2nd admin user "%s" is disabled' % admin2,
+            command=('user_find', [admin2], {}),
+            expected=dict(
+                result=[lambda d: d['nsaccountlock'] == True],
+                summary=u'1 user matched',
+                count=1,
+                truncated=False,
+            ),
+        ),
+
+        dict(
+            desc='Try to disable the origin admin user "%s"' % admin1,
+            command=('user_disable', [admin1], {}),
+            expected=errors.LastMemberError(key=admin1, label=u'group',
+                container=admins_group),
+        ),
+
+        dict(
+            desc='Try to remove the original admin user "%s"' % admin1,
+            command=('user_del', [admin1], {}),
+            expected=errors.LastMemberError(key=admin1, label=u'group',
+                container=admins_group),
+        ),
+
+        dict(
+            desc='Delete 2nd admin "%s"' % admin2,
+            command=('user_del', [admin2], {}),
             expected=dict(
                 result=dict(failed=u''),
-                summary=u'Deleted user "%s"' % user2,
-                value=user2,
+                summary=u'Deleted user "%s"' % admin2,
+                value=admin2,
             ),
         ),
 
+        dict(
+            desc='Retrieve admins group "%s" to verify membership is "%s"' % (admins_group, admin1),
+            command=('group_show', [admins_group], {}),
+            expected=dict(
+                value=admins_group,
+                result=dict(
+                    cn=[admins_group],
+                    gidnumber=[fuzzy_digits],
+                    description=[u'Account administrators group'],
+                    dn=get_group_dn(admins_group),
+                    member_user=[admin1],
+                ),
+                summary=None,
+            ),
+        ),
+
+        dict(
+            desc='Assert original admin user "%s" is enabled' % admin1,
+            command=('user_find', [admin1], {}),
+            expected=dict(
+                result=[lambda d: d['nsaccountlock'] == False],
+                summary=u'1 user matched',
+                count=1,
+                truncated=False,
+            ),
+        ),
+
+        dict(
+            desc='Try to remove the original admin user "%s"' % admin1,
+            command=('user_del', [admin1], {}),
+            expected=errors.LastMemberError(key=admin1, label=u'group',
+                container=admins_group),
+        ),
+
+        dict(
+            desc='Try to disable the original admin user "%s"' % admin1,
+            command=('user_disable', [admin1], {}),
+            expected=errors.LastMemberError(key=admin1, label=u'group',
+                container=admins_group),
+        ),
+
     ]
-- 
1.7.11.4

_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to