This is an automated email from the git hooks/post-receive script.
tbordaz pushed a commit to branch 389-ds-base-1.3.9
in repository 389-ds-base.
The following commit(s) were added to refs/heads/389-ds-base-1.3.9 by this push:
new 3f8221c Ticket 49985 - memberof may silently fails to update a member
3f8221c is described below
commit 3f8221c8103d19402e8f26ad74adcedf870d0f99
Author: Thierry Bordaz <tbordaz(a)redhat.com>
AuthorDate: Mon Oct 22 12:33:13 2018 +0200
Ticket 49985 - memberof may silently fails to update a member
Bug Description:
when adding 'memberof' to a member entry, the update may fail
(invalid schema, db errors...).
The error is reported at upper level. But in case of MODRDN
the error is lost in memberof_moddn_attr_list where returned
code of memberof_modop_one_replace_r is not tested
Fix Description:
Report a failure in memberof_moddn_attr_list as soon as
memberof_modop_one_replace_r fails
https://pagure.io/389-ds-base/issue/49985
Reviewed by: Simon Pichugi, William Brown
Platforms tested: F27
Flag Day: no
Doc impact: no
---
.../suites/memberof_plugin/regression_test.py | 858 +++++++++++++++++++++
ldap/servers/plugins/memberof/memberof.c | 4 +-
2 files changed, 860 insertions(+), 2 deletions(-)
diff --git a/dirsrvtests/tests/suites/memberof_plugin/regression_test.py
b/dirsrvtests/tests/suites/memberof_plugin/regression_test.py
new file mode 100644
index 0000000..2b0c4ae
--- /dev/null
+++ b/dirsrvtests/tests/suites/memberof_plugin/regression_test.py
@@ -0,0 +1,858 @@
+# --- BEGIN COPYRIGHT BLOCK ---
+# Copyright (C) 2017 Red Hat, Inc.
+# All rights reserved.
+#
+# License: GPL (version 3 or any later version).
+# See LICENSE for details.
+# --- END COPYRIGHT BLOCK ---
+#
+import logging
+import pytest
+import os
+import time
+import ldap
+import subprocess
+from random import sample
+from lib389.utils import ds_is_older, ensure_list_bytes, ensure_bytes, ensure_str
+from lib389.topologies import topology_m1h1c1 as topo, topology_st, topology_m2 as
topo_m2
+from lib389._constants import *
+from lib389.plugins import MemberOfPlugin
+from lib389 import agreement, Entry
+from lib389.idm.user import UserAccount, UserAccounts, TEST_USER_PROPERTIES
+from lib389.idm.group import Groups, Group
+from lib389.replica import ReplicationManager
+from lib389.tasks import *
+from lib389.idm.nscontainer import nsContainers
+
+
+# Skip on older versions
+pytestmark = pytest.mark.skipif(ds_is_older('1.3.7'), reason="Not
implemented")
+
+USER_CN = 'user_'
+GROUP_CN = 'group1'
+DEBUGGING = os.getenv('DEBUGGING', False)
+SUBTREE_1 = 'cn=sub1,%s' % SUFFIX
+SUBTREE_2 = 'cn=sub2,%s' % SUFFIX
+
+
+if DEBUGGING:
+ logging.getLogger(__name__).setLevel(logging.DEBUG)
+else:
+ logging.getLogger(__name__).setLevel(logging.INFO)
+log = logging.getLogger(__name__)
+
+
+def add_users(topo_m2, users_num, suffix):
+ """Add users to the default suffix
+ Return the list of added user DNs.
+ """
+ users_list = []
+ users = UserAccounts(topo_m2.ms["master1"], suffix, rdn=None)
+ log.info('Adding %d users' % users_num)
+ for num in sample(range(1000), users_num):
+ num_ran = int(round(num))
+ USER_NAME = 'test%05d' % num_ran
+ user = users.create(properties={
+ 'uid': USER_NAME,
+ 'sn': USER_NAME,
+ 'cn': USER_NAME,
+ 'uidNumber': '%s' % num_ran,
+ 'gidNumber': '%s' % num_ran,
+ 'homeDirectory': '/home/%s' % USER_NAME,
+ 'mail': '%s(a)redhat.com' % USER_NAME,
+ 'userpassword': 'pass%s' % num_ran,
+ })
+ users_list.append(user)
+ return users_list
+
+
+def config_memberof(server):
+ # Configure fractional to prevent total init to send memberof
+ memberof = MemberOfPlugin(server)
+ memberof.enable()
+ memberof.set_autoaddoc('nsMemberOf')
+ server.restart()
+ ents = server.agreement.list(suffix=DEFAULT_SUFFIX)
+ for ent in ents:
+ log.info('update %s to add nsDS5ReplicatedAttributeListTotal' % ent.dn)
+ server.agreement.setProperties(agmnt_dn=ents[0].dn,
+ properties={RA_FRAC_EXCLUDE:'(objectclass=*) $
EXCLUDE memberOf',
+
RA_FRAC_EXCLUDE_TOTAL_UPDATE:'(objectclass=*) $ EXCLUDE '})
+
+
+def send_updates_now(server):
+ ents = server.agreement.list(suffix=DEFAULT_SUFFIX)
+ for ent in ents:
+ server.agreement.pause(ent.dn)
+ server.agreement.resume(ent.dn)
+
+
+def _find_memberof(server, member_dn, group_dn):
+ #To get the specific server's (M1, C1 and H1) user and group
+ user = UserAccount(server, member_dn)
+ assert user.exists()
+ group = Group(server, group_dn)
+ assert group.exists()
+
+ #test that the user entry should have memberof attribute with sepecified group dn
value
+ assert group._dn in user.get_attr_vals_utf8('memberOf')
+
+
+(a)pytest.mark.bz1352121
+def test_memberof_with_repl(topo):
+ """Test that we allowed to enable MemberOf plugin in dedicated
consumer
+
+ :id: 60c11636-55a1-4704-9e09-2c6bcc828de4
+ :setup: 1 Master - 1 Hub - 1 Consumer
+ :steps:
+ 1. Configure replication to EXCLUDE memberof
+ 2. Enable memberof plugin
+ 3. Create users/groups
+ 4. Make user_0 member of group_0
+ 5. Checks that user_0 is memberof group_0 on M,H,C
+ 6. Make group_0 member of group_1 (nest group)
+ 7. Checks that user_0 is memberof group_0 and group_1 on M,H,C
+ 8. Check group_0 is memberof group_1 on M,H,C
+ 9. Remove group_0 from group_1
+ 10. Check group_0 and user_0 are NOT memberof group_1 on M,H,C
+ 11. Remove user_0 from group_0
+ 12. Check user_0 is not memberof group_0 and group_1 on M,H,C
+ 13. Disable memberof on C
+ 14. make user_0 member of group_1
+ 15. Checks that user_0 is memberof group_0 on M,H but not on C
+ 16. Enable memberof on C
+ 17. Checks that user_0 is memberof group_0 on M,H but not on C
+ 18. Run memberof fixup task
+ 19. Checks that user_0 is memberof group_0 on M,H,C
+ :expectedresults:
+ 1. Configuration should be successful
+ 2. Plugin should be enabled
+ 3. Users and groups should be created
+ 4. user_0 should be member of group_0
+ 5. user_0 should be memberof group_0 on M,H,C
+ 6. group_0 should be member of group_1
+ 7. user_0 should be memberof group_0 and group_1 on M,H,C
+ 8. group_0 should be memberof group_1 on M,H,C
+ 9. group_0 from group_1 removal should be successful
+ 10. group_0 and user_0 should not be memberof group_1 on M,H,C
+ 11. user_0 from group_0 remove should be successful
+ 12. user_0 should not be memberof group_0 and group_1 on M,H,C
+ 13. memberof should be disabled on C
+ 14. user_0 should be member of group_1
+ 15. user_0 should be memberof group_0 on M,H and should not on C
+ 16. Enable memberof on C should be successful
+ 17. user_0 should be memberof group_0 on M,H should not on C
+ 18. memberof fixup task should be successful
+ 19. user_0 should be memberof group_0 on M,H,C
+ """
+
+ M1 = topo.ms["master1"]
+ H1 = topo.hs["hub1"]
+ C1 = topo.cs["consumer1"]
+
+ # Step 1 & 2
+ M1.config.enable_log('audit')
+ config_memberof(M1)
+ M1.restart()
+
+ H1.config.enable_log('audit')
+ config_memberof(H1)
+ H1.restart()
+
+ C1.config.enable_log('audit')
+ config_memberof(C1)
+ C1.restart()
+
+ #Declare lists of users and groups
+ test_users = []
+ test_groups = []
+
+ # Step 3
+ #In for loop create users and add them in the user list
+ #it creates user_0 to user_9 (range is fun)
+ for i in range(10):
+ CN = '%s%d' % (USER_CN, i)
+ users = UserAccounts(M1, SUFFIX)
+ user_props = TEST_USER_PROPERTIES.copy()
+ user_props.update({'uid': CN, 'cn': CN, 'sn':
'_%s' % CN})
+ testuser = users.create(properties=user_props)
+ time.sleep(2)
+ test_users.append(testuser)
+
+ #In for loop create groups and add them to the group list
+ #it creates group_0 to group_2 (range is fun)
+ for i in range(3):
+ CN = '%s%d' % (GROUP_CN, i)
+ groups = Groups(M1, SUFFIX)
+ testgroup = groups.create(properties={'cn' : CN})
+ time.sleep(2)
+ test_groups.append(testgroup)
+
+ # Step 4
+ #Now start testing by adding differnt user to differn group
+ if not ds_is_older('1.3.7'):
+ test_groups[0].remove('objectClass', 'nsMemberOf')
+
+ member_dn = test_users[0].dn
+ grp0_dn = test_groups[0].dn
+ grp1_dn = test_groups[1].dn
+
+ test_groups[0].add_member(member_dn)
+ time.sleep(5)
+
+ # Step 5
+ for i in [M1, H1, C1]:
+ _find_memberof(i, member_dn, grp0_dn)
+
+ # Step 6
+ test_groups[1].add_member(test_groups[0].dn)
+ time.sleep(5)
+
+ # Step 7
+ for i in [grp0_dn, grp1_dn]:
+ for inst in [M1, H1, C1]:
+ _find_memberof(inst, member_dn, i)
+
+ # Step 8
+ for i in [M1, H1, C1]:
+ _find_memberof(i, grp0_dn, grp1_dn)
+
+ # Step 9
+ test_groups[1].remove_member(test_groups[0].dn)
+ time.sleep(5)
+
+ # Step 10
+ # For negative testcase, we are using assertionerror
+ for inst in [M1, H1, C1]:
+ for i in [grp0_dn, member_dn]:
+ with pytest.raises(AssertionError):
+ _find_memberof(inst, i, grp1_dn)
+
+ # Step 11
+ test_groups[0].remove_member(member_dn)
+ time.sleep(5)
+
+ # Step 12
+ for inst in [M1, H1, C1]:
+ for grp in [grp0_dn, grp1_dn]:
+ with pytest.raises(AssertionError):
+ _find_memberof(inst, member_dn, grp)
+
+ # Step 13
+ C1.plugins.disable(name=PLUGIN_MEMBER_OF)
+ C1.restart()
+
+ # Step 14
+ test_groups[0].add_member(member_dn)
+ time.sleep(5)
+
+ # Step 15
+ for i in [M1, H1]:
+ _find_memberof(i, member_dn, grp0_dn)
+ with pytest.raises(AssertionError):
+ _find_memberof(C1, member_dn, grp0_dn)
+
+ # Step 16
+ memberof = MemberOfPlugin(C1)
+ memberof.enable()
+ C1.restart()
+
+ # Step 17
+ for i in [M1, H1]:
+ _find_memberof(i, member_dn, grp0_dn)
+ with pytest.raises(AssertionError):
+ _find_memberof(C1, member_dn, grp0_dn)
+
+ # Step 18
+ memberof.fixup(SUFFIX)
+ time.sleep(5)
+
+ # Step 19
+ for i in [M1, H1, C1]:
+ _find_memberof(i, member_dn, grp0_dn)
+
+
+(a)pytest.mark.skipif(ds_is_older('1.3.7'), reason="Not implemented")
+def test_scheme_violation_errors_logged(topo_m2):
+ """Check that ERR messages are verbose enough, if a member entry
+ doesn't have the appropriate objectclass to support 'memberof' attribute
+
+ :id: e2af0aaa-447e-4e85-a5ce-57ae66260d0b
+ :setup: Standalone instance
+ :steps:
+ 1. Enable memberofPlugin and set autoaddoc to nsMemberOf
+ 2. Restart the instance
+ 3. Add a user without nsMemberOf attribute
+ 4. Create a group and add the user to the group
+ 5. Check that user has memberOf attribute
+ 6. Check the error log for ".*oc_check_allowed_sv.*USER_DN.*memberOf.*not
allowed.*"
+ and ".*schema violation caught - repair operation.*" patterns
+ :expectedresults:
+ 1. Should be successful
+ 2. Should be successful
+ 3. Should be successful
+ 4. Should be successful
+ 5. User should have the attribute
+ 6. Errors should be logged
+ """
+
+ inst = topo_m2.ms["master1"]
+ memberof = MemberOfPlugin(inst)
+ memberof.enable()
+ memberof.set_autoaddoc('nsMemberOf')
+ inst.restart()
+
+ users = UserAccounts(inst, SUFFIX)
+ user_props = TEST_USER_PROPERTIES.copy()
+ user_props.update({'uid': USER_CN, 'cn': USER_CN, 'sn':
USER_CN})
+ testuser = users.create(properties=user_props)
+ testuser.remove('objectclass', 'nsMemberOf')
+
+ groups = Groups(inst, SUFFIX)
+ testgroup = groups.create(properties={'cn': GROUP_CN})
+
+ testgroup.add('member', testuser.dn)
+
+ user_memberof_attr = testuser.get_attr_val_utf8('memberof')
+ assert user_memberof_attr
+ log.info('memberOf attr value - {}'.format(user_memberof_attr))
+
+ pattern = ".*oc_check_allowed_sv.*{}.*memberOf.*not
allowed.*".format(testuser.dn)
+ log.info("pattern = %s" % pattern)
+ assert inst.ds_error_log.match(pattern)
+
+ pattern = ".*schema violation caught - repair operation.*"
+ assert inst.ds_error_log.match(pattern)
+
+
+(a)pytest.mark.bz1192099
+def test_memberof_with_changelog_reset(topo_m2):
+ """Test that replication does not break, after DS stop-start, due to
changelog reset
+
+ :id: 60c11636-55a1-4704-9e09-2c6bcc828de4
+ :setup: 2 Masters
+ :steps:
+ 1. On M1 and M2, Enable memberof
+ 2. On M1, add 999 entries allowing memberof
+ 3. On M1, add a group with these 999 entries as members
+ 4. Stop M1 in between,
+ when add the group memerof is called and before it is finished the
+ add, so step 4 should be executed after memberof has started and
+ before the add has finished
+ 5. Check that replication is working fine
+ :expectedresults:
+ 1. memberof should be enabled
+ 2. Entries should be added
+ 3. Add operation should start
+ 4. M1 should be stopped
+ 5. Replication should be working fine
+ """
+ m1 = topo_m2.ms["master1"]
+ m2 = topo_m2.ms["master2"]
+
+ log.info("Configure memberof on M1 and M2")
+ memberof = MemberOfPlugin(m1)
+ memberof.enable()
+ memberof.set_autoaddoc('nsMemberOf')
+ m1.restart()
+
+ memberof = MemberOfPlugin(m2)
+ memberof.enable()
+ memberof.set_autoaddoc('nsMemberOf')
+ m2.restart()
+
+ log.info("On M1, add 999 test entries allowing memberof")
+ users_list = add_users(topo_m2, 999, DEFAULT_SUFFIX)
+
+ log.info("On M1, add a group with these 999 entries as members")
+ dic_of_attributes = {'cn': ensure_bytes('testgroup'),
+ 'objectclass': ensure_list_bytes(['top',
'groupOfNames'])}
+
+ for user in users_list:
+ dic_of_attributes.setdefault('member',[])
+ dic_of_attributes['member'].append(user.dn)
+
+ log.info('Adding the test group using async function')
+ groupdn = 'cn=testgroup,%s' % DEFAULT_SUFFIX
+ m1.add(Entry((groupdn, dic_of_attributes)))
+
+ #shutdown the server in-between adding the group
+ m1.stop()
+
+ #start the server
+ m1.start()
+
+ log.info("Check the log messages for error")
+ error_msg = "ERR - NSMMReplicationPlugin - ruv_compare_ruv"
+ assert not m1.ds_error_log.match(error_msg)
+
+ log.info("Check that the replication is working fine both ways, M1 <->
M2")
+ repl = ReplicationManager(DEFAULT_SUFFIX)
+ repl.test_replication_topology(topo_m2)
+
+
+def add_container(inst, dn, name, sleep=False):
+ """Creates container entry"""
+ conts = nsContainers(inst, dn)
+ cont = conts.create(properties={'cn': name})
+ if sleep:
+ time.sleep(1)
+ return cont
+
+
+def add_member(server, cn, subtree):
+ dn = subtree
+ users = UserAccounts(server, dn, rdn=None)
+ users.create(properties={'uid': 'test_%s' % cn,
+ 'cn': "%s" % cn,
+ 'sn': 'SN',
+ 'description': 'member',
+ 'uidNumber': '1000',
+ 'gidNumber': '2000',
+ 'homeDirectory': '/home/testuser'
+ })
+
+
+def add_group(server, cn, subtree):
+ group = Groups(server, subtree, rdn=None)
+ group.create(properties={'cn': "%s" % cn,
+ 'member': ['uid=test_m1,%s' % SUBTREE_1,
'uid=test_m2,%s' % SUBTREE_1],
+ 'description': 'group'})
+
+
+def rename_entry(server, cn, from_subtree, to_subtree):
+ dn = '%s,%s' % (cn, from_subtree)
+ nrdn = '%s-new' % cn
+ log.fatal('Renaming user (%s): new %s' % (dn, nrdn))
+ server.rename_s(dn, nrdn, newsuperior=to_subtree, delold=0)
+
+
+def _find_memberof(server, user_dn=None, group_dn=None, find_result=True):
+ assert (server)
+ assert (user_dn)
+ assert (group_dn)
+ ent = server.getEntry(user_dn, ldap.SCOPE_BASE, "(objectclass=*)",
['memberof'])
+ found = False
+ if ent.hasAttr('memberof'):
+
+ for val in ent.getValues('memberof'):
+ server.log.info("!!!!!!! %s: memberof->%s" % (user_dn, val))
+ if ensure_str(val) == group_dn:
+ found = True
+ break
+
+ if find_result:
+ assert found
+ else:
+ assert (not found)
+
+
+(a)pytest.mark.ds49161
+def test_memberof_group(topology_st):
+ """Test memberof does not fail if group is moved into scope
+
+ :id: 552850aa-agc3-473e-9d39-aae812b46f11
+
+ :setup: Single instance
+
+ :steps:
+ 1. Enable memberof plugin and set memberofentryscope
+ 2. Restart the server
+ 3. Add test sub-suffixes
+ 4. Add test users
+ 5. Add test groups
+ 6. Check for memberof attribute added to the test users
+ 7. Rename the group entry
+ 8. Check the new name is reflected in memberof attribute of user
+
+ :expectedresults:
+ 1. memberof plugin should be enabled and memberofentryscope should be set
+ 2. Server should be restarted
+ 3. Sub-suffixes should be added
+ 4. Test users should be added
+ 5. Test groups should be added
+ 6. memberof attribute should be present in the test users
+ 7. Group entry should be renamed
+ 8. New group name should be present in memberof attribute of user
+ """
+
+ inst = topology_st.standalone
+ log.info('Enable memberof plugin and set the scope as
cn=sub1,dc=example,dc=com')
+ memberof = MemberOfPlugin(inst)
+ memberof.enable()
+ memberof.replace('memberOfEntryScope', SUBTREE_1)
+ inst.restart()
+
+ add_container(inst, SUFFIX, 'sub1')
+ add_container(inst, SUFFIX, 'sub2')
+ add_member(inst, 'm1', SUBTREE_1)
+ add_member(inst, 'm2', SUBTREE_1)
+ add_group(inst, 'g1', SUBTREE_1)
+ add_group(inst, 'g2', SUBTREE_2)
+
+ # _check_memberof
+ dn1 = '%s,%s' % ('uid=test_m1', SUBTREE_1)
+ dn2 = '%s,%s' % ('uid=test_m2', SUBTREE_1)
+ g1 = '%s,%s' % ('cn=g1', SUBTREE_1)
+ g2 = '%s,%s' % ('cn=g2', SUBTREE_2)
+ _find_memberof(inst, dn1, g1, True)
+ _find_memberof(inst, dn2, g1, True)
+ _find_memberof(inst, dn1, g2, False)
+ _find_memberof(inst, dn2, g2, False)
+
+ rename_entry(inst, 'cn=g2', SUBTREE_2, SUBTREE_1)
+
+ g2n = '%s,%s' % ('cn=g2-new', SUBTREE_1)
+ _find_memberof(inst, dn1, g1, True)
+ _find_memberof(inst, dn2, g1, True)
+ _find_memberof(inst, dn1, g2n, True)
+ _find_memberof(inst, dn2, g2n, True)
+
+def _config_memberof_entrycache_on_modrdn_failure(server):
+
+ server.plugins.enable(name=PLUGIN_MEMBER_OF)
+ peoplebase = 'ou=people,%s' % SUFFIX
+ MEMBEROF_PLUGIN_DN = ('cn=' + PLUGIN_MEMBER_OF +
',cn=plugins,cn=config')
+ server.modify_s(MEMBEROF_PLUGIN_DN, [(ldap.MOD_REPLACE,
'memberOfAllBackends', b'on'),
+ (ldap.MOD_REPLACE, 'memberOfEntryScope',
peoplebase.encode()),
+ (ldap.MOD_REPLACE, 'memberOfAutoAddOC',
b'nsMemberOf')])
+
+def _disable_auto_oc_memberof(server):
+ MEMBEROF_PLUGIN_DN = ('cn=' + PLUGIN_MEMBER_OF +
',cn=plugins,cn=config')
+ server.modify_s(MEMBEROF_PLUGIN_DN,
+ [(ldap.MOD_REPLACE, 'memberOfAutoAddOC', b'nsContainer')])
+
+(a)pytest.mark.ds49967
+def test_entrycache_on_modrdn_failure(topology_st):
+ """This test checks that when a modrdn fails, the destination entry is
not returned by a search
+ This could happen in case the destination entry remains in the entry cache
+
+ :id: a4d8ac0b-2448-406a-9dc2-5a72851e30b6
+ :setup: Standalone Instance
+ :steps:
+ 1. configure memberof to only scope ou=people,SUFFIX
+ 2. Creates 10 users
+ 3. Create groups0 (in peoplebase) that contain user0 and user1
+ 4. Check user0 and user1 have memberof=group0.dn
+ 5. Create group1 (OUT peoplebase) that contain user0 and user1
+ 6. Check user0 and user1 have NOT memberof=group1.dn
+ 7. Move group1 IN peoplebase and check users0 and user1 HAVE memberof=group1.dn
+ 8. Create group2 (OUT peoplebase) that contain user2 and user3. Group2 contains a
specific description value
+ 9. Check user2 and user3 have NOT memberof=group2.dn
+ 10. configure memberof so that added objectclass does not allow
'memberof' attribute
+ 11. Move group2 IN peoplebase and check move failed OPERATIONS_ERROR (because
memberof failed)
+ 12. Search all groups and check that the group, having the specific description
value,
+ has the original DN of group2.dn
+ :expectedresults:
+ 1. should succeed
+ 2. should succeed
+ 3. should succeed
+ 4. should succeed
+ 5. should succeed
+ 6. should succeed
+ 7. should succeed
+ 8. should succeed
+ 9. should succeed
+ 10. should succeed
+ 11. should fail OPERATION_ERROR because memberof plugin fails to add
'memberof' to members.
+ 12. should succeed
+
+ """
+
+ # only scopes peoplebase
+ _config_memberof_entrycache_on_modrdn_failure(topology_st.standalone)
+ topology_st.standalone.restart(timeout=10)
+
+ # create 10 users
+ peoplebase = 'ou=people,%s' % SUFFIX
+ for i in range(10):
+ cn = 'user%d' % i
+ dn = 'cn=%s,%s' % (cn, peoplebase)
+ log.fatal('Adding user (%s): ' % dn)
+ topology_st.standalone.add_s(Entry((dn, {'objectclass': ['top',
'person'],
+ 'sn': 'user_%s' % cn,
+ 'description': 'add on standalone'})))
+
+ # Check that members of group0 (in the scope) have 'memberof
+ group0_dn = 'cn=group_in0,%s' % peoplebase
+ topology_st.standalone.add_s(Entry((group0_dn, {'objectclass':
['top', 'groupofnames'],
+ 'member': [
+ 'cn=user0,%s' % peoplebase,
+ 'cn=user1,%s' % peoplebase,
+ ],
+ 'description': 'mygroup'})))
+
+ # Check the those entries have memberof with group0
+ for i in range(2):
+ user_dn = 'cn=user%d,%s' % (i, peoplebase)
+ ent = topology_st.standalone.getEntry(user_dn, ldap.SCOPE_BASE,
"(objectclass=*)", ['memberof'])
+ assert ent.hasAttr('memberof')
+ found = False
+ for val in ent.getValues('memberof'):
+ topology_st.standalone.log.info("!!!!!!! %s: memberof->%s (vs
%s)" % (user_dn, val, group0_dn.encode().lower()))
+ if val.lower() == group0_dn.encode().lower():
+ found = True
+ break
+ assert found
+
+ # Create a group1 out of the scope
+ group1_dn = 'cn=group_out1,%s' % SUFFIX
+ topology_st.standalone.add_s(Entry((group1_dn, {'objectclass':
['top', 'groupofnames'],
+ 'member': [
+ 'cn=user0,%s' % peoplebase,
+ 'cn=user1,%s' % peoplebase,
+ ],
+ 'description': 'mygroup'})))
+
+ # Check the those entries have not memberof with group1
+ for i in range(2):
+ user_dn = 'cn=user%d,%s' % (i, peoplebase)
+ ent = topology_st.standalone.getEntry(user_dn, ldap.SCOPE_BASE,
"(objectclass=*)", ['memberof'])
+ assert ent.hasAttr('memberof')
+ found = False
+ for val in ent.getValues('memberof'):
+ topology_st.standalone.log.info("!!!!!!! %s: memberof->%s (vs
%s)" % (user_dn, val, group1_dn.encode().lower()))
+ if val.lower() == group1_dn.encode().lower():
+ found = True
+ break
+ assert not found
+
+ # move group1 into the scope and check user0 and user1 are memberof group1
+ topology_st.standalone.rename_s(group1_dn, 'cn=group_in1',
newsuperior=peoplebase, delold=0)
+ new_group1_dn = 'cn=group_in1,%s' % peoplebase
+ for i in range(2):
+ user_dn = 'cn=user%d,%s' % (i, peoplebase)
+ ent = topology_st.standalone.getEntry(user_dn, ldap.SCOPE_BASE,
"(objectclass=*)", ['memberof'])
+ assert ent.hasAttr('memberof')
+ found = False
+ for val in ent.getValues('memberof'):
+ topology_st.standalone.log.info("!!!!!!! %s: memberof->%s (vs
%s)" % (user_dn, val, new_group1_dn.encode().lower()))
+ if val.lower() == new_group1_dn.encode().lower():
+ found = True
+ break
+ assert found
+
+ # Create a group2 out of the scope with a SPECIFIC description value
+ entry_description = "this is to check that the entry having this description has
the appropriate DN"
+ group2_dn = 'cn=group_out2,%s' % SUFFIX
+ topology_st.standalone.add_s(Entry((group2_dn, {'objectclass':
['top', 'groupofnames'],
+ 'member': [
+ 'cn=user2,%s' % peoplebase,
+ 'cn=user3,%s' % peoplebase,
+ ],
+ 'description': entry_description})))
+
+ # Check the those entries have not memberof with group2
+ for i in (2, 3):
+ user_dn = 'cn=user%d,%s' % (i, peoplebase)
+ ent = topology_st.standalone.getEntry(user_dn, ldap.SCOPE_BASE,
"(objectclass=*)", ['memberof'])
+ assert not ent.hasAttr('memberof')
+
+ # memberof will not add the missing objectclass
+ _disable_auto_oc_memberof(topology_st.standalone)
+ topology_st.standalone.restart(timeout=10)
+
+ # move group2 into the scope and check it fails
+ try:
+ topology_st.standalone.rename_s(group2_dn, 'cn=group_in2',
newsuperior=peoplebase, delold=0)
+ topology_st.standalone.log.info("This is unexpected, modrdn should fail as
the member entry have not the appropriate objectclass")
+ assert False
+ except ldap.OPERATIONS_ERROR:
+ pass
+
+ # retrieve the entry having the specific description value
+ # check that the entry DN is the original group2 DN
+ ents = topology_st.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE,
'(cn=gr*)')
+ found = False
+ for ent in ents:
+ topology_st.standalone.log.info("retrieve: %s with desc=%s" % (ent.dn,
ent.getValue('description')))
+ if ent.getValue('description') == entry_description.encode():
+ found = True
+ assert ent.dn == group2_dn
+ assert found
+
+def _config_memberof_silent_memberof_failure(server):
+ _config_memberof_entrycache_on_modrdn_failure(server)
+
+def test_silent_memberof_failure(topology_st):
+ """This test checks that if during a MODRDN, the memberof plugin
fails
+ then MODRDN also fails
+
+ :id: 095aee01-581c-43dd-a241-71f9631a18bb
+ :setup: Standalone Instance
+ :steps:
+ 1. configure memberof to only scope ou=people,SUFFIX
+ 2. Do some cleanup and Creates 10 users
+ 3. Create groups0 (IN peoplebase) that contain user0 and user1
+ 4. Check user0 and user1 have memberof=group0.dn
+ 5. Create group1 (OUT peoplebase) that contain user0 and user1
+ 6. Check user0 and user1 have NOT memberof=group1.dn
+ 7. Move group1 IN peoplebase and check users0 and user1 HAVE memberof=group1.dn
+ 8. Create group2 (OUT peoplebase) that contain user2 and user3.
+ 9. Check user2 and user3 have NOT memberof=group2.dn
+ 10. configure memberof so that added objectclass does not allow
'memberof' attribute
+ 11. Move group2 IN peoplebase and check move failed OPERATIONS_ERROR (because
memberof failed)
+ 12. Check user2 and user3 have NOT memberof=group2.dn
+ 13. ADD group3 (IN peoplebase) with user4 and user5 members and check add failed
OPERATIONS_ERROR (because memberof failed)
+ 14. Check user4 and user5 have NOT memberof=group2.dn
+ :expectedresults:
+ 1. should succeed
+ 2. should succeed
+ 3. should succeed
+ 4. should succeed
+ 5. should succeed
+ 6. should succeed
+ 7. should succeed
+ 8. should succeed
+ 9. should succeed
+ 10. should succeed
+ 11. should fail OPERATION_ERROR because memberof plugin fails to add
'memberof' to members.
+ 12. should succeed
+ 14. should fail OPERATION_ERROR because memberof plugin fails to add
'memberof' to members
+ 14. should succeed
+ """
+ # only scopes peoplebase
+ _config_memberof_silent_memberof_failure(topology_st.standalone)
+ topology_st.standalone.restart(timeout=10)
+
+ # first do some cleanup
+ peoplebase = 'ou=people,%s' % SUFFIX
+ for i in range(10):
+ cn = 'user%d' % i
+ dn = 'cn=%s,%s' % (cn, peoplebase)
+ topology_st.standalone.delete_s(dn)
+ topology_st.standalone.delete_s('cn=group_in0,%s' % peoplebase)
+ topology_st.standalone.delete_s('cn=group_in1,%s' % peoplebase)
+ topology_st.standalone.delete_s('cn=group_out2,%s' % SUFFIX)
+
+ # create 10 users
+ for i in range(10):
+ cn = 'user%d' % i
+ dn = 'cn=%s,%s' % (cn, peoplebase)
+ log.fatal('Adding user (%s): ' % dn)
+ topology_st.standalone.add_s(Entry((dn, {'objectclass': ['top',
'person'],
+ 'sn': 'user_%s' % cn,
+ 'description': 'add on standalone'})))
+
+ # Check that members of group0 (in the scope) have 'memberof
+ group0_dn = 'cn=group_in0,%s' % peoplebase
+ topology_st.standalone.add_s(Entry((group0_dn, {'objectclass':
['top', 'groupofnames'],
+ 'member': [
+ 'cn=user0,%s' % peoplebase,
+ 'cn=user1,%s' % peoplebase,
+ ],
+ 'description': 'mygroup'})))
+
+ # Check the those entries have memberof with group0
+ for i in range(2):
+ user_dn = 'cn=user%d,%s' % (i, peoplebase)
+ ent = topology_st.standalone.getEntry(user_dn, ldap.SCOPE_BASE,
"(objectclass=*)", ['memberof'])
+ assert ent.hasAttr('memberof')
+ found = False
+ for val in ent.getValues('memberof'):
+ topology_st.standalone.log.info("!!!!!!! %s: memberof->%s (vs
%s)" % (user_dn, val, group0_dn.encode().lower()))
+ if val.lower() == group0_dn.encode().lower():
+ found = True
+ break
+ assert found
+
+ # Create a group1 out of the scope
+ group1_dn = 'cn=group_out1,%s' % SUFFIX
+ topology_st.standalone.add_s(Entry((group1_dn, {'objectclass':
['top', 'groupofnames'],
+ 'member': [
+ 'cn=user0,%s' % peoplebase,
+ 'cn=user1,%s' % peoplebase,
+ ],
+ 'description': 'mygroup'})))
+
+ # Check the those entries have not memberof with group1
+ for i in range(2):
+ user_dn = 'cn=user%d,%s' % (i, peoplebase)
+ ent = topology_st.standalone.getEntry(user_dn, ldap.SCOPE_BASE,
"(objectclass=*)", ['memberof'])
+ assert ent.hasAttr('memberof')
+ found = False
+ for val in ent.getValues('memberof'):
+ topology_st.standalone.log.info("!!!!!!! %s: memberof->%s (vs
%s)" % (user_dn, val, group1_dn.encode().lower()))
+ if val.lower() == group1_dn.encode().lower():
+ found = True
+ break
+ assert not found
+
+ # move group1 into the scope and check user0 and user1 are memberof group1
+ topology_st.standalone.rename_s(group1_dn, 'cn=group_in1',
newsuperior=peoplebase, delold=0)
+ new_group1_dn = 'cn=group_in1,%s' % peoplebase
+ for i in range(2):
+ user_dn = 'cn=user%d,%s' % (i, peoplebase)
+ ent = topology_st.standalone.getEntry(user_dn, ldap.SCOPE_BASE,
"(objectclass=*)", ['memberof'])
+ assert ent.hasAttr('memberof')
+ found = False
+ for val in ent.getValues('memberof'):
+ topology_st.standalone.log.info("!!!!!!! %s: memberof->%s (vs
%s)" % (user_dn, val, new_group1_dn.encode().lower()))
+ if val.lower() == new_group1_dn.encode().lower():
+ found = True
+ break
+ assert found
+
+ # Create a group2 out of the scope
+ group2_dn = 'cn=group_out2,%s' % SUFFIX
+ topology_st.standalone.add_s(Entry((group2_dn, {'objectclass':
['top', 'groupofnames'],
+ 'member': [
+ 'cn=user2,%s' % peoplebase,
+ 'cn=user3,%s' % peoplebase,
+ ],
+ 'description': 'mygroup'})))
+
+ # Check the those entries have not memberof with group2
+ for i in (2, 3):
+ user_dn = 'cn=user%d,%s' % (i, peoplebase)
+ ent = topology_st.standalone.getEntry(user_dn, ldap.SCOPE_BASE,
"(objectclass=*)", ['memberof'])
+ assert not ent.hasAttr('memberof')
+
+ # memberof will not add the missing objectclass
+ _disable_auto_oc_memberof(topology_st.standalone)
+ topology_st.standalone.restart(timeout=10)
+
+ # move group2 into the scope and check it fails
+ try:
+ topology_st.standalone.rename_s(group2_dn, 'cn=group_in2',
newsuperior=peoplebase, delold=0)
+ topology_st.standalone.log.info("This is unexpected, modrdn should fail as
the member entry have not the appropriate objectclass")
+ assert False
+ except ldap.OPERATIONS_ERROR:
+ pass
+
+ # Check the those entries have not memberof
+ for i in (2, 3):
+ user_dn = 'cn=user%d,%s' % (i, peoplebase)
+ ent = topology_st.standalone.getEntry(user_dn, ldap.SCOPE_BASE,
"(objectclass=*)", ['memberof'])
+ topology_st.standalone.log.info("Should assert %s has memberof is %s" %
(user_dn, ent.hasAttr('memberof')))
+ assert not ent.hasAttr('memberof')
+
+ # Create a group3 in the scope
+ group3_dn = 'cn=group3_in,%s' % peoplebase
+ try:
+ topology_st.standalone.add_s(Entry((group3_dn, {'objectclass':
['top', 'groupofnames'],
+ 'member': [
+ 'cn=user4,%s' % peoplebase,
+ 'cn=user5,%s' % peoplebase,
+ ],
+ 'description': 'mygroup'})))
+ topology_st.standalone.log.info("This is unexpected, ADD should fail as the
member entry have not the appropriate objectclass")
+ assert False
+ except ldap.OBJECT_CLASS_VIOLATION:
+ pass
+ except ldap.OPERATIONS_ERROR:
+ pass
+
+ # Check the those entries have not memberof
+ for i in (4, 5):
+ user_dn = 'cn=user%d,%s' % (i, peoplebase)
+ ent = topology_st.standalone.getEntry(user_dn, ldap.SCOPE_BASE,
"(objectclass=*)", ['memberof'])
+ topology_st.standalone.log.info("Should assert %s has memberof is %s" %
(user_dn, ent.hasAttr('memberof')))
+ assert not ent.hasAttr('memberof')
+
+if __name__ == '__main__':
+ # Run isolated
+ # -s for DEBUG mode
+ CURRENT_FILE = os.path.realpath(__file__)
+ pytest.main("-s %s" % CURRENT_FILE)
+
diff --git a/ldap/servers/plugins/memberof/memberof.c
b/ldap/servers/plugins/memberof/memberof.c
index f4d45ed..329a845 100644
--- a/ldap/servers/plugins/memberof/memberof.c
+++ b/ldap/servers/plugins/memberof/memberof.c
@@ -1972,7 +1972,7 @@ memberof_moddn_attr_list(Slapi_PBlock *pb, MemberOfConfig *config,
Slapi_DN *pre
int hint = slapi_attr_first_value(attr, &val);
Slapi_DN *sdn = slapi_sdn_new();
- while (val) {
+ while (val && (rc == 0)) {
char *dn_str = 0;
struct berval *bv = (struct berval *)slapi_value_get_berval(val);
@@ -1995,7 +1995,7 @@ memberof_moddn_attr_list(Slapi_PBlock *pb, MemberOfConfig *config,
Slapi_DN *pre
strncpy(dn_str, bv->bv_val, (size_t)bv->bv_len);
slapi_sdn_set_normdn_byref(sdn, dn_str); /* dn_str is normalized */
- memberof_modop_one_replace_r(pb, config, LDAP_MOD_REPLACE,
+ rc = memberof_modop_one_replace_r(pb, config, LDAP_MOD_REPLACE,
post_sdn, pre_sdn, post_sdn, sdn, 0);
hint = slapi_attr_next_value(attr, hint, &val);
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.