s4:password_hash LDB module - allow empty ("") passwords
[Samba/gebeck_regimport.git] / source4 / dsdb / tests / python / deletetest.py
blob4ed125dd8fab9439c01102dcb5ca723806d20bef
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
4 import optparse
5 import sys
6 import os
8 sys.path.append("bin/python")
9 import samba
10 samba.ensure_external_module("testtools", "testtools")
11 samba.ensure_external_module("subunit", "subunit/python")
13 import samba.getopt as options
15 from samba.auth import system_session
16 from ldb import SCOPE_BASE, LdbError
17 from ldb import ERR_NO_SUCH_OBJECT, ERR_NOT_ALLOWED_ON_NON_LEAF
18 from ldb import ERR_UNWILLING_TO_PERFORM
19 from samba.samdb import SamDB
20 from samba.tests import delete_force
22 from subunit.run import SubunitTestRunner
23 import unittest
25 parser = optparse.OptionParser("deletetest.py [options] <host|file>")
26 sambaopts = options.SambaOptions(parser)
27 parser.add_option_group(sambaopts)
28 parser.add_option_group(options.VersionOptions(parser))
29 # use command line creds if available
30 credopts = options.CredentialsOptions(parser)
31 parser.add_option_group(credopts)
32 opts, args = parser.parse_args()
34 if len(args) < 1:
35 parser.print_usage()
36 sys.exit(1)
38 host = args[0]
40 lp = sambaopts.get_loadparm()
41 creds = credopts.get_credentials(lp)
43 class BasicDeleteTests(unittest.TestCase):
46 def GUID_string(self, guid):
47 return self.ldb.schema_format_value("objectGUID", guid)
49 def setUp(self):
50 self.ldb = ldb
51 self.base_dn = ldb.domain_dn()
52 self.configuration_dn = ldb.get_config_basedn().get_linearized()
54 def search_guid(self, guid):
55 print "SEARCH by GUID %s" % self.GUID_string(guid)
57 res = ldb.search(base="<GUID=%s>" % self.GUID_string(guid),
58 scope=SCOPE_BASE, controls=["show_deleted:1"])
59 self.assertEquals(len(res), 1)
60 return res[0]
62 def search_dn(self,dn):
63 print "SEARCH by DN %s" % dn
65 res = ldb.search(expression="(objectClass=*)",
66 base=dn,
67 scope=SCOPE_BASE,
68 controls=["show_deleted:1"])
69 self.assertEquals(len(res), 1)
70 return res[0]
72 def del_attr_values(self, delObj):
73 print "Checking attributes for %s" % delObj["dn"]
75 self.assertEquals(delObj["isDeleted"][0],"TRUE")
76 self.assertTrue(not("objectCategory" in delObj))
77 self.assertTrue(not("sAMAccountType" in delObj))
79 def preserved_attributes_list(self, liveObj, delObj):
80 print "Checking for preserved attributes list"
82 preserved_list = ["nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName",
83 "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN",
84 "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID",
85 "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid",
86 "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName",
87 "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection",
88 "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreated"]
90 for a in liveObj:
91 if a in preserved_list:
92 self.assertTrue(a in delObj)
94 def check_rdn(self, liveObj, delObj, rdnName):
95 print "Checking for correct rDN"
96 rdn=liveObj[rdnName][0]
97 rdn2=delObj[rdnName][0]
98 name2=delObj[rdnName][0]
99 guid=liveObj["objectGUID"][0]
100 self.assertEquals(rdn2, rdn + "\nDEL:" + self.GUID_string(guid))
101 self.assertEquals(name2, rdn + "\nDEL:" + self.GUID_string(guid))
103 def delete_deleted(self, ldb, dn):
104 print "Testing the deletion of the already deleted dn %s" % dn
106 try:
107 ldb.delete(dn)
108 self.fail()
109 except LdbError, (num, _):
110 self.assertEquals(num, ERR_NO_SUCH_OBJECT)
112 def test_delete_protection(self):
113 """Delete protection tests"""
115 print self.base_dn
117 delete_force(self.ldb, "cn=entry1,cn=ldaptestcontainer," + self.base_dn)
118 delete_force(self.ldb, "cn=entry2,cn=ldaptestcontainer," + self.base_dn)
119 delete_force(self.ldb, "cn=ldaptestcontainer," + self.base_dn)
121 ldb.add({
122 "dn": "cn=ldaptestcontainer," + self.base_dn,
123 "objectclass": "container"})
124 ldb.add({
125 "dn": "cn=entry1,cn=ldaptestcontainer," + self.base_dn,
126 "objectclass": "container"})
127 ldb.add({
128 "dn": "cn=entry2,cn=ldaptestcontainer," + self.base_dn,
129 "objectclass": "container"})
131 try:
132 ldb.delete("cn=ldaptestcontainer," + self.base_dn)
133 self.fail()
134 except LdbError, (num, _):
135 self.assertEquals(num, ERR_NOT_ALLOWED_ON_NON_LEAF)
137 ldb.delete("cn=ldaptestcontainer," + self.base_dn, ["tree_delete:1"])
139 try:
140 res = ldb.search("cn=ldaptestcontainer," + self.base_dn,
141 scope=SCOPE_BASE, attrs=[])
142 self.fail()
143 except LdbError, (num, _):
144 self.assertEquals(num, ERR_NO_SUCH_OBJECT)
145 try:
146 res = ldb.search("cn=entry1,cn=ldaptestcontainer," + self.base_dn,
147 scope=SCOPE_BASE, attrs=[])
148 self.fail()
149 except LdbError, (num, _):
150 self.assertEquals(num, ERR_NO_SUCH_OBJECT)
151 try:
152 res = ldb.search("cn=entry2,cn=ldaptestcontainer," + self.base_dn,
153 scope=SCOPE_BASE, attrs=[])
154 self.fail()
155 except LdbError, (num, _):
156 self.assertEquals(num, ERR_NO_SUCH_OBJECT)
158 delete_force(self.ldb, "cn=entry1,cn=ldaptestcontainer," + self.base_dn)
159 delete_force(self.ldb, "cn=entry2,cn=ldaptestcontainer," + self.base_dn)
160 delete_force(self.ldb, "cn=ldaptestcontainer," + self.base_dn)
162 # Performs some protected object delete testing
164 res = ldb.search(base="", expression="", scope=SCOPE_BASE,
165 attrs=["dsServiceName", "dNSHostName"])
166 self.assertEquals(len(res), 1)
168 # Delete failing since DC's nTDSDSA object is protected
169 try:
170 ldb.delete(res[0]["dsServiceName"][0])
171 self.fail()
172 except LdbError, (num, _):
173 self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
175 res = ldb.search(self.base_dn, attrs=["rIDSetReferences"],
176 expression="(&(objectClass=computer)(dNSHostName=" + res[0]["dNSHostName"][0] + "))")
177 self.assertEquals(len(res), 1)
179 # Deletes failing since DC's rIDSet object is protected
180 try:
181 ldb.delete(res[0]["rIDSetReferences"][0])
182 self.fail()
183 except LdbError, (num, _):
184 self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
185 try:
186 ldb.delete(res[0]["rIDSetReferences"][0], ["tree_delete:1"])
187 self.fail()
188 except LdbError, (num, _):
189 self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
191 # Deletes failing since three main crossRef objects are protected
193 try:
194 ldb.delete("cn=Enterprise Schema,cn=Partitions," + self.configuration_dn)
195 self.fail()
196 except LdbError, (num, _):
197 self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
198 try:
199 ldb.delete("cn=Enterprise Schema,cn=Partitions," + self.configuration_dn, ["tree_delete:1"])
200 self.fail()
201 except LdbError, (num, _):
202 self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
204 try:
205 ldb.delete("cn=Enterprise Configuration,cn=Partitions," + self.configuration_dn)
206 self.fail()
207 except LdbError, (num, _):
208 self.assertEquals(num, ERR_NOT_ALLOWED_ON_NON_LEAF)
209 try:
210 ldb.delete("cn=Enterprise Configuration,cn=Partitions," + self.configuration_dn, ["tree_delete:1"])
211 self.fail()
212 except LdbError, (num, _):
213 self.assertEquals(num, ERR_NOT_ALLOWED_ON_NON_LEAF)
215 res = ldb.search("cn=Partitions," + self.configuration_dn, attrs=[],
216 expression="(nCName=%s)" % self.base_dn)
217 self.assertEquals(len(res), 1)
219 try:
220 ldb.delete(res[0].dn)
221 self.fail()
222 except LdbError, (num, _):
223 self.assertEquals(num, ERR_NOT_ALLOWED_ON_NON_LEAF)
224 try:
225 ldb.delete(res[0].dn, ["tree_delete:1"])
226 self.fail()
227 except LdbError, (num, _):
228 self.assertEquals(num, ERR_NOT_ALLOWED_ON_NON_LEAF)
230 # Delete failing since "SYSTEM_FLAG_DISALLOW_DELETE"
231 try:
232 ldb.delete("CN=Users," + self.base_dn)
233 self.fail()
234 except LdbError, (num, _):
235 self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
237 # Tree-delete failing since "isCriticalSystemObject"
238 try:
239 ldb.delete("CN=Computers," + self.base_dn, ["tree_delete:1"])
240 self.fail()
241 except LdbError, (num, _):
242 self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
244 def test_all(self):
245 """Basic delete tests"""
247 print self.base_dn
249 usr1="cn=testuser,cn=users," + self.base_dn
250 usr2="cn=testuser2,cn=users," + self.base_dn
251 grp1="cn=testdelgroup1,cn=users," + self.base_dn
252 sit1="cn=testsite1,cn=sites," + self.configuration_dn
253 ss1="cn=NTDS Site Settings,cn=testsite1,cn=sites," + self.configuration_dn
254 srv1="cn=Servers,cn=testsite1,cn=sites," + self.configuration_dn
255 srv2="cn=TESTSRV,cn=Servers,cn=testsite1,cn=sites," + self.configuration_dn
257 delete_force(self.ldb, usr1)
258 delete_force(self.ldb, usr2)
259 delete_force(self.ldb, grp1)
260 delete_force(self.ldb, ss1)
261 delete_force(self.ldb, srv2)
262 delete_force(self.ldb, srv1)
263 delete_force(self.ldb, sit1)
265 ldb.add({
266 "dn": usr1,
267 "objectclass": "user",
268 "description": "test user description",
269 "samaccountname": "testuser"})
271 ldb.add({
272 "dn": usr2,
273 "objectclass": "user",
274 "description": "test user 2 description",
275 "samaccountname": "testuser2"})
277 ldb.add({
278 "dn": grp1,
279 "objectclass": "group",
280 "description": "test group",
281 "samaccountname": "testdelgroup1",
282 "member": [ usr1, usr2 ],
283 "isDeleted": "FALSE" })
285 ldb.add({
286 "dn": sit1,
287 "objectclass": "site" })
289 ldb.add({
290 "dn": ss1,
291 "objectclass": ["applicationSiteSettings", "nTDSSiteSettings"] })
293 ldb.add({
294 "dn": srv1,
295 "objectclass": "serversContainer" })
297 ldb.add({
298 "dn": srv2,
299 "objectClass": "server" })
301 objLive1 = self.search_dn(usr1)
302 guid1=objLive1["objectGUID"][0]
304 objLive2 = self.search_dn(usr2)
305 guid2=objLive2["objectGUID"][0]
307 objLive3 = self.search_dn(grp1)
308 guid3=objLive3["objectGUID"][0]
310 objLive4 = self.search_dn(sit1)
311 guid4=objLive4["objectGUID"][0]
313 objLive5 = self.search_dn(ss1)
314 guid5=objLive5["objectGUID"][0]
316 objLive6 = self.search_dn(srv1)
317 guid6=objLive6["objectGUID"][0]
319 objLive7 = self.search_dn(srv2)
320 guid7=objLive7["objectGUID"][0]
322 ldb.delete(usr1)
323 ldb.delete(usr2)
324 ldb.delete(grp1)
325 ldb.delete(srv1, ["tree_delete:1"])
326 ldb.delete(sit1, ["tree_delete:1"])
328 objDeleted1 = self.search_guid(guid1)
329 objDeleted2 = self.search_guid(guid2)
330 objDeleted3 = self.search_guid(guid3)
331 objDeleted4 = self.search_guid(guid4)
332 objDeleted5 = self.search_guid(guid5)
333 objDeleted6 = self.search_guid(guid6)
334 objDeleted7 = self.search_guid(guid7)
336 self.del_attr_values(objDeleted1)
337 self.del_attr_values(objDeleted2)
338 self.del_attr_values(objDeleted3)
339 self.del_attr_values(objDeleted4)
340 self.del_attr_values(objDeleted5)
341 self.del_attr_values(objDeleted6)
342 self.del_attr_values(objDeleted7)
344 self.preserved_attributes_list(objLive1, objDeleted1)
345 self.preserved_attributes_list(objLive2, objDeleted2)
346 self.preserved_attributes_list(objLive3, objDeleted3)
347 self.preserved_attributes_list(objLive4, objDeleted4)
348 self.preserved_attributes_list(objLive5, objDeleted5)
349 self.preserved_attributes_list(objLive6, objDeleted6)
350 self.preserved_attributes_list(objLive7, objDeleted7)
352 self.check_rdn(objLive1, objDeleted1, "cn")
353 self.check_rdn(objLive2, objDeleted2, "cn")
354 self.check_rdn(objLive3, objDeleted3, "cn")
355 self.check_rdn(objLive4, objDeleted4, "cn")
356 self.check_rdn(objLive5, objDeleted5, "cn")
357 self.check_rdn(objLive6, objDeleted6, "cn")
358 self.check_rdn(objLive7, objDeleted7, "cn")
360 self.delete_deleted(ldb, usr1)
361 self.delete_deleted(ldb, usr2)
362 self.delete_deleted(ldb, grp1)
363 self.delete_deleted(ldb, sit1)
364 self.delete_deleted(ldb, ss1)
365 self.delete_deleted(ldb, srv1)
366 self.delete_deleted(ldb, srv2)
368 self.assertTrue("CN=Deleted Objects" in str(objDeleted1.dn))
369 self.assertTrue("CN=Deleted Objects" in str(objDeleted2.dn))
370 self.assertTrue("CN=Deleted Objects" in str(objDeleted3.dn))
371 self.assertFalse("CN=Deleted Objects" in str(objDeleted4.dn))
372 self.assertTrue("CN=Deleted Objects" in str(objDeleted5.dn))
373 self.assertFalse("CN=Deleted Objects" in str(objDeleted6.dn))
374 self.assertFalse("CN=Deleted Objects" in str(objDeleted7.dn))
376 if not "://" in host:
377 if os.path.isfile(host):
378 host = "tdb://%s" % host
379 else:
380 host = "ldap://%s" % host
382 ldb = SamDB(host, credentials=creds, session_info=system_session(), lp=lp)
384 runner = SubunitTestRunner()
385 rc = 0
386 if not runner.run(unittest.makeSuite(BasicDeleteTests)).wasSuccessful():
387 rc = 1
389 sys.exit(rc)