2 # -*- coding: utf-8 -*-
4 # Unix SMB/CIFS implementation.
5 # Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2010
6 # Copyright (C) Andrew Bartlett <abartlet@samba.org> 2016
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 3 of the License, or
11 # (at your option) any later version.
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # export DC1=dc1_dns_name
25 # export DC2=dc2_dns_name
26 # export SUBUNITRUN=$samba4srcdir/scripting/bin/subunitrun
27 # PYTHONPATH="$PYTHONPATH:$samba4srcdir/torture/drs/python" $SUBUNITRUN repl_move -U"$DOMAIN/$DC_USERNAME"%"$DC_PASSWORD"
33 from samba.ndr import ndr_unpack
34 from samba.dcerpc import drsblobs
35 from samba.dcerpc import misc
36 from samba.drs_utils import drs_DsBind
44 from samba.dcerpc.drsuapi import *
46 class DrsMoveObjectTestCase(drs_base.DrsBaseTestCase):
48 def _ds_bind(self, server_name):
49 binding_str = "ncacn_ip_tcp:%s[print,seal]" % server_name
51 drs = drsuapi(binding_str, self.get_loadparm(), self.get_credentials())
52 (drs_handle, supported_extensions) = drs_DsBind(drs)
53 return (drs, drs_handle)
56 super(DrsMoveObjectTestCase, self).setUp()
57 # disable automatic replication temporary
58 self._disable_inbound_repl(self.dnsname_dc1)
59 self._disable_inbound_repl(self.dnsname_dc2)
61 # make sure DCs are synchronized before the test
62 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
63 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
65 self.ou1_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU1")
66 self.ou1_dn.add_base(self.ldb_dc1.get_default_basedn())
68 ou1["dn"] = self.ou1_dn
69 ou1["objectclass"] = "organizationalUnit"
70 ou1["ou"] = self.ou1_dn.get_component_value(0)
73 self.ou2_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU2")
74 self.ou2_dn.add_base(self.ldb_dc1.get_default_basedn())
76 ou2["dn"] = self.ou2_dn
77 ou2["objectclass"] = "organizationalUnit"
78 ou2["ou"] = self.ou2_dn.get_component_value(0)
81 # trigger replication from DC1 to DC2
82 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
83 self.dc1_guid = self.ldb_dc1.get_invocation_id()
84 self.dc2_guid = self.ldb_dc2.get_invocation_id()
86 self.drs_dc1 = self._ds_bind(self.dnsname_dc1)
87 self.drs_dc2 = self._ds_bind(self.dnsname_dc2)
91 self.ldb_dc1.delete(self.ou1_dn, ["tree_delete:1"])
92 except ldb.LdbError as (enum, string):
93 if enum == ldb.ERR_NO_SUCH_OBJECT:
96 self.ldb_dc1.delete(self.ou2_dn, ["tree_delete:1"])
97 self._enable_inbound_repl(self.dnsname_dc1)
98 self._enable_inbound_repl(self.dnsname_dc2)
99 super(DrsMoveObjectTestCase, self).tearDown()
101 def _make_username(self):
102 return "DrsMoveU_" + time.strftime("%s", time.gmtime())
104 def _check_metadata(self, user_dn, sam_ldb, drs, metadata, expected):
105 repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob, str(metadata[0]))
107 self.assertEqual(len(repl.ctr.array), len(expected))
110 for o in repl.ctr.array:
112 (attid, orig_dsa, version) = e
113 self.assertEquals(attid, o.attid,
114 "(LDAP) Wrong attid "
115 "for expected value %d, wanted 0x%08x got 0x%08x"
116 % (i, attid, o.attid))
117 self.assertEquals(o.originating_invocation_id,
119 "(LDAP) Wrong originating_invocation_id "
120 "for expected value %d, attid 0x%08x, wanted %s got %s"
123 o.originating_invocation_id))
124 # Allow version to be skipped when it does not matter
125 if version is not None:
126 self.assertEquals(o.version, version,
127 "(LDAP) Wrong version for expected value %d, "
137 req8 = DsGetNCChangesRequest8()
139 req8.source_dsa_invocation_id = misc.GUID(sam_ldb.get_invocation_id())
140 req8.naming_context = DsReplicaObjectIdentifier()
141 req8.naming_context.dn = str(user_dn)
142 req8.highwatermark = DsReplicaHighWaterMark()
143 req8.highwatermark.tmp_highest_usn = 0
144 req8.highwatermark.reserved_usn = 0
145 req8.highwatermark.highest_usn = 0
146 req8.uptodateness_vector = None
147 req8.replica_flags = DRSUAPI_DRS_SYNC_FORCED
148 req8.max_object_count = 1
149 req8.max_ndr_size = 402116
150 req8.extended_op = DRSUAPI_EXOP_REPL_OBJ
152 req8.partial_attribute_set = None
153 req8.partial_attribute_set_ex = None
154 req8.mapping_ctr.num_mappings = 0
155 req8.mapping_ctr.mappings = None
157 (drs_conn, drs_handle) = drs
159 (level, drs_ctr) = drs_conn.DsGetNCChanges(drs_handle, 8, req8)
160 self.assertEqual(level, 6)
161 self.assertEqual(drs_ctr.object_count, 1)
163 self.assertEqual(len(drs_ctr.first_object.meta_data_ctr.meta_data), len(expected) - 1)
165 for o in drs_ctr.first_object.meta_data_ctr.meta_data:
167 drs_attid = drs_ctr.first_object.object.attribute_ctr.attributes[att_idx]
169 (attid, orig_dsa, version) = e
171 # Skip the RDN from the expected set, it is not sent over DRS
172 if (user_dn.get_rdn_name().upper() == "CN" \
173 and attid == DRSUAPI_ATTID_cn) \
174 or (user_dn.get_rdn_name().upper() == "OU" \
175 and attid == DRSUAPI_ATTID_ou):
178 (attid, orig_dsa, version) = e
180 self.assertEquals(attid, drs_attid.attid,
182 "for expected value %d, wanted 0x%08x got 0x%08x"
183 % (i, attid, drs_attid.attid))
185 self.assertEquals(o.originating_invocation_id,
187 "(DRS) Wrong originating_invocation_id "
188 "for expected value %d, attid 0x%08x, wanted %s got %s"
191 o.originating_invocation_id))
192 # Allow version to be skipped when it does not matter
193 if version is not None:
194 self.assertEquals(o.version, version,
195 "(DRS) Wrong version for expected value %d, "
198 % (i, attid, version, o.version))
201 att_idx = att_idx + 1
203 # now also used to check the group
204 def _check_obj(self, sam_ldb, obj_orig, is_deleted, expected_metadata=None, drs=None):
205 # search the user by guid as it may be deleted
206 guid_str = self._GUID_string(obj_orig["objectGUID"][0])
207 res = sam_ldb.search(base='<GUID=%s>' % guid_str,
208 controls=["show_deleted:1"],
209 attrs=["*", "parentGUID",
210 "replPropertyMetaData"])
211 self.assertEquals(len(res), 1)
213 rdn_orig = obj_orig[user_cur.dn.get_rdn_name()][0]
214 rdn_cur = user_cur[user_cur.dn.get_rdn_name()][0]
215 name_orig = obj_orig["name"][0]
216 name_cur = user_cur["name"][0]
217 dn_orig = obj_orig["dn"]
218 dn_cur = user_cur["dn"]
219 # now check properties of the user
221 self.assertTrue("isDeleted" in user_cur)
222 self.assertEquals(rdn_cur.split('\n')[0], rdn_orig)
223 self.assertEquals(name_cur.split('\n')[0], name_orig)
224 self.assertEquals(dn_cur.get_rdn_value().split('\n')[0],
225 dn_orig.get_rdn_value())
226 self.assertEqual(name_cur, rdn_cur)
228 self.assertFalse("isDeleted" in user_cur)
229 self.assertEquals(rdn_cur, rdn_orig)
230 self.assertEquals(name_cur, name_orig)
231 self.assertEquals(dn_cur, dn_orig)
232 self.assertEqual(name_cur, rdn_cur)
233 parent_cur = user_cur["parentGUID"][0]
235 parent_orig = obj_orig["parentGUID"][0]
236 self.assertEqual(parent_orig, parent_cur)
239 self.assertEqual(name_cur, user_cur.dn.get_rdn_value())
241 if expected_metadata is not None:
242 self._check_metadata(dn_cur, sam_ldb, drs, user_cur["replPropertyMetaData"],
248 def test_ReplicateMoveObject1(self):
249 """Verifies how a moved container with a user inside is replicated between two DCs.
250 This test should verify that:
251 - the OU is replicated properly
253 - We verify that after replication,
254 that the user has the correct DN (under OU2)
256 - the OU is modified on DC2
257 - We verify that after replication,
258 that the user has the correct DN (deleted) and has not description
261 # work-out unique username to test with
262 username = self._make_username()
265 self.ldb_dc1.newuser(username=username,
266 userou="ou=%s" % self.ou1_dn.get_component_value(0),
267 password=None, setpassword=False)
268 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
270 expression="(samAccountName=%s)" % username,
271 attrs=["*", "parentGUID"])
272 self.assertEquals(len(ldb_res), 1)
273 user_orig = ldb_res[0]
274 user_dn = ldb_res[0]["dn"]
276 # check user info on DC1
277 print "Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0]))
279 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
280 (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
281 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
282 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
283 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
284 (DRSUAPI_ATTID_name, self.dc1_guid, 1),
285 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
286 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
287 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
288 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
289 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
290 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
291 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
292 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
293 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
294 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
295 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
296 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
297 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
298 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
299 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
300 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
302 self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
303 obj_orig=user_orig, is_deleted=False,
304 expected_metadata=initial_metadata)
306 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
307 new_dn.add_base(self.ou2_dn)
308 self.ldb_dc1.rename(user_dn, new_dn)
309 ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
311 expression="(samAccountName=%s)" % username,
312 attrs=["*", "parentGUID"])
313 self.assertEquals(len(ldb_res), 1)
315 user_moved_orig = ldb_res[0]
316 user_moved_dn = ldb_res[0]["dn"]
319 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
320 (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
321 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
322 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
323 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
324 (DRSUAPI_ATTID_name, self.dc1_guid, 2),
325 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
326 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
327 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
328 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
329 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
330 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
331 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
332 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
333 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
334 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
335 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
336 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
337 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
338 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
339 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
340 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
342 # check user info on DC1 after rename - should be valid user
343 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
344 obj_orig=user_moved_orig,
346 expected_metadata=moved_metadata)
348 # trigger replication from DC1 to DC2
349 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
350 moved_metadata_dc2 = [
351 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
352 (DRSUAPI_ATTID_cn, self.dc2_guid, 1),
353 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
354 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
355 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
356 (DRSUAPI_ATTID_name, self.dc1_guid, 2),
357 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
358 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
359 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
360 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
361 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
362 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
363 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
364 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
365 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
366 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
367 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
368 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
369 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
370 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
371 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
372 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
374 # check user info on DC2 - should be valid user
375 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
376 obj_orig=user_moved_orig,
378 expected_metadata=moved_metadata_dc2)
381 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
383 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
384 (DRSUAPI_ATTID_cn, self.dc1_guid, 2),
385 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
386 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
387 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
388 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
389 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
390 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
391 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
392 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
393 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
394 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
395 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
396 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
397 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
398 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
399 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
400 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
401 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
402 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
403 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
404 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
405 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
406 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
407 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
409 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_moved_orig, is_deleted=True, expected_metadata=deleted_metadata)
411 # Modify description on DC2. This triggers a replication, but
412 # not of 'name' and so a bug in Samba regarding the DN.
415 msg["description"] = ldb.MessageElement("User Description", ldb.FLAG_MOD_REPLACE, "description")
416 self.ldb_dc2.modify(msg)
418 modified_metadata = [
419 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
420 (DRSUAPI_ATTID_cn, self.dc2_guid, 1),
421 (DRSUAPI_ATTID_description, self.dc2_guid, 1),
422 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
423 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
424 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
425 (DRSUAPI_ATTID_name, self.dc1_guid, 2),
426 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
427 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
428 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
429 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
430 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
431 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
432 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
433 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
434 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
435 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
436 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
437 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
438 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
439 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
440 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
441 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
443 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
444 obj_orig=user_moved_orig,
446 expected_metadata=modified_metadata)
449 # trigger replication from DC1 to DC2, for cleanup
450 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
452 deleted_modified_metadata_dc2 = [
453 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
454 (DRSUAPI_ATTID_cn, self.dc2_guid, 2),
455 (DRSUAPI_ATTID_description, self.dc2_guid, 2),
456 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
457 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
458 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
459 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
460 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
461 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
462 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
463 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
464 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
465 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
466 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
467 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
468 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
469 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
470 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
471 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
472 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
473 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
474 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
475 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
476 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
477 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
478 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
480 # check user info on DC2 - should be deleted user
481 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
482 obj_orig=user_moved_orig,
484 expected_metadata=deleted_modified_metadata_dc2)
485 self.assertFalse("description" in user_cur)
487 # trigger replication from DC2 to DC1, for cleanup
488 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
490 deleted_modified_metadata_dc1 = [
491 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
492 (DRSUAPI_ATTID_cn, self.dc1_guid, 2),
493 (DRSUAPI_ATTID_description, self.dc2_guid, 2),
494 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
495 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
496 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
497 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
498 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
499 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
500 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
501 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
502 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
503 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
504 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
505 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
506 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
507 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
508 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
509 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
510 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
511 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
512 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
513 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
514 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
515 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
516 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
518 # check user info on DC1 - should be deleted user
519 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
520 obj_orig=user_moved_orig,
522 expected_metadata=deleted_modified_metadata_dc1)
523 self.assertFalse("description" in user_cur)
526 def test_ReplicateMoveObject2(self):
527 """Verifies how a moved container with a user inside is not
528 replicated between two DCs as no replication is triggered
529 This test should verify that:
530 - the OU is not replicated
531 - the user is not replicated
534 # work-out unique username to test with
535 username = self._make_username()
538 self.ldb_dc1.newuser(username=username,
539 userou="ou=%s" % self.ou1_dn.get_component_value(0),
540 password=None, setpassword=False)
541 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
543 expression="(samAccountName=%s)" % username,
544 attrs=["*", "parentGUID"])
545 self.assertEquals(len(ldb_res), 1)
546 user_orig = ldb_res[0]
547 user_dn = ldb_res[0]["dn"]
549 # check user info on DC1
550 print "Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0]))
552 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
553 (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
554 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
555 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
556 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
557 (DRSUAPI_ATTID_name, self.dc1_guid, 1),
558 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
559 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
560 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
561 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
562 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
563 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
564 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
565 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
566 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
567 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
568 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
569 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
570 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
571 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
572 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
573 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
575 self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
576 obj_orig=user_orig, is_deleted=False,
577 expected_metadata=initial_metadata)
579 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
580 new_dn.add_base(self.ou2_dn)
581 self.ldb_dc1.rename(user_dn, new_dn)
582 ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
584 expression="(samAccountName=%s)" % username,
585 attrs=["*", "parentGUID"])
586 self.assertEquals(len(ldb_res), 1)
587 user_moved_orig = ldb_res[0]
590 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
591 (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
592 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
593 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
594 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
595 (DRSUAPI_ATTID_name, self.dc1_guid, 2),
596 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
597 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
598 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
599 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
600 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
601 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
602 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
603 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
604 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
605 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
606 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
607 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
608 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
609 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
610 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
611 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
613 # check user info on DC1 after rename - should be valid user
614 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
615 obj_orig=user_moved_orig,
617 expected_metadata=moved_metadata)
619 # check user info on DC2 - should not be there, we have not done replication
620 ldb_res = self.ldb_dc2.search(base=self.ou2_dn,
622 expression="(samAccountName=%s)" % username,
623 attrs=["*", "parentGUID"])
624 self.assertEquals(len(ldb_res), 0)
627 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
629 deleted_metadata_dc1 = [
630 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
631 (DRSUAPI_ATTID_cn, self.dc1_guid, 2),
632 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
633 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
634 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
635 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
636 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
637 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
638 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
639 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
640 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
641 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
642 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
643 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
644 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
645 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
646 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
647 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
648 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
649 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
650 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
651 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
652 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
653 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
654 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
656 # check user info on DC1 - should be deleted user
657 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
658 obj_orig=user_moved_orig,
660 expected_metadata=deleted_metadata_dc1)
661 # trigger replication from DC1 to DC2, for cleanup
662 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
664 deleted_metadata_dc2 = [
665 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
666 (DRSUAPI_ATTID_cn, self.dc2_guid, 1),
667 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
668 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
669 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
670 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
671 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
672 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
673 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
674 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
675 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
676 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
677 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
678 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
679 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
680 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
681 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
682 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
683 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
684 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
685 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
686 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
687 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
688 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
689 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
691 # check user info on DC2 - should be deleted user
692 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
693 obj_orig=user_moved_orig,
695 expected_metadata=deleted_metadata_dc2)
697 # trigger replication from DC2 to DC1, for cleanup
698 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
700 # check user info on DC1 - should be deleted user
701 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
702 obj_orig=user_moved_orig,
704 expected_metadata=deleted_metadata_dc1)
707 def test_ReplicateMoveObject3(self):
708 """Verifies how a moved container with a user inside is replicated between two DCs.
709 This test should verify that:
710 - the OU is created on DC1
711 - the OU is renamed on DC1
712 - We verify that after replication,
713 that the user has the correct DN (under OU2).
716 # work-out unique username to test with
717 username = self._make_username()
720 self.ldb_dc1.newuser(username=username,
721 userou="ou=%s" % self.ou1_dn.get_component_value(0),
722 password=None, setpassword=False)
723 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
725 expression="(samAccountName=%s)" % username,
726 attrs=["*", "parentGUID"])
727 self.assertEquals(len(ldb_res), 1)
728 user_orig = ldb_res[0]
729 user_dn = ldb_res[0]["dn"]
731 # check user info on DC1
732 print "Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0]))
734 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
735 (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
736 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
737 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
738 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
739 (DRSUAPI_ATTID_name, self.dc1_guid, 1),
740 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
741 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
742 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
743 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
744 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
745 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
746 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
747 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
748 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
749 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
750 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
751 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
752 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
753 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
754 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
755 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
757 self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
758 obj_orig=user_orig, is_deleted=False,
759 expected_metadata=initial_metadata)
762 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
763 new_dn.add_base(self.ou2_dn)
764 self.ldb_dc1.rename(user_dn, new_dn)
765 ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
767 expression="(samAccountName=%s)" % username,
768 attrs=["*", "parentGUID"])
769 self.assertEquals(len(ldb_res), 1)
771 user_moved_orig = ldb_res[0]
772 user_moved_dn = ldb_res[0]["dn"]
774 # trigger replication from DC1 to DC2
775 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
777 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
778 (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
779 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
780 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
781 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
782 (DRSUAPI_ATTID_name, self.dc1_guid, 2),
783 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
784 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
785 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
786 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
787 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
788 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
789 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
790 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
791 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
792 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
793 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
794 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
795 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
796 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
797 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
798 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
800 # check user info on DC1 after rename - should be valid user
801 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
802 obj_orig=user_moved_orig,
804 expected_metadata=moved_metadata)
807 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
808 deleted_metadata_dc1 = [
809 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
810 (DRSUAPI_ATTID_cn, self.dc1_guid, 2),
811 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
812 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
813 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
814 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
815 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
816 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
817 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
818 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
819 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
820 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
821 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
822 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
823 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
824 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
825 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
826 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
827 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
828 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
829 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
830 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
831 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
832 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
833 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
835 # check user info on DC1 - should be deleted user
836 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
837 obj_orig=user_moved_orig,
839 expected_metadata=deleted_metadata_dc1)
841 # trigger replication from DC2 to DC1
842 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
844 # check user info on DC1 - should be deleted user
845 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
846 obj_orig=user_moved_orig,
848 expected_metadata=deleted_metadata_dc1)
850 # trigger replication from DC1 to DC2, for cleanup
851 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
853 deleted_metadata_dc2 = [
854 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
855 (DRSUAPI_ATTID_cn, self.dc2_guid, 2),
856 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
857 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
858 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
859 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
860 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
861 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
862 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
863 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
864 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
865 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
866 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
867 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
868 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
869 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
870 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
871 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
872 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
873 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
874 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
875 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
876 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
877 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
878 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
880 # check user info on DC2 - should be deleted user
881 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
882 obj_orig=user_moved_orig,
884 expected_metadata=deleted_metadata_dc2)
887 def test_ReplicateMoveObject3b(self):
888 """Verifies how a moved container with a user inside is replicated between two DCs.
889 This test should verify that:
890 - the OU is created on DC1
891 - the OU is renamed on DC1
892 - We verify that after replication,
893 that the user has the correct DN (under OU2).
896 # work-out unique username to test with
897 username = self._make_username()
900 self.ldb_dc1.newuser(username=username,
901 userou="ou=%s" % self.ou1_dn.get_component_value(0),
902 password=None, setpassword=False)
903 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
905 expression="(samAccountName=%s)" % username,
906 attrs=["*", "parentGUID"])
907 self.assertEquals(len(ldb_res), 1)
908 user_orig = ldb_res[0]
909 user_dn = ldb_res[0]["dn"]
911 # check user info on DC1
912 print "Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0]))
914 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
915 (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
916 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
917 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
918 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
919 (DRSUAPI_ATTID_name, self.dc1_guid, 1),
920 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
921 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
922 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
923 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
924 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
925 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
926 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
927 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
928 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
929 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
930 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
931 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
932 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
933 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
934 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
935 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
937 self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
938 obj_orig=user_orig, is_deleted=False,
939 expected_metadata=initial_metadata)
942 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
943 new_dn.add_base(self.ou2_dn)
944 self.ldb_dc1.rename(user_dn, new_dn)
945 ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
947 expression="(samAccountName=%s)" % username,
948 attrs=["*", "parentGUID"])
949 self.assertEquals(len(ldb_res), 1)
951 user_moved_orig = ldb_res[0]
952 user_moved_dn = ldb_res[0]["dn"]
954 # trigger replication from DC2 (Which has never seen the object) to DC1
955 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
957 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
958 (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
959 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
960 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
961 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
962 (DRSUAPI_ATTID_name, self.dc1_guid, 2),
963 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
964 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
965 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
966 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
967 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
968 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
969 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
970 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
971 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
972 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
973 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
974 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
975 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
976 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
977 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
978 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
980 # check user info on DC1 after rename - should be valid user
981 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
982 obj_orig=user_moved_orig,
984 expected_metadata=moved_metadata)
987 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
988 deleted_metadata_dc1 = [
989 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
990 (DRSUAPI_ATTID_cn, self.dc1_guid, 2),
991 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
992 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
993 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
994 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
995 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
996 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
997 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
998 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
999 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
1000 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
1001 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
1002 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
1003 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
1004 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
1005 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
1006 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
1007 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
1008 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
1009 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
1010 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
1011 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
1012 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
1013 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
1015 # check user info on DC1 - should be deleted user
1016 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
1017 obj_orig=user_moved_orig,
1019 expected_metadata=deleted_metadata_dc1)
1021 # trigger replication from DC2 to DC1
1022 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1024 # check user info on DC1 - should be deleted user
1025 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
1026 obj_orig=user_moved_orig,
1028 expected_metadata=deleted_metadata_dc1)
1030 # trigger replication from DC1 to DC2, for cleanup
1031 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1033 deleted_metadata_dc2 = [
1034 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
1035 (DRSUAPI_ATTID_cn, self.dc2_guid, 1),
1036 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
1037 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
1038 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
1039 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
1040 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
1041 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
1042 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
1043 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
1044 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
1045 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
1046 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
1047 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
1048 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
1049 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
1050 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
1051 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
1052 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
1053 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
1054 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
1055 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
1056 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
1057 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
1058 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
1060 # check user info on DC2 - should be deleted user
1061 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
1062 obj_orig=user_moved_orig,
1064 expected_metadata=deleted_metadata_dc2)
1067 def test_ReplicateMoveObject4(self):
1068 """Verifies how a moved container with a user inside is replicated between two DCs.
1069 This test should verify that:
1070 - the OU is replicated properly
1071 - the user is modified on DC2
1072 - the OU is renamed on DC1
1073 - We verify that after replication DC1 -> DC2,
1074 that the user has the correct DN (under OU2), and the description
1077 # work-out unique username to test with
1078 username = self._make_username()
1080 # create user on DC1
1081 self.ldb_dc1.newuser(username=username,
1082 userou="ou=%s" % self.ou1_dn.get_component_value(0),
1083 password=None, setpassword=False)
1084 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
1085 scope=SCOPE_SUBTREE,
1086 expression="(samAccountName=%s)" % username,
1087 attrs=["*", "parentGUID"])
1088 self.assertEquals(len(ldb_res), 1)
1089 user_orig = ldb_res[0]
1090 user_dn = ldb_res[0]["dn"]
1092 # check user info on DC1
1093 print "Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0]))
1094 initial_metadata = [
1095 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
1096 (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
1097 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
1098 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
1099 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
1100 (DRSUAPI_ATTID_name, self.dc1_guid, 1),
1101 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
1102 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
1103 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
1104 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
1105 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
1106 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
1107 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
1108 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
1109 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
1110 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
1111 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
1112 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
1113 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
1114 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
1115 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
1116 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
1118 self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
1119 obj_orig=user_orig, is_deleted=False,
1120 expected_metadata=initial_metadata)
1122 # trigger replication from DC1 to DC2
1123 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1125 initial_metadata_dc2 = [
1126 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
1127 (DRSUAPI_ATTID_cn, self.dc2_guid, 1),
1128 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
1129 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
1130 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
1131 (DRSUAPI_ATTID_name, self.dc1_guid, 1),
1132 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
1133 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
1134 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
1135 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
1136 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
1137 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
1138 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
1139 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
1140 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
1141 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
1142 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
1143 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
1144 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
1145 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
1146 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
1147 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
1149 # check user info on DC2 - should still be valid user
1150 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
1151 obj_orig=user_orig, is_deleted=False,
1152 expected_metadata=initial_metadata_dc2)
1154 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
1155 new_dn.add_base(self.ou2_dn)
1156 self.ldb_dc1.rename(user_dn, new_dn)
1157 ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
1158 scope=SCOPE_SUBTREE,
1159 expression="(samAccountName=%s)" % username,
1160 attrs=["*", "parentGUID"])
1161 self.assertEquals(len(ldb_res), 1)
1163 user_moved_orig = ldb_res[0]
1164 user_moved_dn = ldb_res[0]["dn"]
1167 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
1168 (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
1169 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
1170 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
1171 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
1172 (DRSUAPI_ATTID_name, self.dc1_guid, 2),
1173 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
1174 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
1175 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
1176 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
1177 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
1178 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
1179 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
1180 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
1181 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
1182 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
1183 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
1184 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
1185 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
1186 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
1187 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
1188 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
1190 # check user info on DC1 after rename - should be valid user
1191 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
1192 obj_orig=user_moved_orig,
1194 expected_metadata=moved_metadata)
1196 # Modify description on DC2. This triggers a replication, but
1197 # not of 'name' and so a bug in Samba regarding the DN.
1200 msg["description"] = ldb.MessageElement("User Description", ldb.FLAG_MOD_REPLACE, "description")
1201 self.ldb_dc2.modify(msg)
1203 modified_metadata = [
1204 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
1205 (DRSUAPI_ATTID_cn, self.dc2_guid, 1),
1206 (DRSUAPI_ATTID_description, self.dc2_guid, 1),
1207 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
1208 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
1209 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
1210 (DRSUAPI_ATTID_name, self.dc1_guid, 1),
1211 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
1212 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
1213 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
1214 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
1215 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
1216 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
1217 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
1218 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
1219 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
1220 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
1221 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
1222 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
1223 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
1224 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
1225 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
1226 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
1228 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
1231 expected_metadata=modified_metadata)
1233 # trigger replication from DC1 to DC2
1234 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1236 modified_renamed_metadata = [
1237 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
1238 (DRSUAPI_ATTID_cn, self.dc2_guid, 2),
1239 (DRSUAPI_ATTID_description, self.dc2_guid, 1),
1240 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
1241 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
1242 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
1243 (DRSUAPI_ATTID_name, self.dc1_guid, 2),
1244 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
1245 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
1246 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
1247 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
1248 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
1249 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
1250 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
1251 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
1252 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
1253 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
1254 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
1255 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
1256 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
1257 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
1258 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
1259 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
1261 # check user info on DC2 - should still be valid user
1262 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
1263 obj_orig=user_moved_orig,
1265 expected_metadata=modified_renamed_metadata)
1267 self.assertTrue("description" in user_cur)
1269 # delete user on DC1
1270 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
1271 deleted_metadata_dc1 = [
1272 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
1273 (DRSUAPI_ATTID_cn, self.dc1_guid, 2),
1274 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
1275 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
1276 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
1277 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
1278 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
1279 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
1280 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
1281 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
1282 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
1283 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
1284 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
1285 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
1286 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
1287 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
1288 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
1289 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
1290 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
1291 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
1292 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
1293 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
1294 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
1295 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
1296 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
1298 # check user info on DC1 - should be deleted user
1299 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
1300 obj_orig=user_moved_orig,
1302 expected_metadata=deleted_metadata_dc1)
1304 # trigger replication from DC2 to DC1
1305 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1306 # check user info on DC2 - should still be valid user
1307 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
1308 obj_orig=user_moved_orig,
1310 expected_metadata=modified_renamed_metadata)
1312 self.assertTrue("description" in user_cur)
1314 deleted_metadata_dc1 = [
1315 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
1316 (DRSUAPI_ATTID_cn, self.dc1_guid, 2),
1317 (DRSUAPI_ATTID_description, self.dc1_guid, 2),
1318 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
1319 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
1320 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
1321 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
1322 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
1323 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
1324 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
1325 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
1326 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
1327 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
1328 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
1329 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
1330 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
1331 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
1332 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
1333 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
1334 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
1335 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
1336 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
1337 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
1338 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
1339 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
1340 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
1343 # check user info on DC1 - should be deleted user
1344 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
1345 obj_orig=user_moved_orig,
1347 expected_metadata=deleted_metadata_dc1)
1349 self.assertFalse("description" in user_cur)
1351 # trigger replication from DC1 to DC2, for cleanup
1352 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1354 deleted_metadata_dc2 = [
1355 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
1356 (DRSUAPI_ATTID_cn, self.dc2_guid, 3),
1357 (DRSUAPI_ATTID_description, self.dc1_guid, 2),
1358 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
1359 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
1360 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
1361 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
1362 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
1363 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
1364 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
1365 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
1366 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
1367 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
1368 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
1369 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
1370 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
1371 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
1372 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
1373 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
1374 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
1375 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
1376 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
1377 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
1378 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
1379 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
1380 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
1382 # check user info on DC2 - should be deleted user
1383 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
1384 obj_orig=user_moved_orig,
1386 expected_metadata=deleted_metadata_dc2)
1388 self.assertFalse("description" in user_cur)
1390 def test_ReplicateMoveObject5(self):
1391 """Verifies how a moved container with a user inside is replicated between two DCs.
1392 This test should verify that:
1393 - the OU is replicated properly
1394 - the user is modified on DC2
1395 - the OU is renamed on DC1
1396 - We verify that after replication DC2 -> DC1,
1397 that the user has the correct DN (under OU2), and the description
1400 # work-out unique username to test with
1401 username = self._make_username()
1403 # create user on DC1
1404 self.ldb_dc1.newuser(username=username,
1405 userou="ou=%s" % self.ou1_dn.get_component_value(0),
1406 password=None, setpassword=False)
1407 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
1408 scope=SCOPE_SUBTREE,
1409 expression="(samAccountName=%s)" % username,
1410 attrs=["*", "parentGUID"])
1411 self.assertEquals(len(ldb_res), 1)
1412 user_orig = ldb_res[0]
1413 user_dn = ldb_res[0]["dn"]
1415 # trigger replication from DC1 to DC2
1416 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1417 # check user info on DC2 - should still be valid user
1418 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=False)
1420 # check user info on DC1
1421 print "Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0]))
1422 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=False)
1424 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
1425 new_dn.add_base(self.ou2_dn)
1426 self.ldb_dc1.rename(user_dn, new_dn)
1427 ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
1428 scope=SCOPE_SUBTREE,
1429 expression="(samAccountName=%s)" % username,
1430 attrs=["*", "parentGUID"])
1431 self.assertEquals(len(ldb_res), 1)
1433 user_moved_orig = ldb_res[0]
1434 user_moved_dn = ldb_res[0]["dn"]
1436 # Modify description on DC2. This triggers a replication, but
1437 # not of 'name' and so a bug in Samba regarding the DN.
1440 msg["description"] = ldb.MessageElement("User Description", ldb.FLAG_MOD_REPLACE, "description")
1441 self.ldb_dc2.modify(msg)
1443 # trigger replication from DC2 to DC1
1444 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1445 # check user info on DC1 - should still be valid user
1446 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_moved_orig, is_deleted=False)
1447 self.assertTrue("description" in user_cur)
1449 # trigger replication from DC1 to DC2
1450 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1451 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
1452 self.assertTrue("description" in user_cur)
1454 # delete user on DC2
1455 self.ldb_dc2.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
1456 # trigger replication from DC2 to DC1 for cleanup
1457 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1459 # check user info on DC1 - should be deleted user
1460 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_moved_orig, is_deleted=True)
1461 self.assertFalse("description" in user_cur)
1464 def test_ReplicateMoveObject6(self):
1465 """Verifies how a moved container is replicated between two DCs.
1466 This test should verify that:
1467 - the OU1 is replicated properly
1468 - the OU1 is modified on DC2
1469 - the OU1 is renamed on DC1
1470 - We verify that after replication DC1 -> DC2,
1471 that the OU1 has the correct DN (under OU2), and the description
1474 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
1476 attrs=["*", "parentGUID"])
1477 self.assertEquals(len(ldb_res), 1)
1478 ou_orig = ldb_res[0]
1479 ou_dn = ldb_res[0]["dn"]
1481 # check user info on DC1
1482 print "Testing for %s with GUID %s" % (self.ou1_dn, self._GUID_string(ou_orig["objectGUID"][0]))
1483 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1485 # trigger replication from DC1 to DC2
1486 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1487 # check user info on DC2 - should still be valid user
1488 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1490 new_dn = ldb.Dn(self.ldb_dc1, "OU=%s" % self.ou1_dn.get_component_value(0))
1491 new_dn.add_base(self.ou2_dn)
1492 self.ldb_dc1.rename(ou_dn, new_dn)
1493 ldb_res = self.ldb_dc1.search(base=new_dn,
1495 attrs=["*", "parentGUID"])
1496 self.assertEquals(len(ldb_res), 1)
1498 ou_moved_orig = ldb_res[0]
1499 ou_moved_dn = ldb_res[0]["dn"]
1501 # Modify description on DC2. This triggers a replication, but
1502 # not of 'name' and so a bug in Samba regarding the DN.
1505 msg["description"] = ldb.MessageElement("OU Description", ldb.FLAG_MOD_REPLACE, "description")
1506 self.ldb_dc2.modify(msg)
1508 # trigger replication from DC1 to DC2
1509 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1510 # check user info on DC2 - should still be valid user
1511 ou_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=ou_moved_orig, is_deleted=False)
1512 self.assertTrue("description" in ou_cur)
1515 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(ou_orig["objectGUID"][0]))
1516 # trigger replication from DC2 to DC1
1517 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1518 # check user info on DC2 - should be deleted user
1519 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_moved_orig, is_deleted=True)
1520 self.assertFalse("description" in ou_cur)
1522 # trigger replication from DC1 to DC2, for cleanup
1523 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1525 # check user info on DC2 - should be deleted user
1526 ou_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=ou_moved_orig, is_deleted=True)
1527 self.assertFalse("description" in ou_cur)
1530 def test_ReplicateMoveObject7(self):
1531 """Verifies how a moved container is replicated between two DCs.
1532 This test should verify that:
1533 - the OU1 is replicated properly
1534 - the OU1 is modified on DC2
1535 - the OU1 is renamed on DC1 to be under OU2
1536 - We verify that after replication DC2 -> DC1,
1537 that the OU1 has the correct DN (under OU2), and the description
1540 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
1542 attrs=["*", "parentGUID"])
1543 self.assertEquals(len(ldb_res), 1)
1544 ou_orig = ldb_res[0]
1545 ou_dn = ldb_res[0]["dn"]
1547 # check user info on DC1
1548 print "Testing for %s with GUID %s" % (self.ou1_dn, self._GUID_string(ou_orig["objectGUID"][0]))
1549 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1551 # trigger replication from DC1 to DC2
1552 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1553 # check user info on DC2 - should still be valid user
1554 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1556 new_dn = ldb.Dn(self.ldb_dc1, "OU=%s" % self.ou1_dn.get_component_value(0))
1557 new_dn.add_base(self.ou2_dn)
1558 self.ldb_dc1.rename(ou_dn, new_dn)
1559 ldb_res = self.ldb_dc1.search(base=new_dn,
1561 attrs=["*", "parentGUID"])
1562 self.assertEquals(len(ldb_res), 1)
1564 ou_moved_orig = ldb_res[0]
1565 ou_moved_dn = ldb_res[0]["dn"]
1567 # Modify description on DC2. This triggers a replication, but
1568 # not of 'name' and so a bug in Samba regarding the DN.
1571 msg["description"] = ldb.MessageElement("OU Description", ldb.FLAG_MOD_REPLACE, "description")
1572 self.ldb_dc2.modify(msg)
1574 # trigger replication from DC2 to DC1
1575 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1576 # check user info on DC1 - should still be valid user
1577 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_moved_orig, is_deleted=False)
1578 self.assertTrue("description" in ou_cur)
1581 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(ou_orig["objectGUID"][0]))
1582 # trigger replication from DC2 to DC1
1583 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1584 # check user info on DC2 - should be deleted user
1585 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_moved_orig, is_deleted=True)
1586 self.assertFalse("description" in ou_cur)
1588 # trigger replication from DC1 to DC2, for cleanup
1589 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1591 # check user info on DC2 - should be deleted user
1592 ou_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=ou_moved_orig, is_deleted=True)
1593 self.assertFalse("description" in ou_cur)
1596 def test_ReplicateMoveObject8(self):
1597 """Verifies how a moved container is replicated between two DCs.
1598 This test should verify that:
1599 - the OU1 is replicated properly
1600 - the OU1 is modified on DC2
1601 - the OU1 is renamed on DC1 to OU1-renamed
1602 - We verify that after replication DC1 -> DC2,
1603 that the OU1 has the correct DN (OU1-renamed), and the description
1606 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
1608 attrs=["*", "parentGUID"])
1609 self.assertEquals(len(ldb_res), 1)
1610 ou_orig = ldb_res[0]
1611 ou_dn = ldb_res[0]["dn"]
1613 # check user info on DC1
1614 print "Testing for %s with GUID %s" % (self.ou1_dn, self._GUID_string(ou_orig["objectGUID"][0]))
1615 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1617 # trigger replication from DC1 to DC2
1618 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1619 # check user info on DC2 - should still be valid user
1620 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1622 new_dn = ldb.Dn(self.ldb_dc1, "OU=%s-renamed" % self.ou1_dn.get_component_value(0))
1623 new_dn.add_base(self.ou1_dn.parent())
1624 self.ldb_dc1.rename(ou_dn, new_dn)
1625 ldb_res = self.ldb_dc1.search(base=new_dn,
1627 attrs=["*", "parentGUID"])
1628 self.assertEquals(len(ldb_res), 1)
1630 ou_moved_orig = ldb_res[0]
1631 ou_moved_dn = ldb_res[0]["dn"]
1633 # Modify description on DC2. This triggers a replication, but
1634 # not of 'name' and so a bug in Samba regarding the DN.
1637 msg["description"] = ldb.MessageElement("OU Description", ldb.FLAG_MOD_REPLACE, "description")
1638 self.ldb_dc2.modify(msg)
1640 # trigger replication from DC1 to DC2
1641 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1642 # check user info on DC2 - should still be valid user
1643 ou_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=ou_moved_orig, is_deleted=False)
1644 self.assertTrue("description" in ou_cur)
1647 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(ou_orig["objectGUID"][0]))
1648 # trigger replication from DC2 to DC1
1649 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1650 # check user info on DC2 - should be deleted user
1651 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_moved_orig, is_deleted=True)
1652 self.assertFalse("description" in ou_cur)
1654 # trigger replication from DC1 to DC2, for cleanup
1655 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1657 # check user info on DC2 - should be deleted user
1658 ou_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=ou_moved_orig, is_deleted=True)
1659 self.assertFalse("description" in ou_cur)
1662 def test_ReplicateMoveObject9(self):
1663 """Verifies how a moved container is replicated between two DCs.
1664 This test should verify that:
1665 - the OU1 is replicated properly
1666 - the OU1 is modified on DC2
1667 - the OU1 is renamed on DC1 to be under OU2
1668 - the OU1 is renamed on DC1 to OU1-renamed
1669 - We verify that after replication DC1 -> DC2,
1670 that the OU1 has the correct DN (OU1-renamed), and the description
1673 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
1675 attrs=["*", "parentGUID"])
1676 self.assertEquals(len(ldb_res), 1)
1677 ou_orig = ldb_res[0]
1678 ou_dn = ldb_res[0]["dn"]
1680 # check user info on DC1
1681 print "Testing for %s with GUID %s" % (self.ou1_dn, self._GUID_string(ou_orig["objectGUID"][0]))
1682 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1684 # trigger replication from DC1 to DC2
1685 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1686 # check user info on DC2 - should still be valid user
1687 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1689 new_dn = ldb.Dn(self.ldb_dc1, "OU=%s-renamed" % self.ou1_dn.get_component_value(0))
1690 new_dn.add_base(self.ou1_dn.parent())
1691 self.ldb_dc1.rename(ou_dn, new_dn)
1692 ldb_res = self.ldb_dc1.search(base=new_dn,
1694 attrs=["*", "parentGUID"])
1695 self.assertEquals(len(ldb_res), 1)
1697 ou_moved_orig = ldb_res[0]
1698 ou_moved_dn = ldb_res[0]["dn"]
1700 # Modify description on DC2. This triggers a replication, but
1701 # not of 'name' and so a bug in Samba regarding the DN.
1704 msg["description"] = ldb.MessageElement("OU Description", ldb.FLAG_MOD_REPLACE, "description")
1705 self.ldb_dc2.modify(msg)
1707 # trigger replication from DC2 to DC1
1708 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1709 # check user info on DC1 - should still be valid user
1710 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_moved_orig, is_deleted=False)
1711 self.assertTrue("description" in ou_cur)
1714 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(ou_orig["objectGUID"][0]))
1715 # trigger replication from DC2 to DC1
1716 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1717 # check user info on DC2 - should be deleted user
1718 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_moved_orig, is_deleted=True)
1719 self.assertFalse("description" in ou_cur)
1721 # trigger replication from DC1 to DC2, for cleanup
1722 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1724 # check user info on DC2 - should be deleted user
1725 ou_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=ou_moved_orig, is_deleted=True)
1726 self.assertFalse("description" in ou_cur)
1729 def test_ReplicateMoveObject10(self):
1730 """Verifies how a moved container is replicated between two DCs.
1731 This test should verify that:
1732 - the OU1 is replicated properly
1733 - the OU1 is modified on DC2
1734 - the OU1 is deleted on DC1
1735 - We verify that after replication DC1 -> DC2,
1736 that the OU1 is deleted, and the description has gone away
1739 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
1741 attrs=["*", "parentGUID"])
1742 self.assertEquals(len(ldb_res), 1)
1743 ou_orig = ldb_res[0]
1744 ou_dn = ldb_res[0]["dn"]
1746 # check user info on DC1
1747 print "Testing for %s with GUID %s" % (self.ou1_dn, self._GUID_string(ou_orig["objectGUID"][0]))
1748 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1750 # trigger replication from DC1 to DC2
1751 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1752 # check user info on DC2 - should still be valid user
1753 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1755 # Modify description on DC2. This triggers a replication, but
1756 # not of 'name' and so a bug in Samba regarding the DN.
1759 msg["description"] = ldb.MessageElement("OU Description", ldb.FLAG_MOD_REPLACE, "description")
1760 self.ldb_dc2.modify(msg)
1763 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(ou_orig["objectGUID"][0]))
1764 # trigger replication from DC1 to DC2
1765 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1766 # check user info on DC2 - should be deleted OU
1767 ou_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=ou_orig, is_deleted=True)
1768 self.assertFalse("description" in ou_cur)
1770 # trigger replication from DC1 to DC2, for cleanup
1771 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1773 # check user info on DC2 - should be deleted OU
1774 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=True)
1775 self.assertFalse("description" in ou_cur)
1778 def test_ReplicateMoveObject11(self):
1779 """Verifies how a moved container is replicated between two DCs.
1780 This test should verify that:
1781 - the OU1 is replicated properly
1782 - the OU1 is modified on DC2
1783 - the OU1 is deleted on DC1
1784 - We verify that after replication DC2 -> DC1,
1785 that the OU1 is deleted, and the description has gone away
1788 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
1790 attrs=["*", "parentGUID"])
1791 self.assertEquals(len(ldb_res), 1)
1792 ou_orig = ldb_res[0]
1793 ou_dn = ldb_res[0]["dn"]
1795 # check user info on DC1
1796 print "Testing for %s with GUID %s" % (self.ou1_dn, self._GUID_string(ou_orig["objectGUID"][0]))
1797 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1799 # trigger replication from DC1 to DC2
1800 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1801 # check user info on DC2 - should still be valid user
1802 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1804 # Modify description on DC2. This triggers a replication, but
1805 # not of 'name' and so a bug in Samba regarding the DN.
1808 msg["description"] = ldb.MessageElement("OU Description", ldb.FLAG_MOD_REPLACE, "description")
1809 self.ldb_dc2.modify(msg)
1812 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(ou_orig["objectGUID"][0]))
1813 # trigger replication from DC2 to DC1
1814 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1815 # check user info on DC2 - should be deleted OU
1816 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=True)
1817 self.assertFalse("description" in ou_cur)
1819 # trigger replication from DC1 to DC2, for cleanup
1820 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1822 # check user info on DC2 - should be deleted OU
1823 ou_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=ou_orig, is_deleted=True)
1824 self.assertFalse("description" in ou_cur)
1828 class DrsMoveBetweenTreeOfObjectTestCase(drs_base.DrsBaseTestCase):
1831 super(DrsMoveBetweenTreeOfObjectTestCase, self).setUp()
1832 # disable automatic replication temporary
1833 self._disable_inbound_repl(self.dnsname_dc1)
1834 self._disable_inbound_repl(self.dnsname_dc2)
1836 # make sure DCs are synchronized before the test
1837 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1838 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1840 self.ou1_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU1")
1841 self.ou1_dn.add_base(self.ldb_dc1.get_default_basedn())
1843 self.ou1["dn"] = self.ou1_dn
1844 self.ou1["objectclass"] = "organizationalUnit"
1845 self.ou1["ou"] = self.ou1_dn.get_component_value(0)
1847 self.ou2_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU2,OU=DrsOU1")
1848 self.ou2_dn.add_base(self.ldb_dc1.get_default_basedn())
1850 self.ou2["dn"] = self.ou2_dn
1851 self.ou2["objectclass"] = "organizationalUnit"
1852 self.ou2["ou"] = self.ou2_dn.get_component_value(0)
1854 self.ou2b_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU2B,OU=DrsOU1")
1855 self.ou2b_dn.add_base(self.ldb_dc1.get_default_basedn())
1857 self.ou2b["dn"] = self.ou2b_dn
1858 self.ou2b["objectclass"] = "organizationalUnit"
1859 self.ou2b["ou"] = self.ou2b_dn.get_component_value(0)
1861 self.ou2c_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU2C,OU=DrsOU1")
1862 self.ou2c_dn.add_base(self.ldb_dc1.get_default_basedn())
1864 self.ou3_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU3,OU=DrsOU2,OU=DrsOU1")
1865 self.ou3_dn.add_base(self.ldb_dc1.get_default_basedn())
1867 self.ou3["dn"] = self.ou3_dn
1868 self.ou3["objectclass"] = "organizationalUnit"
1869 self.ou3["ou"] = self.ou3_dn.get_component_value(0)
1871 self.ou4_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU4,OU=DrsOU3,OU=DrsOU2,OU=DrsOU1")
1872 self.ou4_dn.add_base(self.ldb_dc1.get_default_basedn())
1874 self.ou4["dn"] = self.ou4_dn
1875 self.ou4["objectclass"] = "organizationalUnit"
1876 self.ou4["ou"] = self.ou4_dn.get_component_value(0)
1878 self.ou5_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU5,OU=DrsOU4,OU=DrsOU3,OU=DrsOU2,OU=DrsOU1")
1879 self.ou5_dn.add_base(self.ldb_dc1.get_default_basedn())
1881 self.ou5["dn"] = self.ou5_dn
1882 self.ou5["objectclass"] = "organizationalUnit"
1883 self.ou5["ou"] = self.ou5_dn.get_component_value(0)
1885 self.ou6_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU6,OU=DrsOU5,OU=DrsOU4,OU=DrsOU3,OU=DrsOU2,OU=DrsOU1")
1886 self.ou6_dn.add_base(self.ldb_dc1.get_default_basedn())
1888 self.ou6["dn"] = self.ou6_dn
1889 self.ou6["objectclass"] = "organizationalUnit"
1890 self.ou6["ou"] = self.ou6_dn.get_component_value(0)
1894 self.ldb_dc1.delete(self.ou1_dn, ["tree_delete:1"])
1895 self._enable_inbound_repl(self.dnsname_dc1)
1896 self._enable_inbound_repl(self.dnsname_dc2)
1897 super(DrsMoveBetweenTreeOfObjectTestCase, self).tearDown()
1899 def _make_username(self):
1900 return "DrsTreeU_" + time.strftime("%s", time.gmtime())
1902 # now also used to check the group
1903 def _check_obj(self, sam_ldb, obj_orig, is_deleted):
1904 # search the user by guid as it may be deleted
1905 guid_str = self._GUID_string(obj_orig["objectGUID"][0])
1906 res = sam_ldb.search(base='<GUID=%s>' % guid_str,
1907 controls=["show_deleted:1"],
1908 attrs=["*", "parentGUID"])
1909 self.assertEquals(len(res), 1)
1911 cn_orig = obj_orig["cn"][0]
1912 cn_cur = user_cur["cn"][0]
1913 name_orig = obj_orig["name"][0]
1914 name_cur = user_cur["name"][0]
1915 dn_orig = obj_orig["dn"]
1916 dn_cur = user_cur["dn"]
1917 # now check properties of the user
1919 self.assertTrue("isDeleted" in user_cur)
1920 self.assertEquals(cn_cur.split('\n')[0], cn_orig)
1921 self.assertEquals(name_cur.split('\n')[0], name_orig)
1922 self.assertEquals(dn_cur.get_rdn_value().split('\n')[0],
1923 dn_orig.get_rdn_value())
1924 self.assertEqual(name_cur, cn_cur)
1926 self.assertFalse("isDeleted" in user_cur)
1927 self.assertEquals(cn_cur, cn_orig)
1928 self.assertEquals(name_cur, name_orig)
1929 self.assertEquals(dn_cur, dn_orig)
1930 self.assertEqual(name_cur, cn_cur)
1931 self.assertEqual(name_cur, user_cur.dn.get_rdn_value())
1936 def test_ReplicateMoveInTree1(self):
1937 """Verifies how an object is replicated between two DCs.
1938 This test should verify that:
1939 - a complex OU tree can be replicated correctly
1940 - the user is in the correct spot (renamed into) within the tree
1943 # work-out unique username to test with
1944 username = self._make_username()
1946 self.ldb_dc1.add(self.ou1)
1948 # create user on DC1
1949 self.ldb_dc1.newuser(username=username,
1950 userou="ou=%s" % self.ou1_dn.get_component_value(0),
1951 password=None, setpassword=False)
1952 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
1953 scope=SCOPE_SUBTREE,
1954 expression="(samAccountName=%s)" % username)
1955 self.assertEquals(len(ldb_res), 1)
1956 user_orig = ldb_res[0]
1957 user_dn = ldb_res[0]["dn"]
1959 # check user info on DC1
1960 print "Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0]))
1961 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=False)
1963 self.ldb_dc1.add(self.ou2)
1964 self.ldb_dc1.add(self.ou3)
1965 self.ldb_dc1.add(self.ou4)
1966 self.ldb_dc1.add(self.ou5)
1968 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
1969 new_dn.add_base(self.ou5_dn)
1970 self.ldb_dc1.rename(user_dn, new_dn)
1971 ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
1972 scope=SCOPE_SUBTREE,
1973 expression="(samAccountName=%s)" % username)
1974 self.assertEquals(len(ldb_res), 1)
1976 user_moved_orig = ldb_res[0]
1977 user_moved_dn = ldb_res[0]["dn"]
1979 # trigger replication from DC1 to DC2
1980 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1981 # check user info on DC2 - should be valid user
1982 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
1984 # delete user on DC1
1985 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
1987 # trigger replication from DC1 to DC2, for cleanup
1988 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1991 def test_ReplicateMoveInTree2(self):
1992 """Verifies how an object is replicated between two DCs.
1993 This test should verify that:
1994 - a complex OU tree can be replicated correctly
1995 - the user is in the correct spot (renamed into) within the tree
1997 - that a rename back works correctly, and is replicated
1999 # work-out unique username to test with
2000 username = self._make_username()
2002 self.ldb_dc1.add(self.ou1)
2004 # create user on DC1
2005 self.ldb_dc1.newuser(username=username,
2006 userou="ou=%s" % self.ou1_dn.get_component_value(0),
2007 password=None, setpassword=False)
2008 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2009 scope=SCOPE_SUBTREE,
2010 expression="(samAccountName=%s)" % username)
2011 self.assertEquals(len(ldb_res), 1)
2012 user_orig = ldb_res[0]
2013 user_dn = ldb_res[0]["dn"]
2015 # check user info on DC1
2016 print "Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0]))
2017 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=False)
2019 self.ldb_dc1.add(self.ou2)
2020 self.ldb_dc1.add(self.ou2b)
2021 self.ldb_dc1.add(self.ou3)
2023 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
2024 new_dn.add_base(self.ou3_dn)
2025 self.ldb_dc1.rename(user_dn, new_dn)
2027 new_dn3 = ldb.Dn(self.ldb_dc1, "OU=%s" % self.ou3_dn.get_component_value(0))
2028 new_dn3.add_base(self.ou2b_dn)
2029 self.ldb_dc1.rename(self.ou3_dn, new_dn3)
2031 ldb_res = self.ldb_dc1.search(base=new_dn3,
2032 scope=SCOPE_SUBTREE,
2033 expression="(samAccountName=%s)" % username)
2034 self.assertEquals(len(ldb_res), 1)
2036 user_moved_orig = ldb_res[0]
2037 user_moved_dn = ldb_res[0]["dn"]
2039 # trigger replication from DC1 to DC2
2040 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2041 # check user info on DC2 - should be valid user
2042 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
2045 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
2046 new_dn.add_base(self.ou1_dn)
2047 self.ldb_dc1.rename(user_moved_dn, new_dn)
2049 # Modify description on DC2
2051 msg.dn = user_moved_dn
2052 msg["description"] = ldb.MessageElement("User Description", ldb.FLAG_MOD_REPLACE, "description")
2053 self.ldb_dc2.modify(msg)
2055 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2056 scope=SCOPE_SUBTREE,
2057 expression="(samAccountName=%s)" % username)
2058 self.assertEquals(len(ldb_res), 1)
2060 user_moved_orig = ldb_res[0]
2061 user_moved_dn = ldb_res[0]["dn"]
2063 # trigger replication from DC1 to DC2
2064 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2065 # check user info on DC2 - should be valid user
2066 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
2067 self.assertTrue("description" in user_cur)
2069 # delete user on DC1
2070 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
2072 # trigger replication from DC2 to DC1
2073 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
2074 # check user info on DC1 - should be deleted user
2075 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_moved_orig, is_deleted=True)
2076 self.assertFalse("description" in user_cur)
2078 # trigger replication from DC1 to DC2, for cleanup
2079 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2080 # check user info on DC2 - should be deleted user
2081 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=True)
2082 self.assertFalse("description" in user_cur)
2085 def test_ReplicateMoveInTree3(self):
2086 """Verifies how an object is replicated between two DCs.
2087 This test should verify that:
2088 - a complex OU tree can be replicated correctly
2089 - the user is in the correct spot (renamed into) within the tree
2091 - that a rename back works correctly, and is replicated
2093 # work-out unique username to test with
2094 username = self._make_username()
2096 self.ldb_dc1.add(self.ou1)
2098 # create user on DC1
2099 self.ldb_dc1.newuser(username=username,
2100 userou="ou=%s" % self.ou1_dn.get_component_value(0),
2101 password=None, setpassword=False)
2102 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2103 scope=SCOPE_SUBTREE,
2104 expression="(samAccountName=%s)" % username)
2105 self.assertEquals(len(ldb_res), 1)
2106 user_orig = ldb_res[0]
2107 user_dn = ldb_res[0]["dn"]
2109 # check user info on DC1
2110 print "Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0]))
2111 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=False)
2113 self.ldb_dc1.add(self.ou2)
2114 self.ldb_dc1.add(self.ou2b)
2115 self.ldb_dc1.add(self.ou3)
2117 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
2118 new_dn.add_base(self.ou3_dn)
2119 self.ldb_dc1.rename(user_dn, new_dn)
2121 new_dn3 = ldb.Dn(self.ldb_dc1, "OU=%s" % self.ou3_dn.get_component_value(0))
2122 new_dn3.add_base(self.ou2b_dn)
2123 self.ldb_dc1.rename(self.ou3_dn, new_dn3)
2125 ldb_res = self.ldb_dc1.search(base=new_dn3,
2126 scope=SCOPE_SUBTREE,
2127 expression="(samAccountName=%s)" % username)
2128 self.assertEquals(len(ldb_res), 1)
2130 user_moved_orig = ldb_res[0]
2131 user_moved_dn = ldb_res[0]["dn"]
2133 # trigger replication from DC1 to DC2
2134 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2135 # check user info on DC2 - should be valid user
2136 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
2138 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
2139 new_dn.add_base(self.ou2_dn)
2140 self.ldb_dc1.rename(user_moved_dn, new_dn)
2142 self.ldb_dc1.rename(self.ou2_dn, self.ou2c_dn)
2143 self.ldb_dc1.rename(self.ou2b_dn, self.ou2_dn)
2144 self.ldb_dc1.rename(self.ou2c_dn, self.ou2b_dn)
2146 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2147 scope=SCOPE_SUBTREE,
2148 expression="(samAccountName=%s)" % username,
2149 attrs=["*", "parentGUID"])
2150 self.assertEquals(len(ldb_res), 1)
2152 user_moved_orig = ldb_res[0]
2153 user_moved_dn = ldb_res[0]["dn"]
2155 # trigger replication from DC1 to DC2
2156 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2157 # check user info on DC2 - should be valid user
2158 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
2160 self.assertEquals(user_cur["parentGUID"], user_moved_orig["parentGUID"])
2162 # delete user on DC1
2163 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
2165 # trigger replication from DC1 to DC2, for cleanup
2166 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2169 def test_ReplicateMoveInTree3b(self):
2170 """Verifies how an object is replicated between two DCs.
2171 This test should verify that:
2172 - a complex OU tree can be replicated correctly
2173 - the user is in the correct spot (renamed into) within the tree
2175 - that a rename back works correctly, and is replicated
2176 - that a complex rename suffle, combined with unrelated changes to the object,
2177 is replicated correctly. The aim here is the send the objects out-of-order
2178 when sorted by usnChanged.
2179 - confirm that the OU tree and (in particular the user DN) is identical between
2180 the DCs once this has been replicated.
2182 # work-out unique username to test with
2183 username = self._make_username()
2185 self.ldb_dc1.add(self.ou1)
2187 # create user on DC1
2188 self.ldb_dc1.newuser(username=username,
2189 userou="ou=%s" % self.ou1_dn.get_component_value(0),
2190 password=None, setpassword=False)
2191 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2192 scope=SCOPE_SUBTREE,
2193 expression="(samAccountName=%s)" % username)
2194 self.assertEquals(len(ldb_res), 1)
2195 user_orig = ldb_res[0]
2196 user_dn = ldb_res[0]["dn"]
2198 # check user info on DC1
2199 print "Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0]))
2200 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=False)
2202 self.ldb_dc1.add(self.ou2)
2203 self.ldb_dc1.add(self.ou2b)
2204 self.ldb_dc1.add(self.ou3)
2206 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
2207 new_dn.add_base(self.ou2_dn)
2208 self.ldb_dc1.rename(user_dn, new_dn)
2210 ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
2211 scope=SCOPE_SUBTREE,
2212 expression="(samAccountName=%s)" % username)
2213 self.assertEquals(len(ldb_res), 1)
2215 user_moved_orig = ldb_res[0]
2216 user_moved_dn = ldb_res[0]["dn"]
2218 # trigger replication from DC1 to DC2
2219 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2220 # check user info on DC2 - should be valid user
2221 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
2225 msg["description"] = ldb.MessageElement("User Description", ldb.FLAG_MOD_REPLACE, "description")
2226 self.ldb_dc1.modify(msg)
2228 # The sleep(1) calls here ensure that the name objects get a
2229 # new 1-sec based timestamp, and so we select how the conflict
2230 # resolution resolves.
2231 self.ldb_dc1.rename(self.ou2_dn, self.ou2c_dn)
2233 self.ldb_dc1.rename(self.ou2b_dn, self.ou2_dn)
2235 self.ldb_dc1.rename(self.ou2c_dn, self.ou2b_dn)
2237 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
2238 new_dn.add_base(self.ou2_dn)
2239 self.ldb_dc1.rename('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]), new_dn)
2242 msg.dn = self.ou2_dn
2243 msg["description"] = ldb.MessageElement("OU2 Description", ldb.FLAG_MOD_REPLACE, "description")
2244 self.ldb_dc1.modify(msg)
2247 msg.dn = self.ou2b_dn
2248 msg["description"] = ldb.MessageElement("OU2b Description", ldb.FLAG_MOD_REPLACE, "description")
2249 self.ldb_dc1.modify(msg)
2251 ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
2252 scope=SCOPE_SUBTREE,
2253 expression="(samAccountName=%s)" % username,
2254 attrs=["*", "parentGUID"])
2255 self.assertEquals(len(ldb_res), 1)
2257 user_moved_orig = ldb_res[0]
2258 user_moved_dn = ldb_res[0]["dn"]
2260 # trigger replication from DC1 to DC2
2261 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2262 # check user info on DC2 - should be valid user
2263 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
2264 self.assertEquals(user_cur["parentGUID"][0], user_moved_orig["parentGUID"][0])
2266 # delete user on DC1
2267 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
2269 # trigger replication from DC1 to DC2, for cleanup
2270 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2273 def test_ReplicateMoveInTree4(self):
2274 """Verifies how an object is replicated between two DCs.
2275 This test should verify that:
2276 - an OU and user can be replicated correctly, even after a rename
2277 - The creation and rename of the OU has been combined with unrelated changes to the object,
2278 The aim here is the send the objects out-of-order when sorted by usnChanged.
2279 - That is, the OU will be sorted by usnChanged after the user that is within that OU.
2280 - That will cause the client to need to get the OU first, by use of the GET_ANC flag
2282 # work-out unique username to test with
2283 username = self._make_username()
2285 self.ldb_dc1.add(self.ou1)
2287 # create user on DC1
2288 self.ldb_dc1.newuser(username=username,
2289 userou="ou=%s" % self.ou1_dn.get_component_value(0),
2290 password=None, setpassword=False)
2291 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2292 scope=SCOPE_SUBTREE,
2293 expression="(samAccountName=%s)" % username)
2294 self.assertEquals(len(ldb_res), 1)
2295 user_orig = ldb_res[0]
2296 user_dn = ldb_res[0]["dn"]
2298 # check user info on DC1
2299 print "Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0]))
2300 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=False)
2302 self.ldb_dc1.add(self.ou2)
2304 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
2305 new_dn.add_base(self.ou2_dn)
2306 self.ldb_dc1.rename(user_dn, new_dn)
2309 msg.dn = self.ou2_dn
2310 msg["description"] = ldb.MessageElement("OU2 Description", ldb.FLAG_MOD_REPLACE, "description")
2311 self.ldb_dc1.modify(msg)
2313 ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
2314 scope=SCOPE_SUBTREE,
2315 expression="(samAccountName=%s)" % username)
2316 self.assertEquals(len(ldb_res), 1)
2318 user_moved_orig = ldb_res[0]
2319 user_moved_dn = ldb_res[0]["dn"]
2321 # trigger replication from DC1 to DC2
2322 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2323 # check user info on DC2 - should be valid user
2324 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
2326 # delete user on DC1
2327 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
2329 # trigger replication from DC1 to DC2, for cleanup
2330 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2333 def test_ReplicateAddInOU(self):
2334 """Verifies how an object is replicated between two DCs.
2335 This test should verify that:
2336 - an OU and user can be replicated correctly
2337 - The creation of the OU has been combined with unrelated changes to the object,
2338 The aim here is the send the objects out-of-order when sorted by usnChanged.
2339 - That is, the OU will be sorted by usnChanged after the user that is within that OU.
2340 - That will cause the client to need to get the OU first, by use of the GET_ANC flag
2342 # work-out unique username to test with
2343 username = self._make_username()
2345 self.ldb_dc1.add(self.ou1)
2347 # create user on DC1
2348 self.ldb_dc1.newuser(username=username,
2349 userou="ou=%s" % self.ou1_dn.get_component_value(0),
2350 password=None, setpassword=False)
2351 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2352 scope=SCOPE_SUBTREE,
2353 expression="(samAccountName=%s)" % username,
2354 attrs=["*", "parentGUID"])
2355 self.assertEquals(len(ldb_res), 1)
2356 user_orig = ldb_res[0]
2357 user_dn = ldb_res[0]["dn"]
2360 msg.dn = self.ou1_dn
2361 msg["description"] = ldb.MessageElement("OU1 Description", ldb.FLAG_MOD_REPLACE, "description")
2362 self.ldb_dc1.modify(msg)
2364 # trigger replication from DC1 to DC2
2365 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2366 # check user info on DC2 - should be valid user
2367 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_orig, is_deleted=False)
2369 self.assertEquals(user_cur["parentGUID"], user_orig["parentGUID"])
2371 # delete user on DC1
2372 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
2374 # trigger replication from DC1 to DC2, for cleanup
2375 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2378 def test_ReplicateAddInMovedOU(self):
2379 """Verifies how an object is replicated between two DCs.
2380 This test should verify that:
2381 - an OU and user can be replicated correctly
2382 - The creation of the OU has been combined with unrelated changes to the object,
2383 The aim here is the send the objects out-of-order when sorted by usnChanged.
2384 - That is, the OU will be sorted by usnChanged after the user that is within that OU.
2385 - That will cause the client to need to get the OU first, by use of the GET_ANC flag
2387 # work-out unique username to test with
2388 username = self._make_username()
2390 self.ldb_dc1.add(self.ou1)
2391 self.ldb_dc1.add(self.ou2)
2393 # create user on DC1
2394 self.ldb_dc1.newuser(username=username,
2395 userou="ou=%s" % self.ou1_dn.get_component_value(0),
2396 password=None, setpassword=False)
2397 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2398 scope=SCOPE_SUBTREE,
2399 expression="(samAccountName=%s)" % username,
2400 attrs=["*", "parentGUID"])
2401 self.assertEquals(len(ldb_res), 1)
2402 user_orig = ldb_res[0]
2403 user_dn = ldb_res[0]["dn"]
2405 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
2406 new_dn.add_base(self.ou2_dn)
2407 self.ldb_dc1.rename(user_dn, new_dn)
2409 self.ldb_dc1.rename(self.ou2_dn, self.ou2b_dn)
2411 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2412 scope=SCOPE_SUBTREE,
2413 expression="(samAccountName=%s)" % username,
2414 attrs=["*", "parentGUID"])
2415 self.assertEquals(len(ldb_res), 1)
2416 user_moved = ldb_res[0]
2417 user_moved_dn = ldb_res[0]["dn"]
2419 # trigger replication from DC1 to DC2
2420 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2421 # check user info on DC2 - should be valid user
2422 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved, is_deleted=False)
2424 self.assertEquals(user_cur["parentGUID"], user_moved["parentGUID"])
2426 # delete user on DC1
2427 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
2429 # trigger replication from DC1 to DC2, for cleanup
2430 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2433 def test_ReplicateAddInConflictOU_time(self):
2434 """Verifies how an object is replicated between two DCs, when created in an ambigious location
2435 This test should verify that:
2436 - Without replication, two conflicting objects can be created
2437 - force the conflict resolution algorithm so we know which copy will win
2438 (by sleeping while creating the objects, therefore increasing that timestamp on 'name')
2439 - confirm that the user object, created on DC1, ends up in the right place on DC2
2440 - therefore confirm that the conflict algorithm worked correctly, and that parentGUID was used.
2443 # work-out unique username to test with
2444 username = self._make_username()
2446 self.ldb_dc1.add(self.ou1)
2448 # create user on DC1
2449 self.ldb_dc1.newuser(username=username,
2450 userou="ou=%s" % self.ou1_dn.get_component_value(0),
2451 password=None, setpassword=False)
2452 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2453 scope=SCOPE_SUBTREE,
2454 expression="(samAccountName=%s)" % username,
2455 attrs=["*", "parentGUID"])
2456 self.assertEquals(len(ldb_res), 1)
2457 user_orig = ldb_res[0]
2458 user_dn = ldb_res[0]["dn"]
2460 # trigger replication from DC1 to DC2
2461 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2463 # Now create two, conflicting objects. This gives the user
2464 # object something to be under on both DCs.
2466 # We sleep between the two adds so that DC1 adds second, and
2467 # so wins the conflict resoution due to a later creation time
2468 # (modification timestamp on the name attribute).
2469 self.ldb_dc2.add(self.ou2)
2471 self.ldb_dc1.add(self.ou2)
2473 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
2474 new_dn.add_base(self.ou2_dn)
2475 self.ldb_dc1.rename(user_dn, new_dn)
2477 # Now that we have renamed the user (and so bumpted the
2478 # usnChanged), bump the value on the OUs.
2480 msg.dn = self.ou2_dn
2481 msg["description"] = ldb.MessageElement("OU2 Description", ldb.FLAG_MOD_REPLACE, "description")
2482 self.ldb_dc1.modify(msg)
2485 msg.dn = self.ou2_dn
2486 msg["description"] = ldb.MessageElement("OU2 Description", ldb.FLAG_MOD_REPLACE, "description")
2487 self.ldb_dc2.modify(msg)
2489 # trigger replication from DC1 to DC2
2490 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2491 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2492 scope=SCOPE_SUBTREE,
2493 expression="(samAccountName=%s)" % username,
2494 attrs=["*", "parentGUID"])
2495 self.assertEquals(len(ldb_res), 1)
2496 user_moved = ldb_res[0]
2497 user_moved_dn = ldb_res[0]["dn"]
2499 # trigger replication from DC1 to DC2
2500 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2501 # check user info on DC2 - should be under the OU2 from DC1
2502 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved, is_deleted=False)
2504 self.assertEquals(user_cur["parentGUID"], user_moved["parentGUID"])
2506 # delete user on DC1
2507 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
2509 # trigger replication from DC1 to DC2, for cleanup
2510 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2512 def test_ReplicateAddInConflictOU2(self):
2513 """Verifies how an object is replicated between two DCs, when created in an ambigious location
2514 This test should verify that:
2515 - Without replication, two conflicting objects can be created
2516 - force the conflict resolution algorithm so we know which copy will win
2517 (by changing the description twice, therefore increasing that version count)
2518 - confirm that the user object, created on DC1, ends up in the right place on DC2
2519 - therefore confirm that the conflict algorithm worked correctly, and that parentGUID was used.
2521 # work-out unique username to test with
2522 username = self._make_username()
2524 self.ldb_dc1.add(self.ou1)
2526 # create user on DC1
2527 self.ldb_dc1.newuser(username=username,
2528 userou="ou=%s" % self.ou1_dn.get_component_value(0),
2529 password=None, setpassword=False)
2530 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2531 scope=SCOPE_SUBTREE,
2532 expression="(samAccountName=%s)" % username,
2533 attrs=["*", "parentGUID"])
2534 self.assertEquals(len(ldb_res), 1)
2535 user_orig = ldb_res[0]
2536 user_dn = ldb_res[0]["dn"]
2538 # trigger replication from DC1 to DC2
2539 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2541 # Now create two, conflicting objects. This gives the user
2542 # object something to be under on both DCs. We create it on
2543 # DC1 1sec later so that it will win the conflict resolution.
2545 self.ldb_dc2.add(self.ou2)
2547 self.ldb_dc1.add(self.ou2)
2549 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
2550 new_dn.add_base(self.ou2_dn)
2551 self.ldb_dc1.rename(user_dn, new_dn)
2553 # Now that we have renamed the user (and so bumpted the
2554 # usnChanged), bump the value on the OUs.
2556 msg.dn = self.ou2_dn
2557 msg["description"] = ldb.MessageElement("OU2 Description", ldb.FLAG_MOD_REPLACE, "description")
2558 self.ldb_dc1.modify(msg)
2561 msg.dn = self.ou2_dn
2562 msg["description"] = ldb.MessageElement("OU2 Description", ldb.FLAG_MOD_REPLACE, "description")
2563 self.ldb_dc2.modify(msg)
2565 # trigger replication from DC1 to DC2
2566 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2567 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2568 scope=SCOPE_SUBTREE,
2569 expression="(samAccountName=%s)" % username,
2570 attrs=["*", "parentGUID"])
2571 self.assertEquals(len(ldb_res), 1)
2572 user_moved = ldb_res[0]
2573 user_moved_dn = ldb_res[0]["dn"]
2575 # trigger replication from DC1 to DC2
2576 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2577 # check user info on DC2 - should be under the OU2 from DC1
2578 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved, is_deleted=False)
2580 self.assertEquals(user_cur["parentGUID"], user_moved["parentGUID"])
2582 # delete user on DC1
2583 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
2585 # trigger replication from DC1 to DC2, for cleanup
2586 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)