def test_betxn_init(topology): # First enable dynamic plugins - makes plugin testing much easier try: topology.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, "nsslapd-dynamic-plugins", "on")]) except ldap.LDAPError as e: ldap.error("Failed to enable dynamic plugin!" + e.message["desc"]) assert False
def test_ticket48013(topology): ''' Content Synchonization: Test that invalid cookies are caught ''' cookies = ('#', '##', 'a#a#a', 'a#a#1') # Enable dynamic plugins try: topology.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'nsslapd-dynamic-plugins', 'on')]) except ldap.LDAPError as e: ldap.error('Failed to enable dynamic plugin!' + e.message['desc']) assert False # Enable retro changelog topology.standalone.plugins.enable(name=PLUGIN_RETRO_CHANGELOG) # Enbale content sync plugin topology.standalone.plugins.enable(name=PLUGIN_REPL_SYNC) # Set everything up ldap_url = ldapurl.LDAPUrl('ldap://%s:%s' % (HOST_STANDALONE, PORT_STANDALONE)) ldap_connection = SyncObject(ldap_url.initializeUrl()) # Authenticate try: ldap_connection.simple_bind_s(DN_DM, PASSWORD) except ldap.LDAPError as e: print('Login to LDAP server failed: %s' % e.message['desc']) assert False # Test invalid cookies for invalid_cookie in cookies: log.info('Testing cookie: %s' % invalid_cookie) try: ldap_connection.sync_search(invalid_cookie) ldap_connection.poll() log.fatal('Invalid cookie accepted!') assert False except Exception as e: log.info('Invalid cookie correctly rejected: %s' % e.message['info']) pass # Success log.info('Test complete')
def test_retrocl_exclude_attr_add(topology_st): """ Test exclude attribute feature of the retrocl plugin for add operation :id: 3481650f-2070-45ef-9600-2500cfc51559 :setup: Standalone instance :steps: 1. Enable dynamic plugins 2. Confige retro changelog plugin 3. Add an entry 4. Ensure entry attrs are in the changelog 5. Exclude an attr 6. Add another entry 7. Ensure excluded attr is not in the changelog :expectedresults: 1. Success 2. Success 3. Success 4. Success 5. Success 6. Success 7. Success """ st = topology_st.standalone log.info('Configure retrocl plugin') rcl = RetroChangelogPlugin(st) rcl.disable() rcl.enable() rcl.replace('nsslapd-attribute', 'nsuniqueid:targetUniqueId') log.info('Restarting instance') try: st.restart() except ldap.LDAPError as e: ldap.error('Failed to restart instance ' + e.args[0]['desc']) assert False users = UserAccounts(st, DEFAULT_SUFFIX) log.info('Adding user1') try: users.create( properties={ 'sn': '1', 'cn': 'user 1', 'uid': 'user1', 'uidNumber': '11', 'gidNumber': '111', 'givenname': 'user1', 'homePhone': '0861234567', 'carLicense': '131D16674', 'mail': '*****@*****.**', 'homeDirectory': '/home/user1', 'userpassword': USER_PW }) except ldap.ALREADY_EXISTS: pass except ldap.LDAPError as e: log.error("Failed to add user1: " + str(e)) log.info( 'Verify homePhone and carLicense attrs are in the changelog changestring' ) try: retro_changelog_suffix = DSLdapObjects(st, basedn=RETROCL_SUFFIX) cllist = retro_changelog_suffix.filter(f'(targetDn={USER1_DN})') except ldap.LDAPError as e: log.fatal("Changelog search failed, error: " + str(e)) assert False assert len(cllist) > 0 if cllist[0].present('changes'): clstr = str(cllist[0].get_attr_vals_utf8('changes')) assert ATTR_HOMEPHONE in clstr assert ATTR_CARLICENSE in clstr log.info('Excluding attribute ' + ATTR_HOMEPHONE) args = FakeArgs() args.connections = [ st.host + ':' + str(st.port) + ':' + DN_DM + ':' + PW_DM ] args.instance = 'standalone1' args.basedn = None args.binddn = None args.starttls = False args.pwdfile = None args.bindpw = None args.prompt = False args.exclude_attrs = ATTR_HOMEPHONE args.func = retrochangelog_add dsrc_inst = dsrc_arg_concat(args, None) inst = connect_instance(dsrc_inst, False, args) result = args.func(inst, None, log, args) disconnect_instance(inst) assert result is None log.info('Restarting instance') try: st.restart() except ldap.LDAPError as e: ldap.error('Failed to restart instance ' + e.args[0]['desc']) assert False log.info('Adding user2') try: users.create( properties={ 'sn': '2', 'cn': 'user 2', 'uid': 'user2', 'uidNumber': '22', 'gidNumber': '222', 'givenname': 'user2', 'homePhone': '0879088363', 'carLicense': '04WX11038', 'mail': '*****@*****.**', 'homeDirectory': '/home/user2', 'userpassword': USER_PW }) except ldap.ALREADY_EXISTS: pass except ldap.LDAPError as e: log.error("Failed to add user2: " + str(e)) log.info('Verify homePhone attr is not in the changelog changestring') try: cllist = retro_changelog_suffix.filter(f'(targetDn={USER2_DN})') assert len(cllist) > 0 if cllist[0].present('changes'): clstr = str(cllist[0].get_attr_vals_utf8('changes')) assert ATTR_HOMEPHONE not in clstr assert ATTR_CARLICENSE in clstr except ldap.LDAPError as e: log.fatal("Changelog search failed, error: " + str(e)) assert False
def test_retrocl_exclude_attr_mod(topology_st): """ Test exclude attribute feature of the retrocl plugin for mod operation :id: f6bef689-685b-4f86-a98d-f7e6b1fcada3 :setup: Standalone instance :steps: 1. Enable dynamic plugins 2. Confige retro changelog plugin 3. Add user1 entry 4. Ensure entry attrs are in the changelog 5. Exclude an attr 6. Modify user1 entry 7. Ensure excluded attr is not in the changelog :expectedresults: 1. Success 2. Success 3. Success 4. Success 5. Success 6. Success 7. Success """ st = topology_st.standalone log.info('Configure retrocl plugin') rcl = RetroChangelogPlugin(st) rcl.disable() rcl.enable() rcl.replace('nsslapd-attribute', 'nsuniqueid:targetUniqueId') log.info('Restarting instance') try: st.restart() except ldap.LDAPError as e: ldap.error('Failed to restart instance ' + e.args[0]['desc']) assert False users = UserAccounts(st, DEFAULT_SUFFIX) log.info('Adding user1') try: user1 = users.create( properties={ 'sn': '1', 'cn': 'user 1', 'uid': 'user1', 'uidNumber': '11', 'gidNumber': '111', 'givenname': 'user1', 'homePhone': '0861234567', 'carLicense': '131D16674', 'mail': '*****@*****.**', 'homeDirectory': '/home/user1', 'userpassword': USER_PW }) except ldap.ALREADY_EXISTS: user1 = UserAccount(st, dn=USER1_DN) except ldap.LDAPError as e: log.error("Failed to add user1: " + str(e)) log.info( 'Verify homePhone and carLicense attrs are in the changelog changestring' ) try: retro_changelog_suffix = DSLdapObjects(st, basedn=RETROCL_SUFFIX) cllist = retro_changelog_suffix.filter(f'(targetDn={USER1_DN})') except ldap.LDAPError as e: log.fatal("Changelog search failed, error: " + str(e)) assert False assert len(cllist) > 0 if cllist[0].present('changes'): clstr = str(cllist[0].get_attr_vals_utf8('changes')) assert ATTR_HOMEPHONE in clstr assert ATTR_CARLICENSE in clstr log.info('Excluding attribute ' + ATTR_CARLICENSE) args = FakeArgs() args.connections = [ st.host + ':' + str(st.port) + ':' + DN_DM + ':' + PW_DM ] args.instance = 'standalone1' args.basedn = None args.binddn = None args.starttls = False args.pwdfile = None args.bindpw = None args.prompt = False args.exclude_attrs = ATTR_CARLICENSE args.func = retrochangelog_add dsrc_inst = dsrc_arg_concat(args, None) inst = connect_instance(dsrc_inst, False, args) result = args.func(inst, None, log, args) disconnect_instance(inst) assert result is None log.info('Restarting instance') try: st.restart() except ldap.LDAPError as e: ldap.error('Failed to restart instance ' + e.args[0]['desc']) assert False log.info('Modify user1 carLicense attribute') try: user1.replace(ATTR_CARLICENSE, "123WX321") except ldap.LDAPError as e: log.fatal( 'test_retrocl_exclude_attr_mod: Failed to update user1 attribute: error ' + e.message['desc']) assert False log.info('Verify carLicense attr is not in the changelog changestring') try: cllist = retro_changelog_suffix.filter(f'(targetDn={USER1_DN})') assert len(cllist) > 0 # There will be 2 entries in the changelog for this user, we are only #interested in the second one, the modify operation. if cllist[1].present('changes'): clstr = str(cllist[1].get_attr_vals_utf8('changes')) assert ATTR_CARLICENSE not in clstr except ldap.LDAPError as e: log.fatal("Changelog search failed, error: " + str(e)) assert False
def test_memberof_auto_add_oc(topology): """ Test the auto add objectclass feature. The plugin should add a predefined objectclass that will allow memberOf to be added to an entry. """ # enable dynamic plugins try: topology.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'nsslapd-dynamic-plugins', 'on')]) except ldap.LDAPError as e: ldap.error('Failed to enable dynamic plugins! ' + e.message['desc']) assert False # Enable the plugin topology.standalone.plugins.enable(name=PLUGIN_MEMBER_OF) # First test invalid value (config validation) topology.standalone.plugins.enable(name=PLUGIN_MEMBER_OF) try: topology.standalone.modify_s(MEMBEROF_PLUGIN_DN, [(ldap.MOD_REPLACE, 'memberofAutoAddOC', 'invalid123')]) log.fatal('Incorrectly added invalid objectclass!') assert False except ldap.UNWILLING_TO_PERFORM: log.info('Correctly rejected invalid objectclass') except ldap.LDAPError as e: ldap.error('Unexpected error adding invalid objectclass - error: ' + e.message['desc']) assert False # Add valid objectclass topology.standalone.plugins.enable(name=PLUGIN_MEMBER_OF) try: topology.standalone.modify_s(MEMBEROF_PLUGIN_DN, [(ldap.MOD_REPLACE, 'memberofAutoAddOC', 'inetuser')]) except ldap.LDAPError as e: log.fatal('Failed to configure memberOf plugin: error ' + e.message['desc']) assert False # Add two users try: topology.standalone.add_s(Entry((USER1_DN, {'objectclass': 'top', 'objectclass': 'person', 'objectclass': 'organizationalPerson', 'objectclass': 'inetorgperson', 'sn': 'last', 'cn': 'full', 'givenname': 'user1', 'uid': 'user1' }))) except ldap.LDAPError as e: log.fatal('Failed to add user1 entry, error: ' + e.message['desc']) assert False try: topology.standalone.add_s(Entry((USER2_DN, {'objectclass': 'top', 'objectclass': 'person', 'objectclass': 'organizationalPerson', 'objectclass': 'inetorgperson', 'sn': 'last', 'cn': 'full', 'givenname': 'user2', 'uid': 'user2' }))) except ldap.LDAPError as e: log.fatal('Failed to add user2 entry, error: ' + e.message['desc']) assert False # Add a group(that already includes one user try: topology.standalone.add_s(Entry((GROUP_DN, {'objectclass': 'top', 'objectclass': 'groupOfNames', 'cn': 'group', 'member': USER1_DN }))) except ldap.LDAPError as e: log.fatal('Failed to add group entry, error: ' + e.message['desc']) assert False # Add a user to the group try: topology.standalone.modify_s(GROUP_DN, [(ldap.MOD_ADD, 'member', USER2_DN)]) except ldap.LDAPError as e: log.fatal('Failed to add user2 to group: error ' + e.message['desc']) assert False log.info('Test complete.')
def test_ticket47931(topology): """Test Retro Changelog and MemberOf deadlock fix. Verification steps: - Enable retro cl and memberOf. - Create two backends: A & B. - Configure retrocl scoping for backend A. - Configure memberOf plugin for uniquemember - Create group in backend A. - In parallel, add members to the group on A, and make modifications to entries in backend B. - Make sure the server does not hang during the updates to both backends. """ # Enable dynamic plugins to make plugin configuration easier try: topology.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'nsslapd-dynamic-plugins', 'on')]) except ldap.LDAPError as e: ldap.error('Failed to enable dynamic plugins! ' + e.message['desc']) assert False # Enable the plugins topology.standalone.plugins.enable(name=PLUGIN_MEMBER_OF) topology.standalone.plugins.enable(name=PLUGIN_RETRO_CHANGELOG) # Create second backend topology.standalone.backend.create(SECOND_SUFFIX, {BACKEND_NAME: SECOND_BACKEND}) topology.standalone.mappingtree.create(SECOND_SUFFIX, bename=SECOND_BACKEND) # Create the root node of the second backend try: topology.standalone.add_s(Entry((SECOND_SUFFIX, {'objectclass': 'top domain'.split(), 'dc': 'deadlock'}))) except ldap.LDAPError as e: log.fatal('Failed to create suffix entry: error ' + e.message['desc']) assert False # Configure retrocl scope try: topology.standalone.modify_s(RETROCL_PLUGIN_DN, [(ldap.MOD_REPLACE, 'nsslapd-include-suffix', DEFAULT_SUFFIX)]) except ldap.LDAPError as e: ldap.error('Failed to configure retrocl plugin: ' + e.message['desc']) assert False # Configure memberOf group attribute try: topology.standalone.modify_s(MEMBEROF_PLUGIN_DN, [(ldap.MOD_REPLACE, 'memberofgroupattr', 'uniquemember')]) except ldap.LDAPError as e: log.fatal('Failed to configure memberOf plugin: error ' + e.message['desc']) assert False # Create group try: topology.standalone.add_s(Entry((GROUP_DN, {'objectclass': 'top extensibleObject'.split(), 'cn': 'group'}))) except ldap.LDAPError as e: log.fatal('Failed to add grouo: error ' + e.message['desc']) assert False # Create 1500 entries (future members of the group) for idx in range(1, 1500): try: USER_DN = ("uid=member%d,%s" % (idx, DEFAULT_SUFFIX)) topology.standalone.add_s(Entry((USER_DN, {'objectclass': 'top extensibleObject'.split(), 'uid': 'member%d' % (x)}))) except ldap.LDAPError as e: log.fatal('Failed to add user (%s): error %s' % (USER_DN, e.message['desc'])) assert False # Modify second backend (separate thread) mod_backend_thrd = modifySecondBackendThread(topology.standalone, TIME_OUT) mod_backend_thrd.start() # Add members to the group - set timeout log.info('Adding members to the group...') topology.standalone.set_option(ldap.OPT_TIMEOUT, TIME_OUT) for idx in range(1, 1500): try: MEMBER_VAL = ("uid=member%d,%s" % (idx, DEFAULT_SUFFIX)) topology.standalone.modify_s(GROUP_DN, [(ldap.MOD_ADD, 'uniquemember', MEMBER_VAL)]) except ldap.TIMEOUT: log.fatal('Deadlock! Bug verification failed.') assert False except ldap.LDAPError as e: log.fatal('Failed to update group(not a deadlock) member (%s) - error: %s' % (MEMBER_VAL, e.message['desc'])) assert False log.info('Finished adding members to the group.') # Wait for the thread to finish mod_backend_thrd.join() # No timeout, test passed! log.info('Test complete\n')
def test_ticket48759(topology): """ The fix for ticket 48759 has to prevent plugin calls for tombstone purging The test uses the memberof and retrocl plugins to verify this. In tombstone purging without the fix the mmeberof plugin is called, if the tombstone entry is a group, it modifies the user entries for the group and if retrocl is enabled this mod is written to the retrocl The test sequence is: - enable replication - enable memberof and retro cl plugin - add user entries - add a group and add the users as members - verify memberof is set to users - delete the group - verify memberof is removed from users - add group again - verify memberof is set to users - get number of changes in retro cl for one user - configure tombstone purging - wait for purge interval to pass - add a dummy entry to increase maxcsn - wait for purge interval to pass two times - get number of changes in retro cl for user again - assert there was no additional change """ log.info('Testing Ticket 48759 - no plugin calls for tombstone purging') # # Setup Replication # log.info('Setting up replication...') topology.standalone.replica.enableReplication(suffix=DEFAULT_SUFFIX, role=REPLICAROLE_MASTER, replicaId=REPLICAID_MASTER_1) # # enable dynamic plugins, memberof and retro cl plugin # log.info('Enable plugins...') try: topology.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'nsslapd-dynamic-plugins', 'on')]) except ldap.LDAPError as e: ldap.error('Failed to enable dynamic plugins! ' + e.message['desc']) assert False topology.standalone.plugins.enable(name=PLUGIN_MEMBER_OF) topology.standalone.plugins.enable(name=PLUGIN_RETRO_CHANGELOG) # Configure memberOf group attribute try: topology.standalone.modify_s(MEMBEROF_PLUGIN_DN, [(ldap.MOD_REPLACE, 'memberofgroupattr', 'member')]) except ldap.LDAPError as e: log.fatal('Failed to configure memberOf plugin: error ' + e.message['desc']) assert False # # create some users and a group # log.info('create users and group...') for idx in range(1, 5): try: USER_DN = ("uid=member%d,%s" % (idx, DEFAULT_SUFFIX)) topology.standalone.add_s(Entry((USER_DN, {'objectclass': 'top extensibleObject'.split(), 'uid': 'member%d' % (idx)}))) except ldap.LDAPError as e: log.fatal('Failed to add user (%s): error %s' % (USER_DN, e.message['desc'])) assert False _add_group_with_members(topology) MEMBER_VAL = ("uid=member2,%s" % DEFAULT_SUFFIX) time.sleep(1) _find_memberof(topology, MEMBER_VAL, GROUP_DN, True) # delete group log.info('delete group...') try: topology.standalone.delete_s(GROUP_DN) except ldap.LDAPError as e: log.error('Failed to delete entry: ' + e.message['desc']) assert False time.sleep(1) _find_memberof(topology, MEMBER_VAL, GROUP_DN, False) # add group again log.info('add group again') _add_group_with_members(topology) time.sleep(1) _find_memberof(topology, MEMBER_VAL, GROUP_DN, True) # # get number of changelog records for one user entry log.info('get number of changes for %s before tombstone purging' % MEMBER_VAL) changes_pre = _find_retrocl_changes(topology, MEMBER_VAL) # configure tombstone purging args = {REPLICA_PRECISE_PURGING: 'on', REPLICA_PURGE_DELAY: '5', REPLICA_PURGE_INTERVAL: '5'} try: topology.standalone.replica.setProperties(DEFAULT_SUFFIX, None, None, args) except: log.fatal('Failed to configure replica') assert False # Wait for the interval to pass log.info('Wait for tombstone purge interval to pass ...') time.sleep(6) # Add an entry to trigger replication log.info('add dummy entry') try: topology.standalone.add_s(Entry(('cn=test_entry,dc=example,dc=com', { 'objectclass': 'top person'.split(), 'sn': 'user', 'cn': 'entry1'}))) except ldap.LDAPError as e: log.error('Failed to add entry: ' + e.message['desc']) assert False # check memberof is still correct time.sleep(1) _find_memberof(topology, MEMBER_VAL, GROUP_DN, True) # Wait for the interval to pass again log.info('Wait for tombstone purge interval to pass again...') time.sleep(10) # # get number of changelog records for one user entry log.info('get number of changes for %s before tombstone purging' % MEMBER_VAL) changes_post = _find_retrocl_changes(topology, MEMBER_VAL) assert (changes_pre == changes_post)