def test_crossRef_object(self): """Test if the urgent replication is activated when handling a crossRef object.""" self.ldb.add({ "dn": "CN=test crossRef,CN=Partitions,CN=Configuration,"+ self.base_dn, "objectClass": "crossRef", "cn": "test crossRef", "dnsRoot": self.get_loadparm().get("realm").lower(), "instanceType": "4", "nCName": self.base_dn, "showInAdvancedViewOnly": "TRUE", "name": "test crossRef", "systemFlags": "1"}, ["relax:0"]) # urgent replication should be enabled when creating res = self.ldb.load_partition_usn("cn=Configuration," + self.base_dn) self.assertEquals(res["uSNHighest"], res["uSNUrgent"]) # urgent replication should NOT be enabled when modifying m = Message() m.dn = Dn(self.ldb, "cn=test crossRef,CN=Partitions,CN=Configuration," + self.base_dn) m["systemFlags"] = MessageElement("0", FLAG_MOD_REPLACE, "systemFlags") self.ldb.modify(m) res = self.ldb.load_partition_usn("cn=Configuration," + self.base_dn) self.assertNotEquals(res["uSNHighest"], res["uSNUrgent"]) # urgent replication should be enabled when deleting self.delete_force(self.ldb, "cn=test crossRef,CN=Partitions,CN=Configuration," + self.base_dn) res = self.ldb.load_partition_usn("cn=Configuration," + self.base_dn) self.assertEquals(res["uSNHighest"], res["uSNUrgent"])
def test_u1_member_of_g4(self): i = 0 import time print "KEYS: total add modify delete" while True: group = i % self.n_groups + 1 start = time.time() self.ldb.add({ "dn": "cn=u%d,%s" % (group, self.ou_users), "objectclass": "user"}) end_add = time.time() start_mod = time.time() m = Message() m.dn = Dn(self.ldb, "CN=g%d,%s" % (group, self.ou_groups)) m["member"] = MessageElement("cn=u%d,%s" % (group, self.ou_users), FLAG_MOD_ADD, "member") self.ldb.modify(m) end_mod = time.time() delete_force(self.ldb, "cn=u%d,%s" % (group, self.ou_users)) end = time.time() print end - start, end_add - start, end_mod - start_mod, end - end_mod i += 1
def test_rIDManager_object(self): """Test if the urgent replication is activated when handling a rIDManager object.""" self.ldb.add_ldif( """dn: CN=RID Manager test,CN=System,%s""" % self.base_dn + """ objectClass: rIDManager cn: RID Manager test instanceType: 4 showInAdvancedViewOnly: TRUE name: RID Manager test systemFlags: -1946157056 isCriticalSystemObject: TRUE rIDAvailablePool: 133001-1073741823""", ["relax:0"]) # urgent replication should be enabled when creating res = self.ldb.load_partition_usn(self.base_dn) self.assertEquals(res["uSNHighest"], res["uSNUrgent"]) # urgent replication should be enabled when modifying m = Message() m.dn = Dn(self.ldb, "CN=RID Manager test,CN=System," + self.base_dn) m["systemFlags"] = MessageElement("0", FLAG_MOD_REPLACE, "systemFlags") self.ldb.modify(m) res = self.ldb.load_partition_usn(self.base_dn) self.assertEquals(res["uSNHighest"], res["uSNUrgent"]) # urgent replication should NOT be enabled when deleting self.delete_force(self.ldb, "CN=RID Manager test,CN=System," + self.base_dn) res = self.ldb.load_partition_usn(self.base_dn) self.assertNotEquals(res["uSNHighest"], res["uSNUrgent"])
def test_attributeSchema_object(self): """Test if the urgent replication is activated when handling an attributeSchema object""" self.ldb.add_ldif( """dn: CN=test attributeSchema,cn=Schema,CN=Configuration,%s""" % self.base_dn + """ objectClass: attributeSchema cn: test attributeSchema instanceType: 4 isSingleValued: FALSE showInAdvancedViewOnly: FALSE attributeID: 1.3.6.1.4.1.7165.4.6.1.4.""" + str(random.randint(1,100000)) + """ attributeSyntax: 2.5.5.12 adminDisplayName: test attributeSchema adminDescription: test attributeSchema oMSyntax: 64 systemOnly: FALSE searchFlags: 8 lDAPDisplayName: testAttributeSchema name: test attributeSchema""") # urgent replication should be enabled when creating res = self.ldb.load_partition_usn("cn=Schema,cn=Configuration," + self.base_dn) self.assertEquals(res["uSNHighest"], res["uSNUrgent"]) # urgent replication should be enabled when modifying m = Message() m.dn = Dn(self.ldb, "CN=test attributeSchema,CN=Schema,CN=Configuration," + self.base_dn) m["lDAPDisplayName"] = MessageElement("updatedTestAttributeSchema", FLAG_MOD_REPLACE, "lDAPDisplayName") self.ldb.modify(m) res = self.ldb.load_partition_usn("cn=Schema,cn=Configuration," + self.base_dn) self.assertEquals(res["uSNHighest"], res["uSNUrgent"])
def test_secret_object(self): """Test if the urgent replication is activated when handling a secret object.""" self.ldb.add({ "dn": "cn=test secret,cn=System," + self.base_dn, "objectClass":"secret", "cn":"test secret", "name":"test secret", "currentValue":"xxxxxxx"}) # urgent replication should be enabled when creating res = self.ldb.load_partition_usn(self.base_dn) self.assertEquals(res["uSNHighest"], res["uSNUrgent"]) # urgent replication should be enabled when modifying m = Message() m.dn = Dn(self.ldb, "cn=test secret,cn=System," + self.base_dn) m["currentValue"] = MessageElement("yyyyyyyy", FLAG_MOD_REPLACE, "currentValue") self.ldb.modify(m) res = self.ldb.load_partition_usn(self.base_dn) self.assertEquals(res["uSNHighest"], res["uSNUrgent"]) # urgent replication should NOT be enabled when deleting self.delete_force(self.ldb, "cn=test secret,cn=System," + self.base_dn) res = self.ldb.load_partition_usn(self.base_dn) self.assertNotEquals(res["uSNHighest"], res["uSNUrgent"])
def _unlink_user_and_group(self, u, g): user = "******" % (u, self.ou_users) group = "CN=g%d,%s" % (g, self.ou_groups) m = Message() m.dn = Dn(self.ldb, group) m["member"] = MessageElement(user, FLAG_MOD_DELETE, "member") self.ldb.modify(m)
def _test_link_many_users_batch(self, n=(LINK_BATCH_SIZE * 10)): # this links unevenly, putting more users in the first group # and fewer in the last. ng = self.state.n_groups nu = self.state.next_user_id messages = [] for g in range(ng): m = Message() m.dn = Dn(self.ldb, "CN=g%d,%s" % (g, self.ou_groups)) messages.append(m) while n: u = random.randrange(nu) g = random.randrange(random.randrange(ng) + 1) link = (u, g) if link in self.state.active_links: continue m = messages[g] m["member%s" % u] = MessageElement("cn=u%d,%s" % (u, self.ou_users), FLAG_MOD_ADD, "member") self.state.active_links.add(link) n -= 1 for m in messages: try: self.ldb.modify(m) except LdbError as e: print(e) print(m)
def test_nonurgent_object(self): """Test if the urgent replication is not activated when handling a non urgent object.""" self.ldb.add({ "dn": "cn=nonurgenttest,cn=users," + self.base_dn, "objectclass":"user", "samaccountname":"nonurgenttest", "description":"nonurgenttest description"}) # urgent replication should not be enabled when creating res = self.ldb.load_partition_usn(self.base_dn) self.assertNotEquals(res["uSNHighest"], res["uSNUrgent"]) # urgent replication should not be enabled when modifying m = Message() m.dn = Dn(self.ldb, "cn=nonurgenttest,cn=users," + self.base_dn) m["description"] = MessageElement("new description", FLAG_MOD_REPLACE, "description") self.ldb.modify(m) res = self.ldb.load_partition_usn(self.base_dn) self.assertNotEquals(res["uSNHighest"], res["uSNUrgent"]) # urgent replication should not be enabled when deleting self.delete_force(self.ldb, "cn=nonurgenttest,cn=users," + self.base_dn) res = self.ldb.load_partition_usn(self.base_dn) self.assertNotEquals(res["uSNHighest"], res["uSNUrgent"])
def test_unicodePwd_clear_set(self): """Performs a password cleartext set operation on 'unicodePwd'""" m = Message() m.dn = Dn(self.ldb, "cn=testuser,cn=users," + self.base_dn) m["unicodePwd"] = MessageElement("\"thatsAcomplPASS2\"".encode('utf-16-le'), FLAG_MOD_REPLACE, "unicodePwd") self.ldb.modify(m)
def enable_recycle_bin(self): msg = Message() msg.dn = Dn(self.samdb, "") msg["enableOptionalFeature"] = MessageElement( "CN=Partitions," + self.configuration_dn + ":766ddcd8-acd0-445e-f3b9-a7f9b6744f2a", FLAG_MOD_ADD, "enableOptionalFeature") try: self.samdb.modify(msg) except LdbError, (num, _): self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
def test_userPassword_clear_set(self): """Performs a password cleartext set operation on 'userPassword'""" # Notice: This works only against Windows if "dSHeuristics" has been set # properly m = Message() m.dn = Dn(self.ldb, "cn=testuser,cn=users," + self.base_dn) m["userPassword"] = MessageElement("thatsAcomplPASS2", FLAG_MOD_REPLACE, "userPassword") self.ldb.modify(m)
def enable_recycle_bin(self): msg = Message() msg.dn = Dn(self.samdb, "") msg["enableOptionalFeature"] = MessageElement( "CN=Partitions," + self.configuration_dn + ":766ddcd8-acd0-445e-f3b9-a7f9b6744f2a", FLAG_MOD_ADD, "enableOptionalFeature") try: self.samdb.modify(msg) except LdbError as e: (num, _) = e.args self.assertEqual(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
def set_attr_search_flags(self, attr_dn, flags): """Modifies the searchFlags for an object in the schema""" m = Message() m.dn = Dn(self.ldb_admin, attr_dn) m['searchFlags'] = MessageElement(flags, FLAG_MOD_REPLACE, 'searchFlags') self.ldb_admin.modify(m) # note we have to update the schema for this change to take effect (on # Windows, at least) self.ldb_admin.set_schema_update_now()
def test_nTDSDSA_object(self): '''Test if the urgent replication is activated when handling a nTDSDSA object''' self.ldb.add( { "dn": "cn=test server,cn=Servers,cn=Default-First-Site-Name,cn=Sites,%s" % self.ldb.get_config_basedn(), "objectclass": "server", "cn": "test server", "name": "test server", "systemFlags": "50000000" }, ["relax:0"]) self.ldb.add_ldif( """dn: cn=NTDS Settings test,cn=test server,cn=Servers,cn=Default-First-Site-Name,cn=Sites,cn=Configuration,%s""" % (self.base_dn) + """ objectclass: nTDSDSA cn: NTDS Settings test options: 1 instanceType: 4 systemFlags: 33554432""", ["relax:0"]) # urgent replication should be enabled when creation res = self.ldb.load_partition_usn("cn=Configuration," + self.base_dn) self.assertEquals(res["uSNHighest"], res["uSNUrgent"]) # urgent replication should NOT be enabled when modifying m = Message() m.dn = Dn( ldb, "cn=NTDS Settings test,cn=test server,cn=Servers,cn=Default-First-Site-Name,cn=Sites,cn=Configuration," + self.base_dn) m["options"] = MessageElement("0", FLAG_MOD_REPLACE, "options") ldb.modify(m) res = self.ldb.load_partition_usn("cn=Configuration," + self.base_dn) self.assertNotEquals(res["uSNHighest"], res["uSNUrgent"]) # urgent replication should be enabled when deleting self.delete_force( self.ldb, "cn=NTDS Settings test,cn=test server,cn=Servers,cn=Default-First-Site-Name,cn=Sites,cn=Configuration," + self.base_dn) res = self.ldb.load_partition_usn("cn=Configuration," + self.base_dn) self.assertEquals(res["uSNHighest"], res["uSNUrgent"]) self.delete_force( self.ldb, "cn=test server,cn=Servers,cn=Default-First-Site-Name,cn=Sites,cn=Configuration," + self.base_dn)
def _link_user_and_group(self, u, g): link = (u, g) if link in self.state.active_links: return False m = Message() m.dn = Dn(self.ldb, "CN=g%d,%s" % (g, self.ou_groups)) m["member"] = MessageElement("cn=u%d,%s" % (u, self.ou_users), FLAG_MOD_ADD, "member") self.ldb.modify(m) self.state.active_links.add(link) return True
def update_lockout_settings(self, threshold, duration, observation_window): """Updates the global user lockout settings""" m = Message() m.dn = Dn(self.ldb, self.base_dn) account_lockout_duration_ticks = -int(duration * (1e7)) m["lockoutDuration"] = MessageElement(str(account_lockout_duration_ticks), FLAG_MOD_REPLACE, "lockoutDuration") m["lockoutThreshold"] = MessageElement(str(threshold), FLAG_MOD_REPLACE, "lockoutThreshold") lockout_observation_window_ticks = -int(observation_window * (1e7)) m["lockOutObservationWindow"] = MessageElement(str(lockout_observation_window_ticks), FLAG_MOD_REPLACE, "lockOutObservationWindow") self.ldb.modify(m)
def _unlink_user_and_group(self, u, g): link = (u, g) if link not in self.state.active_links: return False user = "******" % (u, self.ou_users) group = "CN=g%d,%s" % (g, self.ou_groups) m = Message() m.dn = Dn(self.ldb, group) m["member"] = MessageElement(user, FLAG_MOD_DELETE, "member") self.ldb.modify(m) self.state.active_links.remove(link) return True
def test_dBCSPwd_hash_set(self): """Performs a password hash set operation on 'dBCSPwd' which should be prevented""" # Notice: Direct hash password sets should never work m = Message() m.dn = Dn(self.ldb, "cn=testuser,cn=users," + self.base_dn) m["dBCSPwd"] = MessageElement("XXXXXXXXXXXXXXXX", FLAG_MOD_REPLACE, "dBCSPwd") try: self.ldb.modify(m) self.fail() except LdbError as e6: (num, _) = e6.args self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
def assertAttributesEqual(self, obj_orig, attrs_orig, obj_restored, attrs_rest): self.assertNamesEqual(attrs_orig, attrs_rest) # remove volatile attributes, they can't be equal attrs_orig -= set( ["uSNChanged", "dSCorePropagationData", "whenChanged"]) for attr in attrs_orig: # convert original attr value to ldif orig_val = obj_orig.get(attr) if orig_val is None: continue if not isinstance(orig_val, MessageElement): orig_val = MessageElement(str(orig_val), 0, attr) m = Message() m.add(orig_val) orig_ldif = self.samdb.write_ldif(m, 0) # convert restored attr value to ldif rest_val = obj_restored.get(attr) self.assertFalse(rest_val is None) m = Message() if not isinstance(rest_val, MessageElement): rest_val = MessageElement(str(rest_val), 0, attr) m.add(rest_val) rest_ldif = self.samdb.write_ldif(m, 0) # compare generated ldif's self.assertEqual(orig_ldif, rest_ldif)
def modify_sd_on_dn(self, object_dn, sd, controls=None): """Modify security descriptor using either SDDL string or security.descriptor object """ m = Message() m.dn = Dn(self.ldb, object_dn) assert isinstance(sd, str) or isinstance(sd, security.descriptor) if isinstance(sd, str): tmp_desc = security.descriptor.from_sddl(sd, self.domain_sid) elif isinstance(sd, security.descriptor): tmp_desc = sd m["nTSecurityDescriptor"] = MessageElement(ndr_pack(tmp_desc), FLAG_MOD_REPLACE, "nTSecurityDescriptor") self.ldb.modify(m, controls)
def assertAttributesEqual(self, obj_orig, attrs_orig, obj_restored, attrs_rest): self.assertEqual( attrs_orig, attrs_rest, "Actual object does not have expected attributes, missing from expected (%s), extra (%s)" % (str(attrs_orig.difference(attrs_rest)), str(attrs_rest.difference(attrs_orig)))) # remove volatile attributes, they can't be equal attrs_orig -= set( ["uSNChanged", "dSCorePropagationData", "whenChanged"]) for attr in attrs_orig: # convert original attr value to ldif orig_val = obj_orig.get(attr) if orig_val is None: continue if not isinstance(orig_val, MessageElement): orig_val = MessageElement(str(orig_val), 0, attr) m = Message() m.add(orig_val) orig_ldif = self.samdb.write_ldif(m, 0) # convert restored attr value to ldif rest_val = obj_restored.get(attr) self.assertFalse(rest_val is None) m = Message() if not isinstance(rest_val, MessageElement): rest_val = MessageElement(str(rest_val), 0, attr) m.add(rest_val) rest_ldif = self.samdb.write_ldif(m, 0) # compare generated ldif's self.assertEqual(orig_ldif.lower(), rest_ldif.lower())
def test_classSchema_object(self): """Test if the urgent replication is activated when handling a classSchema object.""" try: self.ldb.add_ldif( """dn: CN=test classSchema,CN=Schema,CN=Configuration,%s""" % self.base_dn + """ objectClass: classSchema cn: test classSchema instanceType: 4 subClassOf: top governsId: 1.3.6.1.4.1.7165.4.6.2.4.""" + str(random.randint(1, 100000)) + """ rDNAttID: cn showInAdvancedViewOnly: TRUE adminDisplayName: test classSchema adminDescription: test classSchema objectClassCategory: 1 lDAPDisplayName: testClassSchema name: test classSchema systemOnly: FALSE systemPossSuperiors: dfsConfiguration systemMustContain: msDFS-SchemaMajorVersion defaultSecurityDescriptor: D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;DA)(A;;RPWPCRCCD CLCLORCWOWDSDDTSW;;;SY)(A;;RPLCLORC;;;AU)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;CO) systemFlags: 16 defaultHidingValue: TRUE""") # urgent replication should be enabled when creating res = self.ldb.load_partition_usn("cn=Schema,cn=Configuration," + self.base_dn) self.assertEqual(res["uSNHighest"], res["uSNUrgent"]) except LdbError: print( "Not testing urgent replication when creating classSchema object ...\n" ) # urgent replication should be enabled when modifying m = Message() m.dn = Dn( self.ldb, "CN=test classSchema,CN=Schema,CN=Configuration," + self.base_dn) m["lDAPDisplayName"] = MessageElement("updatedTestClassSchema", FLAG_MOD_REPLACE, "lDAPDisplayName") self.ldb.modify(m) res = self.ldb.load_partition_usn("cn=Schema,cn=Configuration," + self.base_dn) self.assertEqual(res["uSNHighest"], res["uSNUrgent"])
def test_urgent_attributes(self): '''Test if the urgent replication is activated when handling urgent attributes of an object''' self.ldb.add({ "dn": "cn=user UrgAttr test,cn=users," + self.base_dn, "objectclass":"user", "samaccountname":"user UrgAttr test", "userAccountControl":str(dsdb.UF_NORMAL_ACCOUNT), "lockoutTime":"0", "pwdLastSet":"0", "description":"urgent attributes test description"}) # urgent replication should NOT be enabled when creating res = self.ldb.load_partition_usn(self.base_dn) self.assertNotEquals(res["uSNHighest"], res["uSNUrgent"]) # urgent replication should be enabled when modifying userAccountControl m = Message() m.dn = Dn(ldb, "cn=user UrgAttr test,cn=users," + self.base_dn) m["userAccountControl"] = MessageElement(str(dsdb.UF_NORMAL_ACCOUNT+dsdb.UF_SMARTCARD_REQUIRED), FLAG_MOD_REPLACE, "userAccountControl") ldb.modify(m) res = self.ldb.load_partition_usn(self.base_dn) self.assertEquals(res["uSNHighest"], res["uSNUrgent"]) # urgent replication should be enabled when modifying lockoutTime m = Message() m.dn = Dn(ldb, "cn=user UrgAttr test,cn=users," + self.base_dn) m["lockoutTime"] = MessageElement("1", FLAG_MOD_REPLACE, "lockoutTime") ldb.modify(m) res = self.ldb.load_partition_usn(self.base_dn) self.assertEquals(res["uSNHighest"], res["uSNUrgent"]) # urgent replication should be enabled when modifying pwdLastSet m = Message() m.dn = Dn(ldb, "cn=user UrgAttr test,cn=users," + self.base_dn) m["pwdLastSet"] = MessageElement("1", FLAG_MOD_REPLACE, "pwdLastSet") ldb.modify(m) res = self.ldb.load_partition_usn(self.base_dn) self.assertEquals(res["uSNHighest"], res["uSNUrgent"]) # urgent replication should NOT be enabled when modifying a not-urgent # attribute m = Message() m.dn = Dn(ldb, "cn=user UrgAttr test,cn=users," + self.base_dn) m["description"] = MessageElement("updated urgent attributes test description", FLAG_MOD_REPLACE, "description") ldb.modify(m) res = self.ldb.load_partition_usn(self.base_dn) self.assertNotEquals(res["uSNHighest"], res["uSNUrgent"]) # urgent replication should NOT be enabled when deleting self.delete_force(self.ldb, "cn=user UrgAttr test,cn=users," + self.base_dn) res = self.ldb.load_partition_usn(self.base_dn) self.assertNotEquals(res["uSNHighest"], res["uSNUrgent"])
def restore_deleted_object(samdb, del_dn, new_dn, new_attrs=None): """Restores a deleted object :param samdb: SamDB connection to SAM :param del_dn: str Deleted object DN :param new_dn: str Where to restore the object :param new_attrs: dict Additional attributes to set """ msg = Message() msg.dn = Dn(samdb, str(del_dn)) msg["isDeleted"] = MessageElement([], FLAG_MOD_DELETE, "isDeleted") msg["distinguishedName"] = MessageElement([str(new_dn)], FLAG_MOD_REPLACE, "distinguishedName") if new_attrs is not None: assert isinstance(new_attrs, dict) for attr in new_attrs: msg[attr] = MessageElement(new_attrs[attr], FLAG_MOD_REPLACE, attr) samdb.modify(msg, ["show_deleted:1"])
def modify_sd_on_dn(self, object_dn, sd, controls=None): """Modify security descriptor using either SDDL string or security.descriptor object """ m = Message() m.dn = Dn(self.ldb, object_dn) assert (isinstance(sd, str) or isinstance(sd, security.descriptor)) if isinstance(sd, str): tmp_desc = security.descriptor.from_sddl(sd, self.domain_sid) elif isinstance(sd, security.descriptor): tmp_desc = sd m["nTSecurityDescriptor"] = MessageElement(ndr_pack(tmp_desc), FLAG_MOD_REPLACE, "nTSecurityDescriptor") self.ldb.modify(m, controls)
def test_clearTextPassword_clear_set(self): """Performs a password cleartext set operation on 'clearTextPassword'""" # Notice: This never works against Windows - only supported by us try: m = Message() m.dn = Dn(self.ldb, "cn=testuser,cn=users," + self.base_dn) m["clearTextPassword"] = MessageElement("thatsAcomplPASS2".encode('utf-16-le'), FLAG_MOD_REPLACE, "clearTextPassword") self.ldb.modify(m) # this passes against s4 except LdbError as e10: (num, msg) = e10.args # "NO_SUCH_ATTRIBUTE" is returned by Windows -> ignore it if num != ERR_NO_SUCH_ATTRIBUTE: raise LdbError(num, msg)
def test_all(self): """Basic plan is to create bunch of classSchema and attributeSchema objects, replicate Schema NC and then check all objects are replicated correctly""" # add new classSchema object (c_ldn, c_dn) = self._schema_new_class(self.ldb_dc1, "cls-A", 9) # add new attributeSchema object (a_ldn, a_dn) = self._schema_new_attr(self.ldb_dc1, "attr-A", 3) # add attribute to the class we have m = Message.from_dict(self.ldb_dc1, { "dn": c_dn, "mayContain": a_ldn }, FLAG_MOD_ADD) self.ldb_dc1.modify(m) # force replication from DC1 to DC2 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, nc_dn=self.schema_dn) # check objects are replicated self._check_object(c_dn) self._check_object(a_dn)
def test_classInheritance(self): """Test inheritance through subClassOf I think 5 levels of inheritance is pretty decent for now.""" # add 5 levels deep hierarchy c_dn_list = [] c_ldn_last = None for i in range(1, 6): base_name = "cls-I-%02d" % i (c_ldn, c_dn) = self._schema_new_class(self.ldb_dc1, base_name, i) c_dn_list.append(c_dn) if c_ldn_last: # inherit from last class added m = Message.from_dict(self.ldb_dc1, { "dn": c_dn, "subClassOf": c_ldn_last }, FLAG_MOD_REPLACE) self.ldb_dc1.modify(m) # store last class ldapDisplayName c_ldn_last = c_ldn # force replication from DC1 to DC2 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, nc_dn=self.schema_dn) # check objects are replicated for c_dn in c_dn_list: self._check_object(c_dn)
def update_lockout_settings(self, threshold, duration, observation_window): """Updates the global user lockout settings""" m = Message() m.dn = Dn(self.ldb, self.base_dn) account_lockout_duration_ticks = -int(duration * (1e7)) m["lockoutDuration"] = MessageElement( str(account_lockout_duration_ticks), FLAG_MOD_REPLACE, "lockoutDuration") m["lockoutThreshold"] = MessageElement(str(threshold), FLAG_MOD_REPLACE, "lockoutThreshold") lockout_observation_window_ticks = -int(observation_window * (1e7)) m["lockOutObservationWindow"] = MessageElement( str(lockout_observation_window_ticks), FLAG_MOD_REPLACE, "lockOutObservationWindow") self.ldb.modify(m)
def test_modify_order_member(self): name = "modify_order_member_other_group" dn2 = "cn=%s,%s" % (name, self.base_dn) m = Message() m.dn = Dn(self.admin_dsdb, dn2) self.admin_dsdb.add({"dn": dn2, "objectclass": "group"}) self.addCleanup(self.delete_object, dn2) start_attrs = [("objectclass", "group"), ("member", dn2)] mod_attrs = [ ("member", None, FLAG_MOD_DELETE), ("member", None, FLAG_MOD_REPLACE), ("member", dn2, FLAG_MOD_DELETE), ("member", None, FLAG_MOD_ADD), ] self._test_modify_order(start_attrs, mod_attrs, ["memberOf"])
def test_msDS_IntId_on_class(self): """Testing msDs-IntId creation for Class Reference: MS-ADTS - 3.1.1.2.4.8 Class classSchema""" # 1. Create Class without systemFlags # msDS-IntId should be created if forest functional # level is >= DS_DOMAIN_FUNCTION_2003 # and missing otherwise (class_name, class_ldap_name, class_dn) = self._make_obj_names("msDS-IntId-Class-1-") ldif = self._make_class_ldif(class_dn, class_name) # try to add msDS-IntId during Class creation ldif_add = ldif + "msDS-IntId: -1993108831\n" self.ldb.add_ldif(ldif_add) self._ldap_schemaUpdateNow() res = self.ldb.search(class_dn, scope=SCOPE_BASE, attrs=["*"]) self.assertEquals(len(res), 1) self.assertEquals(res[0]["msDS-IntId"][0], "-1993108831") # add a new Class and update schema (class_name, class_ldap_name, class_dn) = self._make_obj_names("msDS-IntId-Class-2-") ldif = self._make_class_ldif(class_dn, class_name) self.ldb.add_ldif(ldif) self._ldap_schemaUpdateNow() # Search for created Class res = self.ldb.search(class_dn, scope=SCOPE_BASE, attrs=["*"]) self.assertEquals(len(res), 1) self.assertFalse("msDS-IntId" in res[0]) msg = Message() msg.dn = Dn(self.ldb, class_dn) msg["msDS-IntId"] = MessageElement("-1993108831", FLAG_MOD_REPLACE, "msDS-IntId") try: self.ldb.modify(msg) self.fail("Modifying msDS-IntId should return error") except LdbError, (num, _): self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
def test_attributeSchema_object(self): '''Test if the urgent replication is activated when handling an attributeSchema object''' try: self.ldb.add_ldif( """dn: CN=test attributeSchema,cn=Schema,CN=Configuration,%s""" % self.base_dn + """ objectClass: attributeSchema cn: test attributeSchema instanceType: 4 isSingleValued: FALSE showInAdvancedViewOnly: FALSE attributeID: 0.9.2342.19200300.100.1.1 attributeSyntax: 2.5.5.12 adminDisplayName: test attributeSchema adminDescription: test attributeSchema oMSyntax: 64 systemOnly: FALSE searchFlags: 8 lDAPDisplayName: test attributeSchema name: test attributeSchema""") # urgent replication should be enabled when creating res = self.ldb.load_partition_usn("cn=Schema,cn=Configuration," + self.base_dn) self.assertEquals(res["uSNHighest"], res["uSNUrgent"]) except LdbError: print "Not testing urgent replication when creating attributeSchema object ...\n" # urgent replication should be enabled when modifying m = Message() m.dn = Dn( ldb, "CN=test attributeSchema,CN=Schema,CN=Configuration," + self.base_dn) m["lDAPDisplayName"] = MessageElement("updated test attributeSchema", FLAG_MOD_REPLACE, "lDAPDisplayName") ldb.modify(m) res = self.ldb.load_partition_usn("cn=Schema,cn=Configuration," + self.base_dn) self.assertEquals(res["uSNHighest"], res["uSNUrgent"])
def test_classSchema_object(self): '''Test if the urgent replication is activated when handling a classSchema object''' try: self.ldb.add_ldif( """dn: CN=test classSchema,CN=Schema,CN=Configuration,%s""" % self.base_dn + """ objectClass: classSchema cn: test classSchema instanceType: 4 subClassOf: top governsID: 1.2.840.113556.1.5.999 rDNAttID: cn showInAdvancedViewOnly: TRUE adminDisplayName: test classSchema adminDescription: test classSchema objectClassCategory: 1 lDAPDisplayName: test classSchema name: test classSchema systemOnly: FALSE systemPossSuperiors: dfsConfiguration systemMustContain: msDFS-SchemaMajorVersion defaultSecurityDescriptor: D:(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;DA)(A;;RPWPCRCCD CLCLORCWOWDSDDTSW;;;SY)(A;;RPLCLORC;;;AU)(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;CO) systemFlags: 16 defaultHidingValue: TRUE""") # urgent replication should be enabled when creating res = self.ldb.load_partition_usn("cn=Schema,cn=Configuration," + self.base_dn) self.assertEquals(res["uSNHighest"], res["uSNUrgent"]) except LdbError: print "Not testing urgent replication when creating classSchema object ...\n" # urgent replication should be enabled when modifying m = Message() m.dn = Dn(ldb, "CN=test classSchema,CN=Schema,CN=Configuration," + self.base_dn) m["lDAPDisplayName"] = MessageElement("updated test classSchema", FLAG_MOD_REPLACE, "lDAPDisplayName") ldb.modify(m) res = self.ldb.load_partition_usn("cn=Schema,cn=Configuration," + self.base_dn) self.assertEquals(res["uSNHighest"], res["uSNUrgent"])
def test_msDS_IntId_on_class(self): """Testing msDs-IntId creation for Class Reference: MS-ADTS - 3.1.1.2.4.8 Class classSchema""" # 1. Create Class without systemFlags # msDS-IntId should be created if forest functional # level is >= DS_DOMAIN_FUNCTION_2003 # and missing otherwise (class_name, class_ldap_name, class_dn) = self._make_obj_names("msDS-IntId-Class-1-") ldif = self._make_class_ldif(class_dn, class_name) # try to add msDS-IntId during Class creation ldif_add = ldif + "msDS-IntId: -1993108831\n" self.ldb.add_ldif(ldif_add) self._ldap_schemaUpdateNow() res = self.ldb.search(class_dn, scope=SCOPE_BASE, attrs=["msDS-IntId"]) self.assertEquals(len(res), 1) self.assertEquals(res[0]["msDS-IntId"][0], "-1993108831") # add a new Class and update schema (class_name, class_ldap_name, class_dn) = self._make_obj_names("msDS-IntId-Class-2-") ldif = self._make_class_ldif(class_dn, class_name) self.ldb.add_ldif(ldif) self._ldap_schemaUpdateNow() # Search for created Class res = self.ldb.search(class_dn, scope=SCOPE_BASE, attrs=["msDS-IntId"]) self.assertEquals(len(res), 1) self.assertFalse("msDS-IntId" in res[0]) msg = Message() msg.dn = Dn(self.ldb, class_dn) msg["msDS-IntId"] = MessageElement("-1993108831", FLAG_MOD_REPLACE, "msDS-IntId") try: self.ldb.modify(msg) self.fail("Modifying msDS-IntId should return error") except LdbError, (num, _): self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
def assertAttributesEqual(self, obj_orig, attrs_orig, obj_restored, attrs_rest): self.assertEqual(attrs_orig, attrs_rest, "Actual object does not have expected attributes, missing from expected ({0!s}), extra ({1!s})".format(str(attrs_orig.difference(attrs_rest)), str(attrs_rest.difference(attrs_orig)))) # remove volatile attributes, they can't be equal attrs_orig -= set(["uSNChanged", "dSCorePropagationData", "whenChanged"]) for attr in attrs_orig: # convert original attr value to ldif orig_val = obj_orig.get(attr) if orig_val is None: continue if not isinstance(orig_val, MessageElement): orig_val = MessageElement(str(orig_val), 0, attr ) m = Message() m.add(orig_val) orig_ldif = self.samdb.write_ldif(m, 0) # convert restored attr value to ldif rest_val = obj_restored.get(attr) self.assertFalse(rest_val is None) m = Message() if not isinstance(rest_val, MessageElement): rest_val = MessageElement(str(rest_val), 0, attr) m.add(rest_val) rest_ldif = self.samdb.write_ldif(m, 0) # compare generated ldif's self.assertEqual(orig_ldif.lower(), rest_ldif.lower())
def test_attributeSchema_object(self): """Test if the urgent replication is activated when handling an attributeSchema object""" self.ldb.add_ldif( """dn: CN=test attributeSchema,cn=Schema,CN=Configuration,%s""" % self.base_dn + """ objectClass: attributeSchema cn: test attributeSchema instanceType: 4 isSingleValued: FALSE showInAdvancedViewOnly: FALSE attributeID: 1.3.6.1.4.1.7165.4.6.1.4.""" + str(random.randint(1, 100000)) + """ attributeSyntax: 2.5.5.12 adminDisplayName: test attributeSchema adminDescription: test attributeSchema oMSyntax: 64 systemOnly: FALSE searchFlags: 8 lDAPDisplayName: testAttributeSchema name: test attributeSchema""") # urgent replication should be enabled when creating res = self.ldb.load_partition_usn("cn=Schema,cn=Configuration," + self.base_dn) self.assertEqual(res["uSNHighest"], res["uSNUrgent"]) # urgent replication should be enabled when modifying m = Message() m.dn = Dn( self.ldb, "CN=test attributeSchema,CN=Schema,CN=Configuration," + self.base_dn) m["lDAPDisplayName"] = MessageElement("updatedTestAttributeSchema", FLAG_MOD_REPLACE, "lDAPDisplayName") self.ldb.modify(m) res = self.ldb.load_partition_usn("cn=Schema,cn=Configuration," + self.base_dn) self.assertEqual(res["uSNHighest"], res["uSNUrgent"])
def test_crossRef_object(self): '''Test if the urgent replication is activated when handling a crossRef object''' self.ldb.add( { "dn": "CN=test crossRef,CN=Partitions,CN=Configuration," + self.base_dn, "objectClass": "crossRef", "cn": "test crossRef", "dnsRoot": lp.get("realm").lower(), "instanceType": "4", "nCName": self.base_dn, "showInAdvancedViewOnly": "TRUE", "name": "test crossRef", "systemFlags": "1" }, ["relax:0"]) # urgent replication should be enabled when creating res = self.ldb.load_partition_usn("cn=Configuration," + self.base_dn) self.assertEquals(res["uSNHighest"], res["uSNUrgent"]) # urgent replication should NOT be enabled when modifying m = Message() m.dn = Dn( ldb, "cn=test crossRef,CN=Partitions,CN=Configuration," + self.base_dn) m["systemFlags"] = MessageElement("0", FLAG_MOD_REPLACE, "systemFlags") ldb.modify(m) res = self.ldb.load_partition_usn("cn=Configuration," + self.base_dn) self.assertNotEquals(res["uSNHighest"], res["uSNUrgent"]) # urgent replication should be enabled when deleting self.delete_force( self.ldb, "cn=test crossRef,CN=Partitions,CN=Configuration," + self.base_dn) res = self.ldb.load_partition_usn("cn=Configuration," + self.base_dn) self.assertEquals(res["uSNHighest"], res["uSNUrgent"])
def test_attributeSchema_object(self): '''Test if the urgent replication is activated when handling an attributeSchema object''' try: self.ldb.add_ldif( """dn: CN=test attributeSchema,cn=Schema,CN=Configuration,%s""" % self.base_dn + """ objectClass: attributeSchema cn: test attributeSchema instanceType: 4 isSingleValued: FALSE showInAdvancedViewOnly: FALSE attributeID: 0.9.2342.19200300.100.1.1 attributeSyntax: 2.5.5.12 adminDisplayName: test attributeSchema adminDescription: test attributeSchema oMSyntax: 64 systemOnly: FALSE searchFlags: 8 lDAPDisplayName: test attributeSchema name: test attributeSchema""") # urgent replication should be enabled when creating res = self.ldb.load_partition_usn("cn=Schema,cn=Configuration," + self.base_dn) self.assertEquals(res["uSNHighest"], res["uSNUrgent"]) except LdbError: print "Not testing urgent replication when creating attributeSchema object ...\n" # urgent replication should be enabled when modifying m = Message() m.dn = Dn(ldb, "CN=test attributeSchema,CN=Schema,CN=Configuration," + self.base_dn) m["lDAPDisplayName"] = MessageElement("updated test attributeSchema", FLAG_MOD_REPLACE, "lDAPDisplayName") ldb.modify(m) res = self.ldb.load_partition_usn("cn=Schema,cn=Configuration," + self.base_dn) self.assertEquals(res["uSNHighest"], res["uSNUrgent"])
def test_nTDSDSA_object(self): """Test if the urgent replication is activated when handling a nTDSDSA object.""" self.ldb.add({ "dn": "cn=test server,cn=Servers,cn=Default-First-Site-Name,cn=Sites,%s" % self.ldb.get_config_basedn(), "objectclass":"server", "cn":"test server", "name":"test server", "systemFlags":"50000000"}, ["relax:0"]) self.ldb.add_ldif( """dn: cn=NTDS Settings test,cn=test server,cn=Servers,cn=Default-First-Site-Name,cn=Sites,cn=Configuration,%s""" % (self.base_dn) + """ objectclass: nTDSDSA cn: NTDS Settings test options: 1 instanceType: 4 systemFlags: 33554432""", ["relax:0"]) # urgent replication should be enabled when creation res = self.ldb.load_partition_usn("cn=Configuration," + self.base_dn) self.assertEquals(res["uSNHighest"], res["uSNUrgent"]) # urgent replication should NOT be enabled when modifying m = Message() m.dn = Dn(self.ldb, "cn=NTDS Settings test,cn=test server,cn=Servers,cn=Default-First-Site-Name,cn=Sites,cn=Configuration," + self.base_dn) m["options"] = MessageElement("0", FLAG_MOD_REPLACE, "options") self.ldb.modify(m) res = self.ldb.load_partition_usn("cn=Configuration," + self.base_dn) self.assertNotEquals(res["uSNHighest"], res["uSNUrgent"]) # urgent replication should be enabled when deleting self.delete_force(self.ldb, "cn=NTDS Settings test,cn=test server,cn=Servers,cn=Default-First-Site-Name,cn=Sites,cn=Configuration," + self.base_dn) res = self.ldb.load_partition_usn("cn=Configuration," + self.base_dn) self.assertEquals(res["uSNHighest"], res["uSNUrgent"]) self.delete_force(self.ldb, "cn=test server,cn=Servers,cn=Default-First-Site-Name,cn=Sites,cn=Configuration," + self.base_dn)
def test_all(self): """Basic plan is to create bunch of classSchema and attributeSchema objects, replicate Schema NC and then check all objects are replicated correctly""" # add new classSchema object (c_ldn, c_dn) = self._schema_new_class(self.ldb_dc1, "cls-A") # add new attributeSchema object (a_ldn, a_dn) = self._schema_new_attr(self.ldb_dc1, "attr-A") # add attribute to the class we have m = Message.from_dict(self.ldb_dc1, {"dn": c_dn, "mayContain": a_ldn}, FLAG_MOD_ADD) self.ldb_dc1.modify(m) # force replication from DC1 to DC2 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, nc_dn=self.schema_dn) # check objects are replicated self._check_object(c_dn) self._check_object(a_dn)
def test_classInheritance(self): """Test inheritance through subClassOf I think 5 levels of inheritance is pretty decent for now.""" # add 5 levels deep hierarchy c_dn_list = [] c_ldn_last = None for i in range(1, 6): base_name = "cls-I-%02d" % i (c_ldn, c_dn) = self._schema_new_class(self.ldb_dc1, base_name) c_dn_list.append(c_dn) if c_ldn_last: # inherit from last class added m = Message.from_dict(self.ldb_dc1, {"dn": c_dn, "subClassOf": c_ldn_last}, FLAG_MOD_REPLACE) self.ldb_dc1.modify(m) # store last class ldapDisplayName c_ldn_last = c_ldn # force replication from DC1 to DC2 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, nc_dn=self.schema_dn) # check objects are replicated for c_dn in c_dn_list: self._check_object(c_dn)
def assertAttributesEqual(self, obj_orig, attrs_orig, obj_restored, attrs_rest): self.assertNamesEqual(attrs_orig, attrs_rest) # remove volatile attributes, they can't be equal attrs_orig -= set(["uSNChanged", "dSCorePropagationData", "whenChanged"]) for attr in attrs_orig: # convert original attr value to ldif orig_val = obj_orig.get(attr) if orig_val is None: continue if not isinstance(orig_val, MessageElement): orig_val = MessageElement(str(orig_val), 0, attr) m = Message() m.add(orig_val) orig_ldif = self.samdb.write_ldif(m, 0) # convert restored attr value to ldif rest_val = obj_restored.get(attr) self.assertFalse(rest_val is None) m = Message() if not isinstance(rest_val, MessageElement): rest_val = MessageElement(str(rest_val), 0, attr) m.add(rest_val) rest_ldif = self.samdb.write_ldif(m, 0) # compare generated ldif's self.assertEqual(orig_ldif, rest_ldif)
def _ldap_schemaUpdateNow(self, sam_db): rec = {"dn": "", "schemaUpdateNow": "1"} m = Message.from_dict(sam_db, rec, FLAG_MOD_REPLACE) sam_db.modify(m)
def test_dirsync_send_delta(self): """Check that dirsync return correct delta when sending the last cookie""" res = self.ldb_admin.search( self.base_dn, expression="(&(samaccountname=test*)(!(isDeleted=*)))", controls=["dirsync:1:0:10000"]) ctl = str(res.controls[0]).split(":") ctl[1] = "1" ctl[2] = "0" ctl[3] = "10000" control = str(":".join(ctl)) res = self.ldb_admin.search( self.base_dn, expression="(&(samaccountname=test*)(!(isDeleted=*)))", controls=[control]) self.assertEqual(len(res), 0) res = self.ldb_admin.search( self.base_dn, expression="(&(objectClass=organizationalUnit)(!(isDeleted=*)))", controls=["dirsync:1:0:100000"]) ctl = str(res.controls[0]).split(":") ctl[1] = "1" ctl[2] = "0" ctl[3] = "10000" control2 = str(":".join(ctl)) # Let's create an OU ouname = "OU=testou2,%s" % self.base_dn self.ouname = ouname self.ldb_admin.create_ou(ouname) res = self.ldb_admin.search( self.base_dn, expression="(&(objectClass=organizationalUnit)(!(isDeleted=*)))", controls=[control2]) self.assertEqual(len(res), 1) ctl = str(res.controls[0]).split(":") ctl[1] = "1" ctl[2] = "0" ctl[3] = "10000" control3 = str(":".join(ctl)) delta = Message() delta.dn = Dn(self.ldb_admin, str(ouname)) delta["cn"] = MessageElement("test ou", FLAG_MOD_ADD, "cn") self.ldb_admin.modify(delta) res = self.ldb_admin.search( self.base_dn, expression="(&(objectClass=organizationalUnit)(!(isDeleted=*)))", controls=[control3]) self.assertEqual(len(res.msgs), 1) # 3 attributes: instanceType, cn and objectGUID self.assertEqual(len(res.msgs[0]), 3) delta = Message() delta.dn = Dn(self.ldb_admin, str(ouname)) delta["cn"] = MessageElement([], FLAG_MOD_DELETE, "cn") self.ldb_admin.modify(delta) res = self.ldb_admin.search( self.base_dn, expression="(&(objectClass=organizationalUnit)(!(isDeleted=*)))", controls=[control3]) self.assertEqual(len(res.msgs), 1) # So we won't have much attribute returned but instanceType and GUID # are. # 3 attributes: instanceType and objectGUID and cn but empty self.assertEqual(len(res.msgs[0]), 3) ouname = "OU=newouname,%s" % self.base_dn self.ldb_admin.rename(str(res[0].dn), str(Dn(self.ldb_admin, ouname))) self.ouname = ouname ctl = str(res.controls[0]).split(":") ctl[1] = "1" ctl[2] = "0" ctl[3] = "10000" control4 = str(":".join(ctl)) res = self.ldb_admin.search( self.base_dn, expression="(&(objectClass=organizationalUnit)(!(isDeleted=*)))", controls=[control3]) self.assertTrue(res[0].get("parentGUID") != None) self.assertTrue(res[0].get("name") != None) delete_force(self.ldb_admin, ouname)
def test_dirsync_attributes(self): """Check behavior with some attributes """ res = self.ldb_admin.search(self.base_dn, expression="samaccountname=*", controls=["dirsync:1:0:1"]) # Check that nTSecurityDescriptor is returned as it's the case when doing dirsync self.assertTrue(res.msgs[0].get("ntsecuritydescriptor") != None) # Check that non replicated attributes are not returned self.assertTrue(res.msgs[0].get("badPwdCount") == None) # Check that non forward link are not returned self.assertTrue(res.msgs[0].get("memberof") == None) # Asking for instanceType will return also objectGUID res = self.ldb_admin.search(self.base_dn, expression="samaccountname=Administrator", attrs=["instanceType"], controls=["dirsync:1:0:1"]) self.assertTrue(res.msgs[0].get("objectGUID") != None) self.assertTrue(res.msgs[0].get("instanceType") != None) # We don't return an entry if asked for objectGUID res = self.ldb_admin.search(self.base_dn, expression="(distinguishedName=%s)" % str(self.base_dn), attrs=["objectGUID"], controls=["dirsync:1:0:1"]) self.assertEquals(len(res.msgs), 0) # a request on the root of a NC didn't return parentGUID res = self.ldb_admin.search(self.base_dn, expression="(distinguishedName=%s)" % str(self.base_dn), attrs=["name"], controls=["dirsync:1:0:1"]) self.assertTrue(res.msgs[0].get("objectGUID") != None) self.assertTrue(res.msgs[0].get("name") != None) self.assertTrue(res.msgs[0].get("parentGUID") == None) self.assertTrue(res.msgs[0].get("instanceType") != None) # Asking for name will return also objectGUID and parentGUID # and instanceType and of course name res = self.ldb_admin.search(self.base_dn, expression="samaccountname=Administrator", attrs=["name"], controls=["dirsync:1:0:1"]) self.assertTrue(res.msgs[0].get("objectGUID") != None) self.assertTrue(res.msgs[0].get("name") != None) self.assertTrue(res.msgs[0].get("parentGUID") != None) self.assertTrue(res.msgs[0].get("instanceType") != None) # Asking for dn will not return not only DN but more like if attrs=* # parentGUID should be returned res = self.ldb_admin.search(self.base_dn, expression="samaccountname=Administrator", attrs=["dn"], controls=["dirsync:1:0:1"]) count = len(res.msgs[0]) res2 = self.ldb_admin.search(self.base_dn, expression="samaccountname=Administrator", controls=["dirsync:1:0:1"]) count2 = len(res2.msgs[0]) self.assertEqual(count, count2) # Asking for cn will return nothing on objects that have CN as RDN res = self.ldb_admin.search(self.base_dn, expression="samaccountname=Administrator", attrs=["cn"], controls=["dirsync:1:0:1"]) self.assertEqual(len(res.msgs), 0) # Asking for parentGUID will return nothing too res = self.ldb_admin.search(self.base_dn, expression="samaccountname=Administrator", attrs=["parentGUID"], controls=["dirsync:1:0:1"]) self.assertEqual(len(res.msgs), 0) ouname = "OU=testou,%s" % self.base_dn self.ouname = ouname self.ldb_admin.create_ou(ouname) delta = Message() delta.dn = Dn(self.ldb_admin, str(ouname)) delta["cn"] = MessageElement("test ou", FLAG_MOD_ADD, "cn") self.ldb_admin.modify(delta) res = self.ldb_admin.search(self.base_dn, expression="name=testou", attrs=["cn"], controls=["dirsync:1:0:1"]) self.assertEqual(len(res.msgs), 1) self.assertEqual(len(res.msgs[0]), 3) delete_force(self.ldb_admin, ouname)
def test_dirsync_send_delta(self): """Check that dirsync return correct delta when sending the last cookie""" res = self.ldb_admin.search(self.base_dn, expression="(&(samaccountname=test*)(!(isDeleted=*)))", controls=["dirsync:1:0:10000"]) ctl = str(res.controls[0]).split(":") ctl[1] = "1" ctl[2] = "0" ctl[3] = "10000" control = str(":".join(ctl)) res = self.ldb_admin.search(self.base_dn, expression="(&(samaccountname=test*)(!(isDeleted=*)))", controls=[control]) self.assertEqual(len(res), 0) res = self.ldb_admin.search(self.base_dn, expression="(&(objectClass=organizationalUnit)(!(isDeleted=*)))", controls=["dirsync:1:0:100000"]) ctl = str(res.controls[0]).split(":") ctl[1] = "1" ctl[2] = "0" ctl[3] = "10000" control2 = str(":".join(ctl)) # Let's create an OU ouname="OU=testou2,%s" % self.base_dn self.ouname = ouname self.ldb_admin.create_ou(ouname) res = self.ldb_admin.search(self.base_dn, expression="(&(objectClass=organizationalUnit)(!(isDeleted=*)))", controls=[control2]) self.assertEqual(len(res), 1) ctl = str(res.controls[0]).split(":") ctl[1] = "1" ctl[2] = "0" ctl[3] = "10000" control3 = str(":".join(ctl)) delta = Message() delta.dn = Dn(self.ldb_admin, str(ouname)) delta["cn"] = MessageElement("test ou", FLAG_MOD_ADD, "cn" ) self.ldb_admin.modify(delta) res = self.ldb_admin.search(self.base_dn, expression="(&(objectClass=organizationalUnit)(!(isDeleted=*)))", controls=[control3]) self.assertEqual(len(res.msgs), 1) # 3 attributes: instanceType, cn and objectGUID self.assertEqual(len(res.msgs[0]), 3) delta = Message() delta.dn = Dn(self.ldb_admin, str(ouname)) delta["cn"] = MessageElement([], FLAG_MOD_DELETE, "cn" ) self.ldb_admin.modify(delta) res = self.ldb_admin.search(self.base_dn, expression="(&(objectClass=organizationalUnit)(!(isDeleted=*)))", controls=[control3]) self.assertEqual(len(res.msgs), 1) # So we won't have much attribute returned but instanceType and GUID # are. # 3 attributes: instanceType and objectGUID and cn but empty self.assertEqual(len(res.msgs[0]), 3) ouname = "OU=newouname,%s" % self.base_dn self.ldb_admin.rename(str(res[0].dn), str(Dn(self.ldb_admin, ouname))) self.ouname = ouname ctl = str(res.controls[0]).split(":") ctl[1] = "1" ctl[2] = "0" ctl[3] = "10000" control4 = str(":".join(ctl)) res = self.ldb_admin.search(self.base_dn, expression="(&(objectClass=organizationalUnit)(!(isDeleted=*)))", controls=[control3]) self.assertTrue(res[0].get("parentGUID") != None) self.assertTrue(res[0].get("name") != None) delete_force(self.ldb_admin, ouname)
def test_dirsync_attributes(self): """Check behavior with some attributes """ res = self.ldb_admin.search(self.base_dn, expression="samaccountname=*", controls=["dirsync:1:0:1"]) # Check that nTSecurityDescriptor is returned as it's the case when doing dirsync self.assertTrue(res.msgs[0].get("ntsecuritydescriptor") != None) # Check that non replicated attributes are not returned self.assertTrue(res.msgs[0].get("badPwdCount") == None) # Check that non forward link are not returned self.assertTrue(res.msgs[0].get("memberof") == None) # Asking for instanceType will return also objectGUID res = self.ldb_admin.search(self.base_dn, expression="samaccountname=Administrator", attrs=["instanceType"], controls=["dirsync:1:0:1"]) self.assertTrue(res.msgs[0].get("objectGUID") != None) self.assertTrue(res.msgs[0].get("instanceType") != None) # We don't return an entry if asked for objectGUID res = self.ldb_admin.search(self.base_dn, expression="dn=%s" % self.base_dn, attrs=["objectGUID"], controls=["dirsync:1:0:1"]) self.assertEquals(len(res.msgs), 0) # a request on the root of a NC didn't return parentGUID res = self.ldb_admin.search(self.base_dn, expression="dn=%s" % self.base_dn, attrs=["name"], controls=["dirsync:1:0:1"]) self.assertTrue(res.msgs[0].get("objectGUID") != None) self.assertTrue(res.msgs[0].get("name") != None) self.assertTrue(res.msgs[0].get("parentGUID") == None) self.assertTrue(res.msgs[0].get("instanceType") != None) # Asking for name will return also objectGUID and parentGUID # and instanceType and of course name res = self.ldb_admin.search(self.base_dn, expression="samaccountname=Administrator", attrs=["name"], controls=["dirsync:1:0:1"]) self.assertTrue(res.msgs[0].get("objectGUID") != None) self.assertTrue(res.msgs[0].get("name") != None) self.assertTrue(res.msgs[0].get("parentGUID") != None) self.assertTrue(res.msgs[0].get("instanceType") != None) # Asking for dn will not return not only DN but more like if attrs=* # parentGUID should be returned res = self.ldb_admin.search(self.base_dn, expression="samaccountname=Administrator", attrs=["dn"], controls=["dirsync:1:0:1"]) count = len(res.msgs[0]) res2 = self.ldb_admin.search(self.base_dn, expression="samaccountname=Administrator", controls=["dirsync:1:0:1"]) count2 = len(res2.msgs[0]) self.assertEqual(count, count2) # Asking for cn will return nothing on objects that have CN as RDN res = self.ldb_admin.search(self.base_dn, expression="samaccountname=Administrator", attrs=["cn"], controls=["dirsync:1:0:1"]) self.assertEqual(len(res.msgs), 0) # Asking for parentGUID will return nothing too res = self.ldb_admin.search(self.base_dn, expression="samaccountname=Administrator", attrs=["parentGUID"], controls=["dirsync:1:0:1"]) self.assertEqual(len(res.msgs), 0) ouname="OU=testou,%s" % self.base_dn self.ouname = ouname self.ldb_admin.create_ou(ouname) delta = Message() delta.dn = Dn(self.ldb_admin, str(ouname)) delta["cn"] = MessageElement("test ou", FLAG_MOD_ADD, "cn" ) self.ldb_admin.modify(delta) res = self.ldb_admin.search(self.base_dn, expression="name=testou", attrs=["cn"], controls=["dirsync:1:0:1"]) self.assertEqual(len(res.msgs), 1) self.assertEqual(len(res.msgs[0]), 3) delete_force(self.ldb_admin, ouname)
def test_plain_userPassword(self): print("Performs testing about the standard 'userPassword' behaviour") # Delete the "dSHeuristics" self.ldb.set_dsheuristics(None) time.sleep(1) # This switching time is strictly needed! m = Message() m.dn = Dn(self.ldb, "cn=testuser,cn=users," + self.base_dn) m["userPassword"] = MessageElement("myPassword", FLAG_MOD_ADD, "userPassword") self.ldb.modify(m) res = self.ldb.search("cn=testuser,cn=users," + self.base_dn, scope=SCOPE_BASE, attrs=["userPassword"]) self.assertTrue(len(res) == 1) self.assertTrue("userPassword" in res[0]) self.assertEquals(res[0]["userPassword"][0], "myPassword") m = Message() m.dn = Dn(self.ldb, "cn=testuser,cn=users," + self.base_dn) m["userPassword"] = MessageElement("myPassword2", FLAG_MOD_REPLACE, "userPassword") self.ldb.modify(m) res = self.ldb.search("cn=testuser,cn=users," + self.base_dn, scope=SCOPE_BASE, attrs=["userPassword"]) self.assertTrue(len(res) == 1) self.assertTrue("userPassword" in res[0]) self.assertEquals(res[0]["userPassword"][0], "myPassword2") m = Message() m.dn = Dn(self.ldb, "cn=testuser,cn=users," + self.base_dn) m["userPassword"] = MessageElement([], FLAG_MOD_DELETE, "userPassword") self.ldb.modify(m) res = self.ldb.search("cn=testuser,cn=users," + self.base_dn, scope=SCOPE_BASE, attrs=["userPassword"]) self.assertTrue(len(res) == 1) self.assertFalse("userPassword" in res[0]) # Set the test "dSHeuristics" to deactivate "userPassword" pwd changes self.ldb.set_dsheuristics("000000000") m = Message() m.dn = Dn(self.ldb, "cn=testuser,cn=users," + self.base_dn) m["userPassword"] = MessageElement("myPassword3", FLAG_MOD_REPLACE, "userPassword") self.ldb.modify(m) res = self.ldb.search("cn=testuser,cn=users," + self.base_dn, scope=SCOPE_BASE, attrs=["userPassword"]) self.assertTrue(len(res) == 1) self.assertTrue("userPassword" in res[0]) self.assertEquals(res[0]["userPassword"][0], "myPassword3") # Set the test "dSHeuristics" to deactivate "userPassword" pwd changes self.ldb.set_dsheuristics("000000002") m = Message() m.dn = Dn(self.ldb, "cn=testuser,cn=users," + self.base_dn) m["userPassword"] = MessageElement("myPassword4", FLAG_MOD_REPLACE, "userPassword") self.ldb.modify(m) res = self.ldb.search("cn=testuser,cn=users," + self.base_dn, scope=SCOPE_BASE, attrs=["userPassword"]) self.assertTrue(len(res) == 1) self.assertTrue("userPassword" in res[0]) self.assertEquals(res[0]["userPassword"][0], "myPassword4") # Reset the test "dSHeuristics" (reactivate "userPassword" pwd changes) self.ldb.set_dsheuristics("000000001")
class SchemaTests_msDS_IntId(samba.tests.TestCase): def setUp(self): super(SchemaTests_msDS_IntId, self).setUp() self.ldb = SamDB(host, credentials=creds, session_info=system_session(lp), lp=lp, options=ldb_options) res = self.ldb.search(base="", expression="", scope=SCOPE_BASE, attrs=["schemaNamingContext", "defaultNamingContext", "forestFunctionality"]) self.assertEquals(len(res), 1) self.schema_dn = res[0]["schemaNamingContext"][0] self.base_dn = res[0]["defaultNamingContext"][0] self.forest_level = int(res[0]["forestFunctionality"][0]) def _ldap_schemaUpdateNow(self): ldif = """ dn: changetype: modify add: schemaUpdateNow schemaUpdateNow: 1 """ self.ldb.modify_ldif(ldif) def _make_obj_names(self, prefix): class_name = prefix + time.strftime("%s", time.gmtime()) class_ldap_name = class_name.replace("-", "") class_dn = "CN=%s,%s" % (class_name, self.schema_dn) return (class_name, class_ldap_name, class_dn) def _is_schema_base_object(self, ldb_msg): """Test systemFlags for SYSTEM_FLAG_SCHEMA_BASE_OBJECT (16)""" systemFlags = 0 if "systemFlags" in ldb_msg: systemFlags = int(ldb_msg["systemFlags"][0]) return (systemFlags & 16) != 0 def _make_attr_ldif(self, attr_name, attr_dn): ldif = """ dn: """ + attr_dn + """ objectClass: top objectClass: attributeSchema adminDescription: """ + attr_name + """ adminDisplayName: """ + attr_name + """ cn: """ + attr_name + """ attributeId: 1.2.840.""" + str(random.randint(1,100000)) + """.1.5.9940 attributeSyntax: 2.5.5.12 omSyntax: 64 instanceType: 4 isSingleValued: TRUE systemOnly: FALSE """ return ldif def test_msDS_IntId_on_attr(self): """Testing msDs-IntId creation for Attributes. See MS-ADTS - 3.1.1.Attributes This test should verify that: - Creating attribute with 'msDS-IntId' fails with ERR_UNWILLING_TO_PERFORM - Adding 'msDS-IntId' on existing attribute fails with ERR_CONSTRAINT_VIOLATION - Creating attribute with 'msDS-IntId' set and FLAG_SCHEMA_BASE_OBJECT flag set fails with ERR_UNWILLING_TO_PERFORM - Attributes created with FLAG_SCHEMA_BASE_OBJECT not set have 'msDS-IntId' attribute added internally """ # 1. Create attribute without systemFlags # msDS-IntId should be created if forest functional # level is >= DS_DOMAIN_FUNCTION_2003 # and missing otherwise (attr_name, attr_ldap_name, attr_dn) = self._make_obj_names("msDS-IntId-Attr-1-") ldif = self._make_attr_ldif(attr_name, attr_dn) # try to add msDS-IntId during Attribute creation ldif_fail = ldif + "msDS-IntId: -1993108831\n" try: self.ldb.add_ldif(ldif_fail) self.fail("Adding attribute with preset msDS-IntId should fail") except LdbError, (num, _): self.assertEquals(num, ERR_UNWILLING_TO_PERFORM) # add the new attribute and update schema self.ldb.add_ldif(ldif) self._ldap_schemaUpdateNow() # Search for created attribute res = [] res = self.ldb.search(attr_dn, scope=SCOPE_BASE, attrs=["lDAPDisplayName", "msDS-IntId", "systemFlags"]) self.assertEquals(len(res), 1) self.assertEquals(res[0]["lDAPDisplayName"][0], attr_ldap_name) if self.forest_level >= DS_DOMAIN_FUNCTION_2003: if self._is_schema_base_object(res[0]): self.assertTrue("msDS-IntId" not in res[0]) else: self.assertTrue("msDS-IntId" in res[0]) else: self.assertTrue("msDS-IntId" not in res[0]) msg = Message() msg.dn = Dn(self.ldb, attr_dn) msg["msDS-IntId"] = MessageElement("-1993108831", FLAG_MOD_REPLACE, "msDS-IntId") try: self.ldb.modify(msg) self.fail("Modifying msDS-IntId should return error") except LdbError, (num, _): self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
# Search for created attribute res = [] res = self.ldb.search(attr_dn, scope=SCOPE_BASE, attrs=["lDAPDisplayName", "msDS-IntId"]) self.assertEquals(len(res), 1) self.assertEquals(res[0]["lDAPDisplayName"][0], attr_ldap_name) if self.forest_level >= DS_DOMAIN_FUNCTION_2003: if self._is_schema_base_object(res[0]): self.assertTrue("msDS-IntId" not in res[0]) else: self.assertTrue("msDS-IntId" in res[0]) else: self.assertTrue("msDS-IntId" not in res[0]) msg = Message() msg.dn = Dn(self.ldb, attr_dn) msg["msDS-IntId"] = MessageElement("-1993108831", FLAG_MOD_REPLACE, "msDS-IntId") try: self.ldb.modify(msg) self.fail("Modifying msDS-IntId should return error") except LdbError, (num, _): self.assertEquals(num, ERR_CONSTRAINT_VIOLATION) def _make_class_ldif(self, class_dn, class_name): ldif = """ dn: """ + class_dn + """ objectClass: top objectClass: classSchema adminDescription: """ + class_name + """
def add_attr(self, dn, attr, value): m = Message() m.dn = Dn(self.ldb_admin, dn) m[attr] = MessageElement(value, FLAG_MOD_ADD, attr) self.ldb_admin.modify(m)
def test_classWithCustomBinaryDNLinkAttribute(self): # Add a new attribute to the schema, which has binary DN syntax (2.5.5.7) (bin_ldn, bin_dn) = self._schema_new_attr(self.ldb_dc1, "attr-Link-Bin", 18, attrs={"linkID": "1.2.840.113556.1.2.50", "attributeSyntax": "2.5.5.7", "omSyntax": "127"}) (bin_ldn_b, bin_dn_b) = self._schema_new_attr(self.ldb_dc1, "attr-Link-Bin-Back", 19, attrs={"linkID": bin_ldn, "attributeSyntax": "2.5.5.1", "omSyntax": "127"}) # Add a new class to the schema which can have the binary DN attribute (c_ldn, c_dn) = self._schema_new_class(self.ldb_dc1, "cls-Link-Bin", 20, 3, {"mayContain": bin_ldn}) (c_ldn_b, c_dn_b) = self._schema_new_class(self.ldb_dc1, "cls-Link-Bin-Back", 21, 3, {"mayContain": bin_ldn_b}) link_end_dn = ldb.Dn(self.ldb_dc1, "ou=X") link_end_dn.add_base(self.ldb_dc1.get_default_basedn()) link_end_dn.set_component(0, "OU", bin_dn_b.get_component_value(0)) ou_dn = ldb.Dn(self.ldb_dc1, "ou=X") ou_dn.add_base(self.ldb_dc1.get_default_basedn()) ou_dn.set_component(0, "OU", bin_dn.get_component_value(0)) # Add an instance of the class to be pointed at rec = {"dn": link_end_dn, "objectClass": ["top", "organizationalUnit", c_ldn_b], "ou": link_end_dn.get_component_value(0)} self.ldb_dc1.add(rec) # .. and one that does, and points to the first one rec = {"dn": ou_dn, "objectClass": ["top", "organizationalUnit", c_ldn], "ou": ou_dn.get_component_value(0)} self.ldb_dc1.add(rec) m = Message.from_dict(self.ldb_dc1, {"dn": ou_dn, bin_ldn: "B:8:1234ABCD:%s" % str(link_end_dn)}, FLAG_MOD_ADD) self.ldb_dc1.modify(m) self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, nc_dn=self.schema_dn, forced=True) self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, nc_dn=self.domain_dn, forced=True) self._check_object(c_dn) self._check_object(bin_dn) # Make sure we can delete the backlink self.ldb_dc1.delete(link_end_dn) self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, nc_dn=self.schema_dn, forced=True) self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, nc_dn=self.domain_dn, forced=True)
def test_modify_dsheuristics_userPassword(self): print("Performs testing about reading userPassword between dsHeuristic modifies") # Make sure userPassword cannot be read self.ldb.set_dsheuristics("000000000") # Open a new connection (with dsHeuristic=000000000) ldb1 = SamDB(url=host, session_info=system_session(lp), credentials=creds, lp=lp) # Set userPassword to be read # This setting only affects newer connections (ldb2) ldb1.set_dsheuristics("000000001") time.sleep(1) m = Message() m.dn = Dn(ldb1, "cn=testuser,cn=users," + self.base_dn) m["userPassword"] = MessageElement("thatsAcomplPASS1", FLAG_MOD_REPLACE, "userPassword") ldb1.modify(m) res = ldb1.search("cn=testuser,cn=users," + self.base_dn, scope=SCOPE_BASE, attrs=["userPassword"]) # userPassword cannot be read, despite the dsHeuristic setting self.assertTrue(len(res) == 1) self.assertFalse("userPassword" in res[0]) # Open another new connection (with dsHeuristic=000000001) ldb2 = SamDB(url=host, session_info=system_session(lp), credentials=creds, lp=lp) # Set userPassword to be unreadable # This setting does not affect this connection ldb2.set_dsheuristics("000000000") time.sleep(1) res = ldb2.search("cn=testuser,cn=users," + self.base_dn, scope=SCOPE_BASE, attrs=["userPassword"]) # Check that userPassword was not stored from ldb1 self.assertTrue(len(res) == 1) self.assertFalse("userPassword" in res[0]) m = Message() m.dn = Dn(ldb2, "cn=testuser,cn=users," + self.base_dn) m["userPassword"] = MessageElement("thatsAcomplPASS2", FLAG_MOD_REPLACE, "userPassword") ldb2.modify(m) res = ldb2.search("cn=testuser,cn=users," + self.base_dn, scope=SCOPE_BASE, attrs=["userPassword"]) # userPassword can be read in this connection # This is regardless of the current dsHeuristics setting self.assertTrue(len(res) == 1) self.assertTrue("userPassword" in res[0]) self.assertEquals(res[0]["userPassword"][0], "thatsAcomplPASS2") # Only password from ldb1 is the user's password creds2 = Credentials() creds2.set_username("testuser") creds2.set_password("thatsAcomplPASS1") creds2.set_domain(creds.get_domain()) creds2.set_realm(creds.get_realm()) creds2.set_workstation(creds.get_workstation()) creds2.set_gensec_features(creds2.get_gensec_features() | gensec.FEATURE_SEAL) try: SamDB(url=host, credentials=creds2, lp=lp) except: self.fail("testuser used the wrong password") ldb3 = SamDB(url=host, session_info=system_session(lp), credentials=creds, lp=lp) # Check that userPassword was stored from ldb2 res = ldb3.search("cn=testuser,cn=users," + self.base_dn, scope=SCOPE_BASE, attrs=["userPassword"]) # userPassword can be read self.assertTrue(len(res) == 1) self.assertTrue("userPassword" in res[0]) self.assertEquals(res[0]["userPassword"][0], "thatsAcomplPASS2") # Reset the test "dSHeuristics" (reactivate "userPassword" pwd changes) self.ldb.set_dsheuristics("000000001")