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"
30 from __future__ import print_function
35 from samba.ndr import ndr_unpack
36 from samba.dcerpc import drsblobs
37 from samba.dcerpc import misc
38 from samba.drs_utils import drs_DsBind
47 from samba.dcerpc.drsuapi import *
50 class DrsMoveObjectTestCase(drs_base.DrsBaseTestCase):
52 def _ds_bind(self, server_name):
53 binding_str = "ncacn_ip_tcp:%s[print,seal]" % server_name
55 drs = drsuapi(binding_str, self.get_loadparm(), self.get_credentials())
56 (drs_handle, supported_extensions) = drs_DsBind(drs)
57 return (drs, drs_handle)
60 super(DrsMoveObjectTestCase, self).setUp()
61 # disable automatic replication temporary
62 self._disable_all_repl(self.dnsname_dc1)
63 self._disable_all_repl(self.dnsname_dc2)
65 # make sure DCs are synchronized before the test
66 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
67 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
69 self.top_ou = samba.tests.create_test_ou(self.ldb_dc1,
72 self.ou1_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU1")
73 self.ou1_dn.add_base(self.top_ou)
75 ou1["dn"] = self.ou1_dn
76 ou1["objectclass"] = "organizationalUnit"
77 ou1["ou"] = self.ou1_dn.get_component_value(0)
80 self.ou2_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU2")
81 self.ou2_dn.add_base(self.top_ou)
83 ou2["dn"] = self.ou2_dn
84 ou2["objectclass"] = "organizationalUnit"
85 ou2["ou"] = self.ou2_dn.get_component_value(0)
88 # trigger replication from DC1 to DC2
89 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
90 self.dc1_guid = self.ldb_dc1.get_invocation_id()
91 self.dc2_guid = self.ldb_dc2.get_invocation_id()
93 self.drs_dc1 = self._ds_bind(self.dnsname_dc1)
94 self.drs_dc2 = self._ds_bind(self.dnsname_dc2)
98 self.ldb_dc1.delete(self.top_ou, ["tree_delete:1"])
99 except ldb.LdbError as e:
100 (enum, string) = e.args
101 if enum == ldb.ERR_NO_SUCH_OBJECT:
104 self._enable_all_repl(self.dnsname_dc1)
105 self._enable_all_repl(self.dnsname_dc2)
106 super(DrsMoveObjectTestCase, self).tearDown()
108 def _make_username(self):
109 return "DrsMoveU_" + time.strftime("%s", time.gmtime())
111 def _check_metadata(self, user_dn, sam_ldb, drs, metadata, expected):
112 repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob, metadata[0])
114 self.assertEqual(len(repl.ctr.array), len(expected))
117 for o in repl.ctr.array:
119 (attid, orig_dsa, version) = e
120 self.assertEquals(attid, o.attid,
121 "(LDAP) Wrong attid "
122 "for expected value %d, wanted 0x%08x got 0x%08x"
123 % (i, attid, o.attid))
124 self.assertEquals(o.originating_invocation_id,
126 "(LDAP) Wrong originating_invocation_id "
127 "for expected value %d, attid 0x%08x, wanted %s got %s"
130 o.originating_invocation_id))
131 # Allow version to be skipped when it does not matter
132 if version is not None:
133 self.assertEquals(o.version, version,
134 "(LDAP) Wrong version for expected value %d, "
144 req8 = DsGetNCChangesRequest8()
146 req8.source_dsa_invocation_id = misc.GUID(sam_ldb.get_invocation_id())
147 req8.naming_context = DsReplicaObjectIdentifier()
148 req8.naming_context.dn = str(user_dn)
149 req8.highwatermark = DsReplicaHighWaterMark()
150 req8.highwatermark.tmp_highest_usn = 0
151 req8.highwatermark.reserved_usn = 0
152 req8.highwatermark.highest_usn = 0
153 req8.uptodateness_vector = None
154 req8.replica_flags = DRSUAPI_DRS_SYNC_FORCED
155 req8.max_object_count = 1
156 req8.max_ndr_size = 402116
157 req8.extended_op = DRSUAPI_EXOP_REPL_OBJ
159 req8.partial_attribute_set = None
160 req8.partial_attribute_set_ex = None
161 req8.mapping_ctr.num_mappings = 0
162 req8.mapping_ctr.mappings = None
164 (drs_conn, drs_handle) = drs
166 (level, drs_ctr) = drs_conn.DsGetNCChanges(drs_handle, 8, req8)
167 self.assertEqual(level, 6)
168 self.assertEqual(drs_ctr.object_count, 1)
170 self.assertEqual(len(drs_ctr.first_object.meta_data_ctr.meta_data), len(expected) - 1)
172 for o in drs_ctr.first_object.meta_data_ctr.meta_data:
174 drs_attid = drs_ctr.first_object.object.attribute_ctr.attributes[att_idx]
176 (attid, orig_dsa, version) = e
178 # Skip the RDN from the expected set, it is not sent over DRS
179 if (user_dn.get_rdn_name().upper() == "CN" \
180 and attid == DRSUAPI_ATTID_cn) \
181 or (user_dn.get_rdn_name().upper() == "OU" \
182 and attid == DRSUAPI_ATTID_ou):
185 (attid, orig_dsa, version) = e
187 self.assertEquals(attid, drs_attid.attid,
189 "for expected value %d, wanted 0x%08x got 0x%08x"
190 % (i, attid, drs_attid.attid))
192 self.assertEquals(o.originating_invocation_id,
194 "(DRS) Wrong originating_invocation_id "
195 "for expected value %d, attid 0x%08x, wanted %s got %s"
198 o.originating_invocation_id))
199 # Allow version to be skipped when it does not matter
200 if version is not None:
201 self.assertEquals(o.version, version,
202 "(DRS) Wrong version for expected value %d, "
205 % (i, attid, version, o.version))
208 att_idx = att_idx + 1
210 # now also used to check the group
211 def _check_obj(self, sam_ldb, obj_orig, is_deleted, expected_metadata=None, drs=None):
212 # search the user by guid as it may be deleted
213 guid_str = self._GUID_string(obj_orig["objectGUID"][0])
214 res = sam_ldb.search(base='<GUID=%s>' % guid_str,
215 controls=["show_deleted:1"],
216 attrs=["*", "parentGUID",
217 "replPropertyMetaData"])
218 self.assertEquals(len(res), 1)
220 rdn_orig = obj_orig[user_cur.dn.get_rdn_name()][0]
221 rdn_cur = user_cur[user_cur.dn.get_rdn_name()][0]
222 name_orig = obj_orig["name"][0]
223 name_cur = user_cur["name"][0]
224 dn_orig = obj_orig["dn"]
225 dn_cur = user_cur["dn"]
226 # now check properties of the user
228 self.assertTrue("isDeleted" in user_cur)
229 self.assertEquals(rdn_cur.split('\n')[0], rdn_orig)
230 self.assertEquals(name_cur.split('\n')[0], name_orig)
231 self.assertEquals(dn_cur.get_rdn_value().split('\n')[0],
232 dn_orig.get_rdn_value())
233 self.assertEqual(name_cur, rdn_cur)
235 self.assertFalse("isDeleted" in user_cur)
236 self.assertEquals(rdn_cur, rdn_orig)
237 self.assertEquals(name_cur, name_orig)
238 self.assertEquals(dn_cur, dn_orig)
239 self.assertEqual(name_cur, rdn_cur)
240 parent_cur = user_cur["parentGUID"][0]
242 parent_orig = obj_orig["parentGUID"][0]
243 self.assertEqual(parent_orig, parent_cur)
246 self.assertEqual(name_cur, user_cur.dn.get_rdn_value())
248 if expected_metadata is not None:
249 self._check_metadata(dn_cur, sam_ldb, drs, user_cur["replPropertyMetaData"],
254 def test_ReplicateMoveObject1(self):
255 """Verifies how a moved container with a user inside is replicated between two DCs.
256 This test should verify that:
257 - the OU is replicated properly
259 - We verify that after replication,
260 that the user has the correct DN (under OU2)
262 - the OU is modified on DC2
263 - We verify that after replication,
264 that the user has the correct DN (deleted) and has not description
267 # work-out unique username to test with
268 username = self._make_username()
271 self.ldb_dc1.newuser(username=username,
273 % (self.ou1_dn.get_component_value(0),
274 self.top_ou.get_component_value(0)),
275 password=None, setpassword=False)
276 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
278 expression="(samAccountName=%s)" % username,
279 attrs=["*", "parentGUID"])
280 self.assertEquals(len(ldb_res), 1)
281 user_orig = ldb_res[0]
282 user_dn = ldb_res[0]["dn"]
284 # check user info on DC1
285 print("Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])))
287 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
288 (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
289 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
290 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
291 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
292 (DRSUAPI_ATTID_name, self.dc1_guid, 1),
293 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
294 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
295 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
296 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
297 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
298 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
299 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
300 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
301 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
302 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
303 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
304 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
305 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
306 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
307 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
308 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
310 self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
311 obj_orig=user_orig, is_deleted=False,
312 expected_metadata=initial_metadata)
314 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
315 new_dn.add_base(self.ou2_dn)
316 self.ldb_dc1.rename(user_dn, new_dn)
317 ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
319 expression="(samAccountName=%s)" % username,
320 attrs=["*", "parentGUID"])
321 self.assertEquals(len(ldb_res), 1)
323 user_moved_orig = ldb_res[0]
324 user_moved_dn = ldb_res[0]["dn"]
327 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
328 (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
329 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
330 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
331 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
332 (DRSUAPI_ATTID_name, self.dc1_guid, 2),
333 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
334 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
335 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
336 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
337 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
338 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
339 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
340 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
341 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
342 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
343 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
344 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
345 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
346 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
347 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
348 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
350 # check user info on DC1 after rename - should be valid user
351 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
352 obj_orig=user_moved_orig,
354 expected_metadata=moved_metadata)
356 # trigger replication from DC1 to DC2
357 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
358 moved_metadata_dc2 = [
359 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
360 (DRSUAPI_ATTID_cn, self.dc2_guid, 1),
361 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
362 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
363 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
364 (DRSUAPI_ATTID_name, self.dc1_guid, 2),
365 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
366 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
367 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
368 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
369 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
370 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
371 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
372 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
373 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
374 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
375 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
376 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
377 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
378 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
379 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
380 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
382 # check user info on DC2 - should be valid user
383 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
384 obj_orig=user_moved_orig,
386 expected_metadata=moved_metadata_dc2)
389 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
391 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
392 (DRSUAPI_ATTID_cn, self.dc1_guid, 2),
393 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
394 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
395 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
396 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
397 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
398 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
399 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
400 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
401 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
402 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
403 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
404 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
405 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
406 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
407 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
408 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
409 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
410 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
411 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
412 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
413 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
414 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
415 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
417 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_moved_orig, is_deleted=True, expected_metadata=deleted_metadata)
419 # Modify description on DC2. This triggers a replication, but
420 # not of 'name' and so a bug in Samba regarding the DN.
423 msg["description"] = ldb.MessageElement("User Description", ldb.FLAG_MOD_REPLACE, "description")
424 self.ldb_dc2.modify(msg)
426 modified_metadata = [
427 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
428 (DRSUAPI_ATTID_cn, self.dc2_guid, 1),
429 (DRSUAPI_ATTID_description, self.dc2_guid, 1),
430 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
431 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
432 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
433 (DRSUAPI_ATTID_name, self.dc1_guid, 2),
434 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
435 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
436 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
437 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
438 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
439 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
440 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
441 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
442 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
443 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
444 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
445 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
446 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
447 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
448 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
449 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
451 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
452 obj_orig=user_moved_orig,
454 expected_metadata=modified_metadata)
456 # trigger replication from DC1 to DC2, for cleanup
457 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
459 deleted_modified_metadata_dc2 = [
460 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
461 (DRSUAPI_ATTID_cn, self.dc2_guid, 2),
462 (DRSUAPI_ATTID_description, self.dc2_guid, 2),
463 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
464 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
465 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
466 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
467 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
468 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
469 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
470 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
471 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
472 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
473 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
474 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
475 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
476 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
477 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
478 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
479 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
480 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
481 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
482 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
483 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
484 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
485 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
487 # check user info on DC2 - should be deleted user
488 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
489 obj_orig=user_moved_orig,
491 expected_metadata=deleted_modified_metadata_dc2)
492 self.assertFalse("description" in user_cur)
494 # trigger replication from DC2 to DC1, for cleanup
495 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
497 deleted_modified_metadata_dc1 = [
498 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
499 (DRSUAPI_ATTID_cn, self.dc1_guid, 2),
500 (DRSUAPI_ATTID_description, self.dc2_guid, 2),
501 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
502 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
503 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
504 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
505 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
506 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
507 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
508 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
509 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
510 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
511 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
512 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
513 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
514 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
515 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
516 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
517 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
518 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
519 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
520 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
521 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
522 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
523 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
525 # check user info on DC1 - should be deleted user
526 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
527 obj_orig=user_moved_orig,
529 expected_metadata=deleted_modified_metadata_dc1)
530 self.assertFalse("description" in user_cur)
532 def test_ReplicateMoveObject2(self):
533 """Verifies how a moved container with a user inside is not
534 replicated between two DCs as no replication is triggered
535 This test should verify that:
536 - the OU is not replicated
537 - the user is not replicated
540 # work-out unique username to test with
541 username = self._make_username()
544 self.ldb_dc1.newuser(username=username,
546 % (self.ou1_dn.get_component_value(0),
547 self.top_ou.get_component_value(0)),
548 password=None, setpassword=False)
549 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
551 expression="(samAccountName=%s)" % username,
552 attrs=["*", "parentGUID"])
553 self.assertEquals(len(ldb_res), 1)
554 user_orig = ldb_res[0]
555 user_dn = ldb_res[0]["dn"]
557 # check user info on DC1
558 print("Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])))
560 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
561 (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
562 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
563 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
564 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
565 (DRSUAPI_ATTID_name, self.dc1_guid, 1),
566 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
567 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
568 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
569 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
570 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
571 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
572 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
573 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
574 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
575 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
576 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
577 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
578 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
579 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
580 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
581 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
583 self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
584 obj_orig=user_orig, is_deleted=False,
585 expected_metadata=initial_metadata)
587 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
588 new_dn.add_base(self.ou2_dn)
589 self.ldb_dc1.rename(user_dn, new_dn)
590 ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
592 expression="(samAccountName=%s)" % username,
593 attrs=["*", "parentGUID"])
594 self.assertEquals(len(ldb_res), 1)
595 user_moved_orig = ldb_res[0]
598 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
599 (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
600 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
601 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
602 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
603 (DRSUAPI_ATTID_name, self.dc1_guid, 2),
604 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
605 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
606 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
607 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
608 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
609 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
610 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
611 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
612 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
613 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
614 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
615 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
616 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
617 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
618 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
619 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
621 # check user info on DC1 after rename - should be valid user
622 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
623 obj_orig=user_moved_orig,
625 expected_metadata=moved_metadata)
627 # check user info on DC2 - should not be there, we have not done replication
628 ldb_res = self.ldb_dc2.search(base=self.ou2_dn,
630 expression="(samAccountName=%s)" % username,
631 attrs=["*", "parentGUID"])
632 self.assertEquals(len(ldb_res), 0)
635 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
637 deleted_metadata_dc1 = [
638 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
639 (DRSUAPI_ATTID_cn, self.dc1_guid, 2),
640 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
641 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
642 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
643 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
644 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
645 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
646 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
647 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
648 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
649 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
650 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
651 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
652 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
653 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
654 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
655 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
656 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
657 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
658 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
659 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
660 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
661 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
662 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
664 # check user info on DC1 - should be deleted user
665 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
666 obj_orig=user_moved_orig,
668 expected_metadata=deleted_metadata_dc1)
669 # trigger replication from DC1 to DC2, for cleanup
670 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
672 deleted_metadata_dc2 = [
673 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
674 (DRSUAPI_ATTID_cn, self.dc2_guid, 1),
675 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
676 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
677 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
678 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
679 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
680 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
681 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
682 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
683 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
684 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
685 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
686 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
687 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
688 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
689 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
690 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
691 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
692 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
693 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
694 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
695 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
696 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
697 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
699 # check user info on DC2 - should be deleted user
700 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
701 obj_orig=user_moved_orig,
703 expected_metadata=deleted_metadata_dc2)
705 # trigger replication from DC2 to DC1, for cleanup
706 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
708 # check user info on DC1 - should be deleted user
709 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
710 obj_orig=user_moved_orig,
712 expected_metadata=deleted_metadata_dc1)
714 def test_ReplicateMoveObject3(self):
715 """Verifies how a moved container with a user inside is replicated between two DCs.
716 This test should verify that:
717 - the OU is created on DC1
718 - the OU is renamed on DC1
719 - We verify that after replication,
720 that the user has the correct DN (under OU2).
723 # work-out unique username to test with
724 username = self._make_username()
727 self.ldb_dc1.newuser(username=username,
729 % (self.ou1_dn.get_component_value(0),
730 self.top_ou.get_component_value(0)),
731 password=None, setpassword=False)
732 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
734 expression="(samAccountName=%s)" % username,
735 attrs=["*", "parentGUID"])
736 self.assertEquals(len(ldb_res), 1)
737 user_orig = ldb_res[0]
738 user_dn = ldb_res[0]["dn"]
740 # check user info on DC1
741 print("Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])))
743 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
744 (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
745 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
746 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
747 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
748 (DRSUAPI_ATTID_name, self.dc1_guid, 1),
749 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
750 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
751 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
752 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
753 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
754 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
755 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
756 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
757 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
758 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
759 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
760 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
761 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
762 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
763 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
764 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
766 self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
767 obj_orig=user_orig, is_deleted=False,
768 expected_metadata=initial_metadata)
770 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
771 new_dn.add_base(self.ou2_dn)
772 self.ldb_dc1.rename(user_dn, new_dn)
773 ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
775 expression="(samAccountName=%s)" % username,
776 attrs=["*", "parentGUID"])
777 self.assertEquals(len(ldb_res), 1)
779 user_moved_orig = ldb_res[0]
780 user_moved_dn = ldb_res[0]["dn"]
782 # trigger replication from DC1 to DC2
783 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
785 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
786 (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
787 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
788 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
789 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
790 (DRSUAPI_ATTID_name, self.dc1_guid, 2),
791 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
792 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
793 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
794 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
795 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
796 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
797 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
798 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
799 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
800 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
801 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
802 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
803 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
804 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
805 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
806 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
808 # check user info on DC1 after rename - should be valid user
809 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
810 obj_orig=user_moved_orig,
812 expected_metadata=moved_metadata)
815 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
816 deleted_metadata_dc1 = [
817 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
818 (DRSUAPI_ATTID_cn, self.dc1_guid, 2),
819 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
820 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
821 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
822 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
823 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
824 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
825 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
826 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
827 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
828 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
829 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
830 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
831 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
832 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
833 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
834 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
835 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
836 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
837 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
838 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
839 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
840 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
841 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
843 # check user info on DC1 - should be deleted user
844 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
845 obj_orig=user_moved_orig,
847 expected_metadata=deleted_metadata_dc1)
849 # trigger replication from DC2 to DC1
850 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
852 # check user info on DC1 - should be deleted user
853 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
854 obj_orig=user_moved_orig,
856 expected_metadata=deleted_metadata_dc1)
858 # trigger replication from DC1 to DC2, for cleanup
859 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
861 deleted_metadata_dc2 = [
862 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
863 (DRSUAPI_ATTID_cn, self.dc2_guid, 2),
864 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
865 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
866 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
867 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
868 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
869 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
870 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
871 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
872 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
873 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
874 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
875 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
876 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
877 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
878 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
879 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
880 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
881 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
882 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
883 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
884 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
885 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
886 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
888 # check user info on DC2 - should be deleted user
889 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
890 obj_orig=user_moved_orig,
892 expected_metadata=deleted_metadata_dc2)
894 def test_ReplicateMoveObject3b(self):
895 """Verifies how a moved container with a user inside is replicated between two DCs.
896 This test should verify that:
897 - the OU is created on DC1
898 - the OU is renamed on DC1
899 - We verify that after replication,
900 that the user has the correct DN (under OU2).
903 # work-out unique username to test with
904 username = self._make_username()
907 self.ldb_dc1.newuser(username=username,
909 % (self.ou1_dn.get_component_value(0),
910 self.top_ou.get_component_value(0)),
911 password=None, setpassword=False)
912 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
914 expression="(samAccountName=%s)" % username,
915 attrs=["*", "parentGUID"])
916 self.assertEquals(len(ldb_res), 1)
917 user_orig = ldb_res[0]
918 user_dn = ldb_res[0]["dn"]
920 # check user info on DC1
921 print("Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])))
923 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
924 (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
925 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
926 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
927 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
928 (DRSUAPI_ATTID_name, self.dc1_guid, 1),
929 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
930 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
931 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
932 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
933 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
934 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
935 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
936 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
937 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
938 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
939 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
940 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
941 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
942 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
943 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
944 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
946 self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
947 obj_orig=user_orig, is_deleted=False,
948 expected_metadata=initial_metadata)
950 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
951 new_dn.add_base(self.ou2_dn)
952 self.ldb_dc1.rename(user_dn, new_dn)
953 ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
955 expression="(samAccountName=%s)" % username,
956 attrs=["*", "parentGUID"])
957 self.assertEquals(len(ldb_res), 1)
959 user_moved_orig = ldb_res[0]
960 user_moved_dn = ldb_res[0]["dn"]
962 # trigger replication from DC2 (Which has never seen the object) to DC1
963 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
965 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
966 (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
967 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
968 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
969 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
970 (DRSUAPI_ATTID_name, self.dc1_guid, 2),
971 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
972 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
973 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
974 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
975 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
976 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
977 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
978 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
979 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
980 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
981 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
982 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
983 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
984 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
985 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
986 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
988 # check user info on DC1 after rename - should be valid user
989 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
990 obj_orig=user_moved_orig,
992 expected_metadata=moved_metadata)
995 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
996 deleted_metadata_dc1 = [
997 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
998 (DRSUAPI_ATTID_cn, self.dc1_guid, 2),
999 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
1000 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
1001 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
1002 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
1003 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
1004 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
1005 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
1006 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
1007 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
1008 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
1009 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
1010 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
1011 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
1012 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
1013 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
1014 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
1015 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
1016 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
1017 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
1018 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
1019 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
1020 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
1021 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
1023 # check user info on DC1 - should be deleted user
1024 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
1025 obj_orig=user_moved_orig,
1027 expected_metadata=deleted_metadata_dc1)
1029 # trigger replication from DC2 to DC1
1030 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1032 # check user info on DC1 - should be deleted user
1033 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
1034 obj_orig=user_moved_orig,
1036 expected_metadata=deleted_metadata_dc1)
1038 # trigger replication from DC1 to DC2, for cleanup
1039 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1041 deleted_metadata_dc2 = [
1042 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
1043 (DRSUAPI_ATTID_cn, self.dc2_guid, 1),
1044 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
1045 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
1046 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
1047 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
1048 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
1049 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
1050 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
1051 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
1052 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
1053 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
1054 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
1055 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
1056 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
1057 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
1058 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
1059 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
1060 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
1061 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
1062 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
1063 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
1064 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
1065 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
1066 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
1068 # check user info on DC2 - should be deleted user
1069 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
1070 obj_orig=user_moved_orig,
1072 expected_metadata=deleted_metadata_dc2)
1074 def test_ReplicateMoveObject4(self):
1075 """Verifies how a moved container with a user inside is replicated between two DCs.
1076 This test should verify that:
1077 - the OU is replicated properly
1078 - the user is modified on DC2
1079 - the OU is renamed on DC1
1080 - We verify that after replication DC1 -> DC2,
1081 that the user has the correct DN (under OU2), and the description
1084 # work-out unique username to test with
1085 username = self._make_username()
1087 # create user on DC1
1088 self.ldb_dc1.newuser(username=username,
1089 userou="ou=%s,ou=%s"
1090 % (self.ou1_dn.get_component_value(0),
1091 self.top_ou.get_component_value(0)),
1092 password=None, setpassword=False)
1093 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
1094 scope=SCOPE_SUBTREE,
1095 expression="(samAccountName=%s)" % username,
1096 attrs=["*", "parentGUID"])
1097 self.assertEquals(len(ldb_res), 1)
1098 user_orig = ldb_res[0]
1099 user_dn = ldb_res[0]["dn"]
1101 # check user info on DC1
1102 print("Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])))
1103 initial_metadata = [
1104 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
1105 (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
1106 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
1107 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
1108 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
1109 (DRSUAPI_ATTID_name, self.dc1_guid, 1),
1110 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
1111 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
1112 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
1113 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
1114 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
1115 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
1116 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
1117 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
1118 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
1119 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
1120 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
1121 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
1122 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
1123 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
1124 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
1125 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
1127 self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
1128 obj_orig=user_orig, is_deleted=False,
1129 expected_metadata=initial_metadata)
1131 # trigger replication from DC1 to DC2
1132 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1134 initial_metadata_dc2 = [
1135 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
1136 (DRSUAPI_ATTID_cn, self.dc2_guid, 1),
1137 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
1138 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
1139 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
1140 (DRSUAPI_ATTID_name, self.dc1_guid, 1),
1141 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
1142 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
1143 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
1144 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
1145 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
1146 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
1147 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
1148 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
1149 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
1150 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
1151 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
1152 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
1153 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
1154 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
1155 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
1156 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
1158 # check user info on DC2 - should still be valid user
1159 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
1160 obj_orig=user_orig, is_deleted=False,
1161 expected_metadata=initial_metadata_dc2)
1163 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
1164 new_dn.add_base(self.ou2_dn)
1165 self.ldb_dc1.rename(user_dn, new_dn)
1166 ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
1167 scope=SCOPE_SUBTREE,
1168 expression="(samAccountName=%s)" % username,
1169 attrs=["*", "parentGUID"])
1170 self.assertEquals(len(ldb_res), 1)
1172 user_moved_orig = ldb_res[0]
1173 user_moved_dn = ldb_res[0]["dn"]
1176 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
1177 (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
1178 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
1179 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
1180 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
1181 (DRSUAPI_ATTID_name, self.dc1_guid, 2),
1182 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
1183 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
1184 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
1185 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
1186 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
1187 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
1188 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
1189 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
1190 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
1191 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
1192 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
1193 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
1194 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
1195 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
1196 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
1197 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
1199 # check user info on DC1 after rename - should be valid user
1200 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
1201 obj_orig=user_moved_orig,
1203 expected_metadata=moved_metadata)
1205 # Modify description on DC2. This triggers a replication, but
1206 # not of 'name' and so a bug in Samba regarding the DN.
1209 msg["description"] = ldb.MessageElement("User Description", ldb.FLAG_MOD_REPLACE, "description")
1210 self.ldb_dc2.modify(msg)
1212 modified_metadata = [
1213 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
1214 (DRSUAPI_ATTID_cn, self.dc2_guid, 1),
1215 (DRSUAPI_ATTID_description, self.dc2_guid, 1),
1216 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
1217 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
1218 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
1219 (DRSUAPI_ATTID_name, self.dc1_guid, 1),
1220 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
1221 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
1222 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
1223 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
1224 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
1225 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
1226 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
1227 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
1228 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
1229 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
1230 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
1231 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
1232 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
1233 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
1234 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
1235 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
1237 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
1240 expected_metadata=modified_metadata)
1242 # trigger replication from DC1 to DC2
1243 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1245 modified_renamed_metadata = [
1246 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
1247 (DRSUAPI_ATTID_cn, self.dc2_guid, 2),
1248 (DRSUAPI_ATTID_description, self.dc2_guid, 1),
1249 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
1250 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
1251 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
1252 (DRSUAPI_ATTID_name, self.dc1_guid, 2),
1253 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
1254 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
1255 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
1256 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
1257 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
1258 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
1259 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
1260 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
1261 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
1262 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
1263 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
1264 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
1265 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
1266 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
1267 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
1268 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
1270 # check user info on DC2 - should still be valid user
1271 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
1272 obj_orig=user_moved_orig,
1274 expected_metadata=modified_renamed_metadata)
1276 self.assertTrue("description" in user_cur)
1278 # delete user on DC1
1279 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
1280 deleted_metadata_dc1 = [
1281 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
1282 (DRSUAPI_ATTID_cn, self.dc1_guid, 2),
1283 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
1284 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
1285 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
1286 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
1287 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
1288 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
1289 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
1290 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
1291 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
1292 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
1293 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
1294 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
1295 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
1296 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
1297 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
1298 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
1299 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
1300 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
1301 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
1302 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
1303 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
1304 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
1305 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
1307 # check user info on DC1 - should be deleted user
1308 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
1309 obj_orig=user_moved_orig,
1311 expected_metadata=deleted_metadata_dc1)
1313 # trigger replication from DC2 to DC1
1314 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1315 # check user info on DC2 - should still be valid user
1316 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
1317 obj_orig=user_moved_orig,
1319 expected_metadata=modified_renamed_metadata)
1321 self.assertTrue("description" in user_cur)
1323 deleted_metadata_dc1 = [
1324 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
1325 (DRSUAPI_ATTID_cn, self.dc1_guid, 2),
1326 (DRSUAPI_ATTID_description, self.dc1_guid, 2),
1327 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
1328 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
1329 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
1330 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
1331 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
1332 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
1333 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
1334 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
1335 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
1336 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
1337 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
1338 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
1339 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
1340 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
1341 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
1342 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
1343 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
1344 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
1345 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
1346 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
1347 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
1348 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
1349 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
1351 # check user info on DC1 - should be deleted user
1352 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
1353 obj_orig=user_moved_orig,
1355 expected_metadata=deleted_metadata_dc1)
1357 self.assertFalse("description" in user_cur)
1359 # trigger replication from DC1 to DC2, for cleanup
1360 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1362 deleted_metadata_dc2 = [
1363 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
1364 (DRSUAPI_ATTID_cn, self.dc2_guid, 3),
1365 (DRSUAPI_ATTID_description, self.dc1_guid, 2),
1366 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
1367 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
1368 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
1369 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
1370 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
1371 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
1372 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
1373 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
1374 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
1375 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
1376 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
1377 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
1378 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
1379 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
1380 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
1381 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
1382 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
1383 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
1384 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
1385 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
1386 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
1387 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
1388 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
1390 # check user info on DC2 - should be deleted user
1391 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
1392 obj_orig=user_moved_orig,
1394 expected_metadata=deleted_metadata_dc2)
1396 self.assertFalse("description" in user_cur)
1398 def test_ReplicateMoveObject5(self):
1399 """Verifies how a moved container with a user inside is replicated between two DCs.
1400 This test should verify that:
1401 - the OU is replicated properly
1402 - the user is modified on DC2
1403 - the OU is renamed on DC1
1404 - We verify that after replication DC2 -> DC1,
1405 that the user has the correct DN (under OU2), and the description
1408 # work-out unique username to test with
1409 username = self._make_username()
1411 # create user on DC1
1412 self.ldb_dc1.newuser(username=username,
1413 userou="ou=%s,ou=%s"
1414 % (self.ou1_dn.get_component_value(0),
1415 self.top_ou.get_component_value(0)),
1416 password=None, setpassword=False)
1417 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
1418 scope=SCOPE_SUBTREE,
1419 expression="(samAccountName=%s)" % username,
1420 attrs=["*", "parentGUID"])
1421 self.assertEquals(len(ldb_res), 1)
1422 user_orig = ldb_res[0]
1423 user_dn = ldb_res[0]["dn"]
1425 # trigger replication from DC1 to DC2
1426 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1427 # check user info on DC2 - should still be valid user
1428 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=False)
1430 # check user info on DC1
1431 print("Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])))
1432 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=False)
1434 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
1435 new_dn.add_base(self.ou2_dn)
1436 self.ldb_dc1.rename(user_dn, new_dn)
1437 ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
1438 scope=SCOPE_SUBTREE,
1439 expression="(samAccountName=%s)" % username,
1440 attrs=["*", "parentGUID"])
1441 self.assertEquals(len(ldb_res), 1)
1443 user_moved_orig = ldb_res[0]
1444 user_moved_dn = ldb_res[0]["dn"]
1446 # Modify description on DC2. This triggers a replication, but
1447 # not of 'name' and so a bug in Samba regarding the DN.
1450 msg["description"] = ldb.MessageElement("User Description", ldb.FLAG_MOD_REPLACE, "description")
1451 self.ldb_dc2.modify(msg)
1453 # trigger replication from DC2 to DC1
1454 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1455 # check user info on DC1 - should still be valid user
1456 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_moved_orig, is_deleted=False)
1457 self.assertTrue("description" in user_cur)
1459 # trigger replication from DC1 to DC2
1460 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1461 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
1462 self.assertTrue("description" in user_cur)
1464 # delete user on DC2
1465 self.ldb_dc2.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
1466 # trigger replication from DC2 to DC1 for cleanup
1467 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1469 # check user info on DC1 - should be deleted user
1470 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_moved_orig, is_deleted=True)
1471 self.assertFalse("description" in user_cur)
1473 def test_ReplicateMoveObject6(self):
1474 """Verifies how a moved container is replicated between two DCs.
1475 This test should verify that:
1476 - the OU1 is replicated properly
1477 - the OU1 is modified on DC2
1478 - the OU1 is renamed on DC1
1479 - We verify that after replication DC1 -> DC2,
1480 that the OU1 has the correct DN (under OU2), and the description
1483 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
1485 attrs=["*", "parentGUID"])
1486 self.assertEquals(len(ldb_res), 1)
1487 ou_orig = ldb_res[0]
1488 ou_dn = ldb_res[0]["dn"]
1490 # check user info on DC1
1491 print("Testing for %s with GUID %s" % (self.ou1_dn, self._GUID_string(ou_orig["objectGUID"][0])))
1492 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1494 # trigger replication from DC1 to DC2
1495 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1496 # check user info on DC2 - should still be valid user
1497 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1499 new_dn = ldb.Dn(self.ldb_dc1, "OU=%s" % self.ou1_dn.get_component_value(0))
1500 new_dn.add_base(self.ou2_dn)
1501 self.ldb_dc1.rename(ou_dn, new_dn)
1502 ldb_res = self.ldb_dc1.search(base=new_dn,
1504 attrs=["*", "parentGUID"])
1505 self.assertEquals(len(ldb_res), 1)
1507 ou_moved_orig = ldb_res[0]
1508 ou_moved_dn = ldb_res[0]["dn"]
1510 # Modify description on DC2. This triggers a replication, but
1511 # not of 'name' and so a bug in Samba regarding the DN.
1514 msg["description"] = ldb.MessageElement("OU Description", ldb.FLAG_MOD_REPLACE, "description")
1515 self.ldb_dc2.modify(msg)
1517 # trigger replication from DC1 to DC2
1518 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1519 # check user info on DC2 - should still be valid user
1520 ou_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=ou_moved_orig, is_deleted=False)
1521 self.assertTrue("description" in ou_cur)
1524 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(ou_orig["objectGUID"][0]))
1525 # trigger replication from DC2 to DC1
1526 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1527 # check user info on DC2 - should be deleted user
1528 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_moved_orig, is_deleted=True)
1529 self.assertFalse("description" in ou_cur)
1531 # trigger replication from DC1 to DC2, for cleanup
1532 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1534 # check user info on DC2 - should be deleted user
1535 ou_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=ou_moved_orig, is_deleted=True)
1536 self.assertFalse("description" in ou_cur)
1538 def test_ReplicateMoveObject7(self):
1539 """Verifies how a moved container is replicated between two DCs.
1540 This test should verify that:
1541 - the OU1 is replicated properly
1542 - the OU1 is modified on DC2
1543 - the OU1 is renamed on DC1 to be under OU2
1544 - We verify that after replication DC2 -> DC1,
1545 that the OU1 has the correct DN (under OU2), and the description
1548 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
1550 attrs=["*", "parentGUID"])
1551 self.assertEquals(len(ldb_res), 1)
1552 ou_orig = ldb_res[0]
1553 ou_dn = ldb_res[0]["dn"]
1555 # check user info on DC1
1556 print("Testing for %s with GUID %s" % (self.ou1_dn, self._GUID_string(ou_orig["objectGUID"][0])))
1557 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1559 # trigger replication from DC1 to DC2
1560 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1561 # check user info on DC2 - should still be valid user
1562 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1564 new_dn = ldb.Dn(self.ldb_dc1, "OU=%s" % self.ou1_dn.get_component_value(0))
1565 new_dn.add_base(self.ou2_dn)
1566 self.ldb_dc1.rename(ou_dn, new_dn)
1567 ldb_res = self.ldb_dc1.search(base=new_dn,
1569 attrs=["*", "parentGUID"])
1570 self.assertEquals(len(ldb_res), 1)
1572 ou_moved_orig = ldb_res[0]
1573 ou_moved_dn = ldb_res[0]["dn"]
1575 # Modify description on DC2. This triggers a replication, but
1576 # not of 'name' and so a bug in Samba regarding the DN.
1579 msg["description"] = ldb.MessageElement("OU Description", ldb.FLAG_MOD_REPLACE, "description")
1580 self.ldb_dc2.modify(msg)
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 DC1 - should still be valid user
1585 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_moved_orig, is_deleted=False)
1586 self.assertTrue("description" in ou_cur)
1589 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(ou_orig["objectGUID"][0]))
1590 # trigger replication from DC2 to DC1
1591 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1592 # check user info on DC2 - should be deleted user
1593 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_moved_orig, is_deleted=True)
1594 self.assertFalse("description" in ou_cur)
1596 # trigger replication from DC1 to DC2, for cleanup
1597 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1599 # check user info on DC2 - should be deleted user
1600 ou_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=ou_moved_orig, is_deleted=True)
1601 self.assertFalse("description" in ou_cur)
1603 def test_ReplicateMoveObject8(self):
1604 """Verifies how a moved container is replicated between two DCs.
1605 This test should verify that:
1606 - the OU1 is replicated properly
1607 - the OU1 is modified on DC2
1608 - the OU1 is renamed on DC1 to OU1-renamed
1609 - We verify that after replication DC1 -> DC2,
1610 that the OU1 has the correct DN (OU1-renamed), and the description
1613 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
1615 attrs=["*", "parentGUID"])
1616 self.assertEquals(len(ldb_res), 1)
1617 ou_orig = ldb_res[0]
1618 ou_dn = ldb_res[0]["dn"]
1620 # check user info on DC1
1621 print("Testing for %s with GUID %s" % (self.ou1_dn, self._GUID_string(ou_orig["objectGUID"][0])))
1622 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1624 # trigger replication from DC1 to DC2
1625 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1626 # check user info on DC2 - should still be valid user
1627 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1629 new_dn = ldb.Dn(self.ldb_dc1, "OU=%s-renamed" % self.ou1_dn.get_component_value(0))
1630 new_dn.add_base(self.ou1_dn.parent())
1631 self.ldb_dc1.rename(ou_dn, new_dn)
1632 ldb_res = self.ldb_dc1.search(base=new_dn,
1634 attrs=["*", "parentGUID"])
1635 self.assertEquals(len(ldb_res), 1)
1637 ou_moved_orig = ldb_res[0]
1638 ou_moved_dn = ldb_res[0]["dn"]
1640 # Modify description on DC2. This triggers a replication, but
1641 # not of 'name' and so a bug in Samba regarding the DN.
1644 msg["description"] = ldb.MessageElement("OU Description", ldb.FLAG_MOD_REPLACE, "description")
1645 self.ldb_dc2.modify(msg)
1647 # trigger replication from DC1 to DC2
1648 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1649 # check user info on DC2 - should still be valid user
1650 ou_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=ou_moved_orig, is_deleted=False)
1651 self.assertTrue("description" in ou_cur)
1654 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(ou_orig["objectGUID"][0]))
1655 # trigger replication from DC2 to DC1
1656 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1657 # check user info on DC2 - should be deleted user
1658 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_moved_orig, is_deleted=True)
1659 self.assertFalse("description" in ou_cur)
1661 # trigger replication from DC1 to DC2, for cleanup
1662 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1664 # check user info on DC2 - should be deleted user
1665 ou_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=ou_moved_orig, is_deleted=True)
1666 self.assertFalse("description" in ou_cur)
1668 def test_ReplicateMoveObject9(self):
1669 """Verifies how a moved container is replicated between two DCs.
1670 This test should verify that:
1671 - the OU1 is replicated properly
1672 - the OU1 is modified on DC2
1673 - the OU1 is renamed on DC1 to be under OU2
1674 - the OU1 is renamed on DC1 to OU1-renamed
1675 - We verify that after replication DC1 -> DC2,
1676 that the OU1 has the correct DN (OU1-renamed), and the description
1679 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
1681 attrs=["*", "parentGUID"])
1682 self.assertEquals(len(ldb_res), 1)
1683 ou_orig = ldb_res[0]
1684 ou_dn = ldb_res[0]["dn"]
1686 # check user info on DC1
1687 print("Testing for %s with GUID %s" % (self.ou1_dn, self._GUID_string(ou_orig["objectGUID"][0])))
1688 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1690 # trigger replication from DC1 to DC2
1691 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1692 # check user info on DC2 - should still be valid user
1693 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1695 new_dn = ldb.Dn(self.ldb_dc1, "OU=%s-renamed" % self.ou1_dn.get_component_value(0))
1696 new_dn.add_base(self.ou1_dn.parent())
1697 self.ldb_dc1.rename(ou_dn, new_dn)
1698 ldb_res = self.ldb_dc1.search(base=new_dn,
1700 attrs=["*", "parentGUID"])
1701 self.assertEquals(len(ldb_res), 1)
1703 ou_moved_orig = ldb_res[0]
1704 ou_moved_dn = ldb_res[0]["dn"]
1706 # Modify description on DC2. This triggers a replication, but
1707 # not of 'name' and so a bug in Samba regarding the DN.
1710 msg["description"] = ldb.MessageElement("OU Description", ldb.FLAG_MOD_REPLACE, "description")
1711 self.ldb_dc2.modify(msg)
1713 # trigger replication from DC2 to DC1
1714 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1715 # check user info on DC1 - should still be valid user
1716 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_moved_orig, is_deleted=False)
1717 self.assertTrue("description" in ou_cur)
1720 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(ou_orig["objectGUID"][0]))
1721 # trigger replication from DC2 to DC1
1722 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1723 # check user info on DC2 - should be deleted user
1724 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_moved_orig, is_deleted=True)
1725 self.assertFalse("description" in ou_cur)
1727 # trigger replication from DC1 to DC2, for cleanup
1728 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1730 # check user info on DC2 - should be deleted user
1731 ou_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=ou_moved_orig, is_deleted=True)
1732 self.assertFalse("description" in ou_cur)
1734 def test_ReplicateMoveObject10(self):
1735 """Verifies how a moved container is replicated between two DCs.
1736 This test should verify that:
1737 - the OU1 is replicated properly
1738 - the OU1 is modified on DC2
1739 - the OU1 is deleted on DC1
1740 - We verify that after replication DC1 -> DC2,
1741 that the OU1 is deleted, and the description has gone away
1744 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
1746 attrs=["*", "parentGUID"])
1747 self.assertEquals(len(ldb_res), 1)
1748 ou_orig = ldb_res[0]
1749 ou_dn = ldb_res[0]["dn"]
1751 # check user info on DC1
1752 print("Testing for %s with GUID %s" % (self.ou1_dn, self._GUID_string(ou_orig["objectGUID"][0])))
1753 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1755 # trigger replication from DC1 to DC2
1756 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1757 # check user info on DC2 - should still be valid user
1758 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1760 # Modify description on DC2. This triggers a replication, but
1761 # not of 'name' and so a bug in Samba regarding the DN.
1764 msg["description"] = ldb.MessageElement("OU Description", ldb.FLAG_MOD_REPLACE, "description")
1765 self.ldb_dc2.modify(msg)
1768 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(ou_orig["objectGUID"][0]))
1769 # trigger replication from DC1 to DC2
1770 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1771 # check user info on DC2 - should be deleted OU
1772 ou_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=ou_orig, is_deleted=True)
1773 self.assertFalse("description" in ou_cur)
1775 # trigger replication from DC1 to DC2, for cleanup
1776 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1778 # check user info on DC2 - should be deleted OU
1779 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=True)
1780 self.assertFalse("description" in ou_cur)
1782 def test_ReplicateMoveObject11(self):
1783 """Verifies how a moved container is replicated between two DCs.
1784 This test should verify that:
1785 - the OU1 is replicated properly
1786 - the OU1 is modified on DC2
1787 - the OU1 is deleted on DC1
1788 - We verify that after replication DC2 -> DC1,
1789 that the OU1 is deleted, and the description has gone away
1792 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
1794 attrs=["*", "parentGUID"])
1795 self.assertEquals(len(ldb_res), 1)
1796 ou_orig = ldb_res[0]
1797 ou_dn = ldb_res[0]["dn"]
1799 # check user info on DC1
1800 print("Testing for %s with GUID %s" % (self.ou1_dn, self._GUID_string(ou_orig["objectGUID"][0])))
1801 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1803 # trigger replication from DC1 to DC2
1804 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1805 # check user info on DC2 - should still be valid user
1806 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1808 # Modify description on DC2. This triggers a replication, but
1809 # not of 'name' and so a bug in Samba regarding the DN.
1812 msg["description"] = ldb.MessageElement("OU Description", ldb.FLAG_MOD_REPLACE, "description")
1813 self.ldb_dc2.modify(msg)
1816 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(ou_orig["objectGUID"][0]))
1817 # trigger replication from DC2 to DC1
1818 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1819 # check user info on DC2 - should be deleted OU
1820 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=True)
1821 self.assertFalse("description" in ou_cur)
1823 # trigger replication from DC1 to DC2, for cleanup
1824 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1826 # check user info on DC2 - should be deleted OU
1827 ou_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=ou_orig, is_deleted=True)
1828 self.assertFalse("description" in ou_cur)
1831 class DrsMoveBetweenTreeOfObjectTestCase(drs_base.DrsBaseTestCase):
1834 super(DrsMoveBetweenTreeOfObjectTestCase, self).setUp()
1835 # disable automatic replication temporary
1836 self._disable_all_repl(self.dnsname_dc1)
1837 self._disable_all_repl(self.dnsname_dc2)
1839 self.top_ou = samba.tests.create_test_ou(self.ldb_dc1,
1842 # make sure DCs are synchronized before the test
1843 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1844 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1846 self.ou1_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU1")
1847 self.ou1_dn.add_base(self.top_ou)
1849 self.ou1["dn"] = self.ou1_dn
1850 self.ou1["objectclass"] = "organizationalUnit"
1851 self.ou1["ou"] = self.ou1_dn.get_component_value(0)
1853 self.ou2_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU2,OU=DrsOU1")
1854 self.ou2_dn.add_base(self.top_ou)
1856 self.ou2["dn"] = self.ou2_dn
1857 self.ou2["objectclass"] = "organizationalUnit"
1858 self.ou2["ou"] = self.ou2_dn.get_component_value(0)
1860 self.ou2b_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU2B,OU=DrsOU1")
1861 self.ou2b_dn.add_base(self.top_ou)
1863 self.ou2b["dn"] = self.ou2b_dn
1864 self.ou2b["objectclass"] = "organizationalUnit"
1865 self.ou2b["ou"] = self.ou2b_dn.get_component_value(0)
1867 self.ou2c_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU2C,OU=DrsOU1")
1868 self.ou2c_dn.add_base(self.top_ou)
1870 self.ou3_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU3,OU=DrsOU2,OU=DrsOU1")
1871 self.ou3_dn.add_base(self.top_ou)
1873 self.ou3["dn"] = self.ou3_dn
1874 self.ou3["objectclass"] = "organizationalUnit"
1875 self.ou3["ou"] = self.ou3_dn.get_component_value(0)
1877 self.ou4_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU4,OU=DrsOU3,OU=DrsOU2,OU=DrsOU1")
1878 self.ou4_dn.add_base(self.top_ou)
1880 self.ou4["dn"] = self.ou4_dn
1881 self.ou4["objectclass"] = "organizationalUnit"
1882 self.ou4["ou"] = self.ou4_dn.get_component_value(0)
1884 self.ou5_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU5,OU=DrsOU4,OU=DrsOU3,OU=DrsOU2,OU=DrsOU1")
1885 self.ou5_dn.add_base(self.top_ou)
1887 self.ou5["dn"] = self.ou5_dn
1888 self.ou5["objectclass"] = "organizationalUnit"
1889 self.ou5["ou"] = self.ou5_dn.get_component_value(0)
1891 self.ou6_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU6,OU=DrsOU5,OU=DrsOU4,OU=DrsOU3,OU=DrsOU2,OU=DrsOU1")
1892 self.ou6_dn.add_base(self.top_ou)
1894 self.ou6["dn"] = self.ou6_dn
1895 self.ou6["objectclass"] = "organizationalUnit"
1896 self.ou6["ou"] = self.ou6_dn.get_component_value(0)
1899 self.ldb_dc1.delete(self.top_ou, ["tree_delete:1"])
1900 self._enable_all_repl(self.dnsname_dc1)
1901 self._enable_all_repl(self.dnsname_dc2)
1902 super(DrsMoveBetweenTreeOfObjectTestCase, self).tearDown()
1904 def _make_username(self):
1905 return "DrsTreeU_" + time.strftime("%s", time.gmtime())
1907 # now also used to check the group
1908 def _check_obj(self, sam_ldb, obj_orig, is_deleted):
1909 # search the user by guid as it may be deleted
1910 guid_str = self._GUID_string(obj_orig["objectGUID"][0])
1911 res = sam_ldb.search(base='<GUID=%s>' % guid_str,
1912 controls=["show_deleted:1"],
1913 attrs=["*", "parentGUID"])
1914 self.assertEquals(len(res), 1)
1916 cn_orig = obj_orig["cn"][0]
1917 cn_cur = user_cur["cn"][0]
1918 name_orig = obj_orig["name"][0]
1919 name_cur = user_cur["name"][0]
1920 dn_orig = obj_orig["dn"]
1921 dn_cur = user_cur["dn"]
1922 # now check properties of the user
1924 self.assertTrue("isDeleted" in user_cur)
1925 self.assertEquals(cn_cur.split('\n')[0], cn_orig)
1926 self.assertEquals(name_cur.split('\n')[0], name_orig)
1927 self.assertEquals(dn_cur.get_rdn_value().split('\n')[0],
1928 dn_orig.get_rdn_value())
1929 self.assertEqual(name_cur, cn_cur)
1931 self.assertFalse("isDeleted" in user_cur)
1932 self.assertEquals(cn_cur, cn_orig)
1933 self.assertEquals(name_cur, name_orig)
1934 self.assertEquals(dn_cur, dn_orig)
1935 self.assertEqual(name_cur, cn_cur)
1936 self.assertEqual(name_cur, user_cur.dn.get_rdn_value())
1940 def test_ReplicateMoveInTree1(self):
1941 """Verifies how an object is replicated between two DCs.
1942 This test should verify that:
1943 - a complex OU tree can be replicated correctly
1944 - the user is in the correct spot (renamed into) within the tree
1947 # work-out unique username to test with
1948 username = self._make_username()
1950 self.ldb_dc1.add(self.ou1)
1952 # create user on DC1
1953 self.ldb_dc1.newuser(username=username,
1954 userou="ou=%s,ou=%s"
1955 % (self.ou1_dn.get_component_value(0),
1956 self.top_ou.get_component_value(0)),
1957 password=None, setpassword=False)
1958 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
1959 scope=SCOPE_SUBTREE,
1960 expression="(samAccountName=%s)" % username)
1961 self.assertEquals(len(ldb_res), 1)
1962 user_orig = ldb_res[0]
1963 user_dn = ldb_res[0]["dn"]
1965 # check user info on DC1
1966 print("Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])))
1967 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=False)
1969 self.ldb_dc1.add(self.ou2)
1970 self.ldb_dc1.add(self.ou3)
1971 self.ldb_dc1.add(self.ou4)
1972 self.ldb_dc1.add(self.ou5)
1974 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
1975 new_dn.add_base(self.ou5_dn)
1976 self.ldb_dc1.rename(user_dn, new_dn)
1977 ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
1978 scope=SCOPE_SUBTREE,
1979 expression="(samAccountName=%s)" % username)
1980 self.assertEquals(len(ldb_res), 1)
1982 user_moved_orig = ldb_res[0]
1983 user_moved_dn = ldb_res[0]["dn"]
1985 # trigger replication from DC1 to DC2
1986 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1987 # check user info on DC2 - should be valid user
1988 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
1990 # delete user on DC1
1991 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
1993 # trigger replication from DC1 to DC2, for cleanup
1994 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1996 def test_ReplicateMoveInTree2(self):
1997 """Verifies how an object is replicated between two DCs.
1998 This test should verify that:
1999 - a complex OU tree can be replicated correctly
2000 - the user is in the correct spot (renamed into) within the tree
2002 - that a rename back works correctly, and is replicated
2004 # work-out unique username to test with
2005 username = self._make_username()
2007 self.ldb_dc1.add(self.ou1)
2009 # create user on DC1
2010 self.ldb_dc1.newuser(username=username,
2011 userou="ou=%s,ou=%s"
2012 % (self.ou1_dn.get_component_value(0),
2013 self.top_ou.get_component_value(0)),
2014 password=None, setpassword=False)
2015 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2016 scope=SCOPE_SUBTREE,
2017 expression="(samAccountName=%s)" % username)
2018 self.assertEquals(len(ldb_res), 1)
2019 user_orig = ldb_res[0]
2020 user_dn = ldb_res[0]["dn"]
2022 # check user info on DC1
2023 print("Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])))
2024 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=False)
2026 self.ldb_dc1.add(self.ou2)
2027 self.ldb_dc1.add(self.ou2b)
2028 self.ldb_dc1.add(self.ou3)
2030 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
2031 new_dn.add_base(self.ou3_dn)
2032 self.ldb_dc1.rename(user_dn, new_dn)
2034 new_dn3 = ldb.Dn(self.ldb_dc1, "OU=%s" % self.ou3_dn.get_component_value(0))
2035 new_dn3.add_base(self.ou2b_dn)
2036 self.ldb_dc1.rename(self.ou3_dn, new_dn3)
2038 ldb_res = self.ldb_dc1.search(base=new_dn3,
2039 scope=SCOPE_SUBTREE,
2040 expression="(samAccountName=%s)" % username)
2041 self.assertEquals(len(ldb_res), 1)
2043 user_moved_orig = ldb_res[0]
2044 user_moved_dn = ldb_res[0]["dn"]
2046 # trigger replication from DC1 to DC2
2047 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2048 # check user info on DC2 - should be valid user
2049 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
2052 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
2053 new_dn.add_base(self.ou1_dn)
2054 self.ldb_dc1.rename(user_moved_dn, new_dn)
2056 # Modify description on DC2
2058 msg.dn = user_moved_dn
2059 msg["description"] = ldb.MessageElement("User Description", ldb.FLAG_MOD_REPLACE, "description")
2060 self.ldb_dc2.modify(msg)
2062 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2063 scope=SCOPE_SUBTREE,
2064 expression="(samAccountName=%s)" % username)
2065 self.assertEquals(len(ldb_res), 1)
2067 user_moved_orig = ldb_res[0]
2068 user_moved_dn = ldb_res[0]["dn"]
2070 # trigger replication from DC1 to DC2
2071 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2072 # check user info on DC2 - should be valid user
2073 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
2074 self.assertTrue("description" in user_cur)
2076 # delete user on DC1
2077 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
2079 # trigger replication from DC2 to DC1
2080 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
2081 # check user info on DC1 - should be deleted user
2082 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_moved_orig, is_deleted=True)
2083 self.assertFalse("description" in user_cur)
2085 # trigger replication from DC1 to DC2, for cleanup
2086 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2087 # check user info on DC2 - should be deleted user
2088 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=True)
2089 self.assertFalse("description" in user_cur)
2091 def test_ReplicateMoveInTree3(self):
2092 """Verifies how an object is replicated between two DCs.
2093 This test should verify that:
2094 - a complex OU tree can be replicated correctly
2095 - the user is in the correct spot (renamed into) within the tree
2097 - that a rename back works correctly, and is replicated
2099 # work-out unique username to test with
2100 username = self._make_username()
2102 self.ldb_dc1.add(self.ou1)
2104 # create user on DC1
2105 self.ldb_dc1.newuser(username=username,
2106 userou="ou=%s,ou=%s"
2107 % (self.ou1_dn.get_component_value(0),
2108 self.top_ou.get_component_value(0)),
2109 password=None, setpassword=False)
2110 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2111 scope=SCOPE_SUBTREE,
2112 expression="(samAccountName=%s)" % username)
2113 self.assertEquals(len(ldb_res), 1)
2114 user_orig = ldb_res[0]
2115 user_dn = ldb_res[0]["dn"]
2117 # check user info on DC1
2118 print("Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])))
2119 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=False)
2121 self.ldb_dc1.add(self.ou2)
2122 self.ldb_dc1.add(self.ou2b)
2123 self.ldb_dc1.add(self.ou3)
2125 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
2126 new_dn.add_base(self.ou3_dn)
2127 self.ldb_dc1.rename(user_dn, new_dn)
2129 new_dn3 = ldb.Dn(self.ldb_dc1, "OU=%s" % self.ou3_dn.get_component_value(0))
2130 new_dn3.add_base(self.ou2b_dn)
2131 self.ldb_dc1.rename(self.ou3_dn, new_dn3)
2133 ldb_res = self.ldb_dc1.search(base=new_dn3,
2134 scope=SCOPE_SUBTREE,
2135 expression="(samAccountName=%s)" % username)
2136 self.assertEquals(len(ldb_res), 1)
2138 user_moved_orig = ldb_res[0]
2139 user_moved_dn = ldb_res[0]["dn"]
2141 # trigger replication from DC1 to DC2
2142 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2143 # check user info on DC2 - should be valid user
2144 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
2146 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
2147 new_dn.add_base(self.ou2_dn)
2148 self.ldb_dc1.rename(user_moved_dn, new_dn)
2150 self.ldb_dc1.rename(self.ou2_dn, self.ou2c_dn)
2151 self.ldb_dc1.rename(self.ou2b_dn, self.ou2_dn)
2152 self.ldb_dc1.rename(self.ou2c_dn, self.ou2b_dn)
2154 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2155 scope=SCOPE_SUBTREE,
2156 expression="(samAccountName=%s)" % username,
2157 attrs=["*", "parentGUID"])
2158 self.assertEquals(len(ldb_res), 1)
2160 user_moved_orig = ldb_res[0]
2161 user_moved_dn = ldb_res[0]["dn"]
2163 # trigger replication from DC1 to DC2
2164 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2165 # check user info on DC2 - should be valid user
2166 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
2168 self.assertEquals(user_cur["parentGUID"], user_moved_orig["parentGUID"])
2170 # delete user on DC1
2171 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
2173 # trigger replication from DC1 to DC2, for cleanup
2174 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2176 def test_ReplicateMoveInTree3b(self):
2177 """Verifies how an object is replicated between two DCs.
2178 This test should verify that:
2179 - a complex OU tree can be replicated correctly
2180 - the user is in the correct spot (renamed into) within the tree
2182 - that a rename back works correctly, and is replicated
2183 - that a complex rename suffle, combined with unrelated changes to the object,
2184 is replicated correctly. The aim here is the send the objects out-of-order
2185 when sorted by usnChanged.
2186 - confirm that the OU tree and (in particular the user DN) is identical between
2187 the DCs once this has been replicated.
2189 # work-out unique username to test with
2190 username = self._make_username()
2192 self.ldb_dc1.add(self.ou1)
2194 # create user on DC1
2195 self.ldb_dc1.newuser(username=username,
2196 userou="ou=%s,ou=%s"
2197 % (self.ou1_dn.get_component_value(0),
2198 self.top_ou.get_component_value(0)),
2199 password=None, setpassword=False)
2200 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2201 scope=SCOPE_SUBTREE,
2202 expression="(samAccountName=%s)" % username)
2203 self.assertEquals(len(ldb_res), 1)
2204 user_orig = ldb_res[0]
2205 user_dn = ldb_res[0]["dn"]
2207 # check user info on DC1
2208 print("Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])))
2209 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=False)
2211 self.ldb_dc1.add(self.ou2)
2212 self.ldb_dc1.add(self.ou2b)
2213 self.ldb_dc1.add(self.ou3)
2215 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
2216 new_dn.add_base(self.ou2_dn)
2217 self.ldb_dc1.rename(user_dn, new_dn)
2219 ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
2220 scope=SCOPE_SUBTREE,
2221 expression="(samAccountName=%s)" % username)
2222 self.assertEquals(len(ldb_res), 1)
2224 user_moved_orig = ldb_res[0]
2225 user_moved_dn = ldb_res[0]["dn"]
2227 # trigger replication from DC1 to DC2
2228 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2229 # check user info on DC2 - should be valid user
2230 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
2234 msg["description"] = ldb.MessageElement("User Description", ldb.FLAG_MOD_REPLACE, "description")
2235 self.ldb_dc1.modify(msg)
2237 # The sleep(1) calls here ensure that the name objects get a
2238 # new 1-sec based timestamp, and so we select how the conflict
2239 # resolution resolves.
2240 self.ldb_dc1.rename(self.ou2_dn, self.ou2c_dn)
2242 self.ldb_dc1.rename(self.ou2b_dn, self.ou2_dn)
2244 self.ldb_dc1.rename(self.ou2c_dn, self.ou2b_dn)
2246 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
2247 new_dn.add_base(self.ou2_dn)
2248 self.ldb_dc1.rename('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]), new_dn)
2251 msg.dn = self.ou2_dn
2252 msg["description"] = ldb.MessageElement("OU2 Description", ldb.FLAG_MOD_REPLACE, "description")
2253 self.ldb_dc1.modify(msg)
2256 msg.dn = self.ou2b_dn
2257 msg["description"] = ldb.MessageElement("OU2b Description", ldb.FLAG_MOD_REPLACE, "description")
2258 self.ldb_dc1.modify(msg)
2260 ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
2261 scope=SCOPE_SUBTREE,
2262 expression="(samAccountName=%s)" % username,
2263 attrs=["*", "parentGUID"])
2264 self.assertEquals(len(ldb_res), 1)
2266 user_moved_orig = ldb_res[0]
2267 user_moved_dn = ldb_res[0]["dn"]
2269 # trigger replication from DC1 to DC2
2270 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2271 # check user info on DC2 - should be valid user
2272 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
2273 self.assertEquals(user_cur["parentGUID"][0], user_moved_orig["parentGUID"][0])
2275 # delete user on DC1
2276 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
2278 # trigger replication from DC1 to DC2, for cleanup
2279 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2281 def test_ReplicateMoveInTree4(self):
2282 """Verifies how an object is replicated between two DCs.
2283 This test should verify that:
2284 - an OU and user can be replicated correctly, even after a rename
2285 - The creation and rename of the OU has been combined with unrelated changes to the object,
2286 The aim here is the send the objects out-of-order when sorted by usnChanged.
2287 - That is, the OU will be sorted by usnChanged after the user that is within that OU.
2288 - That will cause the client to need to get the OU first, by use of the GET_ANC flag
2290 # work-out unique username to test with
2291 username = self._make_username()
2293 self.ldb_dc1.add(self.ou1)
2295 # create user on DC1
2296 self.ldb_dc1.newuser(username=username,
2297 userou="ou=%s,ou=%s"
2298 % (self.ou1_dn.get_component_value(0),
2299 self.top_ou.get_component_value(0)),
2300 password=None, setpassword=False)
2301 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2302 scope=SCOPE_SUBTREE,
2303 expression="(samAccountName=%s)" % username)
2304 self.assertEquals(len(ldb_res), 1)
2305 user_orig = ldb_res[0]
2306 user_dn = ldb_res[0]["dn"]
2308 # check user info on DC1
2309 print("Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])))
2310 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=False)
2312 self.ldb_dc1.add(self.ou2)
2314 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
2315 new_dn.add_base(self.ou2_dn)
2316 self.ldb_dc1.rename(user_dn, new_dn)
2319 msg.dn = self.ou2_dn
2320 msg["description"] = ldb.MessageElement("OU2 Description", ldb.FLAG_MOD_REPLACE, "description")
2321 self.ldb_dc1.modify(msg)
2323 ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
2324 scope=SCOPE_SUBTREE,
2325 expression="(samAccountName=%s)" % username)
2326 self.assertEquals(len(ldb_res), 1)
2328 user_moved_orig = ldb_res[0]
2329 user_moved_dn = ldb_res[0]["dn"]
2331 # trigger replication from DC1 to DC2
2332 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2333 # check user info on DC2 - should be valid user
2334 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
2336 # delete user on DC1
2337 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
2339 # trigger replication from DC1 to DC2, for cleanup
2340 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2342 def test_ReplicateAddInOU(self):
2343 """Verifies how an object is replicated between two DCs.
2344 This test should verify that:
2345 - an OU and user can be replicated correctly
2346 - The creation of the OU has been combined with unrelated changes to the object,
2347 The aim here is the send the objects out-of-order when sorted by usnChanged.
2348 - That is, the OU will be sorted by usnChanged after the user that is within that OU.
2349 - That will cause the client to need to get the OU first, by use of the GET_ANC flag
2351 # work-out unique username to test with
2352 username = self._make_username()
2354 self.ldb_dc1.add(self.ou1)
2356 # create user on DC1
2357 self.ldb_dc1.newuser(username=username,
2358 userou="ou=%s,ou=%s"
2359 % (self.ou1_dn.get_component_value(0),
2360 self.top_ou.get_component_value(0)),
2361 password=None, setpassword=False)
2362 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2363 scope=SCOPE_SUBTREE,
2364 expression="(samAccountName=%s)" % username,
2365 attrs=["*", "parentGUID"])
2366 self.assertEquals(len(ldb_res), 1)
2367 user_orig = ldb_res[0]
2368 user_dn = ldb_res[0]["dn"]
2371 msg.dn = self.ou1_dn
2372 msg["description"] = ldb.MessageElement("OU1 Description", ldb.FLAG_MOD_REPLACE, "description")
2373 self.ldb_dc1.modify(msg)
2375 # trigger replication from DC1 to DC2
2376 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2377 # check user info on DC2 - should be valid user
2378 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_orig, is_deleted=False)
2380 self.assertEquals(user_cur["parentGUID"], user_orig["parentGUID"])
2382 # delete user on DC1
2383 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
2385 # trigger replication from DC1 to DC2, for cleanup
2386 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2388 def test_ReplicateAddInMovedOU(self):
2389 """Verifies how an object is replicated between two DCs.
2390 This test should verify that:
2391 - an OU and user can be replicated correctly
2392 - The creation of the OU has been combined with unrelated changes to the object,
2393 The aim here is the send the objects out-of-order when sorted by usnChanged.
2394 - That is, the OU will be sorted by usnChanged after the user that is within that OU.
2395 - That will cause the client to need to get the OU first, by use of the GET_ANC flag
2397 # work-out unique username to test with
2398 username = self._make_username()
2400 self.ldb_dc1.add(self.ou1)
2401 self.ldb_dc1.add(self.ou2)
2403 # create user on DC1
2404 self.ldb_dc1.newuser(username=username,
2405 userou="ou=%s,ou=%s"
2406 % (self.ou1_dn.get_component_value(0),
2407 self.top_ou.get_component_value(0)),
2408 password=None, setpassword=False)
2409 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2410 scope=SCOPE_SUBTREE,
2411 expression="(samAccountName=%s)" % username,
2412 attrs=["*", "parentGUID"])
2413 self.assertEquals(len(ldb_res), 1)
2414 user_orig = ldb_res[0]
2415 user_dn = ldb_res[0]["dn"]
2417 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
2418 new_dn.add_base(self.ou2_dn)
2419 self.ldb_dc1.rename(user_dn, new_dn)
2421 self.ldb_dc1.rename(self.ou2_dn, self.ou2b_dn)
2423 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2424 scope=SCOPE_SUBTREE,
2425 expression="(samAccountName=%s)" % username,
2426 attrs=["*", "parentGUID"])
2427 self.assertEquals(len(ldb_res), 1)
2428 user_moved = ldb_res[0]
2429 user_moved_dn = ldb_res[0]["dn"]
2431 # trigger replication from DC1 to DC2
2432 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2433 # check user info on DC2 - should be valid user
2434 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved, is_deleted=False)
2436 self.assertEquals(user_cur["parentGUID"], user_moved["parentGUID"])
2438 # delete user on DC1
2439 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
2441 # trigger replication from DC1 to DC2, for cleanup
2442 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2444 def test_ReplicateAddInConflictOU_time(self):
2445 """Verifies how an object is replicated between two DCs, when created in an ambigious location
2446 This test should verify that:
2447 - Without replication, two conflicting objects can be created
2448 - force the conflict resolution algorithm so we know which copy will win
2449 (by sleeping while creating the objects, therefore increasing that timestamp on 'name')
2450 - confirm that the user object, created on DC1, ends up in the right place on DC2
2451 - therefore confirm that the conflict algorithm worked correctly, and that parentGUID was used.
2454 # work-out unique username to test with
2455 username = self._make_username()
2457 self.ldb_dc1.add(self.ou1)
2459 # create user on DC1
2460 self.ldb_dc1.newuser(username=username,
2461 userou="ou=%s,ou=%s"
2462 % (self.ou1_dn.get_component_value(0),
2463 self.top_ou.get_component_value(0)),
2464 password=None, setpassword=False)
2465 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2466 scope=SCOPE_SUBTREE,
2467 expression="(samAccountName=%s)" % username,
2468 attrs=["*", "parentGUID"])
2469 self.assertEquals(len(ldb_res), 1)
2470 user_orig = ldb_res[0]
2471 user_dn = ldb_res[0]["dn"]
2473 # trigger replication from DC1 to DC2
2474 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2476 # Now create two, conflicting objects. This gives the user
2477 # object something to be under on both DCs.
2479 # We sleep between the two adds so that DC1 adds second, and
2480 # so wins the conflict resoution due to a later creation time
2481 # (modification timestamp on the name attribute).
2482 self.ldb_dc2.add(self.ou2)
2484 self.ldb_dc1.add(self.ou2)
2486 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
2487 new_dn.add_base(self.ou2_dn)
2488 self.ldb_dc1.rename(user_dn, new_dn)
2490 # Now that we have renamed the user (and so bumpted the
2491 # usnChanged), bump the value on the OUs.
2493 msg.dn = self.ou2_dn
2494 msg["description"] = ldb.MessageElement("OU2 Description", ldb.FLAG_MOD_REPLACE, "description")
2495 self.ldb_dc1.modify(msg)
2498 msg.dn = self.ou2_dn
2499 msg["description"] = ldb.MessageElement("OU2 Description", ldb.FLAG_MOD_REPLACE, "description")
2500 self.ldb_dc2.modify(msg)
2502 # trigger replication from DC1 to DC2
2503 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2504 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2505 scope=SCOPE_SUBTREE,
2506 expression="(samAccountName=%s)" % username,
2507 attrs=["*", "parentGUID"])
2508 self.assertEquals(len(ldb_res), 1)
2509 user_moved = ldb_res[0]
2510 user_moved_dn = ldb_res[0]["dn"]
2512 # trigger replication from DC1 to DC2
2513 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2514 # check user info on DC2 - should be under the OU2 from DC1
2515 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved, is_deleted=False)
2517 self.assertEquals(user_cur["parentGUID"], user_moved["parentGUID"])
2519 # delete user on DC1
2520 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
2522 # trigger replication from DC1 to DC2, for cleanup
2523 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2525 def test_ReplicateAddInConflictOU2(self):
2526 """Verifies how an object is replicated between two DCs, when created in an ambigious location
2527 This test should verify that:
2528 - Without replication, two conflicting objects can be created
2529 - force the conflict resolution algorithm so we know which copy will win
2530 (by changing the description twice, therefore increasing that version count)
2531 - confirm that the user object, created on DC1, ends up in the right place on DC2
2532 - therefore confirm that the conflict algorithm worked correctly, and that parentGUID was used.
2534 # work-out unique username to test with
2535 username = self._make_username()
2537 self.ldb_dc1.add(self.ou1)
2539 # create user on DC1
2540 self.ldb_dc1.newuser(username=username,
2541 userou="ou=%s,ou=%s"
2542 % (self.ou1_dn.get_component_value(0),
2543 self.top_ou.get_component_value(0)),
2544 password=None, setpassword=False)
2545 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2546 scope=SCOPE_SUBTREE,
2547 expression="(samAccountName=%s)" % username,
2548 attrs=["*", "parentGUID"])
2549 self.assertEquals(len(ldb_res), 1)
2550 user_orig = ldb_res[0]
2551 user_dn = ldb_res[0]["dn"]
2553 # trigger replication from DC1 to DC2
2554 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2556 # Now create two, conflicting objects. This gives the user
2557 # object something to be under on both DCs. We create it on
2558 # DC1 1sec later so that it will win the conflict resolution.
2560 self.ldb_dc2.add(self.ou2)
2562 self.ldb_dc1.add(self.ou2)
2564 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
2565 new_dn.add_base(self.ou2_dn)
2566 self.ldb_dc1.rename(user_dn, new_dn)
2568 # Now that we have renamed the user (and so bumpted the
2569 # usnChanged), bump the value on the OUs.
2571 msg.dn = self.ou2_dn
2572 msg["description"] = ldb.MessageElement("OU2 Description", ldb.FLAG_MOD_REPLACE, "description")
2573 self.ldb_dc1.modify(msg)
2576 msg.dn = self.ou2_dn
2577 msg["description"] = ldb.MessageElement("OU2 Description", ldb.FLAG_MOD_REPLACE, "description")
2578 self.ldb_dc2.modify(msg)
2580 # trigger replication from DC1 to DC2
2581 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2582 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2583 scope=SCOPE_SUBTREE,
2584 expression="(samAccountName=%s)" % username,
2585 attrs=["*", "parentGUID"])
2586 self.assertEquals(len(ldb_res), 1)
2587 user_moved = ldb_res[0]
2588 user_moved_dn = ldb_res[0]["dn"]
2590 # trigger replication from DC1 to DC2
2591 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2592 # check user info on DC2 - should be under the OU2 from DC1
2593 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved, is_deleted=False)
2595 self.assertEquals(user_cur["parentGUID"], user_moved["parentGUID"])
2597 # delete user on DC1
2598 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
2600 # trigger replication from DC1 to DC2, for cleanup
2601 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)