2 # -*- coding: utf-8 -*-
3 # This is unit with tests for LDAP access checks
12 sys.path.append("bin/python")
14 import samba.getopt as options
16 from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError
17 from ldb import ERR_NO_SUCH_OBJECT, ERR_INVALID_DN_SYNTAX, ERR_UNWILLING_TO_PERFORM
18 from ldb import ERR_INSUFFICIENT_ACCESS_RIGHTS
20 from samba.ndr import ndr_pack, ndr_unpack
21 from samba.dcerpc import security
23 from samba.auth import system_session
25 from subunit.run import SubunitTestRunner
28 parser = optparse.OptionParser("ldap [options] <host>")
29 sambaopts = options.SambaOptions(parser)
30 parser.add_option_group(sambaopts)
31 parser.add_option_group(options.VersionOptions(parser))
33 # use command line creds if available
34 credopts = options.CredentialsOptions(parser)
35 parser.add_option_group(credopts)
36 opts, args = parser.parse_args()
44 lp = sambaopts.get_loadparm()
45 creds = credopts.get_credentials(lp)
51 class AclTests(unittest.TestCase):
53 def delete_force(self, ldb, dn):
56 except LdbError, (num, _):
57 self.assertEquals(num, ERR_NO_SUCH_OBJECT)
59 def find_basedn(self, ldb):
60 res = ldb.search(base="", expression="", scope=SCOPE_BASE,
61 attrs=["defaultNamingContext"])
62 self.assertEquals(len(res), 1)
63 return res[0]["defaultNamingContext"][0]
65 def find_domain_sid(self, ldb):
66 res = ldb.search(base=self.base_dn, expression="(objectClass=*)", scope=SCOPE_BASE)
67 return ndr_unpack( security.dom_sid,res[0]["objectSid"][0])
71 self.base_dn = self.find_basedn(self.ldb_admin)
72 self.domain_sid = self.find_domain_sid(self.ldb_admin)
73 self.user_pass = "samba123@"
74 print "baseDN: %s" % self.base_dn
75 self.SAMBA = False; self.WIN = False
76 res = self.ldb_admin.search(base="",expression="", scope=SCOPE_BASE,
78 if res and "vendorName" in res[0].keys() and res[0]["vendorName"][0].find("Samba Team") != -1:
83 def get_user_dn(self, name):
84 return "CN=%s,CN=Users,%s" % (name, self.base_dn)
86 def modify_desc(self, object_dn, desc):
87 """ Modify security descriptor using either SDDL string
88 or security.descriptor object
90 assert(isinstance(desc, str) or isinstance(desc, security.descriptor))
92 dn: """ + object_dn + """
94 replace: nTSecurityDescriptor
96 if isinstance(desc, str):
97 mod += "nTSecurityDescriptor: %s" % desc
98 elif isinstance(desc, security.descriptor):
99 mod += "nTSecurityDescriptor:: %s" % base64.b64encode(ndr_pack(desc))
100 self.ldb_admin.modify_ldif(mod)
102 # Everything below is used in case of emergency or
103 # double modify verification of some sort
104 assert(isinstance(desc, security.descriptor))
106 f = open(fn, "w"); f.write(mod); f.close()
107 cmd = "ldapmodify -x -h %s -D %s -w %s -f %s" \
108 % (host[7:], self.get_user_dn(creds.get_username()), creds.get_password(), fn)
109 return os.system( cmd ) == 0
111 def add_group_member(self, _ldb, group_dn, member_dn):
112 """ Modify user to ge member of a group
113 e.g. User to be 'Doamin Admin' group member
116 dn: """ + group_dn + """
119 member: """ + member_dn
120 _ldb.modify_ldif(ldif)
122 def create_ou(self, _ldb, ou_dn, desc=None):
124 dn: """ + ou_dn + """
125 ou: """ + ou_dn.split(",")[0][3:] + """
126 objectClass: organizationalUnit
130 assert(isinstance(desc, str) or isinstance(desc, security.descriptor))
131 if isinstance(desc, str):
132 ldif += "nTSecurityDescriptor: %s" % desc
133 elif isinstance(desc, security.descriptor):
134 ldif += "nTSecurityDescriptor:: %s" % base64.b64encode(ndr_pack(desc))
137 def create_user(self, _ldb, user_dn, desc=None):
139 dn: """ + user_dn + """
140 sAMAccountName: """ + user_dn.split(",")[0][3:] + """
142 userPassword: """ + self.user_pass + """
146 assert(isinstance(desc, str) or isinstance(desc, security.descriptor))
147 if isinstance(desc, str):
148 ldif += "nTSecurityDescriptor: %s" % desc
149 elif isinstance(desc, security.descriptor):
150 ldif += "nTSecurityDescriptor:: %s" % base64.b64encode(ndr_pack(desc))
153 def create_group(self, _ldb, group_dn, desc=None):
155 dn: """ + group_dn + """
157 sAMAccountName: """ + group_dn.split(",")[0][3:] + """
162 assert(isinstance(desc, str) or isinstance(desc, security.descriptor))
163 if isinstance(desc, str):
164 ldif += "nTSecurityDescriptor: %s" % desc
165 elif isinstance(desc, security.descriptor):
166 ldif += "nTSecurityDescriptor:: %s" % base64.b64encode(ndr_pack(desc))
169 def read_desc(self, object_dn):
170 res = self.ldb_admin.search(object_dn, SCOPE_BASE, None, ["nTSecurityDescriptor"])
171 desc = res[0]["nTSecurityDescriptor"][0]
172 return ndr_unpack( security.descriptor, desc )
174 def enable_account(self, user_dn):
175 """Enable an account.
176 :param user_dn: Dn of the account to enable.
178 res = self.ldb_admin.search(user_dn, SCOPE_BASE, None, ["userAccountControl"])
180 userAccountControl = res[0]["userAccountControl"][0]
181 userAccountControl = int(userAccountControl)
182 if (userAccountControl & 0x2):
183 userAccountControl = userAccountControl & ~0x2 # remove disabled bit
184 if (userAccountControl & 0x20):
185 userAccountControl = userAccountControl & ~0x20 # remove 'no password required' bit
187 dn: """ + user_dn + """
189 replace: userAccountControl
190 userAccountControl: %s""" % userAccountControl
192 mod = re.sub("userAccountControl: \d.*", "userAccountControl: 544", mod)
193 self.ldb_admin.modify_ldif(mod)
195 def get_ldb_connection(self, target_username):
196 username_save = creds.get_username(); password_save = creds.get_password()
197 creds.set_username(target_username)
198 creds.set_password(self.user_pass)
199 ldb_target = Ldb(host, credentials=creds, session_info=system_session(), lp=lp)
200 creds.set_username(username_save); creds.set_password(password_save)
203 def get_object_sid(self, object_dn):
204 res = self.ldb_admin.search(object_dn)
205 return ndr_unpack( security.dom_sid, res[0]["objectSid"][0] )
207 def dacl_add_ace(self, object_dn, ace):
208 desc = self.read_desc( object_dn )
209 desc_sddl = desc.as_sddl( self.domain_sid )
212 if desc_sddl.find("(") >= 0:
213 desc_sddl = desc_sddl[:desc_sddl.index("(")] + ace + desc_sddl[desc_sddl.index("("):]
215 desc_sddl = desc_sddl + ace
216 self.modify_desc(object_dn, desc_sddl)
218 def get_desc_sddl(self, object_dn):
219 """ Return object nTSecutiryDescriptor in SDDL format
221 desc = self.read_desc(object_dn)
222 return desc.as_sddl(self.domain_sid)
224 # Test if we have any additional groups for users than default ones
225 def assert_user_no_group_member(self, username):
226 res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s)" \
227 % self.get_user_dn(username) )
229 self.assertEqual( res[0]["memberOf"][0], "" )
235 def create_enable_user(self, username):
236 self.create_user(self.ldb_admin, self.get_user_dn(username))
237 self.enable_account(self.get_user_dn(username))
239 #tests on ldap add operations
240 class AclAddTests(AclTests):
243 # Domain admin that will be creator of OU parent-child structure
244 self.usr_admin_owner = "acl_add_user1"
245 # Second domain admin that will not be creator of OU parent-child structure
246 self.usr_admin_not_owner = "acl_add_user2"
248 self.regular_user = "acl_add_user3"
250 self.create_enable_user(self.usr_admin_owner)
251 self.create_enable_user(self.usr_admin_not_owner)
252 self.create_enable_user(self.regular_user)
255 self.assert_user_no_group_member(self.usr_admin_owner)
256 self.assert_user_no_group_member(self.usr_admin_not_owner)
257 self.assert_user_no_group_member(self.regular_user)
259 # add admins to the Domain Admins group
260 self.add_group_member(self.ldb_admin, "CN=Domain Admins,CN=Users," + self.base_dn, \
261 self.get_user_dn(self.usr_admin_owner))
262 self.add_group_member(self.ldb_admin, "CN=Domain Admins,CN=Users," + self.base_dn, \
263 self.get_user_dn(self.usr_admin_not_owner))
265 self.ldb_owner = self.get_ldb_connection(self.usr_admin_owner)
266 self.ldb_notowner = self.get_ldb_connection(self.usr_admin_not_owner)
267 self.ldb_user = self.get_ldb_connection(self.regular_user)
270 self.delete_force(self.ldb_admin, "CN=test_add_user1,OU=test_add_ou2,OU=test_add_ou1," + self.base_dn)
271 self.delete_force(self.ldb_admin, "CN=test_add_group1,OU=test_add_ou2,OU=test_add_ou1," + self.base_dn)
272 self.delete_force(self.ldb_admin, "OU=test_add_ou2,OU=test_add_ou1," + self.base_dn)
273 self.delete_force(self.ldb_admin, "OU=test_add_ou1," + self.base_dn)
275 self.delete_force(self.ldb_admin, self.get_user_dn(self.usr_admin_owner))
276 self.delete_force(self.ldb_admin, self.get_user_dn(self.usr_admin_not_owner))
277 self.delete_force(self.ldb_admin, self.get_user_dn(self.regular_user))
279 # Make sure top OU is deleted (and so everything under it)
280 def assert_top_ou_deleted(self):
281 res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s,%s)" \
282 % ("OU=test_add_ou1", self.base_dn) )
283 self.assertEqual( res, [] )
285 def test_add_u1(self):
286 """Testing OU with the rights of Doman Admin not creator of the OU """
287 self.assert_top_ou_deleted()
288 # Change descriptor for top level OU
289 self.create_ou(self.ldb_owner, "OU=test_add_ou1," + self.base_dn)
290 self.create_ou(self.ldb_owner, "OU=test_add_ou2,OU=test_add_ou1," + self.base_dn)
291 user_sid = self.get_object_sid(self.get_user_dn(self.usr_admin_not_owner))
292 mod = "(D;CI;WPCC;;;%s)" % str(user_sid)
293 self.dacl_add_ace("OU=test_add_ou1," + self.base_dn, mod)
294 # Test user and group creation with another domain admin's credentials
295 self.create_user(self.ldb_notowner, "CN=test_add_user1,OU=test_add_ou2,OU=test_add_ou1," + self.base_dn)
296 self.create_group(self.ldb_notowner, "CN=test_add_group1,OU=test_add_ou2,OU=test_add_ou1," + self.base_dn)
297 # Make sure we HAVE created the two objects -- user and group
298 # !!! We should not be able to do that, but however beacuse of ACE ordering our inherited Deny ACE
299 # !!! comes after explicit (A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;DA) that comes from somewhere
300 res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s,%s)" \
301 % ("CN=test_add_user1,OU=test_add_ou2,OU=test_add_ou1", self.base_dn) )
302 self.assertTrue( len(res) > 0 )
303 res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s,%s)" \
304 % ("CN=test_add_group1,OU=test_add_ou2,OU=test_add_ou1", self.base_dn) )
305 self.assertTrue( len(res) > 0 )
307 def test_add_u2(self):
308 """Testing OU with the regular user that has no rights granted over the OU """
309 self.assert_top_ou_deleted()
310 # Create a parent-child OU structure with domain admin credentials
311 self.create_ou(self.ldb_owner, "OU=test_add_ou1," + self.base_dn)
312 self.create_ou(self.ldb_owner, "OU=test_add_ou2,OU=test_add_ou1," + self.base_dn)
313 # Test user and group creation with regular user credentials
315 self.create_user(self.ldb_user, "CN=test_add_user1,OU=test_add_ou2,OU=test_add_ou1," + self.base_dn)
316 self.create_group(self.ldb_user, "CN=test_add_group1,OU=test_add_ou2,OU=test_add_ou1," + self.base_dn)
317 except LdbError, (num, _):
318 self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
321 # Make sure we HAVEN'T created any of two objects -- user or group
322 res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s,%s)" \
323 % ("CN=test_add_user1,OU=test_add_ou2,OU=test_add_ou1", self.base_dn) )
324 self.assertEqual( res, [])
325 res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s,%s)" \
326 % ("CN=test_add_group1,OU=test_add_ou2,OU=test_add_ou1", self.base_dn) )
327 self.assertEqual( res, [])
329 def test_add_u3(self):
330 """Testing OU with the rights of regular user granted the right 'Create User child objects' """
331 self.assert_top_ou_deleted()
332 # Change descriptor for top level OU
333 self.create_ou(self.ldb_owner, "OU=test_add_ou1," + self.base_dn)
334 user_sid = self.get_object_sid(self.get_user_dn(self.regular_user))
335 mod = "(OA;CI;CC;bf967aba-0de6-11d0-a285-00aa003049e2;;%s)" % str(user_sid)
336 self.dacl_add_ace("OU=test_add_ou1," + self.base_dn, mod)
337 self.create_ou(self.ldb_owner, "OU=test_add_ou2,OU=test_add_ou1," + self.base_dn)
338 # Test user and group creation with granted user only to one of the objects
339 self.create_user(self.ldb_user, "CN=test_add_user1,OU=test_add_ou2,OU=test_add_ou1," + self.base_dn)
341 self.create_group(self.ldb_user, "CN=test_add_group1,OU=test_add_ou2,OU=test_add_ou1," + self.base_dn)
342 except LdbError, (num, _):
343 self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
346 # Make sure we HAVE created the one of two objects -- user
347 res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s,%s)" \
348 % ("CN=test_add_user1,OU=test_add_ou2,OU=test_add_ou1", self.base_dn) )
349 self.assertNotEqual( len(res), 0 )
350 res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s,%s)" \
351 % ("CN=test_add_group1,OU=test_add_ou2,OU=test_add_ou1", self.base_dn) )
352 self.assertEqual( res, [])
354 def test_add_u4(self):
355 """ 4 Testing OU with the rights of Doman Admin creator of the OU"""
356 self.assert_top_ou_deleted()
357 self.create_ou(self.ldb_owner, "OU=test_add_ou1," + self.base_dn)
358 self.create_ou(self.ldb_owner, "OU=test_add_ou2,OU=test_add_ou1," + self.base_dn)
359 self.create_user(self.ldb_owner, "CN=test_add_user1,OU=test_add_ou2,OU=test_add_ou1," + self.base_dn)
360 self.create_group(self.ldb_owner, "CN=test_add_group1,OU=test_add_ou2,OU=test_add_ou1," + self.base_dn)
361 # Make sure we have successfully created the two objects -- user and group
362 res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s,%s)" \
363 % ("CN=test_add_user1,OU=test_add_ou2,OU=test_add_ou1", self.base_dn) )
364 self.assertTrue( len(res) > 0 )
365 res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s,%s)" \
366 % ("CN=test_add_group1,OU=test_add_ou2,OU=test_add_ou1", self.base_dn) )
367 self.assertTrue( len(res) > 0 )
369 #tests on ldap modify operations
370 class AclModifyTests(AclTests):
374 self.user_with_wp = "acl_mod_user1"
377 # Create regular user
378 self.create_enable_user(self.user_with_wp)
380 self.assert_user_no_group_member(self.user_with_wp)
382 self.ldb_user = self.get_ldb_connection(self.user_with_wp)
383 self.user_sid = self.get_object_sid( self.get_user_dn(self.user_with_wp))
386 self.delete_force(self.ldb_admin, self.get_user_dn("test_modify_user1"))
387 self.delete_force(self.ldb_admin, "CN=test_modify_group1,CN=Users," + self.base_dn)
388 self.delete_force(self.ldb_admin, "OU=test_modify_ou1," + self.base_dn)
390 self.delete_force(self.ldb_admin, self.get_user_dn(self.user_with_wp))
392 def test_modify_u1(self):
393 """5 Modify one attribute if you have DS_WRITE_PROPERTY for it"""
394 mod = "(OA;;WP;bf967953-0de6-11d0-a285-00aa003049e2;;%s)" % str(self.user_sid)
395 # First test object -- User
396 print "Testing modify on User object"
397 #self.delete_force(self.ldb_admin, self.get_user_dn("test_modify_user1"))
398 self.create_user(self.ldb_admin, self.get_user_dn("test_modify_user1"))
399 self.dacl_add_ace(self.get_user_dn("test_modify_user1"), mod)
401 dn: """ + self.get_user_dn("test_modify_user1") + """
404 displayName: test_changed"""
405 self.ldb_user.modify_ldif(ldif)
406 res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s)" \
407 % self.get_user_dn("test_modify_user1") )
408 self.assertEqual(res[0]["displayName"][0], "test_changed")
409 # Second test object -- Group
410 print "Testing modify on Group object"
411 #self.delete_force(self.ldb_admin, "CN=test_modify_group1,CN=Users," + self.base_dn)
412 self.create_group(self.ldb_admin, "CN=test_modify_group1,CN=Users," + self.base_dn)
413 self.dacl_add_ace("CN=test_modify_group1,CN=Users," + self.base_dn, mod)
415 dn: CN=test_modify_group1,CN=Users,""" + self.base_dn + """
418 displayName: test_changed"""
419 self.ldb_user.modify_ldif(ldif)
420 res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s)" \
421 % str("CN=test_modify_group1,CN=Users," + self.base_dn) )
422 self.assertEqual(res[0]["displayName"][0], "test_changed")
423 # Third test object -- Organizational Unit
424 print "Testing modify on OU object"
425 #self.delete_force(self.ldb_admin, "OU=test_modify_ou1," + self.base_dn)
426 self.create_ou(self.ldb_admin, "OU=test_modify_ou1," + self.base_dn)
427 self.dacl_add_ace("OU=test_modify_ou1," + self.base_dn, mod)
429 dn: OU=test_modify_ou1,""" + self.base_dn + """
432 displayName: test_changed"""
433 self.ldb_user.modify_ldif(ldif)
434 res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s)" \
435 % str("OU=test_modify_ou1," + self.base_dn) )
436 self.assertEqual(res[0]["displayName"][0], "test_changed")
438 def test_modify_u2(self):
439 """6 Modify two attributes as you have DS_WRITE_PROPERTY granted only for one of them"""
440 mod = "(OA;;WP;bf967953-0de6-11d0-a285-00aa003049e2;;%s)" % str(self.user_sid)
441 # First test object -- User
442 print "Testing modify on User object"
443 #self.delete_force(self.ldb_admin, self.get_user_dn("test_modify_user1"))
444 self.create_user(self.ldb_admin, self.get_user_dn("test_modify_user1"))
445 self.dacl_add_ace(self.get_user_dn("test_modify_user1"), mod)
446 # Modify on attribute you have rights for
448 dn: """ + self.get_user_dn("test_modify_user1") + """
451 displayName: test_changed"""
452 self.ldb_user.modify_ldif(ldif)
453 res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s)" \
454 % self.get_user_dn("test_modify_user1") )
455 self.assertEqual(res[0]["displayName"][0], "test_changed")
456 # Modify on attribute you do not have rights for granted
458 dn: """ + self.get_user_dn("test_modify_user1") + """
461 url: www.samba.org"""
463 self.ldb_user.modify_ldif(ldif)
464 except LdbError, (num, _):
465 self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
467 # This 'modify' operation should always throw ERR_INSUFFICIENT_ACCESS_RIGHTS
469 # Second test object -- Group
470 print "Testing modify on Group object"
471 self.create_group(self.ldb_admin, "CN=test_modify_group1,CN=Users," + self.base_dn)
472 self.dacl_add_ace("CN=test_modify_group1,CN=Users," + self.base_dn, mod)
474 dn: CN=test_modify_group1,CN=Users,""" + self.base_dn + """
477 displayName: test_changed"""
478 self.ldb_user.modify_ldif(ldif)
479 res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s)" \
480 % str("CN=test_modify_group1,CN=Users," + self.base_dn) )
481 self.assertEqual(res[0]["displayName"][0], "test_changed")
482 # Modify on attribute you do not have rights for granted
484 dn: CN=test_modify_group1,CN=Users,""" + self.base_dn + """
487 url: www.samba.org"""
489 self.ldb_user.modify_ldif(ldif)
490 except LdbError, (num, _):
491 self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
493 # This 'modify' operation should always throw ERR_INSUFFICIENT_ACCESS_RIGHTS
495 # Second test object -- Organizational Unit
496 print "Testing modify on OU object"
497 self.create_ou(self.ldb_admin, "OU=test_modify_ou1," + self.base_dn)
498 self.dacl_add_ace("OU=test_modify_ou1," + self.base_dn, mod)
500 dn: OU=test_modify_ou1,""" + self.base_dn + """
503 displayName: test_changed"""
504 self.ldb_user.modify_ldif(ldif)
505 res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s)" \
506 % str("OU=test_modify_ou1," + self.base_dn) )
507 self.assertEqual(res[0]["displayName"][0], "test_changed")
508 # Modify on attribute you do not have rights for granted
510 dn: OU=test_modify_ou1,""" + self.base_dn + """
513 url: www.samba.org"""
515 self.ldb_user.modify_ldif(ldif)
516 except LdbError, (num, _):
517 self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
519 # This 'modify' operation should always throw ERR_INSUFFICIENT_ACCESS_RIGHTS
522 def test_modify_u3(self):
523 """7 Modify one attribute as you have no what so ever rights granted"""
524 # First test object -- User
525 print "Testing modify on User object"
526 self.create_user(self.ldb_admin, self.get_user_dn("test_modify_user1"))
527 # Modify on attribute you do not have rights for granted
529 dn: """ + self.get_user_dn("test_modify_user1") + """
532 url: www.samba.org"""
534 self.ldb_user.modify_ldif(ldif)
535 except LdbError, (num, _):
536 self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
538 # This 'modify' operation should always throw ERR_INSUFFICIENT_ACCESS_RIGHTS
541 # Second test object -- Group
542 print "Testing modify on Group object"
543 self.create_group(self.ldb_admin, "CN=test_modify_group1,CN=Users," + self.base_dn)
544 # Modify on attribute you do not have rights for granted
546 dn: CN=test_modify_group1,CN=Users,""" + self.base_dn + """
549 url: www.samba.org"""
551 self.ldb_user.modify_ldif(ldif)
552 except LdbError, (num, _):
553 self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
555 # This 'modify' operation should always throw ERR_INSUFFICIENT_ACCESS_RIGHTS
558 # Second test object -- Organizational Unit
559 print "Testing modify on OU object"
560 #self.delete_force(self.ldb_admin, "OU=test_modify_ou1," + self.base_dn)
561 self.create_ou(self.ldb_admin, "OU=test_modify_ou1," + self.base_dn)
562 # Modify on attribute you do not have rights for granted
564 dn: OU=test_modify_ou1,""" + self.base_dn + """
567 url: www.samba.org"""
569 self.ldb_user.modify_ldif(ldif)
570 except LdbError, (num, _):
571 self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
573 # This 'modify' operation should always throw ERR_INSUFFICIENT_ACCESS_RIGHTS
577 def test_modify_u4(self):
578 """11 Grant WP to PRINCIPAL_SELF and test modify"""
580 dn: """ + self.get_user_dn(self.user_with_wp) + """
582 add: adminDescription
583 adminDescription: blah blah blah"""
585 self.ldb_user.modify_ldif(ldif)
586 except LdbError, (num, _):
587 self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
589 # This 'modify' operation should always throw ERR_INSUFFICIENT_ACCESS_RIGHTS
592 mod = "(OA;;WP;bf967919-0de6-11d0-a285-00aa003049e2;;PS)"
593 self.dacl_add_ace(self.get_user_dn(self.user_with_wp), mod)
594 # Modify on attribute you have rights for
595 self.ldb_user.modify_ldif(ldif)
596 res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s)" \
597 % self.get_user_dn(self.user_with_wp), attrs=["adminDescription"] )
598 self.assertEqual(res[0]["adminDescription"][0], "blah blah blah")
601 #enable these when we have search implemented
602 class AclSearchTests(AclTests):
606 self.regular_user = "acl_search_user1"
609 # Create regular user
610 self.create_enable_user(self.regular_user)
612 self.assert_user_no_group_member(self.regular_user)
614 self.ldb_user = self.get_ldb_connection(self.regular_user)
617 self.delete_force(self.ldb_admin, "CN=test_search_user1,OU=test_search_ou1," + self.base_dn)
618 self.delete_force(self.ldb_admin, "OU=test_search_ou1," + self.base_dn)
620 self.delete_force(self.ldb_admin, self.get_user_dn(self.regular_user))
622 def test_search_u1(self):
623 """See if can prohibit user to read another User object"""
624 ou_dn = "OU=test_search_ou1," + self.base_dn
625 user_dn = "CN=test_search_user1," + ou_dn
627 self.delete_force(self.ldb_admin, ou_dn)
628 self.create_ou(self.ldb_admin, ou_dn)
629 desc = self.read_desc( ou_dn )
630 desc_sddl = desc.as_sddl( self.domain_sid )
631 # Parse descriptor's SDDL and remove all inherited ACEs reffering
632 # to 'Registered Users' or 'Authenticated Users'
633 desc_aces = re.findall("\(.*?\)", desc_sddl)
634 for ace in desc_aces:
635 if ("I" in ace) and (("RU" in ace) or ("AU" in ace)):
636 desc_sddl = desc_sddl.replace(ace, "")
637 # Add 'P' in the DACL so it breaks further inheritance
638 desc_sddl = desc_sddl.replace("D:AI(", "D:PAI(")
639 # Create a security descriptor object and OU with that descriptor
640 desc = security.descriptor.from_sddl( desc_sddl, self.domain_sid )
641 self.delete_force(self.ldb_admin, ou_dn)
642 self.create_ou(self.ldb_admin, ou_dn, desc)
644 self.delete_force(self.ldb_admin, user_dn)
645 self.create_user(self.ldb_admin, user_dn)
646 desc = self.read_desc( user_dn )
647 desc_sddl = desc.as_sddl( self.domain_sid )
648 # Parse security descriptor SDDL and remove all 'Read' ACEs
650 desc_aces = re.findall("\(.*?\)", desc_sddl)
651 for ace in desc_aces:
652 if ("AU" in ace) and ("R" in ace):
653 desc_sddl = desc_sddl.replace(ace, "")
654 # Create user with the edited descriptor
655 desc = security.descriptor.from_sddl( desc_sddl, self.domain_sid )
656 self.delete_force(self.ldb_admin, user_dn)
657 self.create_user(self.ldb_admin, user_dn, desc)
659 res = ldb_user.search( self.base_dn, expression="(distinguishedName=%s)" \
661 self.assertEqual( res, [] )
663 def test_search_u2(self):
664 """User's group ACEs cleared and after that granted RIGHT_DS_READ_PROPERTY to another User object"""
665 ou_dn = "OU=test_search_ou1," + self.base_dn
666 user_dn = "CN=test_search_user1," + ou_dn
668 self.delete_force(self.ldb_admin, ou_dn)
669 self.create_ou(self.ldb_admin, ou_dn)
670 desc = self.read_desc( ou_dn )
671 desc_sddl = desc.as_sddl( self.domain_sid )
672 # Parse descriptor's SDDL and remove all inherited ACEs reffering
673 # to 'Registered Users' or 'Authenticated Users'
674 desc_aces = re.findall("\(.*?\)", desc_sddl)
675 for ace in desc_aces:
676 if ("I" in ace) and (("RU" in ace) or ("AU" in ace)):
677 desc_sddl = desc_sddl.replace(ace, "")
678 # Add 'P' in the DACL so it breaks further inheritance
679 desc_sddl = desc_sddl.replace("D:AI(", "D:PAI(")
680 # Create a security descriptor object and OU with that descriptor
681 desc = security.descriptor.from_sddl( desc_sddl, self.domain_sid )
682 self.delete_force(self.ldb_admin, ou_dn)
683 self.create_ou(self.ldb_admin, ou_dn, desc)
685 self.delete_force(self.ldb_admin, user_dn)
686 self.create_user(self.ldb_admin, user_dn)
687 # Parse security descriptor SDDL and remove all 'Read' ACEs
689 desc_aces = re.findall("\(.*?\)", desc_sddl)
690 for ace in desc_aces:
691 if ("AU" in ace) and ("R" in ace):
692 desc_sddl = desc_sddl.replace(ace, "")
693 #mod = "(OA;;RP;e48d0154-bcf8-11d1-8702-00c04fb96050;;AU)"
695 self.dacl_add_ace(user_dn, mod)
696 res = self.ldb_user.search( self.base_dn, expression="(distinguishedName=%s)" \
698 self.assertNotEqual( res, [] )
700 #tests on ldap delete operations
701 class AclDeleteTests(AclTests):
705 self.regular_user = "acl_delete_user1"
708 # Create regular user
709 self.create_enable_user(self.regular_user)
711 self.assert_user_no_group_member(self.regular_user)
713 self.ldb_user = self.get_ldb_connection(self.regular_user)
716 self.delete_force(self.ldb_admin, self.get_user_dn("test_delete_user1"))
718 self.delete_force(self.ldb_admin, self.get_user_dn(self.regular_user))
720 def test_delete_u1(self):
721 """User is prohibited by default to delete another User object"""
722 # Create user that we try to delete
723 self.create_user(self.ldb_admin, self.get_user_dn("test_delete_user1"))
724 # Here delete User object should ALWAYS through exception
726 self.ldb_user.delete(self.get_user_dn("test_delete_user1"))
727 except LdbError, (num, _):
728 self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
732 def test_delete_u2(self):
733 """User's group has RIGHT_DELETE to another User object"""
734 user_dn = self.get_user_dn("test_delete_user1")
735 # Create user that we try to delete
736 self.create_user(self.ldb_admin, user_dn)
738 self.dacl_add_ace(user_dn, mod)
739 # Try to delete User object
740 self.ldb_user.delete( user_dn )
741 res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s)" \
743 self.assertEqual( res, [] )
745 def test_delete_u3(self):
746 """User indentified by SID has RIGHT_DELETE to another User object"""
747 user_dn = self.get_user_dn("test_delete_user1")
748 # Create user that we try to delete
749 self.create_user(self.ldb_admin, user_dn)
750 mod = "(A;;SD;;;%s)" % str( self.get_object_sid(self.get_user_dn(self.regular_user)))
751 self.dacl_add_ace(user_dn, mod)
752 # Try to delete User object
753 self.ldb_user.delete( user_dn )
754 res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s)" \
756 self.assertEqual( res, [] )
758 #tests on ldap rename operations
759 class AclRenameTests(AclTests):
763 self.regular_user = "acl_rename_user1"
766 # Create regular user
767 self.create_enable_user(self.regular_user)
769 self.assert_user_no_group_member(self.regular_user)
771 self.ldb_user = self.get_ldb_connection(self.regular_user)
775 self.delete_force(self.ldb_admin, "CN=test_rename_user1,OU=test_rename_ou3,OU=test_rename_ou2," + self.base_dn)
776 self.delete_force(self.ldb_admin, "CN=test_rename_user2,OU=test_rename_ou3,OU=test_rename_ou2," + self.base_dn)
777 self.delete_force(self.ldb_admin, "CN=test_rename_user5,OU=test_rename_ou3,OU=test_rename_ou2," + self.base_dn)
778 self.delete_force(self.ldb_admin, "OU=test_rename_ou3,OU=test_rename_ou2," + self.base_dn)
780 self.delete_force(self.ldb_admin, "CN=test_rename_user1,OU=test_rename_ou2," + self.base_dn)
781 self.delete_force(self.ldb_admin, "CN=test_rename_user2,OU=test_rename_ou2," + self.base_dn)
782 self.delete_force(self.ldb_admin, "CN=test_rename_user5,OU=test_rename_ou2," + self.base_dn)
783 self.delete_force(self.ldb_admin, "OU=test_rename_ou2," + self.base_dn)
785 self.delete_force(self.ldb_admin, "CN=test_rename_user1,OU=test_rename_ou1," + self.base_dn)
786 self.delete_force(self.ldb_admin, "CN=test_rename_user2,OU=test_rename_ou1," + self.base_dn)
787 self.delete_force(self.ldb_admin, "CN=test_rename_user5,OU=test_rename_ou1," + self.base_dn)
788 self.delete_force(self.ldb_admin, "OU=test_rename_ou3,OU=test_rename_ou1," + self.base_dn)
789 self.delete_force(self.ldb_admin, "OU=test_rename_ou1," + self.base_dn)
791 self.delete_force(self.ldb_admin, self.get_user_dn(self.regular_user))
793 def test_rename_u1(self):
794 """Regular user fails to rename 'User object' within single OU"""
795 # Create OU structure
796 self.create_ou(self.ldb_admin, "OU=test_rename_ou1," + self.base_dn)
797 self.create_user(self.ldb_admin, "CN=test_rename_user1,OU=test_rename_ou1," + self.base_dn)
799 self.ldb_user.rename("CN=test_rename_user1,OU=test_rename_ou1," + self.base_dn, \
800 "CN=test_rename_user5,OU=test_rename_ou1," + self.base_dn)
801 except LdbError, (num, _):
802 self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
806 def test_rename_u2(self):
807 """Grant WRITE_PROPERTY to AU so regular user can rename 'User object' within single OU"""
808 ou_dn = "OU=test_rename_ou1," + self.base_dn
809 user_dn = "CN=test_rename_user1," + ou_dn
810 rename_user_dn = "CN=test_rename_user5," + ou_dn
811 # Create OU structure
812 self.create_ou(self.ldb_admin, ou_dn)
813 self.create_user(self.ldb_admin, user_dn)
815 self.dacl_add_ace(user_dn, mod)
816 # Rename 'User object' having WP to AU
817 self.ldb_user.rename(user_dn, rename_user_dn)
818 res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s)" \
820 self.assertEqual( res, [] )
821 res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s)" \
823 self.assertNotEqual( res, [] )
825 def test_rename_u3(self):
826 """Test rename with rights granted to 'User object' SID"""
827 ou_dn = "OU=test_rename_ou1," + self.base_dn
828 user_dn = "CN=test_rename_user1," + ou_dn
829 rename_user_dn = "CN=test_rename_user5," + ou_dn
830 # Create OU structure
831 self.create_ou(self.ldb_admin, ou_dn)
832 self.create_user(self.ldb_admin, user_dn)
833 sid = self.get_object_sid(self.get_user_dn(self.regular_user))
834 mod = "(A;;WP;;;%s)" % str(sid)
835 self.dacl_add_ace(user_dn, mod)
836 # Rename 'User object' having WP to AU
837 self.ldb_user.rename(user_dn, rename_user_dn)
838 res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s)" \
840 self.assertEqual( res, [] )
841 res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s)" \
843 self.assertNotEqual( res, [] )
845 def test_rename_u4(self):
846 """Rename 'User object' cross OU with WP, SD and CC right granted on reg. user to AU"""
847 ou1_dn = "OU=test_rename_ou1," + self.base_dn
848 ou2_dn = "OU=test_rename_ou2," + self.base_dn
849 user_dn = "CN=test_rename_user2," + ou1_dn
850 rename_user_dn = "CN=test_rename_user5," + ou2_dn
851 # Create OU structure
852 self.create_ou(self.ldb_admin, ou1_dn)
853 self.create_ou(self.ldb_admin, ou2_dn)
854 self.create_user(self.ldb_admin, user_dn)
855 mod = "(A;;WPSD;;;AU)"
856 self.dacl_add_ace(user_dn, mod)
858 self.dacl_add_ace(ou2_dn, mod)
859 # Rename 'User object' having SD and CC to AU
860 self.ldb_user.rename(user_dn, rename_user_dn)
861 res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s)" \
863 self.assertEqual( res, [] )
864 res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s)" \
866 self.assertNotEqual( res, [] )
868 def test_rename_u5(self):
869 """Test rename with rights granted to 'User object' SID"""
870 ou1_dn = "OU=test_rename_ou1," + self.base_dn
871 ou2_dn = "OU=test_rename_ou2," + self.base_dn
872 user_dn = "CN=test_rename_user2," + ou1_dn
873 rename_user_dn = "CN=test_rename_user5," + ou2_dn
874 # Create OU structure
875 self.create_ou(self.ldb_admin, ou1_dn)
876 self.create_ou(self.ldb_admin, ou2_dn)
877 self.create_user(self.ldb_admin, user_dn)
878 sid = self.get_object_sid(self.get_user_dn(self.regular_user))
879 mod = "(A;;WPSD;;;%s)" % str(sid)
880 self.dacl_add_ace(user_dn, mod)
881 mod = "(A;;CC;;;%s)" % str(sid)
882 self.dacl_add_ace(ou2_dn, mod)
883 # Rename 'User object' having SD and CC to AU
884 self.ldb_user.rename(user_dn, rename_user_dn)
885 res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s)" \
887 self.assertEqual( res, [] )
888 res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s)" \
890 self.assertNotEqual( res, [] )
892 def test_rename_u6(self):
893 """Rename 'User object' cross OU with WP, DC and CC right granted on OU & user to AU"""
894 ou1_dn = "OU=test_rename_ou1," + self.base_dn
895 ou2_dn = "OU=test_rename_ou2," + self.base_dn
896 user_dn = "CN=test_rename_user2," + ou1_dn
897 rename_user_dn = "CN=test_rename_user2," + ou2_dn
898 # Create OU structure
899 self.create_ou(self.ldb_admin, ou1_dn)
900 self.create_ou(self.ldb_admin, ou2_dn)
901 #mod = "(A;CI;DCWP;;;AU)"
903 self.dacl_add_ace(ou1_dn, mod)
905 self.dacl_add_ace(ou2_dn, mod)
906 self.create_user(self.ldb_admin, user_dn)
908 self.dacl_add_ace(user_dn, mod)
909 # Rename 'User object' having SD and CC to AU
910 self.ldb_user.rename(user_dn, rename_user_dn)
911 res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s)" \
913 self.assertEqual( res, [] )
914 res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s)" \
916 self.assertNotEqual( res, [] )
918 def test_rename_u7(self):
919 """Rename 'User object' cross OU (second level) with WP, DC and CC right granted on OU to AU"""
920 ou1_dn = "OU=test_rename_ou1," + self.base_dn
921 ou2_dn = "OU=test_rename_ou2," + self.base_dn
922 ou3_dn = "OU=test_rename_ou3," + ou2_dn
923 user_dn = "CN=test_rename_user2," + ou1_dn
924 rename_user_dn = "CN=test_rename_user5," + ou3_dn
925 # Create OU structure
926 self.create_ou(self.ldb_admin, ou1_dn)
927 self.create_ou(self.ldb_admin, ou2_dn)
928 self.create_ou(self.ldb_admin, ou3_dn)
929 mod = "(A;CI;WPDC;;;AU)"
930 self.dacl_add_ace(ou1_dn, mod)
932 self.dacl_add_ace(ou3_dn, mod)
933 self.create_user(self.ldb_admin, user_dn)
934 # Rename 'User object' having SD and CC to AU
935 self.ldb_user.rename(user_dn, rename_user_dn)
936 res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s)" \
938 self.assertEqual( res, [] )
939 res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s)" \
941 self.assertNotEqual( res, [] )
943 def test_rename_u8(self):
944 """Test rename on an object with and without modify access on the RDN attribute"""
945 ou1_dn = "OU=test_rename_ou1," + self.base_dn
946 ou2_dn = "OU=test_rename_ou2," + ou1_dn
947 ou3_dn = "OU=test_rename_ou3," + ou1_dn
948 # Create OU structure
949 self.create_ou(self.ldb_admin, ou1_dn)
950 self.create_ou(self.ldb_admin, ou2_dn)
951 sid = self.get_object_sid(self.get_user_dn(self.regular_user))
952 mod = "(OA;;WP;bf967a0e-0de6-11d0-a285-00aa003049e2;;%s)" % str(sid)
953 self.dacl_add_ace(ou2_dn, mod)
954 mod = "(OD;;WP;bf9679f0-0de6-11d0-a285-00aa003049e2;;%s)" % str(sid)
955 self.dacl_add_ace(ou2_dn, mod)
957 self.ldb_user.rename(ou2_dn, ou3_dn)
958 except LdbError, (num, _):
959 self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
961 # This rename operation should always throw ERR_INSUFFICIENT_ACCESS_RIGHTS
963 sid = self.get_object_sid(self.get_user_dn(self.regular_user))
964 mod = "(A;;WP;bf9679f0-0de6-11d0-a285-00aa003049e2;;%s)" % str(sid)
965 self.dacl_add_ace(ou2_dn, mod)
966 self.ldb_user.rename(ou2_dn, ou3_dn)
967 res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s)" \
969 self.assertEqual( res, [] )
970 res = self.ldb_admin.search( self.base_dn, expression="(distinguishedName=%s)" \
972 self.assertNotEqual( res, [] )
974 # Important unit running information
976 if not "://" in host:
977 host = "ldap://%s" % host
978 ldb = Ldb(host, credentials=creds, session_info=system_session(), lp=lp)
980 runner = SubunitTestRunner()
982 if not runner.run(unittest.makeSuite(AclAddTests)).wasSuccessful():
984 if not runner.run(unittest.makeSuite(AclModifyTests)).wasSuccessful():
986 if not runner.run(unittest.makeSuite(AclDeleteTests)).wasSuccessful():
988 if not runner.run(unittest.makeSuite(AclRenameTests)).wasSuccessful():