ctdb-scripts: Support storing statd-callout state in cluster filesystem
[samba4-gss.git] / source4 / torture / drs / python / repl_move.py
blobc206ab818f84972f041dc59d699071c78555b73c
1 #!/usr/bin/env python3
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/>.
23 # Usage:
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 import time
31 import samba.tests
33 from samba.ndr import ndr_unpack
34 from samba.dcerpc import drsblobs
35 from samba.dcerpc import misc
36 from samba.drs_utils import drs_DsBind
38 from ldb import (
39 SCOPE_BASE,
40 SCOPE_SUBTREE,
43 import drs_base
44 import ldb
45 from samba.dcerpc.drsuapi import (
46 drsuapi,
47 DRSUAPI_ATTID_accountExpires,
48 DRSUAPI_ATTID_cn,
49 DRSUAPI_ATTID_codePage,
50 DRSUAPI_ATTID_countryCode,
51 DRSUAPI_ATTID_dBCSPwd,
52 DRSUAPI_ATTID_description,
53 DRSUAPI_ATTID_instanceType,
54 DRSUAPI_ATTID_isDeleted,
55 DRSUAPI_ATTID_isRecycled,
56 DRSUAPI_ATTID_lastKnownParent,
57 DRSUAPI_ATTID_lmPwdHistory,
58 DRSUAPI_ATTID_logonHours,
59 DRSUAPI_ATTID_name,
60 DRSUAPI_ATTID_ntPwdHistory,
61 DRSUAPI_ATTID_ntSecurityDescriptor,
62 DRSUAPI_ATTID_objectCategory,
63 DRSUAPI_ATTID_objectClass,
64 DRSUAPI_ATTID_objectSid,
65 DRSUAPI_ATTID_ou,
66 DRSUAPI_ATTID_primaryGroupID,
67 DRSUAPI_ATTID_pwdLastSet,
68 DRSUAPI_ATTID_sAMAccountName,
69 DRSUAPI_ATTID_sAMAccountType,
70 DRSUAPI_ATTID_unicodePwd,
71 DRSUAPI_ATTID_userAccountControl,
72 DRSUAPI_ATTID_userPrincipalName,
73 DRSUAPI_ATTID_whenCreated,
74 DRSUAPI_DRS_SYNC_FORCED,
75 DRSUAPI_EXOP_REPL_OBJ,
76 DsGetNCChangesRequest8,
77 DsReplicaHighWaterMark,
78 DsReplicaObjectIdentifier)
81 class DrsMoveObjectTestCase(drs_base.DrsBaseTestCase):
83 def setUp(self):
84 super(DrsMoveObjectTestCase, self).setUp()
85 # disable automatic replication temporary
86 self._disable_all_repl(self.dnsname_dc1)
87 self._disable_all_repl(self.dnsname_dc2)
89 # make sure DCs are synchronized before the test
90 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
91 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
93 self.top_ou = samba.tests.create_test_ou(self.ldb_dc1,
94 "replica_move")
96 self.ou1_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU1")
97 self.ou1_dn.add_base(self.top_ou)
98 ou1 = {}
99 ou1["dn"] = self.ou1_dn
100 ou1["objectclass"] = "organizationalUnit"
101 ou1["ou"] = self.ou1_dn.get_component_value(0)
102 self.ldb_dc1.add(ou1)
104 self.ou2_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU2")
105 self.ou2_dn.add_base(self.top_ou)
106 ou2 = {}
107 ou2["dn"] = self.ou2_dn
108 ou2["objectclass"] = "organizationalUnit"
109 ou2["ou"] = self.ou2_dn.get_component_value(0)
110 self.ldb_dc1.add(ou2)
112 # trigger replication from DC1 to DC2
113 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
114 self.dc1_guid = self.ldb_dc1.get_invocation_id()
115 self.dc2_guid = self.ldb_dc2.get_invocation_id()
117 self.drs_dc1 = self._ds_bind(self.dnsname_dc1, ip=self.url_dc1)
118 self.drs_dc2 = self._ds_bind(self.dnsname_dc2, ip=self.url_dc2)
120 def tearDown(self):
121 try:
122 self.ldb_dc1.delete(self.top_ou, ["tree_delete:1"])
123 except ldb.LdbError as e:
124 (enum, string) = e.args
125 if enum == ldb.ERR_NO_SUCH_OBJECT:
126 pass
128 self._enable_all_repl(self.dnsname_dc1)
129 self._enable_all_repl(self.dnsname_dc2)
130 super(DrsMoveObjectTestCase, self).tearDown()
132 def _make_username(self):
133 return "DrsMoveU_" + time.strftime("%s", time.gmtime())
135 def _check_metadata(self, user_dn, sam_ldb, drs, metadata, expected):
136 repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob, metadata[0])
138 self.assertEqual(len(repl.ctr.array), len(expected))
140 i = 0
141 for o in repl.ctr.array:
142 e = expected[i]
143 (attid, orig_dsa, version) = e
144 self.assertEqual(attid, o.attid,
145 "(LDAP) Wrong attid "
146 "for expected value %d, wanted 0x%08x got 0x%08x"
147 % (i, attid, o.attid))
148 self.assertEqual(o.originating_invocation_id,
149 misc.GUID(orig_dsa),
150 "(LDAP) Wrong originating_invocation_id "
151 "for expected value %d, attid 0x%08x, wanted %s got %s"
152 % (i, o.attid,
153 misc.GUID(orig_dsa),
154 o.originating_invocation_id))
155 # Allow version to be skipped when it does not matter
156 if version is not None:
157 self.assertEqual(o.version, version,
158 "(LDAP) Wrong version for expected value %d, "
159 "attid 0x%08x, "
160 "wanted %d got %d"
161 % (i, o.attid,
162 version, o.version))
163 i = i + 1
165 if drs is None:
166 return
168 req8 = DsGetNCChangesRequest8()
170 req8.source_dsa_invocation_id = misc.GUID(sam_ldb.get_invocation_id())
171 req8.naming_context = DsReplicaObjectIdentifier()
172 req8.naming_context.dn = str(user_dn)
173 req8.highwatermark = DsReplicaHighWaterMark()
174 req8.highwatermark.tmp_highest_usn = 0
175 req8.highwatermark.reserved_usn = 0
176 req8.highwatermark.highest_usn = 0
177 req8.uptodateness_vector = None
178 req8.replica_flags = DRSUAPI_DRS_SYNC_FORCED
179 req8.max_object_count = 1
180 req8.max_ndr_size = 402116
181 req8.extended_op = DRSUAPI_EXOP_REPL_OBJ
182 req8.fsmo_info = 0
183 req8.partial_attribute_set = None
184 req8.partial_attribute_set_ex = None
185 req8.mapping_ctr.num_mappings = 0
186 req8.mapping_ctr.mappings = None
188 (drs_conn, drs_handle) = drs
190 (level, drs_ctr) = drs_conn.DsGetNCChanges(drs_handle, 8, req8)
191 self.assertEqual(level, 6)
192 self.assertEqual(drs_ctr.object_count, 1)
194 self.assertEqual(len(drs_ctr.first_object.meta_data_ctr.meta_data), len(expected) - 1)
195 att_idx = 0
196 for o in drs_ctr.first_object.meta_data_ctr.meta_data:
197 i = 0
198 drs_attid = drs_ctr.first_object.object.attribute_ctr.attributes[att_idx]
199 e = expected[i]
200 (attid, orig_dsa, version) = e
202 # Skip the RDN from the expected set, it is not sent over DRS
203 if (user_dn.get_rdn_name().upper() == "CN"
204 and attid == DRSUAPI_ATTID_cn) \
205 or (user_dn.get_rdn_name().upper() == "OU"
206 and attid == DRSUAPI_ATTID_ou):
207 i = i + 1
208 e = expected[i]
209 (attid, orig_dsa, version) = e
211 self.assertEqual(attid, drs_attid.attid,
212 "(DRS) Wrong attid "
213 "for expected value %d, wanted 0x%08x got 0x%08x"
214 % (i, attid, drs_attid.attid))
216 self.assertEqual(o.originating_invocation_id,
217 misc.GUID(orig_dsa),
218 "(DRS) Wrong originating_invocation_id "
219 "for expected value %d, attid 0x%08x, wanted %s got %s"
220 % (i, attid,
221 misc.GUID(orig_dsa),
222 o.originating_invocation_id))
223 # Allow version to be skipped when it does not matter
224 if version is not None:
225 self.assertEqual(o.version, version,
226 "(DRS) Wrong version for expected value %d, "
227 "attid 0x%08x, "
228 "wanted %d got %d"
229 % (i, attid, version, o.version))
230 break
231 i = i + 1
232 att_idx = att_idx + 1
234 # now also used to check the group
235 def _check_obj(self, sam_ldb, obj_orig, is_deleted, expected_metadata=None, drs=None):
236 # search the user by guid as it may be deleted
237 guid_str = self._GUID_string(obj_orig["objectGUID"][0])
238 res = sam_ldb.search(base='<GUID=%s>' % guid_str,
239 controls=["show_deleted:1"],
240 attrs=["*", "parentGUID",
241 "replPropertyMetaData"])
242 self.assertEqual(len(res), 1)
243 user_cur = res[0]
244 rdn_orig = str(obj_orig[user_cur.dn.get_rdn_name()][0])
245 rdn_cur = str(user_cur[user_cur.dn.get_rdn_name()][0])
246 name_orig = str(obj_orig["name"][0])
247 name_cur = str(user_cur["name"][0])
248 dn_orig = obj_orig["dn"]
249 dn_cur = user_cur["dn"]
250 # now check properties of the user
251 if is_deleted:
252 self.assertTrue("isDeleted" in user_cur)
253 self.assertEqual(rdn_cur.split('\n')[0], rdn_orig)
254 self.assertEqual(name_cur.split('\n')[0], name_orig)
255 self.assertEqual(dn_cur.get_rdn_value().split('\n')[0],
256 dn_orig.get_rdn_value())
257 self.assertEqual(name_cur, rdn_cur)
258 else:
259 self.assertFalse("isDeleted" in user_cur)
260 self.assertEqual(rdn_cur, rdn_orig)
261 self.assertEqual(name_cur, name_orig)
262 self.assertEqual(dn_cur, dn_orig)
263 self.assertEqual(name_cur, rdn_cur)
264 parent_cur = user_cur["parentGUID"][0]
265 try:
266 parent_orig = obj_orig["parentGUID"][0]
267 self.assertEqual(parent_orig, parent_cur)
268 except KeyError:
269 pass
270 self.assertEqual(name_cur, user_cur.dn.get_rdn_value())
272 if expected_metadata is not None:
273 self._check_metadata(dn_cur, sam_ldb, drs, user_cur["replPropertyMetaData"],
274 expected_metadata)
276 return user_cur
278 def test_ReplicateMoveObject1(self):
279 """Verifies how a moved container with a user inside is replicated between two DCs.
280 This test should verify that:
281 - the OU is replicated properly
282 - the OU is renamed
283 - We verify that after replication,
284 that the user has the correct DN (under OU2)
285 - the OU is deleted
286 - the OU is modified on DC2
287 - We verify that after replication,
288 that the user has the correct DN (deleted) and has not description
291 # work-out unique username to test with
292 username = self._make_username()
294 # create user on DC1
295 self.ldb_dc1.newuser(username=username,
296 userou="ou=%s,ou=%s"
297 % (self.ou1_dn.get_component_value(0),
298 self.top_ou.get_component_value(0)),
299 password=None, setpassword=False)
300 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
301 scope=SCOPE_SUBTREE,
302 expression="(samAccountName=%s)" % username,
303 attrs=["*", "parentGUID"])
304 self.assertEqual(len(ldb_res), 1)
305 user_orig = ldb_res[0]
306 user_dn = ldb_res[0]["dn"]
308 # check user info on DC1
309 print("Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])))
310 initial_metadata = [
311 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
312 (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
313 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
314 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
315 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
316 (DRSUAPI_ATTID_name, self.dc1_guid, 1),
317 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
318 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
319 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
320 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
321 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
322 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
323 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
324 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
325 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
326 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
327 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
328 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
329 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
330 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
331 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
332 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
334 self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
335 obj_orig=user_orig, is_deleted=False,
336 expected_metadata=initial_metadata)
338 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
339 new_dn.add_base(self.ou2_dn)
340 self.ldb_dc1.rename(user_dn, new_dn)
341 ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
342 scope=SCOPE_SUBTREE,
343 expression="(samAccountName=%s)" % username,
344 attrs=["*", "parentGUID"])
345 self.assertEqual(len(ldb_res), 1)
347 user_moved_orig = ldb_res[0]
349 moved_metadata = [
350 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
351 (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
352 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
353 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
354 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
355 (DRSUAPI_ATTID_name, self.dc1_guid, 2),
356 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
357 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
358 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
359 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
360 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
361 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
362 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
363 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
364 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
365 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
366 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
367 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
368 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
369 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
370 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
371 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
373 # check user info on DC1 after rename - should be valid user
374 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
375 obj_orig=user_moved_orig,
376 is_deleted=False,
377 expected_metadata=moved_metadata)
379 # trigger replication from DC1 to DC2
380 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
381 moved_metadata_dc2 = [
382 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
383 (DRSUAPI_ATTID_cn, self.dc2_guid, 1),
384 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
385 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
386 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
387 (DRSUAPI_ATTID_name, self.dc1_guid, 2),
388 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
389 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
390 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
391 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
392 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
393 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
394 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
395 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
396 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
397 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
398 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
399 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
400 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
401 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
402 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
403 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
405 # check user info on DC2 - should be valid user
406 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
407 obj_orig=user_moved_orig,
408 is_deleted=False,
409 expected_metadata=moved_metadata_dc2)
411 # delete user on DC1
412 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
413 deleted_metadata = [
414 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
415 (DRSUAPI_ATTID_cn, self.dc1_guid, 2),
416 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
417 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
418 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
419 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
420 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
421 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
422 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
423 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
424 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
425 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
426 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
427 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
428 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
429 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
430 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
431 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
432 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
433 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
434 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
435 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
436 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
437 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
438 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
440 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_moved_orig, is_deleted=True, expected_metadata=deleted_metadata)
442 # Modify description on DC2. This triggers a replication, but
443 # not of 'name' and so a bug in Samba regarding the DN.
444 msg = ldb.Message()
445 msg.dn = new_dn
446 msg["description"] = ldb.MessageElement("User Description", ldb.FLAG_MOD_REPLACE, "description")
447 self.ldb_dc2.modify(msg)
449 modified_metadata = [
450 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
451 (DRSUAPI_ATTID_cn, self.dc2_guid, 1),
452 (DRSUAPI_ATTID_description, self.dc2_guid, 1),
453 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
454 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
455 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
456 (DRSUAPI_ATTID_name, self.dc1_guid, 2),
457 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
458 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
459 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
460 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
461 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
462 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
463 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
464 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
465 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
466 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
467 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
468 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
469 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
470 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
471 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
472 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
474 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
475 obj_orig=user_moved_orig,
476 is_deleted=False,
477 expected_metadata=modified_metadata)
479 # trigger replication from DC1 to DC2, for cleanup
480 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
482 deleted_modified_metadata_dc2 = [
483 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
484 (DRSUAPI_ATTID_cn, self.dc2_guid, 2),
485 (DRSUAPI_ATTID_description, self.dc2_guid, 2),
486 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
487 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
488 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
489 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
490 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
491 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
492 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
493 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
494 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
495 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
496 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
497 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
498 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
499 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
500 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
501 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
502 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
503 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
504 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
505 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
506 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
507 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
508 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
510 # check user info on DC2 - should be deleted user
511 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
512 obj_orig=user_moved_orig,
513 is_deleted=True,
514 expected_metadata=deleted_modified_metadata_dc2)
515 self.assertFalse("description" in user_cur)
517 # trigger replication from DC2 to DC1, for cleanup
518 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
520 deleted_modified_metadata_dc1 = [
521 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
522 (DRSUAPI_ATTID_cn, self.dc1_guid, 2),
523 (DRSUAPI_ATTID_description, self.dc2_guid, 2),
524 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
525 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
526 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
527 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
528 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
529 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
530 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
531 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
532 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
533 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
534 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
535 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
536 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
537 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
538 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
539 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
540 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
541 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
542 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
543 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
544 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
545 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
546 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
548 # check user info on DC1 - should be deleted user
549 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
550 obj_orig=user_moved_orig,
551 is_deleted=True,
552 expected_metadata=deleted_modified_metadata_dc1)
553 self.assertFalse("description" in user_cur)
555 def test_ReplicateMoveObject2(self):
556 """Verifies how a moved container with a user inside is not
557 replicated between two DCs as no replication is triggered
558 This test should verify that:
559 - the OU is not replicated
560 - the user is not replicated
563 # work-out unique username to test with
564 username = self._make_username()
566 # create user on DC1
567 self.ldb_dc1.newuser(username=username,
568 userou="ou=%s,ou=%s"
569 % (self.ou1_dn.get_component_value(0),
570 self.top_ou.get_component_value(0)),
571 password=None, setpassword=False)
572 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
573 scope=SCOPE_SUBTREE,
574 expression="(samAccountName=%s)" % username,
575 attrs=["*", "parentGUID"])
576 self.assertEqual(len(ldb_res), 1)
577 user_orig = ldb_res[0]
578 user_dn = ldb_res[0]["dn"]
580 # check user info on DC1
581 print("Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])))
582 initial_metadata = [
583 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
584 (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
585 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
586 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
587 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
588 (DRSUAPI_ATTID_name, self.dc1_guid, 1),
589 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
590 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
591 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
592 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
593 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
594 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
595 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
596 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
597 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
598 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
599 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
600 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
601 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
602 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
603 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
604 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
606 self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
607 obj_orig=user_orig, is_deleted=False,
608 expected_metadata=initial_metadata)
610 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
611 new_dn.add_base(self.ou2_dn)
612 self.ldb_dc1.rename(user_dn, new_dn)
613 ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
614 scope=SCOPE_SUBTREE,
615 expression="(samAccountName=%s)" % username,
616 attrs=["*", "parentGUID"])
617 self.assertEqual(len(ldb_res), 1)
618 user_moved_orig = ldb_res[0]
620 moved_metadata = [
621 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
622 (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
623 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
624 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
625 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
626 (DRSUAPI_ATTID_name, self.dc1_guid, 2),
627 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
628 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
629 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
630 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
631 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
632 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
633 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
634 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
635 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
636 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
637 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
638 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
639 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
640 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
641 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
642 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
644 # check user info on DC1 after rename - should be valid user
645 self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
646 obj_orig=user_moved_orig,
647 is_deleted=False,
648 expected_metadata=moved_metadata)
650 # check user info on DC2 - should not be there, we have not done replication
651 ldb_res = self.ldb_dc2.search(base=self.ou2_dn,
652 scope=SCOPE_SUBTREE,
653 expression="(samAccountName=%s)" % username,
654 attrs=["*", "parentGUID"])
655 self.assertEqual(len(ldb_res), 0)
657 # delete user on DC1
658 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
660 deleted_metadata_dc1 = [
661 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
662 (DRSUAPI_ATTID_cn, self.dc1_guid, 2),
663 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
664 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
665 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
666 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
667 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
668 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
669 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
670 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
671 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
672 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
673 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
674 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
675 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
676 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
677 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
678 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
679 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
680 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
681 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
682 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
683 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
684 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
685 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
687 # check user info on DC1 - should be deleted user
688 self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
689 obj_orig=user_moved_orig,
690 is_deleted=True,
691 expected_metadata=deleted_metadata_dc1)
692 # trigger replication from DC1 to DC2, for cleanup
693 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
695 deleted_metadata_dc2 = [
696 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
697 (DRSUAPI_ATTID_cn, self.dc2_guid, 1),
698 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
699 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
700 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
701 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
702 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
703 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
704 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
705 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
706 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
707 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
708 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
709 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
710 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
711 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
712 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
713 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
714 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
715 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
716 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
717 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
718 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
719 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
720 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
722 # check user info on DC2 - should be deleted user
723 self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
724 obj_orig=user_moved_orig,
725 is_deleted=True,
726 expected_metadata=deleted_metadata_dc2)
728 # trigger replication from DC2 to DC1, for cleanup
729 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
731 # check user info on DC1 - should be deleted user
732 self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
733 obj_orig=user_moved_orig,
734 is_deleted=True,
735 expected_metadata=deleted_metadata_dc1)
737 def test_ReplicateMoveObject3(self):
738 """Verifies how a moved container with a user inside is replicated between two DCs.
739 This test should verify that:
740 - the OU is created on DC1
741 - the OU is renamed on DC1
742 - We verify that after replication,
743 that the user has the correct DN (under OU2).
746 # work-out unique username to test with
747 username = self._make_username()
749 # create user on DC1
750 self.ldb_dc1.newuser(username=username,
751 userou="ou=%s,ou=%s"
752 % (self.ou1_dn.get_component_value(0),
753 self.top_ou.get_component_value(0)),
754 password=None, setpassword=False)
755 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
756 scope=SCOPE_SUBTREE,
757 expression="(samAccountName=%s)" % username,
758 attrs=["*", "parentGUID"])
759 self.assertEqual(len(ldb_res), 1)
760 user_orig = ldb_res[0]
761 user_dn = ldb_res[0]["dn"]
763 # check user info on DC1
764 print("Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])))
765 initial_metadata = [
766 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
767 (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
768 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
769 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
770 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
771 (DRSUAPI_ATTID_name, self.dc1_guid, 1),
772 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
773 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
774 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
775 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
776 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
777 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
778 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
779 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
780 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
781 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
782 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
783 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
784 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
785 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
786 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
787 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
789 self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
790 obj_orig=user_orig, is_deleted=False,
791 expected_metadata=initial_metadata)
793 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
794 new_dn.add_base(self.ou2_dn)
795 self.ldb_dc1.rename(user_dn, new_dn)
796 ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
797 scope=SCOPE_SUBTREE,
798 expression="(samAccountName=%s)" % username,
799 attrs=["*", "parentGUID"])
800 self.assertEqual(len(ldb_res), 1)
802 user_moved_orig = ldb_res[0]
804 # trigger replication from DC1 to DC2
805 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
806 moved_metadata = [
807 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
808 (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
809 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
810 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
811 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
812 (DRSUAPI_ATTID_name, self.dc1_guid, 2),
813 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
814 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
815 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
816 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
817 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
818 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
819 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
820 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
821 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
822 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
823 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
824 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
825 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
826 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
827 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
828 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
830 # check user info on DC1 after rename - should be valid user
831 self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
832 obj_orig=user_moved_orig,
833 is_deleted=False,
834 expected_metadata=moved_metadata)
836 # delete user on DC1
837 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
838 deleted_metadata_dc1 = [
839 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
840 (DRSUAPI_ATTID_cn, self.dc1_guid, 2),
841 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
842 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
843 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
844 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
845 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
846 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
847 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
848 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
849 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
850 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
851 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
852 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
853 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
854 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
855 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
856 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
857 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
858 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
859 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
860 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
861 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
862 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
863 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
865 # check user info on DC1 - should be deleted user
866 self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
867 obj_orig=user_moved_orig,
868 is_deleted=True,
869 expected_metadata=deleted_metadata_dc1)
871 # trigger replication from DC2 to DC1
872 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
874 # check user info on DC1 - should be deleted user
875 self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
876 obj_orig=user_moved_orig,
877 is_deleted=True,
878 expected_metadata=deleted_metadata_dc1)
880 # trigger replication from DC1 to DC2, for cleanup
881 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
883 deleted_metadata_dc2 = [
884 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
885 (DRSUAPI_ATTID_cn, self.dc2_guid, 2),
886 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
887 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
888 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
889 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
890 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
891 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
892 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
893 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
894 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
895 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
896 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
897 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
898 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
899 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
900 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
901 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
902 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
903 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
904 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
905 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
906 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
907 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
908 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
910 # check user info on DC2 - should be deleted user
911 self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
912 obj_orig=user_moved_orig,
913 is_deleted=True,
914 expected_metadata=deleted_metadata_dc2)
916 def test_ReplicateMoveObject3b(self):
917 """Verifies how a moved container with a user inside is replicated between two DCs.
918 This test should verify that:
919 - the OU is created on DC1
920 - the OU is renamed on DC1
921 - We verify that after replication,
922 that the user has the correct DN (under OU2).
925 # work-out unique username to test with
926 username = self._make_username()
928 # create user on DC1
929 self.ldb_dc1.newuser(username=username,
930 userou="ou=%s,ou=%s"
931 % (self.ou1_dn.get_component_value(0),
932 self.top_ou.get_component_value(0)),
933 password=None, setpassword=False)
934 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
935 scope=SCOPE_SUBTREE,
936 expression="(samAccountName=%s)" % username,
937 attrs=["*", "parentGUID"])
938 self.assertEqual(len(ldb_res), 1)
939 user_orig = ldb_res[0]
940 user_dn = ldb_res[0]["dn"]
942 # check user info on DC1
943 print("Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])))
944 initial_metadata = [
945 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
946 (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
947 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
948 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
949 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
950 (DRSUAPI_ATTID_name, self.dc1_guid, 1),
951 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
952 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
953 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
954 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
955 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
956 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
957 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
958 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
959 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
960 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
961 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
962 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
963 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
964 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
965 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
966 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
968 self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
969 obj_orig=user_orig, is_deleted=False,
970 expected_metadata=initial_metadata)
972 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
973 new_dn.add_base(self.ou2_dn)
974 self.ldb_dc1.rename(user_dn, new_dn)
975 ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
976 scope=SCOPE_SUBTREE,
977 expression="(samAccountName=%s)" % username,
978 attrs=["*", "parentGUID"])
979 self.assertEqual(len(ldb_res), 1)
981 user_moved_orig = ldb_res[0]
983 # trigger replication from DC2 (Which has never seen the object) to DC1
984 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
985 moved_metadata = [
986 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
987 (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
988 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
989 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
990 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
991 (DRSUAPI_ATTID_name, self.dc1_guid, 2),
992 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
993 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
994 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
995 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
996 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
997 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
998 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
999 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
1000 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
1001 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
1002 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
1003 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
1004 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
1005 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
1006 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
1007 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
1009 # check user info on DC1 after rename - should be valid user
1010 self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
1011 obj_orig=user_moved_orig,
1012 is_deleted=False,
1013 expected_metadata=moved_metadata)
1015 # delete user on DC1
1016 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
1017 deleted_metadata_dc1 = [
1018 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
1019 (DRSUAPI_ATTID_cn, self.dc1_guid, 2),
1020 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
1021 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
1022 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
1023 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
1024 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
1025 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
1026 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
1027 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
1028 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
1029 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
1030 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
1031 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
1032 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
1033 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
1034 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
1035 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
1036 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
1037 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
1038 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
1039 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
1040 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
1041 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
1042 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
1044 # check user info on DC1 - should be deleted user
1045 self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
1046 obj_orig=user_moved_orig,
1047 is_deleted=True,
1048 expected_metadata=deleted_metadata_dc1)
1050 # trigger replication from DC2 to DC1
1051 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1053 # check user info on DC1 - should be deleted user
1054 self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
1055 obj_orig=user_moved_orig,
1056 is_deleted=True,
1057 expected_metadata=deleted_metadata_dc1)
1059 # trigger replication from DC1 to DC2, for cleanup
1060 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1062 deleted_metadata_dc2 = [
1063 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
1064 (DRSUAPI_ATTID_cn, self.dc2_guid, 1),
1065 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
1066 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
1067 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
1068 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
1069 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
1070 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
1071 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
1072 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
1073 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
1074 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
1075 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
1076 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
1077 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
1078 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
1079 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
1080 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
1081 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
1082 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
1083 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
1084 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
1085 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
1086 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
1087 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
1089 # check user info on DC2 - should be deleted user
1090 self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
1091 obj_orig=user_moved_orig,
1092 is_deleted=True,
1093 expected_metadata=deleted_metadata_dc2)
1095 def test_ReplicateMoveObject4(self):
1096 """Verifies how a moved container with a user inside is replicated between two DCs.
1097 This test should verify that:
1098 - the OU is replicated properly
1099 - the user is modified on DC2
1100 - the OU is renamed on DC1
1101 - We verify that after replication DC1 -> DC2,
1102 that the user has the correct DN (under OU2), and the description
1105 # work-out unique username to test with
1106 username = self._make_username()
1108 # create user on DC1
1109 self.ldb_dc1.newuser(username=username,
1110 userou="ou=%s,ou=%s"
1111 % (self.ou1_dn.get_component_value(0),
1112 self.top_ou.get_component_value(0)),
1113 password=None, setpassword=False)
1114 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
1115 scope=SCOPE_SUBTREE,
1116 expression="(samAccountName=%s)" % username,
1117 attrs=["*", "parentGUID"])
1118 self.assertEqual(len(ldb_res), 1)
1119 user_orig = ldb_res[0]
1120 user_dn = ldb_res[0]["dn"]
1122 # check user info on DC1
1123 print("Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])))
1124 initial_metadata = [
1125 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
1126 (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
1127 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
1128 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
1129 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
1130 (DRSUAPI_ATTID_name, self.dc1_guid, 1),
1131 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
1132 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
1133 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
1134 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
1135 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
1136 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
1137 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
1138 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
1139 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
1140 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
1141 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
1142 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
1143 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
1144 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
1145 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
1146 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
1148 self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
1149 obj_orig=user_orig, is_deleted=False,
1150 expected_metadata=initial_metadata)
1152 # trigger replication from DC1 to DC2
1153 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1155 initial_metadata_dc2 = [
1156 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
1157 (DRSUAPI_ATTID_cn, self.dc2_guid, 1),
1158 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
1159 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
1160 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
1161 (DRSUAPI_ATTID_name, self.dc1_guid, 1),
1162 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
1163 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
1164 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
1165 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
1166 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
1167 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
1168 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
1169 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
1170 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
1171 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
1172 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
1173 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
1174 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
1175 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
1176 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
1177 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
1179 # check user info on DC2 - should still be valid user
1180 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
1181 obj_orig=user_orig, is_deleted=False,
1182 expected_metadata=initial_metadata_dc2)
1184 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
1185 new_dn.add_base(self.ou2_dn)
1186 self.ldb_dc1.rename(user_dn, new_dn)
1187 ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
1188 scope=SCOPE_SUBTREE,
1189 expression="(samAccountName=%s)" % username,
1190 attrs=["*", "parentGUID"])
1191 self.assertEqual(len(ldb_res), 1)
1193 user_moved_orig = ldb_res[0]
1195 moved_metadata = [
1196 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
1197 (DRSUAPI_ATTID_cn, self.dc1_guid, 1),
1198 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
1199 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
1200 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
1201 (DRSUAPI_ATTID_name, self.dc1_guid, 2),
1202 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
1203 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
1204 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
1205 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
1206 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
1207 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
1208 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
1209 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
1210 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
1211 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
1212 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
1213 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
1214 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
1215 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
1216 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
1217 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
1219 # check user info on DC1 after rename - should be valid user
1220 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
1221 obj_orig=user_moved_orig,
1222 is_deleted=False,
1223 expected_metadata=moved_metadata)
1225 # Modify description on DC2. This triggers a replication, but
1226 # not of 'name' and so a bug in Samba regarding the DN.
1227 msg = ldb.Message()
1228 msg.dn = user_dn
1229 msg["description"] = ldb.MessageElement("User Description", ldb.FLAG_MOD_REPLACE, "description")
1230 self.ldb_dc2.modify(msg)
1232 modified_metadata = [
1233 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
1234 (DRSUAPI_ATTID_cn, self.dc2_guid, 1),
1235 (DRSUAPI_ATTID_description, self.dc2_guid, 1),
1236 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
1237 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
1238 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
1239 (DRSUAPI_ATTID_name, self.dc1_guid, 1),
1240 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
1241 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
1242 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
1243 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
1244 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
1245 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
1246 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
1247 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
1248 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
1249 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
1250 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
1251 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
1252 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
1253 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
1254 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
1255 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
1257 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
1258 obj_orig=user_orig,
1259 is_deleted=False,
1260 expected_metadata=modified_metadata)
1262 # trigger replication from DC1 to DC2
1263 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1265 modified_renamed_metadata = [
1266 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
1267 (DRSUAPI_ATTID_cn, self.dc2_guid, 2),
1268 (DRSUAPI_ATTID_description, self.dc2_guid, 1),
1269 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
1270 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
1271 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
1272 (DRSUAPI_ATTID_name, self.dc1_guid, 2),
1273 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
1274 (DRSUAPI_ATTID_codePage, self.dc1_guid, 1),
1275 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 1),
1276 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
1277 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
1278 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
1279 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
1280 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 1),
1281 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 1),
1282 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
1283 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 1),
1284 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
1285 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
1286 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 1),
1287 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 1),
1288 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 1)]
1290 # check user info on DC2 - should still be valid user
1291 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
1292 obj_orig=user_moved_orig,
1293 is_deleted=False,
1294 expected_metadata=modified_renamed_metadata)
1296 self.assertTrue("description" in user_cur)
1298 # delete user on DC1
1299 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
1300 deleted_metadata_dc1 = [
1301 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
1302 (DRSUAPI_ATTID_cn, self.dc1_guid, 2),
1303 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
1304 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
1305 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
1306 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
1307 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
1308 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
1309 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
1310 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
1311 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
1312 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
1313 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
1314 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
1315 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
1316 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
1317 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
1318 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
1319 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
1320 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
1321 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
1322 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
1323 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
1324 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
1325 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
1327 # check user info on DC1 - should be deleted user
1328 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
1329 obj_orig=user_moved_orig,
1330 is_deleted=True,
1331 expected_metadata=deleted_metadata_dc1)
1333 # trigger replication from DC2 to DC1
1334 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1335 # check user info on DC2 - should still be valid user
1336 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
1337 obj_orig=user_moved_orig,
1338 is_deleted=False,
1339 expected_metadata=modified_renamed_metadata)
1341 self.assertTrue("description" in user_cur)
1343 deleted_metadata_dc1 = [
1344 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
1345 (DRSUAPI_ATTID_cn, self.dc1_guid, 2),
1346 (DRSUAPI_ATTID_description, self.dc1_guid, 2),
1347 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
1348 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
1349 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
1350 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
1351 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
1352 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
1353 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
1354 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
1355 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
1356 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
1357 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
1358 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
1359 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
1360 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
1361 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
1362 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
1363 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
1364 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
1365 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
1366 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
1367 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
1368 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
1369 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
1371 # check user info on DC1 - should be deleted user
1372 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, drs=self.drs_dc1,
1373 obj_orig=user_moved_orig,
1374 is_deleted=True,
1375 expected_metadata=deleted_metadata_dc1)
1377 self.assertFalse("description" in user_cur)
1379 # trigger replication from DC1 to DC2, for cleanup
1380 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1382 deleted_metadata_dc2 = [
1383 (DRSUAPI_ATTID_objectClass, self.dc1_guid, 1),
1384 (DRSUAPI_ATTID_cn, self.dc2_guid, 3),
1385 (DRSUAPI_ATTID_description, self.dc1_guid, 2),
1386 (DRSUAPI_ATTID_instanceType, self.dc1_guid, 1),
1387 (DRSUAPI_ATTID_whenCreated, self.dc1_guid, 1),
1388 (DRSUAPI_ATTID_isDeleted, self.dc1_guid, 1),
1389 (DRSUAPI_ATTID_ntSecurityDescriptor, self.dc1_guid, 1),
1390 (DRSUAPI_ATTID_name, self.dc1_guid, 3),
1391 (DRSUAPI_ATTID_userAccountControl, self.dc1_guid, None),
1392 (DRSUAPI_ATTID_codePage, self.dc1_guid, 2),
1393 (DRSUAPI_ATTID_countryCode, self.dc1_guid, 2),
1394 (DRSUAPI_ATTID_dBCSPwd, self.dc1_guid, 1),
1395 (DRSUAPI_ATTID_logonHours, self.dc1_guid, 1),
1396 (DRSUAPI_ATTID_unicodePwd, self.dc1_guid, 1),
1397 (DRSUAPI_ATTID_ntPwdHistory, self.dc1_guid, 1),
1398 (DRSUAPI_ATTID_pwdLastSet, self.dc1_guid, 2),
1399 (DRSUAPI_ATTID_primaryGroupID, self.dc1_guid, 2),
1400 (DRSUAPI_ATTID_objectSid, self.dc1_guid, 1),
1401 (DRSUAPI_ATTID_accountExpires, self.dc1_guid, 2),
1402 (DRSUAPI_ATTID_lmPwdHistory, self.dc1_guid, 1),
1403 (DRSUAPI_ATTID_sAMAccountName, self.dc1_guid, 1),
1404 (DRSUAPI_ATTID_sAMAccountType, self.dc1_guid, 2),
1405 (DRSUAPI_ATTID_userPrincipalName, self.dc1_guid, 2),
1406 (DRSUAPI_ATTID_lastKnownParent, self.dc1_guid, 1),
1407 (DRSUAPI_ATTID_objectCategory, self.dc1_guid, 2),
1408 (DRSUAPI_ATTID_isRecycled, self.dc1_guid, 1)]
1410 # check user info on DC2 - should be deleted user
1411 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, drs=self.drs_dc2,
1412 obj_orig=user_moved_orig,
1413 is_deleted=True,
1414 expected_metadata=deleted_metadata_dc2)
1416 self.assertFalse("description" in user_cur)
1418 def test_ReplicateMoveObject5(self):
1419 """Verifies how a moved container with a user inside is replicated between two DCs.
1420 This test should verify that:
1421 - the OU is replicated properly
1422 - the user is modified on DC2
1423 - the OU is renamed on DC1
1424 - We verify that after replication DC2 -> DC1,
1425 that the user has the correct DN (under OU2), and the description
1428 # work-out unique username to test with
1429 username = self._make_username()
1431 # create user on DC1
1432 self.ldb_dc1.newuser(username=username,
1433 userou="ou=%s,ou=%s"
1434 % (self.ou1_dn.get_component_value(0),
1435 self.top_ou.get_component_value(0)),
1436 password=None, setpassword=False)
1437 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
1438 scope=SCOPE_SUBTREE,
1439 expression="(samAccountName=%s)" % username,
1440 attrs=["*", "parentGUID"])
1441 self.assertEqual(len(ldb_res), 1)
1442 user_orig = ldb_res[0]
1443 user_dn = ldb_res[0]["dn"]
1445 # trigger replication from DC1 to DC2
1446 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1447 # check user info on DC2 - should still be valid user
1448 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=False)
1450 # check user info on DC1
1451 print("Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])))
1452 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=False)
1454 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
1455 new_dn.add_base(self.ou2_dn)
1456 self.ldb_dc1.rename(user_dn, new_dn)
1457 ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
1458 scope=SCOPE_SUBTREE,
1459 expression="(samAccountName=%s)" % username,
1460 attrs=["*", "parentGUID"])
1461 self.assertEqual(len(ldb_res), 1)
1463 user_moved_orig = ldb_res[0]
1465 # Modify description on DC2. This triggers a replication, but
1466 # not of 'name' and so a bug in Samba regarding the DN.
1467 msg = ldb.Message()
1468 msg.dn = user_dn
1469 msg["description"] = ldb.MessageElement("User Description", ldb.FLAG_MOD_REPLACE, "description")
1470 self.ldb_dc2.modify(msg)
1472 # trigger replication from DC2 to DC1
1473 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1474 # check user info on DC1 - should still be valid user
1475 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_moved_orig, is_deleted=False)
1476 self.assertTrue("description" in user_cur)
1478 # trigger replication from DC1 to DC2
1479 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1480 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
1481 self.assertTrue("description" in user_cur)
1483 # delete user on DC2
1484 self.ldb_dc2.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
1485 # trigger replication from DC2 to DC1 for cleanup
1486 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1488 # check user info on DC1 - should be deleted user
1489 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_moved_orig, is_deleted=True)
1490 self.assertFalse("description" in user_cur)
1492 def test_ReplicateMoveObject6(self):
1493 """Verifies how a moved container is replicated between two DCs.
1494 This test should verify that:
1495 - the OU1 is replicated properly
1496 - the OU1 is modified on DC2
1497 - the OU1 is renamed on DC1
1498 - We verify that after replication DC1 -> DC2,
1499 that the OU1 has the correct DN (under OU2), and the description
1502 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
1503 scope=SCOPE_BASE,
1504 attrs=["*", "parentGUID"])
1505 self.assertEqual(len(ldb_res), 1)
1506 ou_orig = ldb_res[0]
1507 ou_dn = ldb_res[0]["dn"]
1509 # check user info on DC1
1510 print("Testing for %s with GUID %s" % (self.ou1_dn, self._GUID_string(ou_orig["objectGUID"][0])))
1511 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1513 # trigger replication from DC1 to DC2
1514 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1515 # check user info on DC2 - should still be valid user
1516 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1518 new_dn = ldb.Dn(self.ldb_dc1, "OU=%s" % self.ou1_dn.get_component_value(0))
1519 new_dn.add_base(self.ou2_dn)
1520 self.ldb_dc1.rename(ou_dn, new_dn)
1521 ldb_res = self.ldb_dc1.search(base=new_dn,
1522 scope=SCOPE_BASE,
1523 attrs=["*", "parentGUID"])
1524 self.assertEqual(len(ldb_res), 1)
1526 ou_moved_orig = ldb_res[0]
1528 # Modify description on DC2. This triggers a replication, but
1529 # not of 'name' and so a bug in Samba regarding the DN.
1530 msg = ldb.Message()
1531 msg.dn = ou_dn
1532 msg["description"] = ldb.MessageElement("OU Description", ldb.FLAG_MOD_REPLACE, "description")
1533 self.ldb_dc2.modify(msg)
1535 # trigger replication from DC1 to DC2
1536 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1537 # check user info on DC2 - should still be valid user
1538 ou_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=ou_moved_orig, is_deleted=False)
1539 self.assertTrue("description" in ou_cur)
1541 # delete OU on DC1
1542 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(ou_orig["objectGUID"][0]))
1543 # trigger replication from DC2 to DC1
1544 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1545 # check user info on DC2 - should be deleted user
1546 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_moved_orig, is_deleted=True)
1547 self.assertFalse("description" in ou_cur)
1549 # trigger replication from DC1 to DC2, for cleanup
1550 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1552 # check user info on DC2 - should be deleted user
1553 ou_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=ou_moved_orig, is_deleted=True)
1554 self.assertFalse("description" in ou_cur)
1556 def test_ReplicateMoveObject7(self):
1557 """Verifies how a moved container is replicated between two DCs.
1558 This test should verify that:
1559 - the OU1 is replicated properly
1560 - the OU1 is modified on DC2
1561 - the OU1 is renamed on DC1 to be under OU2
1562 - We verify that after replication DC2 -> DC1,
1563 that the OU1 has the correct DN (under OU2), and the description
1566 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
1567 scope=SCOPE_BASE,
1568 attrs=["*", "parentGUID"])
1569 self.assertEqual(len(ldb_res), 1)
1570 ou_orig = ldb_res[0]
1571 ou_dn = ldb_res[0]["dn"]
1573 # check user info on DC1
1574 print("Testing for %s with GUID %s" % (self.ou1_dn, self._GUID_string(ou_orig["objectGUID"][0])))
1575 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1577 # trigger replication from DC1 to DC2
1578 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1579 # check user info on DC2 - should still be valid user
1580 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1582 new_dn = ldb.Dn(self.ldb_dc1, "OU=%s" % self.ou1_dn.get_component_value(0))
1583 new_dn.add_base(self.ou2_dn)
1584 self.ldb_dc1.rename(ou_dn, new_dn)
1585 ldb_res = self.ldb_dc1.search(base=new_dn,
1586 scope=SCOPE_BASE,
1587 attrs=["*", "parentGUID"])
1588 self.assertEqual(len(ldb_res), 1)
1590 ou_moved_orig = ldb_res[0]
1592 # Modify description on DC2. This triggers a replication, but
1593 # not of 'name' and so a bug in Samba regarding the DN.
1594 msg = ldb.Message()
1595 msg.dn = ou_dn
1596 msg["description"] = ldb.MessageElement("OU Description", ldb.FLAG_MOD_REPLACE, "description")
1597 self.ldb_dc2.modify(msg)
1599 # trigger replication from DC2 to DC1
1600 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1601 # check user info on DC1 - should still be valid user
1602 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_moved_orig, is_deleted=False)
1603 self.assertTrue("description" in ou_cur)
1605 # delete OU on DC1
1606 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(ou_orig["objectGUID"][0]))
1607 # trigger replication from DC2 to DC1
1608 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1609 # check user info on DC2 - should be deleted user
1610 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_moved_orig, is_deleted=True)
1611 self.assertFalse("description" in ou_cur)
1613 # trigger replication from DC1 to DC2, for cleanup
1614 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1616 # check user info on DC2 - should be deleted user
1617 ou_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=ou_moved_orig, is_deleted=True)
1618 self.assertFalse("description" in ou_cur)
1620 def test_ReplicateMoveObject8(self):
1621 """Verifies how a moved container is replicated between two DCs.
1622 This test should verify that:
1623 - the OU1 is replicated properly
1624 - the OU1 is modified on DC2
1625 - the OU1 is renamed on DC1 to OU1-renamed
1626 - We verify that after replication DC1 -> DC2,
1627 that the OU1 has the correct DN (OU1-renamed), and the description
1630 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
1631 scope=SCOPE_BASE,
1632 attrs=["*", "parentGUID"])
1633 self.assertEqual(len(ldb_res), 1)
1634 ou_orig = ldb_res[0]
1635 ou_dn = ldb_res[0]["dn"]
1637 # check user info on DC1
1638 print("Testing for %s with GUID %s" % (self.ou1_dn, self._GUID_string(ou_orig["objectGUID"][0])))
1639 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1641 # trigger replication from DC1 to DC2
1642 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1643 # check user info on DC2 - should still be valid user
1644 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1646 new_dn = ldb.Dn(self.ldb_dc1, "OU=%s-renamed" % self.ou1_dn.get_component_value(0))
1647 new_dn.add_base(self.ou1_dn.parent())
1648 self.ldb_dc1.rename(ou_dn, new_dn)
1649 ldb_res = self.ldb_dc1.search(base=new_dn,
1650 scope=SCOPE_BASE,
1651 attrs=["*", "parentGUID"])
1652 self.assertEqual(len(ldb_res), 1)
1654 ou_moved_orig = ldb_res[0]
1656 # Modify description on DC2. This triggers a replication, but
1657 # not of 'name' and so a bug in Samba regarding the DN.
1658 msg = ldb.Message()
1659 msg.dn = ou_dn
1660 msg["description"] = ldb.MessageElement("OU Description", ldb.FLAG_MOD_REPLACE, "description")
1661 self.ldb_dc2.modify(msg)
1663 # trigger replication from DC1 to DC2
1664 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1665 # check user info on DC2 - should still be valid user
1666 ou_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=ou_moved_orig, is_deleted=False)
1667 self.assertTrue("description" in ou_cur)
1669 # delete OU on DC1
1670 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(ou_orig["objectGUID"][0]))
1671 # trigger replication from DC2 to DC1
1672 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1673 # check user info on DC2 - should be deleted user
1674 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_moved_orig, is_deleted=True)
1675 self.assertFalse("description" in ou_cur)
1677 # trigger replication from DC1 to DC2, for cleanup
1678 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1680 # check user info on DC2 - should be deleted user
1681 ou_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=ou_moved_orig, is_deleted=True)
1682 self.assertFalse("description" in ou_cur)
1684 def test_ReplicateMoveObject9(self):
1685 """Verifies how a moved container is replicated between two DCs.
1686 This test should verify that:
1687 - the OU1 is replicated properly
1688 - the OU1 is modified on DC2
1689 - the OU1 is renamed on DC1 to be under OU2
1690 - the OU1 is renamed on DC1 to OU1-renamed
1691 - We verify that after replication DC1 -> DC2,
1692 that the OU1 has the correct DN (OU1-renamed), and the description
1695 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
1696 scope=SCOPE_BASE,
1697 attrs=["*", "parentGUID"])
1698 self.assertEqual(len(ldb_res), 1)
1699 ou_orig = ldb_res[0]
1700 ou_dn = ldb_res[0]["dn"]
1702 # check user info on DC1
1703 print("Testing for %s with GUID %s" % (self.ou1_dn, self._GUID_string(ou_orig["objectGUID"][0])))
1704 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1706 # trigger replication from DC1 to DC2
1707 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1708 # check user info on DC2 - should still be valid user
1709 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1711 new_dn = ldb.Dn(self.ldb_dc1, "OU=%s-renamed" % self.ou1_dn.get_component_value(0))
1712 new_dn.add_base(self.ou1_dn.parent())
1713 self.ldb_dc1.rename(ou_dn, new_dn)
1714 ldb_res = self.ldb_dc1.search(base=new_dn,
1715 scope=SCOPE_BASE,
1716 attrs=["*", "parentGUID"])
1717 self.assertEqual(len(ldb_res), 1)
1719 ou_moved_orig = ldb_res[0]
1721 # Modify description on DC2. This triggers a replication, but
1722 # not of 'name' and so a bug in Samba regarding the DN.
1723 msg = ldb.Message()
1724 msg.dn = ou_dn
1725 msg["description"] = ldb.MessageElement("OU Description", ldb.FLAG_MOD_REPLACE, "description")
1726 self.ldb_dc2.modify(msg)
1728 # trigger replication from DC2 to DC1
1729 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1730 # check user info on DC1 - should still be valid user
1731 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_moved_orig, is_deleted=False)
1732 self.assertTrue("description" in ou_cur)
1734 # delete OU on DC1
1735 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(ou_orig["objectGUID"][0]))
1736 # trigger replication from DC2 to DC1
1737 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1738 # check user info on DC2 - should be deleted user
1739 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_moved_orig, is_deleted=True)
1740 self.assertFalse("description" in ou_cur)
1742 # trigger replication from DC1 to DC2, for cleanup
1743 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1745 # check user info on DC2 - should be deleted user
1746 ou_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=ou_moved_orig, is_deleted=True)
1747 self.assertFalse("description" in ou_cur)
1749 def test_ReplicateMoveObject10(self):
1750 """Verifies how a moved container is replicated between two DCs.
1751 This test should verify that:
1752 - the OU1 is replicated properly
1753 - the OU1 is modified on DC2
1754 - the OU1 is deleted on DC1
1755 - We verify that after replication DC1 -> DC2,
1756 that the OU1 is deleted, and the description has gone away
1759 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
1760 scope=SCOPE_BASE,
1761 attrs=["*", "parentGUID"])
1762 self.assertEqual(len(ldb_res), 1)
1763 ou_orig = ldb_res[0]
1764 ou_dn = ldb_res[0]["dn"]
1766 # check user info on DC1
1767 print("Testing for %s with GUID %s" % (self.ou1_dn, self._GUID_string(ou_orig["objectGUID"][0])))
1768 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1770 # trigger replication from DC1 to DC2
1771 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1772 # check user info on DC2 - should still be valid user
1773 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1775 # Modify description on DC2. This triggers a replication, but
1776 # not of 'name' and so a bug in Samba regarding the DN.
1777 msg = ldb.Message()
1778 msg.dn = ou_dn
1779 msg["description"] = ldb.MessageElement("OU Description", ldb.FLAG_MOD_REPLACE, "description")
1780 self.ldb_dc2.modify(msg)
1782 # delete OU on DC1
1783 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(ou_orig["objectGUID"][0]))
1784 # trigger replication from DC1 to DC2
1785 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1786 # check user info on DC2 - should be deleted OU
1787 ou_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=ou_orig, is_deleted=True)
1788 self.assertFalse("description" in ou_cur)
1790 # trigger replication from DC1 to DC2, for cleanup
1791 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1793 # check user info on DC2 - should be deleted OU
1794 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=True)
1795 self.assertFalse("description" in ou_cur)
1797 def test_ReplicateMoveObject11(self):
1798 """Verifies how a moved container is replicated between two DCs.
1799 This test should verify that:
1800 - the OU1 is replicated properly
1801 - the OU1 is modified on DC2
1802 - the OU1 is deleted on DC1
1803 - We verify that after replication DC2 -> DC1,
1804 that the OU1 is deleted, and the description has gone away
1807 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
1808 scope=SCOPE_BASE,
1809 attrs=["*", "parentGUID"])
1810 self.assertEqual(len(ldb_res), 1)
1811 ou_orig = ldb_res[0]
1812 ou_dn = ldb_res[0]["dn"]
1814 # check user info on DC1
1815 print("Testing for %s with GUID %s" % (self.ou1_dn, self._GUID_string(ou_orig["objectGUID"][0])))
1816 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1818 # trigger replication from DC1 to DC2
1819 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1820 # check user info on DC2 - should still be valid user
1821 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=False)
1823 # Modify description on DC2. This triggers a replication, but
1824 # not of 'name' and so a bug in Samba regarding the DN.
1825 msg = ldb.Message()
1826 msg.dn = ou_dn
1827 msg["description"] = ldb.MessageElement("OU Description", ldb.FLAG_MOD_REPLACE, "description")
1828 self.ldb_dc2.modify(msg)
1830 # delete OU on DC1
1831 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(ou_orig["objectGUID"][0]))
1832 # trigger replication from DC2 to DC1
1833 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1834 # check user info on DC2 - should be deleted OU
1835 ou_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=ou_orig, is_deleted=True)
1836 self.assertFalse("description" in ou_cur)
1838 # trigger replication from DC1 to DC2, for cleanup
1839 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1841 # check user info on DC2 - should be deleted OU
1842 ou_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=ou_orig, is_deleted=True)
1843 self.assertFalse("description" in ou_cur)
1846 class DrsMoveBetweenTreeOfObjectTestCase(drs_base.DrsBaseTestCase):
1848 def setUp(self):
1849 super(DrsMoveBetweenTreeOfObjectTestCase, self).setUp()
1850 # disable automatic replication temporary
1851 self._disable_all_repl(self.dnsname_dc1)
1852 self._disable_all_repl(self.dnsname_dc2)
1854 self.top_ou = samba.tests.create_test_ou(self.ldb_dc1,
1855 "replica_move")
1857 # make sure DCs are synchronized before the test
1858 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
1859 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
1861 self.ou1_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU1")
1862 self.ou1_dn.add_base(self.top_ou)
1863 self.ou1 = {}
1864 self.ou1["dn"] = self.ou1_dn
1865 self.ou1["objectclass"] = "organizationalUnit"
1866 self.ou1["ou"] = self.ou1_dn.get_component_value(0)
1868 self.ou2_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU2,OU=DrsOU1")
1869 self.ou2_dn.add_base(self.top_ou)
1870 self.ou2 = {}
1871 self.ou2["dn"] = self.ou2_dn
1872 self.ou2["objectclass"] = "organizationalUnit"
1873 self.ou2["ou"] = self.ou2_dn.get_component_value(0)
1875 self.ou2b_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU2B,OU=DrsOU1")
1876 self.ou2b_dn.add_base(self.top_ou)
1877 self.ou2b = {}
1878 self.ou2b["dn"] = self.ou2b_dn
1879 self.ou2b["objectclass"] = "organizationalUnit"
1880 self.ou2b["ou"] = self.ou2b_dn.get_component_value(0)
1882 self.ou2c_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU2C,OU=DrsOU1")
1883 self.ou2c_dn.add_base(self.top_ou)
1885 self.ou3_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU3,OU=DrsOU2,OU=DrsOU1")
1886 self.ou3_dn.add_base(self.top_ou)
1887 self.ou3 = {}
1888 self.ou3["dn"] = self.ou3_dn
1889 self.ou3["objectclass"] = "organizationalUnit"
1890 self.ou3["ou"] = self.ou3_dn.get_component_value(0)
1892 self.ou4_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU4,OU=DrsOU3,OU=DrsOU2,OU=DrsOU1")
1893 self.ou4_dn.add_base(self.top_ou)
1894 self.ou4 = {}
1895 self.ou4["dn"] = self.ou4_dn
1896 self.ou4["objectclass"] = "organizationalUnit"
1897 self.ou4["ou"] = self.ou4_dn.get_component_value(0)
1899 self.ou5_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU5,OU=DrsOU4,OU=DrsOU3,OU=DrsOU2,OU=DrsOU1")
1900 self.ou5_dn.add_base(self.top_ou)
1901 self.ou5 = {}
1902 self.ou5["dn"] = self.ou5_dn
1903 self.ou5["objectclass"] = "organizationalUnit"
1904 self.ou5["ou"] = self.ou5_dn.get_component_value(0)
1906 self.ou6_dn = ldb.Dn(self.ldb_dc1, "OU=DrsOU6,OU=DrsOU5,OU=DrsOU4,OU=DrsOU3,OU=DrsOU2,OU=DrsOU1")
1907 self.ou6_dn.add_base(self.top_ou)
1908 self.ou6 = {}
1909 self.ou6["dn"] = self.ou6_dn
1910 self.ou6["objectclass"] = "organizationalUnit"
1911 self.ou6["ou"] = self.ou6_dn.get_component_value(0)
1913 def tearDown(self):
1914 self.ldb_dc1.delete(self.top_ou, ["tree_delete:1"])
1915 self._enable_all_repl(self.dnsname_dc1)
1916 self._enable_all_repl(self.dnsname_dc2)
1917 super(DrsMoveBetweenTreeOfObjectTestCase, self).tearDown()
1919 def _make_username(self):
1920 return "DrsTreeU_" + time.strftime("%s", time.gmtime())
1922 # now also used to check the group
1923 def _check_obj(self, sam_ldb, obj_orig, is_deleted):
1924 # search the user by guid as it may be deleted
1925 guid_str = self._GUID_string(obj_orig["objectGUID"][0])
1926 res = sam_ldb.search(base='<GUID=%s>' % guid_str,
1927 controls=["show_deleted:1"],
1928 attrs=["*", "parentGUID"])
1929 self.assertEqual(len(res), 1)
1930 user_cur = res[0]
1931 cn_orig = str(obj_orig["cn"][0])
1932 cn_cur = str(user_cur["cn"][0])
1933 name_orig = str(obj_orig["name"][0])
1934 name_cur = str(user_cur["name"][0])
1935 dn_orig = obj_orig["dn"]
1936 dn_cur = user_cur["dn"]
1937 # now check properties of the user
1938 if is_deleted:
1939 self.assertTrue("isDeleted" in user_cur)
1940 self.assertEqual(cn_cur.split('\n')[0], cn_orig)
1941 self.assertEqual(name_cur.split('\n')[0], name_orig)
1942 self.assertEqual(dn_cur.get_rdn_value().split('\n')[0],
1943 dn_orig.get_rdn_value())
1944 self.assertEqual(name_cur, cn_cur)
1945 else:
1946 self.assertFalse("isDeleted" in user_cur)
1947 self.assertEqual(cn_cur, cn_orig)
1948 self.assertEqual(name_cur, name_orig)
1949 self.assertEqual(dn_cur, dn_orig)
1950 self.assertEqual(name_cur, cn_cur)
1951 self.assertEqual(name_cur, user_cur.dn.get_rdn_value())
1953 return user_cur
1955 def test_ReplicateMoveInTree1(self):
1956 """Verifies how an object is replicated between two DCs.
1957 This test should verify that:
1958 - a complex OU tree can be replicated correctly
1959 - the user is in the correct spot (renamed into) within the tree
1960 on both DCs
1962 # work-out unique username to test with
1963 username = self._make_username()
1965 self.ldb_dc1.add(self.ou1)
1967 # create user on DC1
1968 self.ldb_dc1.newuser(username=username,
1969 userou="ou=%s,ou=%s"
1970 % (self.ou1_dn.get_component_value(0),
1971 self.top_ou.get_component_value(0)),
1972 password=None, setpassword=False)
1973 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
1974 scope=SCOPE_SUBTREE,
1975 expression="(samAccountName=%s)" % username)
1976 self.assertEqual(len(ldb_res), 1)
1977 user_orig = ldb_res[0]
1978 user_dn = ldb_res[0]["dn"]
1980 # check user info on DC1
1981 print("Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])))
1982 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=False)
1984 self.ldb_dc1.add(self.ou2)
1985 self.ldb_dc1.add(self.ou3)
1986 self.ldb_dc1.add(self.ou4)
1987 self.ldb_dc1.add(self.ou5)
1989 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
1990 new_dn.add_base(self.ou5_dn)
1991 self.ldb_dc1.rename(user_dn, new_dn)
1992 ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
1993 scope=SCOPE_SUBTREE,
1994 expression="(samAccountName=%s)" % username)
1995 self.assertEqual(len(ldb_res), 1)
1997 user_moved_orig = ldb_res[0]
1999 # trigger replication from DC1 to DC2
2000 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2001 # check user info on DC2 - should be valid user
2002 self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
2004 # delete user on DC1
2005 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
2007 # trigger replication from DC1 to DC2, for cleanup
2008 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2010 def test_ReplicateMoveInTree2(self):
2011 """Verifies how an object is replicated between two DCs.
2012 This test should verify that:
2013 - a complex OU tree can be replicated correctly
2014 - the user is in the correct spot (renamed into) within the tree
2015 on both DCs
2016 - that a rename back works correctly, and is replicated
2018 # work-out unique username to test with
2019 username = self._make_username()
2021 self.ldb_dc1.add(self.ou1)
2023 # create user on DC1
2024 self.ldb_dc1.newuser(username=username,
2025 userou="ou=%s,ou=%s"
2026 % (self.ou1_dn.get_component_value(0),
2027 self.top_ou.get_component_value(0)),
2028 password=None, setpassword=False)
2029 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2030 scope=SCOPE_SUBTREE,
2031 expression="(samAccountName=%s)" % username)
2032 self.assertEqual(len(ldb_res), 1)
2033 user_orig = ldb_res[0]
2034 user_dn = ldb_res[0]["dn"]
2036 # check user info on DC1
2037 print("Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])))
2038 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=False)
2040 self.ldb_dc1.add(self.ou2)
2041 self.ldb_dc1.add(self.ou2b)
2042 self.ldb_dc1.add(self.ou3)
2044 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
2045 new_dn.add_base(self.ou3_dn)
2046 self.ldb_dc1.rename(user_dn, new_dn)
2048 new_dn3 = ldb.Dn(self.ldb_dc1, "OU=%s" % self.ou3_dn.get_component_value(0))
2049 new_dn3.add_base(self.ou2b_dn)
2050 self.ldb_dc1.rename(self.ou3_dn, new_dn3)
2052 ldb_res = self.ldb_dc1.search(base=new_dn3,
2053 scope=SCOPE_SUBTREE,
2054 expression="(samAccountName=%s)" % username)
2055 self.assertEqual(len(ldb_res), 1)
2057 user_moved_orig = ldb_res[0]
2058 user_moved_dn = ldb_res[0]["dn"]
2060 # trigger replication from DC1 to DC2
2061 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2062 # check user info on DC2 - should be valid user
2063 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
2065 # Rename on DC1
2066 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
2067 new_dn.add_base(self.ou1_dn)
2068 self.ldb_dc1.rename(user_moved_dn, new_dn)
2070 # Modify description on DC2
2071 msg = ldb.Message()
2072 msg.dn = user_moved_dn
2073 msg["description"] = ldb.MessageElement("User Description", ldb.FLAG_MOD_REPLACE, "description")
2074 self.ldb_dc2.modify(msg)
2076 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2077 scope=SCOPE_SUBTREE,
2078 expression="(samAccountName=%s)" % username)
2079 self.assertEqual(len(ldb_res), 1)
2081 user_moved_orig = ldb_res[0]
2082 user_moved_dn = ldb_res[0]["dn"]
2084 # trigger replication from DC1 to DC2
2085 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2086 # check user info on DC2 - should be valid user
2087 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
2088 self.assertTrue("description" in user_cur)
2090 # delete user on DC1
2091 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
2093 # trigger replication from DC2 to DC1
2094 self._net_drs_replicate(DC=self.dnsname_dc1, fromDC=self.dnsname_dc2, forced=True)
2095 # check user info on DC1 - should be deleted user
2096 user_cur = self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_moved_orig, is_deleted=True)
2097 self.assertFalse("description" in user_cur)
2099 # trigger replication from DC1 to DC2, for cleanup
2100 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2101 # check user info on DC2 - should be deleted user
2102 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=True)
2103 self.assertFalse("description" in user_cur)
2105 def test_ReplicateMoveInTree3(self):
2106 """Verifies how an object is replicated between two DCs.
2107 This test should verify that:
2108 - a complex OU tree can be replicated correctly
2109 - the user is in the correct spot (renamed into) within the tree
2110 on both DCs
2111 - that a rename back works correctly, and is replicated
2113 # work-out unique username to test with
2114 username = self._make_username()
2116 self.ldb_dc1.add(self.ou1)
2118 # create user on DC1
2119 self.ldb_dc1.newuser(username=username,
2120 userou="ou=%s,ou=%s"
2121 % (self.ou1_dn.get_component_value(0),
2122 self.top_ou.get_component_value(0)),
2123 password=None, setpassword=False)
2124 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2125 scope=SCOPE_SUBTREE,
2126 expression="(samAccountName=%s)" % username)
2127 self.assertEqual(len(ldb_res), 1)
2128 user_orig = ldb_res[0]
2129 user_dn = ldb_res[0]["dn"]
2131 # check user info on DC1
2132 print("Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])))
2133 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=False)
2135 self.ldb_dc1.add(self.ou2)
2136 self.ldb_dc1.add(self.ou2b)
2137 self.ldb_dc1.add(self.ou3)
2139 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
2140 new_dn.add_base(self.ou3_dn)
2141 self.ldb_dc1.rename(user_dn, new_dn)
2143 new_dn3 = ldb.Dn(self.ldb_dc1, "OU=%s" % self.ou3_dn.get_component_value(0))
2144 new_dn3.add_base(self.ou2b_dn)
2145 self.ldb_dc1.rename(self.ou3_dn, new_dn3)
2147 ldb_res = self.ldb_dc1.search(base=new_dn3,
2148 scope=SCOPE_SUBTREE,
2149 expression="(samAccountName=%s)" % username)
2150 self.assertEqual(len(ldb_res), 1)
2152 user_moved_orig = ldb_res[0]
2153 user_moved_dn = ldb_res[0]["dn"]
2155 # trigger replication from DC1 to DC2
2156 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2157 # check user info on DC2 - should be valid user
2158 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
2160 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
2161 new_dn.add_base(self.ou2_dn)
2162 self.ldb_dc1.rename(user_moved_dn, new_dn)
2164 self.ldb_dc1.rename(self.ou2_dn, self.ou2c_dn)
2165 self.ldb_dc1.rename(self.ou2b_dn, self.ou2_dn)
2166 self.ldb_dc1.rename(self.ou2c_dn, self.ou2b_dn)
2168 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2169 scope=SCOPE_SUBTREE,
2170 expression="(samAccountName=%s)" % username,
2171 attrs=["*", "parentGUID"])
2172 self.assertEqual(len(ldb_res), 1)
2174 user_moved_orig = ldb_res[0]
2175 user_moved_dn = ldb_res[0]["dn"]
2177 # trigger replication from DC1 to DC2
2178 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2179 # check user info on DC2 - should be valid user
2180 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
2182 self.assertEqual(user_cur["parentGUID"], user_moved_orig["parentGUID"])
2184 # delete user on DC1
2185 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
2187 # trigger replication from DC1 to DC2, for cleanup
2188 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2190 def test_ReplicateMoveInTree3b(self):
2191 """Verifies how an object is replicated between two DCs.
2192 This test should verify that:
2193 - a complex OU tree can be replicated correctly
2194 - the user is in the correct spot (renamed into) within the tree
2195 on both DCs
2196 - that a rename back works correctly, and is replicated
2197 - that a complex rename suffle, combined with unrelated changes to the object,
2198 is replicated correctly. The aim here is the send the objects out-of-order
2199 when sorted by usnChanged.
2200 - confirm that the OU tree and (in particular the user DN) is identical between
2201 the DCs once this has been replicated.
2203 # work-out unique username to test with
2204 username = self._make_username()
2206 self.ldb_dc1.add(self.ou1)
2208 # create user on DC1
2209 self.ldb_dc1.newuser(username=username,
2210 userou="ou=%s,ou=%s"
2211 % (self.ou1_dn.get_component_value(0),
2212 self.top_ou.get_component_value(0)),
2213 password=None, setpassword=False)
2214 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2215 scope=SCOPE_SUBTREE,
2216 expression="(samAccountName=%s)" % username)
2217 self.assertEqual(len(ldb_res), 1)
2218 user_orig = ldb_res[0]
2219 user_dn = ldb_res[0]["dn"]
2221 # check user info on DC1
2222 print("Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])))
2223 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=False)
2225 self.ldb_dc1.add(self.ou2)
2226 self.ldb_dc1.add(self.ou2b)
2227 self.ldb_dc1.add(self.ou3)
2229 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
2230 new_dn.add_base(self.ou2_dn)
2231 self.ldb_dc1.rename(user_dn, new_dn)
2233 ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
2234 scope=SCOPE_SUBTREE,
2235 expression="(samAccountName=%s)" % username)
2236 self.assertEqual(len(ldb_res), 1)
2238 user_moved_orig = ldb_res[0]
2240 # trigger replication from DC1 to DC2
2241 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2242 # check user info on DC2 - should be valid user
2243 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
2245 msg = ldb.Message()
2246 msg.dn = new_dn
2247 msg["description"] = ldb.MessageElement("User Description", ldb.FLAG_MOD_REPLACE, "description")
2248 self.ldb_dc1.modify(msg)
2250 # The sleep(1) calls here ensure that the name objects get a
2251 # new 1-sec based timestamp, and so we select how the conflict
2252 # resolution resolves.
2253 self.ldb_dc1.rename(self.ou2_dn, self.ou2c_dn)
2254 time.sleep(1)
2255 self.ldb_dc1.rename(self.ou2b_dn, self.ou2_dn)
2256 time.sleep(1)
2257 self.ldb_dc1.rename(self.ou2c_dn, self.ou2b_dn)
2259 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
2260 new_dn.add_base(self.ou2_dn)
2261 self.ldb_dc1.rename('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]), new_dn)
2263 msg = ldb.Message()
2264 msg.dn = self.ou2_dn
2265 msg["description"] = ldb.MessageElement("OU2 Description", ldb.FLAG_MOD_REPLACE, "description")
2266 self.ldb_dc1.modify(msg)
2268 msg = ldb.Message()
2269 msg.dn = self.ou2b_dn
2270 msg["description"] = ldb.MessageElement("OU2b Description", ldb.FLAG_MOD_REPLACE, "description")
2271 self.ldb_dc1.modify(msg)
2273 ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
2274 scope=SCOPE_SUBTREE,
2275 expression="(samAccountName=%s)" % username,
2276 attrs=["*", "parentGUID"])
2277 self.assertEqual(len(ldb_res), 1)
2279 user_moved_orig = ldb_res[0]
2281 # trigger replication from DC1 to DC2
2282 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2283 # check user info on DC2 - should be valid user
2284 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
2285 self.assertEqual(user_cur["parentGUID"][0], user_moved_orig["parentGUID"][0])
2287 # delete user on DC1
2288 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
2290 # trigger replication from DC1 to DC2, for cleanup
2291 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2293 def test_ReplicateMoveInTree4(self):
2294 """Verifies how an object is replicated between two DCs.
2295 This test should verify that:
2296 - an OU and user can be replicated correctly, even after a rename
2297 - The creation and rename of the OU has been combined with unrelated changes to the object,
2298 The aim here is the send the objects out-of-order when sorted by usnChanged.
2299 - That is, the OU will be sorted by usnChanged after the user that is within that OU.
2300 - That will cause the client to need to get the OU first, by use of the GET_ANC flag
2302 # work-out unique username to test with
2303 username = self._make_username()
2305 self.ldb_dc1.add(self.ou1)
2307 # create user on DC1
2308 self.ldb_dc1.newuser(username=username,
2309 userou="ou=%s,ou=%s"
2310 % (self.ou1_dn.get_component_value(0),
2311 self.top_ou.get_component_value(0)),
2312 password=None, setpassword=False)
2313 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2314 scope=SCOPE_SUBTREE,
2315 expression="(samAccountName=%s)" % username)
2316 self.assertEqual(len(ldb_res), 1)
2317 user_orig = ldb_res[0]
2318 user_dn = ldb_res[0]["dn"]
2320 # check user info on DC1
2321 print("Testing for %s with GUID %s" % (username, self._GUID_string(user_orig["objectGUID"][0])))
2322 self._check_obj(sam_ldb=self.ldb_dc1, obj_orig=user_orig, is_deleted=False)
2324 self.ldb_dc1.add(self.ou2)
2326 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
2327 new_dn.add_base(self.ou2_dn)
2328 self.ldb_dc1.rename(user_dn, new_dn)
2330 msg = ldb.Message()
2331 msg.dn = self.ou2_dn
2332 msg["description"] = ldb.MessageElement("OU2 Description", ldb.FLAG_MOD_REPLACE, "description")
2333 self.ldb_dc1.modify(msg)
2335 ldb_res = self.ldb_dc1.search(base=self.ou2_dn,
2336 scope=SCOPE_SUBTREE,
2337 expression="(samAccountName=%s)" % username)
2338 self.assertEqual(len(ldb_res), 1)
2340 user_moved_orig = ldb_res[0]
2342 # trigger replication from DC1 to DC2
2343 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2344 # check user info on DC2 - should be valid user
2345 self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved_orig, is_deleted=False)
2347 # delete user on DC1
2348 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
2350 # trigger replication from DC1 to DC2, for cleanup
2351 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2353 def test_ReplicateAddInOU(self):
2354 """Verifies how an object is replicated between two DCs.
2355 This test should verify that:
2356 - an OU and user can be replicated correctly
2357 - The creation of the OU has been combined with unrelated changes to the object,
2358 The aim here is the send the objects out-of-order when sorted by usnChanged.
2359 - That is, the OU will be sorted by usnChanged after the user that is within that OU.
2360 - That will cause the client to need to get the OU first, by use of the GET_ANC flag
2362 # work-out unique username to test with
2363 username = self._make_username()
2365 self.ldb_dc1.add(self.ou1)
2367 # create user on DC1
2368 self.ldb_dc1.newuser(username=username,
2369 userou="ou=%s,ou=%s"
2370 % (self.ou1_dn.get_component_value(0),
2371 self.top_ou.get_component_value(0)),
2372 password=None, setpassword=False)
2373 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2374 scope=SCOPE_SUBTREE,
2375 expression="(samAccountName=%s)" % username,
2376 attrs=["*", "parentGUID"])
2377 self.assertEqual(len(ldb_res), 1)
2378 user_orig = ldb_res[0]
2380 msg = ldb.Message()
2381 msg.dn = self.ou1_dn
2382 msg["description"] = ldb.MessageElement("OU1 Description", ldb.FLAG_MOD_REPLACE, "description")
2383 self.ldb_dc1.modify(msg)
2385 # trigger replication from DC1 to DC2
2386 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2387 # check user info on DC2 - should be valid user
2388 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_orig, is_deleted=False)
2390 self.assertEqual(user_cur["parentGUID"], user_orig["parentGUID"])
2392 # delete user on DC1
2393 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
2395 # trigger replication from DC1 to DC2, for cleanup
2396 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2398 def test_ReplicateAddInMovedOU(self):
2399 """Verifies how an object is replicated between two DCs.
2400 This test should verify that:
2401 - an OU and user can be replicated correctly
2402 - The creation of the OU has been combined with unrelated changes to the object,
2403 The aim here is the send the objects out-of-order when sorted by usnChanged.
2404 - That is, the OU will be sorted by usnChanged after the user that is within that OU.
2405 - That will cause the client to need to get the OU first, by use of the GET_ANC flag
2407 # work-out unique username to test with
2408 username = self._make_username()
2410 self.ldb_dc1.add(self.ou1)
2411 self.ldb_dc1.add(self.ou2)
2413 # create user on DC1
2414 self.ldb_dc1.newuser(username=username,
2415 userou="ou=%s,ou=%s"
2416 % (self.ou1_dn.get_component_value(0),
2417 self.top_ou.get_component_value(0)),
2418 password=None, setpassword=False)
2419 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2420 scope=SCOPE_SUBTREE,
2421 expression="(samAccountName=%s)" % username,
2422 attrs=["*", "parentGUID"])
2423 self.assertEqual(len(ldb_res), 1)
2424 user_orig = ldb_res[0]
2425 user_dn = ldb_res[0]["dn"]
2427 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
2428 new_dn.add_base(self.ou2_dn)
2429 self.ldb_dc1.rename(user_dn, new_dn)
2431 self.ldb_dc1.rename(self.ou2_dn, self.ou2b_dn)
2433 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2434 scope=SCOPE_SUBTREE,
2435 expression="(samAccountName=%s)" % username,
2436 attrs=["*", "parentGUID"])
2437 self.assertEqual(len(ldb_res), 1)
2438 user_moved = ldb_res[0]
2440 # trigger replication from DC1 to DC2
2441 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2442 # check user info on DC2 - should be valid user
2443 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved, is_deleted=False)
2445 self.assertEqual(user_cur["parentGUID"], user_moved["parentGUID"])
2447 # delete user on DC1
2448 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
2450 # trigger replication from DC1 to DC2, for cleanup
2451 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2453 def test_ReplicateAddInConflictOU_time(self):
2454 """Verifies how an object is replicated between two DCs, when created in an ambiguous location
2455 This test should verify that:
2456 - Without replication, two conflicting objects can be created
2457 - force the conflict resolution algorithm so we know which copy will win
2458 (by sleeping while creating the objects, therefore increasing that timestamp on 'name')
2459 - confirm that the user object, created on DC1, ends up in the right place on DC2
2460 - therefore confirm that the conflict algorithm worked correctly, and that parentGUID was used.
2463 # work-out unique username to test with
2464 username = self._make_username()
2466 self.ldb_dc1.add(self.ou1)
2468 # create user on DC1
2469 self.ldb_dc1.newuser(username=username,
2470 userou="ou=%s,ou=%s"
2471 % (self.ou1_dn.get_component_value(0),
2472 self.top_ou.get_component_value(0)),
2473 password=None, setpassword=False)
2474 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2475 scope=SCOPE_SUBTREE,
2476 expression="(samAccountName=%s)" % username,
2477 attrs=["*", "parentGUID"])
2478 self.assertEqual(len(ldb_res), 1)
2479 user_orig = ldb_res[0]
2480 user_dn = ldb_res[0]["dn"]
2482 # trigger replication from DC1 to DC2
2483 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2485 # Now create two, conflicting objects. This gives the user
2486 # object something to be under on both DCs.
2488 # We sleep between the two adds so that DC1 adds second, and
2489 # so wins the conflict resolution due to a later creation time
2490 # (modification timestamp on the name attribute).
2491 self.ldb_dc2.add(self.ou2)
2492 time.sleep(1)
2493 self.ldb_dc1.add(self.ou2)
2495 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
2496 new_dn.add_base(self.ou2_dn)
2497 self.ldb_dc1.rename(user_dn, new_dn)
2499 # Now that we have renamed the user (and so bumped the
2500 # usnChanged), bump the value on the OUs.
2501 msg = ldb.Message()
2502 msg.dn = self.ou2_dn
2503 msg["description"] = ldb.MessageElement("OU2 Description", ldb.FLAG_MOD_REPLACE, "description")
2504 self.ldb_dc1.modify(msg)
2506 msg = ldb.Message()
2507 msg.dn = self.ou2_dn
2508 msg["description"] = ldb.MessageElement("OU2 Description", ldb.FLAG_MOD_REPLACE, "description")
2509 self.ldb_dc2.modify(msg)
2511 # trigger replication from DC1 to DC2
2512 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2513 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2514 scope=SCOPE_SUBTREE,
2515 expression="(samAccountName=%s)" % username,
2516 attrs=["*", "parentGUID"])
2517 self.assertEqual(len(ldb_res), 1)
2518 user_moved = ldb_res[0]
2520 # trigger replication from DC1 to DC2
2521 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2522 # check user info on DC2 - should be under the OU2 from DC1
2523 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved, is_deleted=False)
2525 self.assertEqual(user_cur["parentGUID"], user_moved["parentGUID"])
2527 # delete user on DC1
2528 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
2530 # trigger replication from DC1 to DC2, for cleanup
2531 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2533 def test_ReplicateAddInConflictOU2(self):
2534 """Verifies how an object is replicated between two DCs, when created in an ambiguous location
2535 This test should verify that:
2536 - Without replication, two conflicting objects can be created
2537 - force the conflict resolution algorithm so we know which copy will win
2538 (by changing the description twice, therefore increasing that version count)
2539 - confirm that the user object, created on DC1, ends up in the right place on DC2
2540 - therefore confirm that the conflict algorithm worked correctly, and that parentGUID was used.
2542 # work-out unique username to test with
2543 username = self._make_username()
2545 self.ldb_dc1.add(self.ou1)
2547 # create user on DC1
2548 self.ldb_dc1.newuser(username=username,
2549 userou="ou=%s,ou=%s"
2550 % (self.ou1_dn.get_component_value(0),
2551 self.top_ou.get_component_value(0)),
2552 password=None, setpassword=False)
2553 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2554 scope=SCOPE_SUBTREE,
2555 expression="(samAccountName=%s)" % username,
2556 attrs=["*", "parentGUID"])
2557 self.assertEqual(len(ldb_res), 1)
2558 user_orig = ldb_res[0]
2559 user_dn = ldb_res[0]["dn"]
2561 # trigger replication from DC1 to DC2
2562 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2564 # Now create two, conflicting objects. This gives the user
2565 # object something to be under on both DCs. We create it on
2566 # DC1 1sec later so that it will win the conflict resolution.
2568 self.ldb_dc2.add(self.ou2)
2569 time.sleep(1)
2570 self.ldb_dc1.add(self.ou2)
2572 new_dn = ldb.Dn(self.ldb_dc1, "CN=%s" % username)
2573 new_dn.add_base(self.ou2_dn)
2574 self.ldb_dc1.rename(user_dn, new_dn)
2576 # Now that we have renamed the user (and so bumped the
2577 # usnChanged), bump the value on the OUs.
2578 msg = ldb.Message()
2579 msg.dn = self.ou2_dn
2580 msg["description"] = ldb.MessageElement("OU2 Description", ldb.FLAG_MOD_REPLACE, "description")
2581 self.ldb_dc1.modify(msg)
2583 msg = ldb.Message()
2584 msg.dn = self.ou2_dn
2585 msg["description"] = ldb.MessageElement("OU2 Description", ldb.FLAG_MOD_REPLACE, "description")
2586 self.ldb_dc2.modify(msg)
2588 # trigger replication from DC1 to DC2
2589 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2590 ldb_res = self.ldb_dc1.search(base=self.ou1_dn,
2591 scope=SCOPE_SUBTREE,
2592 expression="(samAccountName=%s)" % username,
2593 attrs=["*", "parentGUID"])
2594 self.assertEqual(len(ldb_res), 1)
2595 user_moved = ldb_res[0]
2597 # trigger replication from DC1 to DC2
2598 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)
2599 # check user info on DC2 - should be under the OU2 from DC1
2600 user_cur = self._check_obj(sam_ldb=self.ldb_dc2, obj_orig=user_moved, is_deleted=False)
2602 self.assertEqual(user_cur["parentGUID"], user_moved["parentGUID"])
2604 # delete user on DC1
2605 self.ldb_dc1.delete('<GUID=%s>' % self._GUID_string(user_orig["objectGUID"][0]))
2607 # trigger replication from DC1 to DC2, for cleanup
2608 self._net_drs_replicate(DC=self.dnsname_dc2, fromDC=self.dnsname_dc1, forced=True)