def test_ticket47676_skip_oc_at(topology): ''' This test ADD an entry on MASTER1 where 47676 is fixed. Then it checks that entry is replicated on MASTER2 (even if on MASTER2 47676 is NOT fixed). Then update on MASTER2. If the schema has successfully been pushed, updating Master2 should succeed ''' topology.master1.log.info("\n\n######################### ADD ######################\n") # bind as 'cn=Directory manager' topology.master1.log.info("Bind as %s and add the add the entry with specific oc" % DN_DM) topology.master1.simple_bind_s(DN_DM, PASSWORD) # Prepare the entry with multivalued members entry = Entry(ENTRY_DN) entry.setValues('objectclass', 'top', 'person', 'OCticket47676') entry.setValues('sn', ENTRY_NAME) entry.setValues('cn', ENTRY_NAME) entry.setValues('postalAddress', 'here') entry.setValues('postalCode', '1234') members = [] for cpt in range(MAX_OTHERS): name = "%s%d" % (OTHER_NAME, cpt) members.append("cn=%s,%s" % (name, SUFFIX)) members.append(BIND_DN) entry.setValues('member', members) topology.master1.log.info("Try to add Add %s should be successful" % ENTRY_DN) topology.master1.add_s(entry) # # Now check the entry as been replicated # topology.master2.simple_bind_s(DN_DM, PASSWORD) topology.master1.log.info("Try to retrieve %s from Master2" % ENTRY_DN) loop = 0 while loop <= 10: try: ent = topology.master2.getEntry(ENTRY_DN, ldap.SCOPE_BASE, "(objectclass=*)") break except ldap.NO_SUCH_OBJECT: time.sleep(2) loop += 1 assert loop <= 10 # Now update the entry on Master2 (as DM because 47676 is possibly not fixed on M2) topology.master1.log.info("Update %s on M2" % ENTRY_DN) mod = [(ldap.MOD_REPLACE, 'description', 'test_add')] topology.master2.modify_s(ENTRY_DN, mod) topology.master1.simple_bind_s(DN_DM, PASSWORD) loop = 0 while loop <= 10: ent = topology.master1.getEntry(ENTRY_DN, ldap.SCOPE_BASE, "(objectclass=*)") if ent.hasAttr('description') and (ent.getValue('description') == 'test_add'): break time.sleep(1) loop += 1 assert ent.getValue('description') == 'test_add'
def add_group(topology): """Create a group for the user to have some rights to""" log.info("Create a group entry: %s" % TEST_GROUP) gentry = Entry(TEST_GROUP) gentry.setValues("objectclass", "top", "extensibleobject") gentry.setValues("cn", "testgroup") topology.instance.add_s(gentry)
def user(topology): """Create user entries""" for i in range(0, 2): uentry = Entry('uid=test%s,%s' % (i, DEFAULT_SUFFIX)) uentry.setValues('objectclass', 'top', 'extensibleobject') uentry.setValues('uid', 'test') topology.standalone.add_s(uentry)
def add_group(topology): """Create a group for the user to have some rights to""" log.info('Create a group entry: %s' % TEST_GROUP) gentry = Entry(TEST_GROUP) gentry.setValues('objectclass', 'top', 'extensibleobject') gentry.setValues('cn', 'testgroup') topology.instance.add_s(gentry)
def add_user(topology): """Create a user entry""" log.info('Create a user entry: %s' % TEST_USER) uentry = Entry(TEST_USER) uentry.setValues('objectclass', 'top', 'extensibleobject') uentry.setValues('uid', 'test') topology.instance.add_s(uentry)
def add_user(topology): """Create a user entry""" log.info("Create a user entry: %s" % TEST_USER) uentry = Entry(TEST_USER) uentry.setValues("objectclass", "top", "extensibleobject") uentry.setValues("uid", "test") topology.instance.add_s(uentry)
def _test_ticket47560_setup(): """ - Create entry cn=group,SUFFIX - Create entry cn=member,SUFFIX - Update 'cn=member,SUFFIX' to add "memberOf: cn=group,SUFFIX" - Enable Memberof Plugins """ log.debug("-------- > _test_ticket47560_setup\n") # # By default the memberof plugin is disabled create # - create a group entry # - create a member entry # - set the member entry as memberof the group entry # entry = Entry(group_DN) entry.setValues('objectclass', 'top', 'groupOfNames', 'inetUser') entry.setValues('cn', 'group') try: topology_st.standalone.add_s(entry) except ldap.ALREADY_EXISTS: log.debug("Entry %s already exists" % (group_DN)) entry = Entry(member_DN) entry.setValues('objectclass', 'top', 'person', 'organizationalPerson', 'inetorgperson', 'inetUser') entry.setValues('uid', 'member') entry.setValues('cn', 'member') entry.setValues('sn', 'member') try: topology_st.standalone.add_s(entry) except ldap.ALREADY_EXISTS: log.debug("Entry %s already exists" % (member_DN)) replace = [(ldap.MOD_REPLACE, 'memberof', ensure_bytes(group_DN))] topology_st.standalone.modify_s(member_DN, replace) # # enable the memberof plugin and restart the instance # _enable_disable_mbo('on') # # check memberof attribute is still present # filt = 'uid=member' ents = topology_st.standalone.search_s(member_DN, ldap.SCOPE_BASE, filt) assert len(ents) == 1 ent = ents[0] # print ent value = ensure_str(ent.getValue('memberof')) # print "memberof: %s" % (value) assert value == group_DN
def makeADUserEnt(idnum): id = str(idnum) userid = 'testuser' + id cn = 'Test User' + id dn = 'cn=%s,%s,%s' % (cn, adusersubtree, suffix) ent = Entry(dn) ent.setValues('objectclass', aduserObjClasses) ent.setValues('cn', cn) ent.setValues('sn', 'User' + id) ent.setValues('userPrincipalName', '%s@%s' % (userid, realm)) ent.setValues('sAMAccountName', userid) return ent
def automemberExport(self, suffix=DEFAULT_SUFFIX, scope='sub', fstr='objectclass=top', ldif_out=None, args=None): ''' @param suffix - The suffix the task should examine - default is "dc=example,dc=com" @param scope - The scope of the search to find entries @param fstr - The search filter to find entries @param ldif_out - The name for the output LDIF file @param args - is a dictionary that contains modifier of the task wait: True/[False] - If True, waits for the completion of the task before to return @return exit code @raise ValueError: if ldif_out is not provided ''' if not ldif_out: raise ValueError("Missing ldif_out") cn = 'task-' + time.strftime("%m%d%Y_%H%M%S", time.localtime()) dn = ('cn=%s,cn=automember export updates,cn=tasks,cn=config' % cn) entry = Entry(dn) entry.setValues('objectclass', 'top', 'extensibleObject') entry.setValues('cn', cn) entry.setValues('basedn', suffix) entry.setValues('filter', fstr) entry.setValues('scope', scope) entry.setValues('ldif', ldif_out) # start the task and possibly wait for task completion try: self.conn.add_s(entry) except ldap.ALREADY_EXISTS: self.log.error("Fail to add Automember Export Updates task") return -1 exitCode = 0 if args and args.get(TASK_WAIT, False): (done, exitCode) = self.conn.tasks.checkTask(entry, True) if exitCode: self.log.error( "Error: Automember Export Updates task (%s) exited with %d" % (cn, exitCode)) else: self.log.info( "Automember Export Updates task (%s) completed successfully" % (cn)) self.dn = dn self.entry = entry return exitCode
def _test_ticket47560_setup(): """ - Create entry cn=group,SUFFIX - Create entry cn=member,SUFFIX - Update 'cn=member,SUFFIX' to add "memberOf: cn=group,SUFFIX" - Enable Memberof Plugins """ log.debug("-------- > _test_ticket47560_setup\n") # # By default the memberof plugin is disabled create # - create a group entry # - create a member entry # - set the member entry as memberof the group entry # entry = Entry(group_DN) entry.setValues('objectclass', 'top', 'groupOfNames', 'inetUser') entry.setValues('cn', 'group') try: topology.standalone.add_s(entry) except ldap.ALREADY_EXISTS: log.debug("Entry %s already exists" % (group_DN)) entry = Entry(member_DN) entry.setValues('objectclass', 'top', 'person', 'organizationalPerson', 'inetorgperson', 'inetUser') entry.setValues('uid', 'member') entry.setValues('cn', 'member') entry.setValues('sn', 'member') try: topology.standalone.add_s(entry) except ldap.ALREADY_EXISTS: log.debug("Entry %s already exists" % (member_DN)) replace = [(ldap.MOD_REPLACE, 'memberof', group_DN)] topology.standalone.modify_s(member_DN, replace) # # enable the memberof plugin and restart the instance # _enable_disable_mbo('on') # # check memberof attribute is still present # filt = 'uid=member' ents = topology.standalone.search_s(member_DN, ldap.SCOPE_BASE, filt) assert len(ents) == 1 ent = ents[0] #print ent value = ent.getValue('memberof') #print "memberof: %s" % (value) assert value == group_DN
def syntaxValidate(self, suffix=DEFAULT_SUFFIX, fstr='objectclass=top', args=None): ''' @param suffix - The suffix the task should validate - default is "dc=example,dc=com" @param fstr - The search filter to find entries @param args - is a dictionary that contains modifier of the task wait: True/[False] - If True, waits for the completion of the task before to return @return exit code ''' cn = 'task-' + time.strftime("%m%d%Y_%H%M%S", time.localtime()) dn = ('cn=%s,cn=syntax validate,cn=tasks,cn=config' % cn) entry = Entry(dn) entry.setValues('objectclass', 'top', 'extensibleObject') entry.setValues('cn', cn) entry.setValues('basedn', suffix) entry.setValues('filter', fstr) # start the task and possibly wait for task completion try: self.conn.add_s(entry) except ldap.ALREADY_EXISTS: self.log.error("Fail to add Syntax Validate task") return -1 exitCode = 0 if args and args.get(TASK_WAIT, False): (done, exitCode) = self.conn.tasks.checkTask(entry, True) if exitCode: self.log.error("Error: Syntax Validate (%s) exited with %d" % (cn, exitCode)) else: self.log.info("Syntax Validate task (%s) completed successfully" % (cn)) return exitCode
def addIndex(self, suffix, be_name, attr, indexTypes, matchingRules, postReadCtrl=None): """Specify the suffix (should contain 1 local database backend), the name of the attribute to index, and the types of indexes to create e.g. "pres", "eq", "sub" """ msg_id = None if be_name: dn = ( 'cn=%s,cn=index,cn=%s,cn=ldbm database,cn=plugins,cn=config' % (attr, be_name)) else: entries_backend = self.conn.backend.list(suffix=suffix) # assume 1 local backend dn = "cn=%s,cn=index,%s" % (attr, entries_backend[0].dn) if postReadCtrl: add_record = [('nsSystemIndex', ['false']), ('cn', [attr]), ('objectclass', ['top', 'nsindex']), ('nsIndexType', indexTypes)] if matchingRules: add_record.append(('nsMatchingRule', matchingRules)) else: entry = Entry(dn) entry.setValues('objectclass', 'top', 'nsIndex') entry.setValues('cn', attr) entry.setValues('nsSystemIndex', "false") entry.setValues('nsIndexType', indexTypes) if matchingRules: entry.setValues('nsMatchingRule', matchingRules) if MAJOR >= 3 or (MAJOR == 2 and MINOR >= 7): try: if postReadCtrl: pr = PostReadControl(criticality=True, attrList=['*']) msg_id = self.conn.add_ext(dn, add_record, serverctrls=[pr]) else: self.conn.add_s(entry) except ldap.LDAPError as e: raise e return msg_id
def usnTombstoneCleanup(self, suffix=DEFAULT_SUFFIX, bename=None, maxusn_to_delete=None, args=None): ''' @param suffix - The suffix the task should cleanup - default is "dc=example,dc=com" @param backend - The 'backend' the task should cleanup @param maxusn_to_delete - Maximum number of usn's to delete @param args - is a dictionary that contains modifier of the task wait: True/[False] - If True, waits for the completion of the task before to return @return exit code ''' cn = 'task-' + time.strftime("%m%d%Y_%H%M%S", time.localtime()) dn = ('cn=%s,cn=USN tombstone cleanup task,cn=tasks,cn=config' % cn) entry = Entry(dn) entry.setValues('objectclass', 'top', 'extensibleObject') entry.setValues('cn', cn) if not bename: entry.setValues('suffix', suffix) else: entry.setValues('backend', bename) if maxusn_to_delete: entry.setValues('maxusn_to_delete') # start the task and possibly wait for task completion try: self.conn.add_s(entry) except ldap.ALREADY_EXISTS: self.log.error("Fail to add USN tombstone cleanup task") return -1 exitCode = 0 if args and args.get(TASK_WAIT, False): (done, exitCode) = self.conn.tasks.checkTask(entry, True) if exitCode: self.log.error( "Error: USN tombstone cleanup task (%s) exited with %d" % (cn, exitCode)) else: self.log.info( "USN tombstone cleanup task (%s) completed successfully" % (cn)) self.dn = dn self.entry = entry return exitCode
def add_user(topology): """ Create a user entry """ log.info('Create a user entry: %s' % TEST_USER) uentry = Entry(TEST_USER) uentry.setValues('objectclass', 'top', 'extensibleobject') uentry.setValues('uid', 'test') topology.instance.add_s(uentry) # This doesn't matter that we re-open the realm krb = MitKrb5(realm=REALM) krb.create_principal("test") # We extract the kt so we can kinit from it krb.create_keytab("test", "/tmp/test.keytab")
def fixupTombstones(self, bename=None, args=None): ''' Trigger a tombstone fixup task on the specified backend @param bename - 'commonname'/'cn' of the backend (e.g. 'userRoot'). Optional. @param args - is a dictionary that contains modifier of the task wait: True/[False] - If True, waits for the completion of the task before to return @return exit code @raise ValueError: if bename name does not exist ''' if not bename: bename = DEFAULT_BENAME # Verify the backend name if bename: ents = self.conn.mappingtree.list(bename=bename) if len(ents) != 1: raise ValueError("invalid backend name: %s" % bename) cn = "fixupTombstone_" + time.strftime("%m%d%Y_%H%M%S", time.localtime()) dn = "cn=%s,%s" % (cn, DN_TOMB_FIXUP_TASK) entry = Entry(dn) entry.setValues('objectclass', 'top', 'extensibleObject') entry.setValues('cn', cn) entry.setValues('backend', bename) if args and args.get(TASK_TOMB_STRIP, False): entry.setValues('stripcsn', 'yes') # start the task and possibly wait for task completion try: self.conn.add_s(entry) except ldap.ALREADY_EXISTS: self.log.error("Fail to add the fixup tombstone task") return -1 exitCode = 0 if args and args.get(TASK_WAIT, False): (done, exitCode) = self.conn.tasks.checkTask(entry, True) if exitCode: self.log.error( "Error: tombstone fixup task %s for backend %s exited with %d" % (cn, bename, exitCode)) else: self.log.info( "tombstone fixup task %s for backend %s completed successfully" % (cn, bename)) self.dn = dn self.entry = entry return exitCode
def cleanAllRUV(self, suffix=None, replicaid=None, force=None, args=None): ''' @param replicaid - The replica ID to remove/clean @param force - True/False - Clean all the replicas, even if one is down @param args - is a dictionary that contains modifier of the task wait: True/[False] - If True, waits for the completion of the task before to return @return tuple (task dn, and the exit code) @raise ValueError: If missing replicaid ''' if not replicaid: raise ValueError("Missing required paramter: replicaid") if not suffix: raise ValueError("Missing required paramter: suffix") cn = 'task-' + time.strftime("%m%d%Y_%H%M%S", time.localtime()) dn = ('cn=%s,cn=cleanallruv,cn=tasks,cn=config' % cn) entry = Entry(dn) entry.setValues('objectclass', 'top', 'extensibleObject') entry.setValues('cn', cn) entry.setValues('replica-base-dn', suffix) entry.setValues('replica-id', replicaid) if force: entry.setValues('replica-force-cleaning', 'yes') # start the task and possibly wait for task completion try: self.conn.add_s(entry) except ldap.ALREADY_EXISTS: self.log.error("Fail to add cleanAllRUV task") return (dn, -1) exitCode = 0 if args and args.get(TASK_WAIT, False): (done, exitCode) = self.conn.tasks.checkTask(entry, True) if exitCode: self.log.error("Error: cleanAllRUV task (%s) exited with %d" % (cn, exitCode)) else: self.log.info("cleanAllRUV task (%s) completed successfully" % (cn)) self.dn = dn self.entry = entry return (dn, exitCode)
def upgradeDB(self, nsArchiveDir=None, nsDatabaseType=None, nsForceToReindex=None, args=None): ''' @param nsArchiveDir - The archive directory @param nsDatabaseType - The database type - default is "ldbm database" @param nsForceToReindex - True/False - force reindexing to occur @param args - is a dictionary that contains modifier of the task wait: True/[False] - If True, waits for the completion of the task before to return @return exit code @raise ValueError: If missing nsArchiveDir ''' if not nsArchiveDir: raise ValueError("Missing required paramter: nsArchiveDir") cn = 'task-' + time.strftime("%m%d%Y_%H%M%S", time.localtime()) dn = ('cn=%s,cn=upgradedb,cn=tasks,cn=config' % cn) entry = Entry(dn) entry.setValues('objectclass', 'top', 'extensibleObject') entry.setValues('cn', cn) entry.setValues('nsArchiveDir', nsArchiveDir) if nsDatabaseType: entry.setValues('nsDatabaseType', nsDatabaseType) if nsForceToReindex: entry.setValues('nsForceToReindex', 'True') # start the task and possibly wait for task completion try: self.conn.add_s(entry) except ldap.ALREADY_EXISTS: self.log.error("Fail to add upgradedb task") return -1 exitCode = 0 if args and args.get(TASK_WAIT, False): (done, exitCode) = self.conn.tasks.checkTask(entry, True) if exitCode: self.log.error("Error: upgradedb task (%s) exited with %d" % (cn, exitCode)) else: self.log.info("Upgradedb task (%s) completed successfully" % (cn)) self.dn = dn self.entry = entry return exitCode
def test_ticket47676_skip_oc_at(topology_m2): ''' This test ADD an entry on SUPPLIER1 where 47676 is fixed. Then it checks that entry is replicated on SUPPLIER2 (even if on SUPPLIER2 47676 is NOT fixed). Then update on SUPPLIER2. If the schema has successfully been pushed, updating Supplier2 should succeed ''' topology_m2.ms["supplier1"].log.info("\n\n######################### ADD ######################\n") # bind as 'cn=Directory manager' topology_m2.ms["supplier1"].log.info("Bind as %s and add the add the entry with specific oc" % DN_DM) topology_m2.ms["supplier1"].simple_bind_s(DN_DM, PASSWORD) # Prepare the entry with multivalued members entry = Entry(ENTRY_DN) entry.setValues('objectclass', 'top', 'person', 'OCticket47676') entry.setValues('sn', ENTRY_NAME) entry.setValues('cn', ENTRY_NAME) entry.setValues('postalAddress', 'here') entry.setValues('postalCode', '1234') members = [] for cpt in range(MAX_OTHERS): name = "%s%d" % (OTHER_NAME, cpt) members.append("cn=%s,%s" % (name, SUFFIX)) members.append(BIND_DN) entry.setValues('member', members) topology_m2.ms["supplier1"].log.info("Try to add Add %s should be successful" % ENTRY_DN) topology_m2.ms["supplier1"].add_s(entry) # # Now check the entry as been replicated # topology_m2.ms["supplier2"].simple_bind_s(DN_DM, PASSWORD) topology_m2.ms["supplier1"].log.info("Try to retrieve %s from Supplier2" % ENTRY_DN) replication_check(topology_m2) ent = topology_m2.ms["supplier2"].getEntry(ENTRY_DN, ldap.SCOPE_BASE, "(objectclass=*)") assert ent # Now update the entry on Supplier2 (as DM because 47676 is possibly not fixed on M2) topology_m2.ms["supplier1"].log.info("Update %s on M2" % ENTRY_DN) mod = [(ldap.MOD_REPLACE, 'description', b'test_add')] topology_m2.ms["supplier2"].modify_s(ENTRY_DN, mod) topology_m2.ms["supplier1"].simple_bind_s(DN_DM, PASSWORD) replication_check(topology_m2) ent = topology_m2.ms["supplier1"].getEntry(ENTRY_DN, ldap.SCOPE_BASE, "(objectclass=*)") assert ensure_str(ent.getValue('description')) == 'test_add'
def automemberRebuild(self, suffix=DEFAULT_SUFFIX, scope='sub', filterstr='objectclass=top', args=None): ''' @param suffix - The suffix the task should examine - defualt is "dc=example,dc=com" @param scope - The scope of the search to find entries @param fitlerstr - THe search filter to find entries @param args - is a dictionary that contains modifier of the task wait: True/[False] - If True, waits for the completion of the task before to return @return exit code ''' cn = 'task-' + time.strftime("%m%d%Y_%H%M%S", time.localtime()) dn = ('cn=%s,cn=automember rebuild membership,cn=tasks,cn=config' % cn) entry = Entry(dn) entry.setValues('objectclass', 'top', 'extensibleObject') entry.setValues('cn', cn) entry.setValues('basedn', suffix) entry.setValues('filter', filterstr) entry.setValues('scope', scope) # start the task and possibly wait for task completion try: self.conn.add_s(entry) except ldap.ALREADY_EXISTS: self.log.error("Fail to add Automember Rebuild Membership task") return -1 exitCode = 0 if args and args.get(TASK_WAIT, False): (done, exitCode) = self.conn.tasks.checkTask(entry, True) if exitCode: self.log.error( "Error: Automember Rebuild Membership task (%s) exited with %d" % (cn, exitCode)) else: self.log.info( "Automember Rebuild Membership task (%s) completed successfully" % (cn)) return exitCode
def addIndex(self, suffix, be_name, attr, indexTypes, matchingRules, postReadCtrl=None): """Specify the suffix (should contain 1 local database backend), the name of the attribute to index, and the types of indexes to create e.g. "pres", "eq", "sub" """ msg_id = None if be_name: dn = ('cn=%s,cn=index,cn=%s,cn=ldbm database,cn=plugins,cn=config' % (attr, be_name)) else: entries_backend = self.conn.backend.list(suffix=suffix) # assume 1 local backend dn = "cn=%s,cn=index,%s" % (attr, entries_backend[0].dn) if postReadCtrl: add_record = [('nsSystemIndex', ['false']), ('cn', [attr]), ('objectclass', ['top', 'nsindex']), ('nsIndexType', indexTypes)] if matchingRules: add_record.append(('nsMatchingRule', matchingRules)) else: entry = Entry(dn) entry.setValues('objectclass', 'top', 'nsIndex') entry.setValues('cn', attr) entry.setValues('nsSystemIndex', "false") entry.setValues('nsIndexType', indexTypes) if matchingRules: entry.setValues('nsMatchingRule', matchingRules) if MAJOR >= 3 or (MAJOR == 2 and MINOR >= 7): try: if postReadCtrl: pr = PostReadControl(criticality=True, attrList=['*']) msg_id = self.conn.add_ext(dn, add_record, serverctrls=[pr]) else: self.conn.add_s(entry) except ldap.LDAPError as e: raise e return msg_id
def addIndex(self, suffix, attr, indexTypes, matchingRules): """Specify the suffix (should contain 1 local database backend), the name of the attribute to index, and the types of indexes to create e.g. "pres", "eq", "sub" """ entries_backend = self.conn.backend.list(suffix=suffix) # assume 1 local backend dn = "cn=%s,cn=index,%s" % (attr, entries_backend[0].dn) entry = Entry(dn) entry.setValues('objectclass', 'top', 'nsIndex') entry.setValues('cn', attr) entry.setValues('nsSystemIndex', "false") entry.setValues('nsIndexType', indexTypes) if matchingRules: entry.setValues('nsMatchingRule', matchingRules) try: self.conn.add_s(entry) except ldap.ALREADY_EXISTS: print "Index for attr %s for backend %s already exists" % ( attr, dn)
def schemaReload(self, schemadir=None, args=None): ''' @param schemadir - The directory to look for schema files(optional) @param args - Is a dictionary that contains modifier of the task wait: True/[False] - If True, waits for the completion of the task before to return @return exit code ''' cn = 'task-' + time.strftime("%m%d%Y_%H%M%S", time.localtime()) dn = ('cn=%s,cn=schema reload task,cn=tasks,cn=config' % cn) entry = Entry(dn) entry.setValues('objectclass', 'top', 'extensibleObject') entry.setValues('cn', cn) if schemadir: entry.setValues('schemadir', schemadir) # start the task and possibly wait for task completion try: self.conn.add_s(entry) except ldap.ALREADY_EXISTS: self.log.error("Fail to add Schema Reload task") return -1 exitCode = 0 if args and args.get(TASK_WAIT, False): (done, exitCode) = self.conn.tasks.checkTask(entry, True) if exitCode: self.log.error("Error: Schema Reload task (%s) exited with %d" % (cn, exitCode)) else: self.log.info("Schema Reload task (%s) completed successfully" % (cn)) return exitCode
def fixupLinkedAttrs(self, linkdn=None, args=None): ''' @param linkdn - The DN of linked attr config entry (if None all possible configurations are checked) @param args - Is a dictionary that contains modifier of the task wait: True/[False] - If True, waits for the completion of the task before to return @return exit code ''' cn = 'task-' + time.strftime("%m%d%Y_%H%M%S", time.localtime()) dn = ('cn=%s,cn=fixup linked attributes,cn=tasks,cn=config' % cn) entry = Entry(dn) entry.setValues('objectclass', 'top', 'extensibleObject') entry.setValues('cn', cn) if linkdn: entry.setValues('linkdn', linkdn) # start the task and possibly wait for task completion try: self.conn.add_s(entry) except ldap.ALREADY_EXISTS: self.log.error("Fail to add Fixup Linked Attributes task") return -1 exitCode = 0 if args and args.get(TASK_WAIT, False): (done, exitCode) = self.conn.tasks.checkTask(entry, True) if exitCode: self.log.error("Error: Fixup Linked Attributes task (%s) exited with %d" % (cn, exitCode)) else: self.log.info("Fixup Linked Attributes task (%s) completed successfully" % (cn)) return exitCode
def group(topology): """Create a group entry""" gentry = Entry('cn=testgroup,%s' % DEFAULT_SUFFIX) gentry.setValues('objectclass', 'top', 'extensibleobject') gentry.setValues('cn', 'testgroup') for i in range(0, 2): gentry.setValues('uniqueMember', 'uid=test%s,%s' % (i, DEFAULT_SUFFIX)) topology.standalone.add_s(gentry)
def automemberMap(self, ldif_in=None, ldif_out=None, args=None): ''' @param ldif_in - Entries to pass into the task for processing @param ldif_out - The resulting LDIF of changes from ldif_in @param args - is a dictionary that contains modifier of the task wait: True/[False] - If True, waits for the completion of the task before to return @return exit code @raise ValueError: if ldif_out/ldif_in is not provided ''' if not ldif_out or not ldif_in: raise ValueError("Missing ldif_out and/or ldif_in") cn = 'task-' + time.strftime("%m%d%Y_%H%M%S", time.localtime()) dn = ('cn=%s,cn=automember map updates,cn=tasks,cn=config' % cn) entry = Entry(dn) entry.setValues('objectclass', 'top', 'extensibleObject') entry.setValues('cn', cn) entry.setValues('ldif_in', ldif_in) entry.setValues('ldif_out', ldif_out) # start the task and possibly wait for task completion try: self.conn.add_s(entry) except ldap.ALREADY_EXISTS: self.log.error("Fail to add Automember Map Updates task") return -1 exitCode = 0 if args and args.get(TASK_WAIT, False): (done, exitCode) = self.conn.tasks.checkTask(entry, True) if exitCode: self.log.error( "Error: Automember Map Updates task (%s) exited with %d" % (cn, exitCode)) else: self.log.info( "Automember Map Updates task (%s) completed successfully" % (cn)) self.dn = dn self.entry = entry return exitCode
def sysconfigReload(self, configfile=None, logchanges=None, args=None): ''' @param configfile - The sysconfig file: /etc/sysconfig/dirsrv-localhost @param logchanges - True/False - Tell the server to log the changes made by the task @param args - is a dictionary that contains modifier of the task wait: True/[False] - If True, waits for the completion of the task before to return @return exit code @raise ValueError: If sysconfig file not provided ''' if not configfile: raise ValueError("Missing required paramter: configfile") cn = 'task-' + time.strftime("%m%d%Y_%H%M%S", time.localtime()) dn = ('cn=%s,cn=cn=sysconfig reload,cn=tasks,cn=config' % cn) entry = Entry(dn) entry.setValues('objectclass', 'top', 'extensibleObject') entry.setValues('cn', cn) entry.setValues('sysconfigfile', configfile) if logchanges: entry.setValues('logchanges', logchanges) # start the task and possibly wait for task completion try: self.conn.add_s(entry) except ldap.ALREADY_EXISTS: self.log.error("Fail to add Sysconfig Reload task") return -1 exitCode = 0 if args and args.get(TASK_WAIT, False): (done, exitCode) = self.conn.tasks.checkTask(entry, True) if exitCode: self.log.error("Error: Sysconfig Reload task (%s) exited with %d" % (cn, exitCode)) else: self.log.info("Sysconfig Reload task (%s) completed successfully" % (cn)) self.dn = dn self.entry = entry return exitCode
def fixupLinkedAttrs(self, linkdn=None, args=None): ''' @param linkdn - The DN of linked attr config entry (if None all possible configurations are checked) @param args - Is a dictionary that contains modifier of the task wait: True/[False] - If True, waits for the completion of the task before to return @return exit code ''' cn = 'task-' + time.strftime("%m%d%Y_%H%M%S", time.localtime()) dn = ('cn=%s,cn=fixup linked attributes,cn=tasks,cn=config' % cn) entry = Entry(dn) entry.setValues('objectclass', 'top', 'extensibleObject') entry.setValues('cn', cn) if linkdn: entry.setValues('linkdn', linkdn) # start the task and possibly wait for task completion try: self.conn.add_s(entry) except ldap.ALREADY_EXISTS: self.log.error("Fail to add Fixup Linked Attributes task") return -1 exitCode = 0 if args and args.get(TASK_WAIT, False): (done, exitCode) = self.conn.tasks.checkTask(entry, True) if exitCode: self.log.error( "Error: Fixup Linked Attributes task (%s) exited with %d" % (cn, exitCode)) else: self.log.info( "Fixup Linked Attributes task (%s) completed successfully" % (cn)) self.dn = dn self.entry = entry return exitCode
def complex_aci(topology): ACI_TARGET = ('(targetfilter ="(ou=groups)")(targetattr ="uniqueMember ' '|| member")') ACI_ALLOW = ('(version 3.0; acl "Allow test aci";allow (read, search, ' 'write)') ACI_SUBJECT = ('(userdn="ldap:///dc=example,dc=com??sub?(ou=engineering)" ' 'and userdn="ldap:///dc=example,dc=com??sub?(manager=uid=' 'wbrown,ou=managers,dc=example,dc=com) || ldap:///dc=examp' 'le,dc=com??sub?(manager=uid=tbrown,ou=managers,dc=exampl' 'e,dc=com)" );)') ACI_BODY = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT gentry = Entry('cn=testgroup,%s' % DEFAULT_SUFFIX) gentry.setValues('objectclass', 'top', 'extensibleobject') gentry.setValues('cn', 'testgroup') gentry.setValues('aci', ACI_BODY) topology.standalone.add_s(gentry) return ensure_str(ACI_BODY)
def create(self, suffix=None, bename=None, parent=None): ''' Create a mapping tree entry (under "cn=mapping tree,cn=config"), for the 'suffix' and that is stored in 'bename' backend. 'bename' backend must exists before creating the mapping tree entry. If a 'parent' is provided that means that we are creating a sub-suffix mapping tree. @param suffix - suffix mapped by this mapping tree entry. It will be the common name ('cn') of the entry @param benamebase - backend common name (e.g. 'userRoot') @param parent - if provided is a parent suffix of 'suffix' @return DN of the mapping tree entry @raise ldap.NO_SUCH_OBJECT - if the backend entry or parent mapping tree does not exist ''' # Check suffix is provided if not suffix: raise ValueError("suffix is mandatory") else: nsuffix = normalizeDN(suffix) # Check backend name is provided if not bename: raise ValueError("backend name is mandatory") # Check that if the parent suffix is provided then # it exists a mapping tree for it if parent: nparent = normalizeDN(parent) filt = suffixfilt(parent) try: entry = self.conn.getEntry(DN_MAPPING_TREE, ldap.SCOPE_SUBTREE, filt) pass except NoSuchEntryError: raise ValueError("parent suffix has no mapping tree") else: nparent = "" # Check if suffix exists, return filt = suffixfilt(suffix) try: entry = self.conn.getEntry(DN_MAPPING_TREE, ldap.SCOPE_SUBTREE, filt) return entry except NoSuchEntryError: entry = None # # Now start the real work # # fix me when we can actually used escaped DNs dn = ','.join(('cn="%s"' % nsuffix, DN_MAPPING_TREE)) entry = Entry(dn) entry.update({ 'objectclass': ['top', 'extensibleObject', MT_OBJECTCLASS_VALUE], 'nsslapd-state': 'backend', # the value in the dn has to be DN escaped # internal code will add the quoted value - unquoted value is useful for searching MT_PROPNAME_TO_ATTRNAME[MT_SUFFIX]: nsuffix, MT_PROPNAME_TO_ATTRNAME[MT_BACKEND]: bename }) # possibly add the parent if parent: entry.setValues(MT_PROPNAME_TO_ATTRNAME[MT_PARENT_SUFFIX], nparent) try: self.log.debug("Creating entry: %s" % entry.dn) self.log.info("Entry %r" % entry) self.conn.add_s(entry) except ldap.LDAPError, e: raise ldap.LDAPError("Error adding suffix entry " + dn, e)
def test_update_complex(self): # compare two entries created with different methods nsuffix, replid, replicatype = ("dc=example,dc=com", 5, lib389.REPLICA_RDWR_TYPE) binddnlist, legacy = ['uid=pippo, cn=config'], 'off' dn = "dc=example,dc=com" entry = Entry(dn) entry.setValues('objectclass', "top", "nsds5replica", "extensibleobject") entry.setValues('cn', "replica") entry.setValues('nsds5replicaroot', nsuffix) entry.setValues('nsds5replicaid', str(replid)) entry.setValues('nsds5replicatype', str(replicatype)) entry.setValues('nsds5flags', "1") entry.setValues('nsds5replicabinddn', binddnlist) entry.setValues('nsds5replicalegacyconsumer', legacy) uentry = Entry((dn, { 'objectclass': ["top", "nsds5replica", "extensibleobject"], 'cn': ["replica"] })) log.debug("Entry created with dict:", uentry) # Entry.update *replaces*, so be careful with multi-valued attrs uentry.update({ 'nsds5replicaroot': nsuffix, 'nsds5replicaid': str(replid), 'nsds5replicatype': str(replicatype), 'nsds5flags': '1', 'nsds5replicabinddn': binddnlist, 'nsds5replicalegacyconsumer': legacy }) uentry_s, entry_s = list(map(str, (uentry, entry))) assert uentry_s == entry_s, "Mismatching entries [%r] vs [%r]" % ( uentry, entry)
def test_ticket47653_add(topology_m2): ''' This test ADD an entry on MASTER1 where 47653 is fixed. Then it checks that entry is replicated on MASTER2 (even if on MASTER2 47653 is NOT fixed). Then update on MASTER2 and check the update on MASTER1 It checks that, bound as bind_entry, - we can not ADD an entry without the proper SELFDN aci. - with the proper ACI we can not ADD with 'member' attribute - with the proper ACI and 'member' it succeeds to ADD ''' topology_m2.ms["master1"].log.info("\n\n######################### ADD ######################\n") # bind as bind_entry topology_m2.ms["master1"].log.info("Bind as %s" % BIND_DN) topology_m2.ms["master1"].simple_bind_s(BIND_DN, BIND_PW) # Prepare the entry with multivalued members entry_with_members = Entry(ENTRY_DN) entry_with_members.setValues('objectclass', 'top', 'person', 'OCticket47653') entry_with_members.setValues('sn', ENTRY_NAME) entry_with_members.setValues('cn', ENTRY_NAME) entry_with_members.setValues('postalAddress', 'here') entry_with_members.setValues('postalCode', '1234') members = [] for cpt in range(MAX_OTHERS): name = "%s%d" % (OTHER_NAME, cpt) members.append("cn=%s,%s" % (name, SUFFIX)) members.append(BIND_DN) entry_with_members.setValues('member', members) # Prepare the entry with only one member value entry_with_member = Entry(ENTRY_DN) entry_with_member.setValues('objectclass', 'top', 'person', 'OCticket47653') entry_with_member.setValues('sn', ENTRY_NAME) entry_with_member.setValues('cn', ENTRY_NAME) entry_with_member.setValues('postalAddress', 'here') entry_with_member.setValues('postalCode', '1234') member = [] member.append(BIND_DN) entry_with_member.setValues('member', member) # entry to add WITH member being BIND_DN but WITHOUT the ACI -> ldap.INSUFFICIENT_ACCESS try: topology_m2.ms["master1"].log.info("Try to add Add %s (aci is missing): %r" % (ENTRY_DN, entry_with_member)) topology_m2.ms["master1"].add_s(entry_with_member) except Exception as e: topology_m2.ms["master1"].log.info("Exception (expected): %s" % type(e).__name__) assert isinstance(e, ldap.INSUFFICIENT_ACCESS) # Ok Now add the proper ACI topology_m2.ms["master1"].log.info("Bind as %s and add the ADD SELFDN aci" % DN_DM) topology_m2.ms["master1"].simple_bind_s(DN_DM, PASSWORD) ACI_TARGET = "(target = \"ldap:///cn=*,%s\")" % SUFFIX ACI_TARGETFILTER = "(targetfilter =\"(objectClass=%s)\")" % OC_NAME ACI_ALLOW = "(version 3.0; acl \"SelfDN add\"; allow (add)" ACI_SUBJECT = " userattr = \"member#selfDN\";)" ACI_BODY = ACI_TARGET + ACI_TARGETFILTER + ACI_ALLOW + ACI_SUBJECT mod = [(ldap.MOD_ADD, 'aci', ACI_BODY)] topology_m2.ms["master1"].modify_s(SUFFIX, mod) time.sleep(1) # bind as bind_entry topology_m2.ms["master1"].log.info("Bind as %s" % BIND_DN) topology_m2.ms["master1"].simple_bind_s(BIND_DN, BIND_PW) # entry to add WITHOUT member and WITH the ACI -> ldap.INSUFFICIENT_ACCESS try: topology_m2.ms["master1"].log.info("Try to add Add %s (member is missing)" % ENTRY_DN) topology_m2.ms["master1"].add_s(Entry((ENTRY_DN, { 'objectclass': ENTRY_OC.split(), 'sn': ENTRY_NAME, 'cn': ENTRY_NAME, 'postalAddress': 'here', 'postalCode': '1234'}))) except Exception as e: topology_m2.ms["master1"].log.info("Exception (expected): %s" % type(e).__name__) assert isinstance(e, ldap.INSUFFICIENT_ACCESS) time.sleep(1) # entry to add WITH memberS and WITH the ACI -> ldap.INSUFFICIENT_ACCESS # member should contain only one value try: topology_m2.ms["master1"].log.info("Try to add Add %s (with several member values)" % ENTRY_DN) topology_m2.ms["master1"].add_s(entry_with_members) except Exception as e: topology_m2.ms["master1"].log.info("Exception (expected): %s" % type(e).__name__) assert isinstance(e, ldap.INSUFFICIENT_ACCESS) time.sleep(2) topology_m2.ms["master1"].log.info("Try to add Add %s should be successful" % ENTRY_DN) try: topology_m2.ms["master1"].add_s(entry_with_member) except ldap.LDAPError as e: topology_m2.ms["master1"].log.info("Failed to add entry, error: " + e.message['desc']) assert False # # Now check the entry as been replicated # topology_m2.ms["master2"].simple_bind_s(DN_DM, PASSWORD) topology_m2.ms["master1"].log.info("Try to retrieve %s from Master2" % ENTRY_DN) loop = 0 while loop <= 10: try: ent = topology_m2.ms["master2"].getEntry(ENTRY_DN, ldap.SCOPE_BASE, "(objectclass=*)") break except ldap.NO_SUCH_OBJECT: time.sleep(1) loop += 1 assert loop <= 10 # Now update the entry on Master2 (as DM because 47653 is possibly not fixed on M2) topology_m2.ms["master1"].log.info("Update %s on M2" % ENTRY_DN) mod = [(ldap.MOD_REPLACE, 'description', 'test_add')] topology_m2.ms["master2"].modify_s(ENTRY_DN, mod) time.sleep(1) topology_m2.ms["master1"].simple_bind_s(DN_DM, PASSWORD) loop = 0 while loop <= 10: try: ent = topology_m2.ms["master1"].getEntry(ENTRY_DN, ldap.SCOPE_BASE, "(objectclass=*)") if ent.hasAttr('description') and (ent.getValue('description') == 'test_add'): break except ldap.NO_SUCH_OBJECT: time.sleep(1) loop += 1 assert ent.getValue('description') == 'test_add'
'normal, regular AD account disabled, do not expire password', 'userAccountControl': 512 + 2 + 65536 }] userids_disabled = {} if useds: print "Create sub-ou's on the AD side and add users . . ." ii = 0 dns = [ 'ou=people,' + suffix, 'ou=1,ou=people,' + suffix, 'ou=2,ou=people,' + suffix, 'ou=11,ou=1,ou=people,' + suffix, 'ou=12,ou=1,ou=people,' + suffix ] for dn in dns: ent = Entry(dn) ent.setValues('objectclass', 'organizationalUnit') try: ad.add_s(ent) except ldap.ALREADY_EXISTS: pass print "Add users to", dn for jj in range(0, 5): strii = str(ii) userdn = 'cn=Test User' + strii + ',' + dn ent = Entry(userdn) userid = 'userid' + strii ent.setValues('objectclass', ['person', 'adPerson']) ent.setValues('sn', 'User' + strii) ent.setValues('samAccountName', userid) ent.setValues('objectGUID', struct.pack('B', ii)) ent.setValues('name', 'Test User' + strii) # same as cn
def importLDIF(self, suffix=None, benamebase=None, input_file=None, args=None): ''' Import from a LDIF format a given 'suffix' (or 'benamebase' that stores that suffix). It uses an internal task to acheive this request. If 'suffix' and 'benamebase' are specified, it uses 'benamebase' first else 'suffix'. If both 'suffix' and 'benamebase' are missing it raise ValueError 'input_file' is the ldif input file @param suffix - suffix of the backend @param benamebase - 'commonname'/'cn' of the backend (e.g. 'userRoot') @param ldif_input - file that will contain the entries in LDIF format, to import @param args - is a dictionary that contains modifier of the import task wait: True/[False] - If True, 'export' waits for the completion of the task before to return @return None @raise ValueError ''' # Checking the parameters if not benamebase and not suffix: raise ValueError("Specify either bename or suffix") if not input_file: raise ValueError("input_file is mandatory") if not os.path.exists(input_file): raise ValueError("Import file (%s) does not exist" % input_file) # Prepare the task entry cn = "import_" + time.strftime("%m%d%Y_%H%M%S", time.localtime()) dn = "cn=%s,%s" % (cn, DN_IMPORT_TASK) entry = Entry(dn) entry.setValues('objectclass', 'top', 'extensibleObject') entry.setValues('cn', cn) entry.setValues('nsFilename', input_file) if benamebase: entry.setValues('nsInstance', benamebase) else: entry.setValues('nsIncludeSuffix', suffix) # start the task and possibly wait for task completion try: self.conn.add_s(entry) except ldap.ALREADY_EXISTS: self.log.error("Fail to add the import task of %s" % input_file) return -1 exitCode = 0 if args and args.get(TASK_WAIT, False): (done, exitCode) = self.conn.tasks.checkTask(entry, True) if exitCode: self.log.error("Error: import task %s for file %s exited with %d" % (cn, input_file, exitCode)) else: self.log.info("Import task %s for file %s completed successfully" % (cn, input_file)) return exitCode
#del os.environ['USE_DBX'] m2.replicaSetupAll(m2replargs) print "create agreements and init consumers" agmtm1tom2 = m1.agreement.create(basedn, m2.host, m2.port, agmtargs) m1.replica.start_and_wait(agmtm1tom2) agmtm2tom1 = m2.agreement.create(basedn, m1.host, m1.port, agmtargs) nents = 5 m1ents = range(nents) m2ents = range(len(m1ents), len(m1ents)+nents+1) print "Add %d entries to m2" % len(m2ents) for ii in m2ents: dn = "cn=%d, %s" % (ii, basedn) ent = Entry(dn) ent.setValues('objectclass', 'person') ent.setValues('sn', 'testuser') m2.add_s(ent) print "Added m2 entry", dn print "Add %d entries to m1" % len(m1ents) for ii in m1ents: dn = "cn=%d, %s" % (ii, basedn) ent = Entry(dn) ent.setValues('objectclass', 'person') ent.setValues('sn', 'testuser') m1.add_s(ent) print "Added m1 entry", dn print "Sleep for 5 seconds to let changes propagate . . ." time.sleep(5)
def importLDIF(self, suffix=None, benamebase=None, input_file=None, args=None): ''' Import from a LDIF format a given 'suffix' (or 'benamebase' that stores that suffix). It uses an internal task to acheive this request. If 'suffix' and 'benamebase' are specified, it uses 'benamebase' first else 'suffix'. If both 'suffix' and 'benamebase' are missing it raise ValueError 'input_file' is the ldif input file @param suffix - suffix of the backend @param benamebase - 'commonname'/'cn' of the backend (e.g. 'userRoot') @param ldif_input - file that will contain the entries in LDIF format, to import @param args - is a dictionary that contains modifier of the import task wait: True/[False] - If True, 'export' waits for the completion of the task before to return @return None @raise ValueError ''' # Checking the parameters if not benamebase and not suffix: raise ValueError("Specify either bename or suffix") if not input_file: raise ValueError("input_file is mandatory") if not os.path.exists(input_file): raise ValueError("Import file (%s) does not exist" % input_file) # Prepare the task entry cn = "import_" + time.strftime("%m%d%Y_%H%M%S", time.localtime()) dn = "cn=%s,%s" % (cn, DN_IMPORT_TASK) entry = Entry(dn) entry.setValues('objectclass', 'top', 'extensibleObject') entry.setValues('cn', cn) entry.setValues('nsFilename', input_file) if benamebase: entry.setValues('nsInstance', benamebase) else: entry.setValues('nsIncludeSuffix', suffix) # start the task and possibly wait for task completion try: self.conn.add_s(entry) except ldap.ALREADY_EXISTS: self.log.error("Fail to add the import task of %s" % input_file) return -1 exitCode = 0 if args and args.get(TASK_WAIT, False): (done, exitCode) = self.conn.tasks.checkTask(entry, True) if exitCode: self.log.error("Error: import task %s for file %s exited with %d" % ( cn, input_file, exitCode)) else: self.log.info("Import task %s for file %s completed successfully" % ( cn, input_file)) return exitCode
def test_ticket47808_run(topology): """ It enables attribute uniqueness plugin with sn as a unique attribute Add an entry 1 with sn = ENTRY_NAME Add an entry 2 with sn = ENTRY_NAME If the second add does not crash the server and the following search found none, the bug is fixed. """ # bind as directory manager topology.standalone.log.info("Bind as %s" % DN_DM) topology.standalone.simple_bind_s(DN_DM, PASSWORD) topology.standalone.log.info("\n\n######################### SETUP ATTR UNIQ PLUGIN ######################\n") # enable attribute uniqueness plugin mod = [(ldap.MOD_REPLACE, 'nsslapd-pluginEnabled', 'on'), (ldap.MOD_REPLACE, 'nsslapd-pluginarg0', 'sn'), (ldap.MOD_REPLACE, 'nsslapd-pluginarg1', SUFFIX)] topology.standalone.modify_s(ATTRIBUTE_UNIQUENESS_PLUGIN, mod) topology.standalone.log.info("\n\n######################### ADD USER 1 ######################\n") # Prepare entry 1 entry_name = '%s 1' % (ENTRY_NAME) entry_dn_1 = 'cn=%s, %s' % (entry_name, SUFFIX) entry_1 = Entry(entry_dn_1) entry_1.setValues('objectclass', 'top', 'person') entry_1.setValues('sn', ENTRY_NAME) entry_1.setValues('cn', entry_name) topology.standalone.log.info("Try to add Add %s: %r" % (entry_1, entry_1)) topology.standalone.add_s(entry_1) topology.standalone.log.info("\n\n######################### Restart Server ######################\n") topology.standalone.stop(timeout=10) topology.standalone.start(timeout=10) topology.standalone.log.info("\n\n######################### ADD USER 2 ######################\n") # Prepare entry 2 having the same sn, which crashes the server entry_name = '%s 2' % (ENTRY_NAME) entry_dn_2 = 'cn=%s, %s' % (entry_name, SUFFIX) entry_2 = Entry(entry_dn_2) entry_2.setValues('objectclass', 'top', 'person') entry_2.setValues('sn', ENTRY_NAME) entry_2.setValues('cn', entry_name) topology.standalone.log.info("Try to add Add %s: %r" % (entry_2, entry_2)) try: topology.standalone.add_s(entry_2) except: topology.standalone.log.warn("Adding %s failed" % entry_dn_2) pass topology.standalone.log.info("\n\n######################### IS SERVER UP? ######################\n") ents = topology.standalone.search_s(entry_dn_1, ldap.SCOPE_BASE, '(objectclass=*)') assert len(ents) == 1 topology.standalone.log.info("Yes, it's up.") topology.standalone.log.info("\n\n######################### CHECK USER 2 NOT ADDED ######################\n") topology.standalone.log.info("Try to search %s" % entry_dn_2) try: ents = topology.standalone.search_s(entry_dn_2, ldap.SCOPE_BASE, '(objectclass=*)') except ldap.NO_SUCH_OBJECT: topology.standalone.log.info("Found none") topology.standalone.log.info("\n\n######################### DELETE USER 1 ######################\n") topology.standalone.log.info("Try to delete %s " % entry_dn_1) topology.standalone.delete_s(entry_dn_1) log.info('Testcase PASSED')
def create(self, suffix=None, bename=None, parent=None): ''' Create a mapping tree entry (under "cn=mapping tree,cn=config"), for the 'suffix' and that is stored in 'bename' backend. 'bename' backend must exist before creating the mapping tree entry. If a 'parent' is provided that means that we are creating a sub-suffix mapping tree. @param suffix - suffix mapped by this mapping tree entry. It will be the common name ('cn') of the entry @param benamebase - backend common name (e.g. 'userRoot') @param parent - if provided is a parent suffix of 'suffix' @return DN of the mapping tree entry @raise ldap.NO_SUCH_OBJECT - if the backend entry or parent mapping tree does not exist ValueError - if missing a parameter, ''' # Check suffix is provided if not suffix: raise ValueError("suffix is mandatory") else: nsuffix = normalizeDN(suffix) # Check backend name is provided if not bename: raise ValueError("backend name is mandatory") # Check that if the parent suffix is provided then # it exists a mapping tree for it if parent: nparent = normalizeDN(parent) filt = suffixfilt(parent) try: entry = self.conn.getEntry(DN_MAPPING_TREE, ldap.SCOPE_SUBTREE, filt) pass except NoSuchEntryError: raise ValueError("parent suffix has no mapping tree") else: nparent = "" # Check if suffix exists, return filt = suffixfilt(suffix) try: entry = self.conn.getEntry(DN_MAPPING_TREE, ldap.SCOPE_SUBTREE, filt) return entry except ldap.NO_SUCH_OBJECT: entry = None # # Now start the real work # # fix me when we can actually used escaped DNs dn = ','.join(('cn="%s"' % nsuffix, DN_MAPPING_TREE)) entry = Entry(dn) entry.update({ 'objectclass': ['top', 'extensibleObject', MT_OBJECTCLASS_VALUE], 'nsslapd-state': 'backend', # the value in the dn has to be DN escaped # internal code will add the quoted value - unquoted value is # useful for searching. MT_PROPNAME_TO_ATTRNAME[MT_SUFFIX]: nsuffix, MT_PROPNAME_TO_ATTRNAME[MT_BACKEND]: bename }) # possibly add the parent if parent: entry.setValues(MT_PROPNAME_TO_ATTRNAME[MT_PARENT_SUFFIX], nparent) try: self.log.debug("Creating entry: %s", entry.dn) self.log.info("Entry %r", entry) self.conn.add_s(entry) except ldap.LDAPError as e: raise ldap.LDAPError("Error adding suffix entry " + dn, e) ret = self.conn._test_entry(dn, ldap.SCOPE_BASE) return ret
def test_ticket47653_add(topology_st): ''' It checks that, bound as bind_entry, - we can not ADD an entry without the proper SELFDN aci. - with the proper ACI we can not ADD with 'member' attribute - with the proper ACI and 'member' it succeeds to ADD ''' topology_st.standalone.log.info( "\n\n######################### ADD ######################\n") # bind as bind_entry topology_st.standalone.log.info("Bind as %s" % BIND_DN) topology_st.standalone.simple_bind_s(BIND_DN, BIND_PW) # Prepare the entry with multivalued members entry_with_members = Entry(ENTRY_DN) entry_with_members.setValues('objectclass', 'top', 'person', 'OCticket47653') entry_with_members.setValues('sn', ENTRY_NAME) entry_with_members.setValues('cn', ENTRY_NAME) entry_with_members.setValues('postalAddress', 'here') entry_with_members.setValues('postalCode', '1234') members = [] for cpt in range(MAX_OTHERS): name = "%s%d" % (OTHER_NAME, cpt) members.append("cn=%s,%s" % (name, SUFFIX)) members.append(BIND_DN) entry_with_members.setValues('member', members) # Prepare the entry with one member entry_with_member = Entry(ENTRY_DN) entry_with_member.setValues('objectclass', 'top', 'person', 'OCticket47653') entry_with_member.setValues('sn', ENTRY_NAME) entry_with_member.setValues('cn', ENTRY_NAME) entry_with_member.setValues('postalAddress', 'here') entry_with_member.setValues('postalCode', '1234') member = [] member.append(BIND_DN) entry_with_member.setValues('member', member) # entry to add WITH member being BIND_DN but WITHOUT the ACI -> ldap.INSUFFICIENT_ACCESS try: topology_st.standalone.log.info( "Try to add Add %s (aci is missing): %r" % (ENTRY_DN, entry_with_member)) topology_st.standalone.add_s(entry_with_member) except Exception as e: topology_st.standalone.log.info("Exception (expected): %s" % type(e).__name__) assert isinstance(e, ldap.INSUFFICIENT_ACCESS) # Ok Now add the proper ACI topology_st.standalone.log.info("Bind as %s and add the ADD SELFDN aci" % DN_DM) topology_st.standalone.simple_bind_s(DN_DM, PASSWORD) ACI_TARGET = "(target = \"ldap:///cn=*,%s\")" % SUFFIX ACI_TARGETFILTER = "(targetfilter =\"(objectClass=%s)\")" % OC_NAME ACI_ALLOW = "(version 3.0; acl \"SelfDN add\"; allow (add)" ACI_SUBJECT = " userattr = \"member#selfDN\";)" ACI_BODY = ACI_TARGET + ACI_TARGETFILTER + ACI_ALLOW + ACI_SUBJECT mod = [(ldap.MOD_ADD, 'aci', ACI_BODY)] topology_st.standalone.modify_s(SUFFIX, mod) # bind as bind_entry topology_st.standalone.log.info("Bind as %s" % BIND_DN) topology_st.standalone.simple_bind_s(BIND_DN, BIND_PW) # entry to add WITHOUT member and WITH the ACI -> ldap.INSUFFICIENT_ACCESS try: topology_st.standalone.log.info( "Try to add Add %s (member is missing)" % ENTRY_DN) topology_st.standalone.add_s( Entry((ENTRY_DN, { 'objectclass': ENTRY_OC.split(), 'sn': ENTRY_NAME, 'cn': ENTRY_NAME, 'postalAddress': 'here', 'postalCode': '1234' }))) except Exception as e: topology_st.standalone.log.info("Exception (expected): %s" % type(e).__name__) assert isinstance(e, ldap.INSUFFICIENT_ACCESS) # entry to add WITH memberS and WITH the ACI -> ldap.INSUFFICIENT_ACCESS # member should contain only one value try: topology_st.standalone.log.info( "Try to add Add %s (with several member values)" % ENTRY_DN) topology_st.standalone.add_s(entry_with_members) except Exception as e: topology_st.standalone.log.info("Exception (expected): %s" % type(e).__name__) assert isinstance(e, ldap.INSUFFICIENT_ACCESS) topology_st.standalone.log.info("Try to add Add %s should be successful" % ENTRY_DN) topology_st.standalone.add_s(entry_with_member)
def test_ticket47313_run(topology): """ It adds 2 test entries Search with filters including subtype and ! It deletes the added entries """ # bind as directory manager topology.standalone.log.info("Bind as %s" % DN_DM) topology.standalone.simple_bind_s(DN_DM, PASSWORD) # enable filter error logging #mod = [(ldap.MOD_REPLACE, 'nsslapd-errorlog-level', '32')] #topology.standalone.modify_s(DN_CONFIG, mod) topology.standalone.log.info("\n\n######################### ADD ######################\n") # Prepare the entry with cn;fr & cn;en entry_name_fr = '%s fr' % (ENTRY_NAME) entry_name_en = '%s en' % (ENTRY_NAME) entry_name_both = '%s both' % (ENTRY_NAME) entry_dn_both = 'cn=%s, %s' % (entry_name_both, SUFFIX) entry_both = Entry(entry_dn_both) entry_both.setValues('objectclass', 'top', 'person') entry_both.setValues('sn', entry_name_both) entry_both.setValues('cn', entry_name_both) entry_both.setValues('cn;fr', entry_name_fr) entry_both.setValues('cn;en', entry_name_en) # Prepare the entry with one member entry_name_en_only = '%s en only' % (ENTRY_NAME) entry_dn_en_only = 'cn=%s, %s' % (entry_name_en_only, SUFFIX) entry_en_only = Entry(entry_dn_en_only) entry_en_only.setValues('objectclass', 'top', 'person') entry_en_only.setValues('sn', entry_name_en_only) entry_en_only.setValues('cn', entry_name_en_only) entry_en_only.setValues('cn;en', entry_name_en) topology.standalone.log.info("Try to add Add %s: %r" % (entry_dn_both, entry_both)) topology.standalone.add_s(entry_both) topology.standalone.log.info("Try to add Add %s: %r" % (entry_dn_en_only, entry_en_only)) topology.standalone.add_s(entry_en_only) topology.standalone.log.info("\n\n######################### SEARCH ######################\n") # filter: (&(cn=test_entry en only)(!(cn=test_entry fr))) myfilter = '(&(sn=%s)(!(cn=%s)))' % (entry_name_en_only, entry_name_fr) topology.standalone.log.info("Try to search with filter %s" % myfilter) ents = topology.standalone.search_s(SUFFIX, ldap.SCOPE_SUBTREE, myfilter) assert len(ents) == 1 assert ents[0].sn == entry_name_en_only topology.standalone.log.info("Found %s" % ents[0].dn) # filter: (&(cn=test_entry en only)(!(cn;fr=test_entry fr))) myfilter = '(&(sn=%s)(!(cn;fr=%s)))' % (entry_name_en_only, entry_name_fr) topology.standalone.log.info("Try to search with filter %s" % myfilter) ents = topology.standalone.search_s(SUFFIX, ldap.SCOPE_SUBTREE, myfilter) assert len(ents) == 1 assert ents[0].sn == entry_name_en_only topology.standalone.log.info("Found %s" % ents[0].dn) # filter: (&(cn=test_entry en only)(!(cn;en=test_entry en))) myfilter = '(&(sn=%s)(!(cn;en=%s)))' % (entry_name_en_only, entry_name_en) topology.standalone.log.info("Try to search with filter %s" % myfilter) ents = topology.standalone.search_s(SUFFIX, ldap.SCOPE_SUBTREE, myfilter) assert len(ents) == 0 topology.standalone.log.info("Found none") topology.standalone.log.info("\n\n######################### DELETE ######################\n") topology.standalone.log.info("Try to delete %s " % entry_dn_both) topology.standalone.delete_s(entry_dn_both) topology.standalone.log.info("Try to delete %s " % entry_dn_en_only) topology.standalone.delete_s(entry_dn_en_only) log.info('Testcase PASSED')
def test_ticket47653_add(topology): ''' This test ADD an entry on MASTER1 where 47653 is fixed. Then it checks that entry is replicated on MASTER2 (even if on MASTER2 47653 is NOT fixed). Then update on MASTER2 and check the update on MASTER1 It checks that, bound as bind_entry, - we can not ADD an entry without the proper SELFDN aci. - with the proper ACI we can not ADD with 'member' attribute - with the proper ACI and 'member' it succeeds to ADD ''' topology.master1.log.info("\n\n######################### ADD ######################\n") # bind as bind_entry topology.master1.log.info("Bind as %s" % BIND_DN) topology.master1.simple_bind_s(BIND_DN, BIND_PW) # Prepare the entry with multivalued members entry_with_members = Entry(ENTRY_DN) entry_with_members.setValues('objectclass', 'top', 'person', 'OCticket47653') entry_with_members.setValues('sn', ENTRY_NAME) entry_with_members.setValues('cn', ENTRY_NAME) entry_with_members.setValues('postalAddress', 'here') entry_with_members.setValues('postalCode', '1234') members = [] for cpt in range(MAX_OTHERS): name = "%s%d" % (OTHER_NAME, cpt) members.append("cn=%s,%s" % (name, SUFFIX)) members.append(BIND_DN) entry_with_members.setValues('member', members) # Prepare the entry with only one member value entry_with_member = Entry(ENTRY_DN) entry_with_member.setValues('objectclass', 'top', 'person', 'OCticket47653') entry_with_member.setValues('sn', ENTRY_NAME) entry_with_member.setValues('cn', ENTRY_NAME) entry_with_member.setValues('postalAddress', 'here') entry_with_member.setValues('postalCode', '1234') member = [] member.append(BIND_DN) entry_with_member.setValues('member', member) # entry to add WITH member being BIND_DN but WITHOUT the ACI -> ldap.INSUFFICIENT_ACCESS try: topology.master1.log.info("Try to add Add %s (aci is missing): %r" % (ENTRY_DN, entry_with_member)) topology.master1.add_s(entry_with_member) except Exception as e: topology.master1.log.info("Exception (expected): %s" % type(e).__name__) assert isinstance(e, ldap.INSUFFICIENT_ACCESS) # Ok Now add the proper ACI topology.master1.log.info("Bind as %s and add the ADD SELFDN aci" % DN_DM) topology.master1.simple_bind_s(DN_DM, PASSWORD) ACI_TARGET = "(target = \"ldap:///cn=*,%s\")" % SUFFIX ACI_TARGETFILTER = "(targetfilter =\"(objectClass=%s)\")" % OC_NAME ACI_ALLOW = "(version 3.0; acl \"SelfDN add\"; allow (add)" ACI_SUBJECT = " userattr = \"member#selfDN\";)" ACI_BODY = ACI_TARGET + ACI_TARGETFILTER + ACI_ALLOW + ACI_SUBJECT mod = [(ldap.MOD_ADD, 'aci', ACI_BODY)] topology.master1.modify_s(SUFFIX, mod) time.sleep(1) # bind as bind_entry topology.master1.log.info("Bind as %s" % BIND_DN) topology.master1.simple_bind_s(BIND_DN, BIND_PW) # entry to add WITHOUT member and WITH the ACI -> ldap.INSUFFICIENT_ACCESS try: topology.master1.log.info("Try to add Add %s (member is missing)" % ENTRY_DN) topology.master1.add_s(Entry((ENTRY_DN, { 'objectclass': ENTRY_OC.split(), 'sn': ENTRY_NAME, 'cn': ENTRY_NAME, 'postalAddress': 'here', 'postalCode': '1234'}))) except Exception as e: topology.master1.log.info("Exception (expected): %s" % type(e).__name__) assert isinstance(e, ldap.INSUFFICIENT_ACCESS) # entry to add WITH memberS and WITH the ACI -> ldap.INSUFFICIENT_ACCESS # member should contain only one value try: topology.master1.log.info("Try to add Add %s (with several member values)" % ENTRY_DN) topology.master1.add_s(entry_with_members) except Exception as e: topology.master1.log.info("Exception (expected): %s" % type(e).__name__) assert isinstance(e, ldap.INSUFFICIENT_ACCESS) topology.master1.log.info("Try to add Add %s should be successful" % ENTRY_DN) try: topology.master1.add_s(entry_with_member) except ldap.LDAPError as e: topology.master1.log.info("Failed to add entry, error: " + e.message['desc']) assert False # # Now check the entry as been replicated # topology.master2.simple_bind_s(DN_DM, PASSWORD) topology.master1.log.info("Try to retrieve %s from Master2" % ENTRY_DN) loop = 0 while loop <= 10: try: ent = topology.master2.getEntry(ENTRY_DN, ldap.SCOPE_BASE, "(objectclass=*)") break except ldap.NO_SUCH_OBJECT: time.sleep(1) loop += 1 assert loop <= 10 # Now update the entry on Master2 (as DM because 47653 is possibly not fixed on M2) topology.master1.log.info("Update %s on M2" % ENTRY_DN) mod = [(ldap.MOD_REPLACE, 'description', 'test_add')] topology.master2.modify_s(ENTRY_DN, mod) topology.master1.simple_bind_s(DN_DM, PASSWORD) loop = 0 while loop <= 10: try: ent = topology.master1.getEntry(ENTRY_DN, ldap.SCOPE_BASE, "(objectclass=*)") if ent.hasAttr('description') and (ent.getValue('description') == 'test_add'): break except ldap.NO_SUCH_OBJECT: time.sleep(1) loop += 1 assert ent.getValue('description') == 'test_add'
def exportLDIF(self, suffix=None, benamebase=None, output_file=None, args=None): ''' Export in a LDIF format a given 'suffix' (or 'benamebase' that stores that suffix). It uses an internal task to acheive this request. If 'suffix' and 'benamebase' are specified, it uses 'benamebase' first else 'suffix'. If both 'suffix' and 'benamebase' are missing it raises ValueError 'output_file' is the output file of the export @param suffix - suffix of the backend @param benamebase - 'commonname'/'cn' of the backend (e.g. 'userRoot') @param output_file - file that will contain the exported suffix in LDIF format @param args - is a dictionary that contains modifier of the export task wait: True/[False] - If True, 'export' waits for the completion of the task before to return repl-info: True/[False] - If True, it adds the replication meta data (state information, tombstones and RUV) in the exported file @return None @raise ValueError ''' # Checking the parameters if not benamebase and not suffix: raise ValueError("Specify either bename or suffix") if not output_file: raise ValueError("output_file is mandatory") # Prepare the task entry cn = "export_" + time.strftime("%m%d%Y_%H%M%S", time.localtime()) dn = "cn=%s,%s" % (cn, DN_EXPORT_TASK) entry = Entry(dn) entry.update({ 'objectclass': ['top', 'extensibleObject'], 'cn': cn, 'nsFilename': output_file }) if benamebase: entry.setValues('nsInstance', benamebase) else: entry.setValues('nsIncludeSuffix', suffix) if args.get(EXPORT_REPL_INFO, False): entry.setValues('nsExportReplica', 'true') # start the task and possibly wait for task completion self.conn.add_s(entry) exitCode = 0 if args and args.get(TASK_WAIT, False): (done, exitCode) = self.conn.tasks.checkTask(entry, True) if exitCode: self.log.error("Error: export task %s for file %s exited with %d" % ( cn, output_file, exitCode)) else: self.log.info("Export task %s for file %s completed successfully" % ( cn, output_file)) return exitCode
def test_pwdAdmin_init(topology): ''' Create our future Password Admin entry, set the password policy, and test that its working ''' log.info('test_pwdAdmin_init: Creating Password Administator entries...') # Add Password Admin 1 try: topology.standalone.add_s(Entry((ADMIN_DN, {'objectclass': "top extensibleObject".split(), 'cn': ADMIN_NAME, 'userpassword': ADMIN_PWD}))) except ldap.LDAPError as e: log.fatal('test_pwdAdmin_init: Failed to add test user' + ADMIN_DN + ': error ' + e.message['desc']) assert False # Add Password Admin 2 try: topology.standalone.add_s(Entry((ADMIN2_DN, {'objectclass': "top extensibleObject".split(), 'cn': ADMIN2_NAME, 'userpassword': ADMIN_PWD}))) except ldap.LDAPError as e: log.fatal('test_pwdAdmin_init: Failed to add test user ' + ADMIN2_DN + ': error ' + e.message['desc']) assert False # Add Password Admin Group try: topology.standalone.add_s(Entry((ADMIN_GROUP_DN, {'objectclass': "top groupOfUNiqueNames".split(), 'cn': 'password admin group', 'uniquemember': ADMIN_DN, 'uniquemember': ADMIN2_DN}))) except ldap.LDAPError as e: log.fatal('test_pwdAdmin_init: Failed to add group' + ADMIN_GROUP_DN + ': error ' + e.message['desc']) assert False # Configure password policy log.info('test_pwdAdmin_init: Configuring password policy...') try: topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_REPLACE, 'nsslapd-pwpolicy-local', 'on'), (ldap.MOD_REPLACE, 'passwordCheckSyntax', 'on'), (ldap.MOD_REPLACE, 'passwordMinCategories', '1'), (ldap.MOD_REPLACE, 'passwordMinTokenLength', '1'), (ldap.MOD_REPLACE, 'passwordExp', 'on'), (ldap.MOD_REPLACE, 'passwordMinDigits', '1'), (ldap.MOD_REPLACE, 'passwordMinSpecials', '1')]) except ldap.LDAPError as e: log.fatal('test_pwdAdmin_init: Failed configure password policy: ' + e.message['desc']) assert False # # Add an aci to allow everyone all access (just makes things easier) # log.info('Add aci to allow password admin to add/update entries...') ACI_TARGET = "(target = \"ldap:///%s\")" % SUFFIX ACI_TARGETATTR = "(targetattr = *)" ACI_ALLOW = "(version 3.0; acl \"Password Admin Access\"; allow (all) " ACI_SUBJECT = "(userdn = \"ldap:///anyone\");)" ACI_BODY = ACI_TARGET + ACI_TARGETATTR + ACI_ALLOW + ACI_SUBJECT mod = [(ldap.MOD_ADD, 'aci', ACI_BODY)] try: topology.standalone.modify_s(SUFFIX, mod) except ldap.LDAPError as e: log.fatal('test_pwdAdmin_init: Failed to add aci for password admin: ' + e.message['desc']) assert False # # Bind as the future Password Admin # log.info('test_pwdAdmin_init: Bind as the Password Administator (before activating)...') try: topology.standalone.simple_bind_s(ADMIN_DN, ADMIN_PWD) except ldap.LDAPError as e: log.fatal('test_pwdAdmin_init: Failed to bind as the Password Admin: ' + e.message['desc']) assert False # # Setup our test entry, and test password policy is working # entry = Entry(ENTRY_DN) entry.setValues('objectclass', 'top', 'person') entry.setValues('sn', ENTRY_NAME) entry.setValues('cn', ENTRY_NAME) # # Start by attempting to add an entry with an invalid password # log.info('test_pwdAdmin_init: Attempt to add entries with invalid passwords, these adds should fail...') for passwd in INVALID_PWDS: failed_as_expected = False entry.setValues('userpassword', passwd) log.info('test_pwdAdmin_init: Create a regular user entry %s with password (%s)...' % (ENTRY_DN, passwd)) try: topology.standalone.add_s(entry) except ldap.LDAPError as e: # We failed as expected failed_as_expected = True log.info('test_pwdAdmin_init: Add failed as expected: password (%s) result (%s)' % (passwd, e.message['desc'])) if not failed_as_expected: log.fatal('test_pwdAdmin_init: We were incorrectly able to add an entry ' + 'with an invalid password (%s)' % (passwd)) assert False
def fixupMemberOf(self, suffix=None, benamebase=None, filt=None, args=None): ''' Trigger a fixup task on 'suffix' (or 'benamebase' that stores that suffix) related to the entries 'memberof' of groups. It uses an internal task to acheive this request. If 'suffix' and 'benamebase' are specified, it uses 'benamebase' first else 'suffix'. If both 'suffix' and 'benamebase' are missing it raise ValueError 'filt' is a filter that will select all the entries (under 'suffix') that we need to evaluate/fix. If missing, the default value is "(|(objectclass=inetuser)(objectclass=inetadmin))" @param suffix - suffix of the backend @param benamebase - 'commonname'/'cn' of the backend (e.g. 'userRoot') @param args - is a dictionary that contains modifier of the fixupMemberOf task wait: True/[False] - If True, waits for the completion of the task before to return @return exit code @raise ValueError: if benamebase and suffix are specified, or can not retrieve the suffix from the mapping tree entry ''' if not benamebase and not suffix: raise ValueError("Specify either bename or suffix") # If backend name was provided, retrieve the suffix if benamebase: ents = self.conn.mappingtree.list(bename=benamebase) if len(ents) != 1: raise ValueError("invalid backend name: %s" % benamebase) attr = MT_PROPNAME_TO_ATTRNAME[MT_SUFFIX] if not ents[0].hasAttr(attr): raise ValueError("invalid backend name: %s, or entry without %s" % (benamebase, attr)) suffix = ents[0].getValue(attr) cn = "fixupmemberof_" + time.strftime("%m%d%Y_%H%M%S", time.localtime()) dn = "cn=%s,%s" % (cn, DN_MBO_TASK) entry = Entry(dn) entry.setValues('objectclass', 'top', 'extensibleObject') entry.setValues('cn', cn) entry.setValues('basedn', suffix) if filt: entry.setValues('filter', filt) # start the task and possibly wait for task completion try: self.conn.add_s(entry) except ldap.ALREADY_EXISTS: self.log.error("Fail to add the memberOf fixup task") return -1 exitCode = 0 if args and args.get(TASK_WAIT, False): (done, exitCode) = self.conn.tasks.checkTask(entry, True) if exitCode: self.log.error("Error: fixupMemberOf task %s for basedn %s exited with %d" % (cn, suffix, exitCode)) else: self.log.info("fixupMemberOf task %s for basedn %s completed successfully" % (cn, suffix)) return exitCode
def makeDSUserEnt(idnum): id = str(idnum) userid = 'testuser' + id dn = 'uid=%s,%s,%s' % (userid, usersubtree, suffix) ent = Entry(dn) ent.setValues('objectclass', userObjClasses) ent.setValues('cn', 'Test User' + id) ent.setValues('sn', 'User' + id) ent.setValues('uid', userid) ent.setValues('userPassword', 'Password' + id) ent.setValues('ntUserDomainId', userid) ent.setValues('userPassword', 'Ornette1') if ipawinsync: ent.setValues('krbPrincipalName', '%s@%s' % (userid, realm)) ent.setValues('uidNumber', str(500 + idnum)) ent.setValues('gidNumber', '1002') ent.setValues('homeDirectory', '/home/' + userid) if idnum % 2: ent.setValues('description', 'User added disabled to DS') ent.setValues('nsAccountLock', 'TRUE') else: ent.setValues('description', 'User added enabled to DS') else: ent.setValues('description', 'User added to DS') ent.setValues('ntUserCreateNewAccount', 'TRUE') ent.setValues('ntUserDeleteAccount', 'TRUE') return ent
def test_selfdn_permission_add(topology_st, allow_user_init): """Check add entry operation with and without SelfDN aci :id: e837a9ef-be92-48da-ad8b-ebf42b0fede1 :setup: Standalone instance, add a entry which is used to bind, enable acl error logging by setting 'nsslapd-errorlog-level' to '128', remove aci's to start with a clean slate, and add dummy entries :steps: 1. Check we can not ADD an entry without the proper SELFDN aci 2. Check with the proper ACI we can not ADD with 'member' attribute 3. Check entry to add with memberS and with the ACI 4. Check with the proper ACI and 'member' it succeeds to ADD :expectedresults: 1. Operation should be successful 2. Operation should be successful 3. Operation should fail with Insufficient Access 4. Operation should be successful """ topology_st.standalone.log.info( "\n\n######################### ADD ######################\n") # bind as bind_entry topology_st.standalone.log.info("Bind as %s" % BIND_DN) topology_st.standalone.simple_bind_s(BIND_DN, BIND_PW) # Prepare the entry with multivalued members entry_with_members = Entry(ENTRY_DN) entry_with_members.setValues('objectclass', 'top', 'person', 'OCticket47653') entry_with_members.setValues('sn', ENTRY_NAME) entry_with_members.setValues('cn', ENTRY_NAME) entry_with_members.setValues('postalAddress', 'here') entry_with_members.setValues('postalCode', '1234') members = [] for cpt in range(MAX_OTHERS): name = "%s%d" % (OTHER_NAME, cpt) members.append("cn=%s,%s" % (name, SUFFIX)) members.append(BIND_DN) entry_with_members.setValues('member', members) # Prepare the entry with one member entry_with_member = Entry(ENTRY_DN) entry_with_member.setValues('objectclass', 'top', 'person', 'OCticket47653') entry_with_member.setValues('sn', ENTRY_NAME) entry_with_member.setValues('cn', ENTRY_NAME) entry_with_member.setValues('postalAddress', 'here') entry_with_member.setValues('postalCode', '1234') member = [] member.append(BIND_DN) entry_with_member.setValues('member', member) # entry to add WITH member being BIND_DN but WITHOUT the ACI -> ldap.INSUFFICIENT_ACCESS try: topology_st.standalone.log.info( "Try to add Add %s (aci is missing): %r" % (ENTRY_DN, entry_with_member)) topology_st.standalone.add_s(entry_with_member) except Exception as e: topology_st.standalone.log.info("Exception (expected): %s" % type(e).__name__) assert isinstance(e, ldap.INSUFFICIENT_ACCESS) # Ok Now add the proper ACI topology_st.standalone.log.info("Bind as %s and add the ADD SELFDN aci" % DN_DM) topology_st.standalone.simple_bind_s(DN_DM, PASSWORD) ACI_TARGET = "(target = \"ldap:///cn=*,%s\")" % SUFFIX ACI_TARGETFILTER = "(targetfilter =\"(objectClass=%s)\")" % OC_NAME ACI_ALLOW = "(version 3.0; acl \"SelfDN add\"; allow (add)" ACI_SUBJECT = " userattr = \"member#selfDN\";)" ACI_BODY = ACI_TARGET + ACI_TARGETFILTER + ACI_ALLOW + ACI_SUBJECT mod = [(ldap.MOD_ADD, 'aci', ensure_bytes(ACI_BODY))] topology_st.standalone.modify_s(SUFFIX, mod) # bind as bind_entry topology_st.standalone.log.info("Bind as %s" % BIND_DN) topology_st.standalone.simple_bind_s(BIND_DN, BIND_PW) # entry to add WITHOUT member and WITH the ACI -> ldap.INSUFFICIENT_ACCESS try: topology_st.standalone.log.info( "Try to add Add %s (member is missing)" % ENTRY_DN) topology_st.standalone.add_s( Entry((ENTRY_DN, { 'objectclass': ENTRY_OC.split(), 'sn': ENTRY_NAME, 'cn': ENTRY_NAME, 'postalAddress': 'here', 'postalCode': '1234' }))) except Exception as e: topology_st.standalone.log.info("Exception (expected): %s" % type(e).__name__) assert isinstance(e, ldap.INSUFFICIENT_ACCESS) # entry to add WITH memberS and WITH the ACI -> ldap.INSUFFICIENT_ACCESS # member should contain only one value try: topology_st.standalone.log.info( "Try to add Add %s (with several member values)" % ENTRY_DN) topology_st.standalone.add_s(entry_with_members) except Exception as e: topology_st.standalone.log.info("Exception (expected): %s" % type(e).__name__) assert isinstance(e, ldap.INSUFFICIENT_ACCESS) topology_st.standalone.log.info("Try to add Add %s should be successful" % ENTRY_DN) topology_st.standalone.add_s(entry_with_member)
def test_update_complex(self): # compare two entries created with different methods nsuffix, replid, replicatype = ("dc=example,dc=com", 5, lib389.REPLICA_RDWR_TYPE) binddnlist, legacy = ['uid=pippo, cn=config'], 'off' dn = "dc=example,dc=com" entry = Entry(dn) entry.setValues( 'objectclass', "top", "nsds5replica", "extensibleobject") entry.setValues('cn', "replica") entry.setValues('nsds5replicaroot', nsuffix) entry.setValues('nsds5replicaid', str(replid)) entry.setValues('nsds5replicatype', str(replicatype)) entry.setValues('nsds5flags', "1") entry.setValues('nsds5replicabinddn', binddnlist) entry.setValues('nsds5replicalegacyconsumer', legacy) uentry = Entry(( dn, {'objectclass': ["top", "nsds5replica", "extensibleobject"], 'cn': ["replica"]}) ) log.debug("Entry created with dict:", uentry) # Entry.update *replaces*, so be careful with multi-valued attrs uentry.update({ 'nsds5replicaroot': nsuffix, 'nsds5replicaid': str(replid), 'nsds5replicatype': str(replicatype), 'nsds5flags': '1', 'nsds5replicabinddn': binddnlist, 'nsds5replicalegacyconsumer': legacy }) uentry_s, entry_s = list(map(str, (uentry, entry))) assert uentry_s == entry_s, "Mismatching entries [%r] vs [%r]" % ( uentry, entry)
def exportLDIF(self, suffix=None, benamebase=None, output_file=None, args=None): ''' Export in a LDIF format a given 'suffix' (or 'benamebase' that stores that suffix). It uses an internal task to acheive this request. If 'suffix' and 'benamebase' are specified, it uses 'benamebase' first else 'suffix'. If both 'suffix' and 'benamebase' are missing it raises ValueError 'output_file' is the output file of the export @param suffix - suffix of the backend @param benamebase - 'commonname'/'cn' of the backend (e.g. 'userRoot') @param output_file - file that will contain the exported suffix in LDIF format @param args - is a dictionary that contains modifier of the export task wait: True/[False] - If True, 'export' waits for the completion of the task before to return repl-info: True/[False] - If True, it adds the replication meta data (state information, tombstones and RUV) in the exported file @return None @raise ValueError ''' # Checking the parameters if not benamebase and not suffix: raise ValueError("Specify either bename or suffix") if not output_file: raise ValueError("output_file is mandatory") # Prepare the task entry cn = "export_" + time.strftime("%m%d%Y_%H%M%S", time.localtime()) dn = "cn=%s,%s" % (cn, DN_EXPORT_TASK) entry = Entry(dn) entry.update({ 'objectclass': ['top', 'extensibleObject'], 'cn': cn, 'nsFilename': output_file }) if benamebase: entry.setValues('nsInstance', benamebase) else: entry.setValues('nsIncludeSuffix', suffix) if args.get(EXPORT_REPL_INFO, False): entry.setValues('nsExportReplica', 'true') # start the task and possibly wait for task completion self.conn.add_s(entry) exitCode = 0 if args and args.get(TASK_WAIT, False): (done, exitCode) = self.conn.tasks.checkTask(entry, True) if exitCode: self.log.error("Error: export task %s for file %s exited with %d" % (cn, output_file, exitCode)) else: self.log.info("Export task %s for file %s completed successfully" % (cn, output_file)) return exitCode
def fixupMemberOf(self, suffix=None, benamebase=None, filt=None, args=None): ''' Trigger a fixup task on 'suffix' (or 'benamebase' that stores that suffix) related to the entries 'memberof' of groups. It uses an internal task to acheive this request. If 'suffix' and 'benamebase' are specified, it uses 'benamebase' first else 'suffix'. If both 'suffix' and 'benamebase' are missing it raise ValueError 'filt' is a filter that will select all the entries (under 'suffix') that we need to evaluate/fix. If missing, the default value is "(|(objectclass=inetuser)(objectclass=inetadmin))" @param suffix - suffix of the backend @param benamebase - 'commonname'/'cn' of the backend (e.g. 'userRoot') @param args - is a dictionary that contains modifier of the fixupMemberOf task wait: True/[False] - If True, waits for the completion of the task before to return @return exit code @raise ValueError: if benamebase and suffix are specified, or can not retrieve the suffix from the mapping tree entry ''' if not benamebase and not suffix: raise ValueError("Specify either bename or suffix") # If backend name was provided, retrieve the suffix if benamebase: ents = self.conn.mappingtree.list(bename=benamebase) if len(ents) != 1: raise ValueError("invalid backend name: %s" % benamebase) attr = MT_PROPNAME_TO_ATTRNAME[MT_SUFFIX] if not ents[0].hasAttr(attr): raise ValueError( "invalid backend name: %s, or entry without %s" % (benamebase, attr)) suffix = ents[0].getValue(attr) cn = "fixupmemberof_" + time.strftime("%m%d%Y_%H%M%S", time.localtime()) dn = "cn=%s,%s" % (cn, DN_MBO_TASK) entry = Entry(dn) entry.setValues('objectclass', 'top', 'extensibleObject') entry.setValues('cn', cn) entry.setValues('basedn', suffix) if filt: entry.setValues('filter', filt) # start the task and possibly wait for task completion try: self.conn.add_s(entry) except ldap.ALREADY_EXISTS: self.log.error("Fail to add the memberOf fixup task") return -1 exitCode = 0 if args and args.get(TASK_WAIT, False): (done, exitCode) = self.conn.tasks.checkTask(entry, True) if exitCode: self.log.error( "Error: fixupMemberOf task %s for basedn %s exited with %d" % (cn, suffix, exitCode)) else: self.log.info( "fixupMemberOf task %s for basedn %s completed successfully" % (cn, suffix)) return exitCode