2 # -*- coding: utf-8 -*-
4 # Unix SMB/CIFS implementation.
5 # Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2010
6 # Copyright (C) Andrew Bartlett <abartlet@samba.org> 2016
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 3 of the License, or
11 # (at your option) any later version.
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # export DC1=dc1_dns_name
25 # export DC2=dc2_dns_name
26 # export SUBUNITRUN=$samba4srcdir/scripting/bin/subunitrun
27 # PYTHONPATH="$PYTHONPATH:$samba4srcdir/torture/drs/python" $SUBUNITRUN repl_move -U"$DOMAIN/$DC_USERNAME"%"$DC_PASSWORD"
33 from samba
.ndr
import ndr_unpack
34 from samba
.dcerpc
import drsblobs
35 from samba
.dcerpc
import misc
36 from samba
.drs_utils
import drs_DsBind
45 from samba
.dcerpc
.drsuapi
import (
47 DRSUAPI_ATTID_accountExpires
,
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
,
60 DRSUAPI_ATTID_ntPwdHistory
,
61 DRSUAPI_ATTID_ntSecurityDescriptor
,
62 DRSUAPI_ATTID_objectCategory
,
63 DRSUAPI_ATTID_objectClass
,
64 DRSUAPI_ATTID_objectSid
,
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
):
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
,
96 self
.ou1_dn
= ldb
.Dn(self
.ldb_dc1
, "OU=DrsOU1")
97 self
.ou1_dn
.add_base(self
.top_ou
)
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
)
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
)
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
:
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
))
141 for o
in repl
.ctr
.array
:
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
,
150 "(LDAP) Wrong originating_invocation_id "
151 "for expected value %d, attid 0x%08x, wanted %s got %s"
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, "
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
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)
196 for o
in drs_ctr
.first_object
.meta_data_ctr
.meta_data
:
198 drs_attid
= drs_ctr
.first_object
.object.attribute_ctr
.attributes
[att_idx
]
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
):
209 (attid
, orig_dsa
, version
) = e
211 self
.assertEqual(attid
, drs_attid
.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
,
218 "(DRS) Wrong originating_invocation_id "
219 "for expected value %d, attid 0x%08x, wanted %s got %s"
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, "
229 % (i
, attid
, version
, o
.version
))
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)
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
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
)
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]
266 parent_orig
= obj_orig
["parentGUID"][0]
267 self
.assertEqual(parent_orig
, parent_cur
)
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"],
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
283 - We verify that after replication,
284 that the user has the correct DN (under OU2)
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
()
295 self
.ldb_dc1
.newuser(username
=username
,
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
,
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])))
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
,
343 expression
="(samAccountName=%s)" % username
,
344 attrs
=["*", "parentGUID"])
345 self
.assertEqual(len(ldb_res
), 1)
347 user_moved_orig
= ldb_res
[0]
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
,
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
,
409 expected_metadata
=moved_metadata_dc2
)
412 self
.ldb_dc1
.delete('<GUID=%s>' % self
._GUID
_string
(user_orig
["objectGUID"][0]))
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.
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
,
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
,
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
,
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
()
567 self
.ldb_dc1
.newuser(username
=username
,
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
,
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])))
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
,
615 expression
="(samAccountName=%s)" % username
,
616 attrs
=["*", "parentGUID"])
617 self
.assertEqual(len(ldb_res
), 1)
618 user_moved_orig
= ldb_res
[0]
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
,
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
,
653 expression
="(samAccountName=%s)" % username
,
654 attrs
=["*", "parentGUID"])
655 self
.assertEqual(len(ldb_res
), 0)
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
,
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
,
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
,
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
()
750 self
.ldb_dc1
.newuser(username
=username
,
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
,
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])))
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
,
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)
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
,
834 expected_metadata
=moved_metadata
)
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
,
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
,
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
,
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
()
929 self
.ldb_dc1
.newuser(username
=username
,
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
,
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])))
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
,
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)
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
,
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
,
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
,
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
,
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]
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
,
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.
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
,
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
,
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
,
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
,
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
,
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
,
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.
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
,
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
,
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.
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
)
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
,
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
,
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.
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
)
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
,
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
,
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.
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
)
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
,
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
,
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.
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
)
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
,
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.
1779 msg
["description"] = ldb
.MessageElement("OU Description", ldb
.FLAG_MOD_REPLACE
, "description")
1780 self
.ldb_dc2
.modify(msg
)
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
,
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.
1827 msg
["description"] = ldb
.MessageElement("OU Description", ldb
.FLAG_MOD_REPLACE
, "description")
1828 self
.ldb_dc2
.modify(msg
)
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
):
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
,
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
)
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
)
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
)
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
)
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
)
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
)
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
)
1909 self
.ou6
["dn"] = self
.ou6_dn
1910 self
.ou6
["objectclass"] = "organizationalUnit"
1911 self
.ou6
["ou"] = self
.ou6_dn
.get_component_value(0)
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)
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
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
)
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())
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
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
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)
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
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
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
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)
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
)
2255 self
.ldb_dc1
.rename(self
.ou2b_dn
, self
.ou2_dn
)
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
)
2264 msg
.dn
= self
.ou2_dn
2265 msg
["description"] = ldb
.MessageElement("OU2 Description", ldb
.FLAG_MOD_REPLACE
, "description")
2266 self
.ldb_dc1
.modify(msg
)
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
)
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]
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
)
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.
2502 msg
.dn
= self
.ou2_dn
2503 msg
["description"] = ldb
.MessageElement("OU2 Description", ldb
.FLAG_MOD_REPLACE
, "description")
2504 self
.ldb_dc1
.modify(msg
)
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
)
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.
2579 msg
.dn
= self
.ou2_dn
2580 msg
["description"] = ldb
.MessageElement("OU2 Description", ldb
.FLAG_MOD_REPLACE
, "description")
2581 self
.ldb_dc1
.modify(msg
)
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)