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