ctdb-scripts: Improve update and listing code
[samba4-gss.git] / python / samba / tests / samba_tool / domain_auth_policy.py
blobd5fa295ecd183e238d49d8ae88b1311ca47acbb5
1 # Unix SMB/CIFS implementation.
3 # Tests for samba-tool domain auth policy command
5 # Copyright (C) Catalyst.Net Ltd. 2023
7 # Written by Rob van der Linde <rob@catalyst.net.nz>
9 # This program is free software; you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 3 of the License, or
12 # (at your option) any later version.
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with this program. If not, see <http://www.gnu.org/licenses/>.
23 import json
24 from optparse import OptionValueError
25 from unittest.mock import patch
27 from samba.dcerpc import security
28 from samba.domain.models.exceptions import ModelError
29 from samba.ndr import ndr_pack, ndr_unpack
30 from samba.nt_time import NT_TICKS_PER_SEC
31 from samba.samdb import SamDB
32 from samba.sd_utils import SDUtils
34 from .silo_base import SiloTest
37 def mins_to_tgt_lifetime(minutes):
38 """Convert minutes to the tgt_lifetime attributes unit which is 10^-7 seconds"""
39 if minutes is not None:
40 return minutes * 60 * NT_TICKS_PER_SEC
41 return minutes
43 class AuthPolicyCmdTestCase(SiloTest):
45 def test_list(self):
46 """Test listing authentication policies in list format."""
47 result, out, err = self.runcmd("domain", "auth", "policy", "list")
48 self.assertIsNone(result, msg=err)
50 expected_policies = ["User Policy", "Service Policy", "Computer Policy"]
52 for policy in expected_policies:
53 self.assertIn(policy, out)
55 def test_list__json(self):
56 """Test listing authentication policies in JSON format."""
57 result, out, err = self.runcmd("domain", "auth", "policy",
58 "list", "--json")
59 self.assertIsNone(result, msg=err)
61 # we should get valid json
62 policies = json.loads(out)
64 expected_policies = ["User Policy", "Service Policy", "Computer Policy"]
66 for name in expected_policies:
67 policy = policies[name]
68 self.assertIn("name", policy)
69 self.assertIn("msDS-AuthNPolicy", list(policy["objectClass"]))
70 self.assertIn("msDS-AuthNPolicyEnforced", policy)
71 self.assertIn("msDS-StrongNTLMPolicy", policy)
72 self.assertIn("objectGUID", policy)
74 def test_view(self):
75 """Test viewing a single authentication policy."""
76 result, out, err = self.runcmd("domain", "auth", "policy", "view",
77 "--name", "User Policy")
78 self.assertIsNone(result, msg=err)
80 # we should get valid json
81 policy = json.loads(out)
83 # check a few fields only
84 self.assertEqual(policy["cn"], "User Policy")
85 self.assertEqual(policy["msDS-AuthNPolicyEnforced"], True)
87 def test_view__notfound(self):
88 """Test viewing an authentication policy that doesn't exist."""
89 result, out, err = self.runcmd("domain", "auth", "policy", "view",
90 "--name", "doesNotExist")
91 self.assertEqual(result, -1)
92 self.assertIn("Authentication policy doesNotExist not found.", err)
94 def test_view__name_required(self):
95 """Test view authentication policy without --name argument."""
96 result, out, err = self.runcmd("domain", "auth", "policy", "view")
97 self.assertEqual(result, -1)
98 self.assertIn("Argument --name is required.", err)
100 def test_create__success(self):
101 """Test creating a new authentication policy."""
102 name = self.unique_name()
104 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
105 result, out, err = self.runcmd("domain", "auth", "policy", "create",
106 "--name", name)
107 self.assertIsNone(result, msg=err)
109 # Check policy that was created
110 policy = self.get_authentication_policy(name)
111 self.assertEqual(str(policy["cn"]), name)
112 self.assertEqual(str(policy["msDS-AuthNPolicyEnforced"]), "TRUE")
114 def test_create__description(self):
115 """Test creating a new authentication policy with description set."""
116 name = self.unique_name()
118 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
119 result, out, err = self.runcmd("domain", "auth", "policy", "create",
120 "--name", name,
121 "--description", "Custom Description")
122 self.assertIsNone(result, msg=err)
124 # Check policy description
125 policy = self.get_authentication_policy(name)
126 self.assertEqual(str(policy["cn"]), name)
127 self.assertEqual(str(policy["description"]), "Custom Description")
129 def test_create__user_tgt_lifetime_mins(self):
130 """Test create a new authentication policy with --user-tgt-lifetime-mins.
132 Also checks the upper and lower bounds are handled.
134 name = self.unique_name()
136 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
137 result, out, err = self.runcmd("domain", "auth", "policy", "create",
138 "--name", name,
139 "--user-tgt-lifetime-mins", "60")
140 self.assertIsNone(result, msg=err)
142 # Check policy fields.
143 policy = self.get_authentication_policy(name)
144 self.assertEqual(str(policy["cn"]), name)
145 self.assertEqual(str(policy["msDS-UserTGTLifetime"]), str(mins_to_tgt_lifetime(60)))
147 # check lower bounds (45)
148 result, out, err = self.runcmd("domain", "auth", "policy", "create",
149 "--name", name + "Lower",
150 "--user-tgt-lifetime-mins", "44")
151 self.assertEqual(result, -1)
152 self.assertIn("--user-tgt-lifetime-mins must be between 45 and 2147483647",
153 err)
155 # check upper bounds (2147483647)
156 result, out, err = self.runcmd("domain", "auth", "policy", "create",
157 "--name", name + "Upper",
158 "--user-tgt-lifetime-mins", "2147483648")
159 self.assertEqual(result, -1)
160 self.assertIn("--user-tgt-lifetime-mins must be between 45 and 2147483647",
161 err)
163 def test_create__service_tgt_lifetime_mins(self):
164 """Test create a new authentication policy with --service-tgt-lifetime-mins.
166 Also checks the upper and lower bounds are handled.
168 name = self.unique_name()
170 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
171 result, out, err = self.runcmd("domain", "auth", "policy", "create",
172 "--name", name,
173 "--service-tgt-lifetime-mins", "60")
174 self.assertIsNone(result, msg=err)
176 # Check policy fields.
177 policy = self.get_authentication_policy(name)
178 self.assertEqual(str(policy["cn"]), name)
179 self.assertEqual(str(policy["msDS-ServiceTGTLifetime"]), str(mins_to_tgt_lifetime(60)))
181 # check lower bounds (45)
182 result, out, err = self.runcmd("domain", "auth", "policy", "create",
183 "--name", name,
184 "--service-tgt-lifetime-mins", "44")
185 self.assertEqual(result, -1)
186 self.assertIn("--service-tgt-lifetime-mins must be between 45 and 2147483647",
187 err)
189 # check upper bounds (2147483647)
190 result, out, err = self.runcmd("domain", "auth", "policy", "create",
191 "--name", name,
192 "--service-tgt-lifetime-mins", "2147483648")
193 self.assertEqual(result, -1)
194 self.assertIn("--service-tgt-lifetime-mins must be between 45 and 2147483647",
195 err)
197 def test_create__computer_tgt_lifetime_mins(self):
198 """Test create a new authentication policy with --computer-tgt-lifetime-mins.
200 Also checks the upper and lower bounds are handled.
202 name = self.unique_name()
204 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
205 result, out, err = self.runcmd("domain", "auth", "policy", "create",
206 "--name", name,
207 "--computer-tgt-lifetime-mins", "60")
208 self.assertIsNone(result, msg=err)
210 # Check policy fields.
211 policy = self.get_authentication_policy(name)
212 self.assertEqual(str(policy["cn"]), name)
213 self.assertEqual(str(policy["msDS-ComputerTGTLifetime"]), str(mins_to_tgt_lifetime(60)))
215 # check lower bounds (45)
216 result, out, err = self.runcmd("domain", "auth", "policy", "create",
217 "--name", name + "Lower",
218 "--computer-tgt-lifetime-mins", "44")
219 self.assertEqual(result, -1)
220 self.assertIn("--computer-tgt-lifetime-mins must be between 45 and 2147483647",
221 err)
223 # check upper bounds (2147483647)
224 result, out, err = self.runcmd("domain", "auth", "policy", "create",
225 "--name", name + "Upper",
226 "--computer-tgt-lifetime-mins", "2147483648")
227 self.assertEqual(result, -1)
228 self.assertIn("--computer-tgt-lifetime-mins must be between 45 and 2147483647",
229 err)
231 def test_create__valid_sddl(self):
232 """Test creating a new authentication policy with valid SDDL in a field."""
233 name = self.unique_name()
234 expected = "O:SYG:SYD:(XA;OICI;CR;;;WD;(Member_of {SID(AO)}))"
236 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
237 result, out, err = self.runcmd("domain", "auth", "policy", "create",
238 "--name", name,
239 "--user-allowed-to-authenticate-from",
240 expected)
241 self.assertIsNone(result, msg=err)
243 # Check policy fields.
244 policy = self.get_authentication_policy(name)
245 self.assertEqual(str(policy["cn"]), name)
246 desc = policy["msDS-UserAllowedToAuthenticateFrom"][0]
247 sddl = ndr_unpack(security.descriptor, desc).as_sddl()
248 self.assertEqual(sddl, expected)
250 def test_create__invalid_sddl(self):
251 """Test creating a new authentication policy with invalid SDDL in a field."""
252 name = self.unique_name()
254 result, out, err = self.runcmd("domain", "auth", "policy", "create",
255 "--name", name,
256 "--user-allowed-to-authenticate-from",
257 "*INVALID SDDL*")
259 self.assertEqual(result, -1)
260 self.assertIn("Unable to parse SDDL", err)
261 self.assertIn(" *INVALID SDDL*\n ^\n expected '[OGDS]:' section start ", err)
263 def test_create__invalid_sddl_conditional_ace(self):
264 """Test creating a new authentication policy with invalid SDDL in a field."""
265 sddl = "O:SYG:SYD:(XA;OICI;CR;;;WD;(Member_of {secret club}))"
266 result, out, err = self.runcmd("domain", "auth", "policy", "create",
267 "--name", "invalidSDDLPolicy2",
268 "--user-allowed-to-authenticate-from",
269 sddl)
270 self.assertEqual(result, -1)
271 self.assertIn("Unable to parse SDDL", err)
272 self.assertIn(sddl, err)
273 self.assertIn(f"\n{'^':>41}", err)
274 self.assertIn("unexpected byte 0x73 's' parsing literal", err)
275 self.assertNotIn(" File ", err)
277 def test_create__invalid_sddl_conditional_ace_non_ascii(self):
278 """Test creating a new authentication policy with invalid SDDL in a field."""
279 sddl = 'O:SYG:SYD:(XA;OICI;CR;;;WD;(@User.āāēē == "łē¶ŧ¹⅓þōīŋ“đ¢ð»" && Member_of {secret club}))'
280 result, out, err = self.runcmd("domain", "auth", "policy", "create",
281 "--name", "invalidSDDLPolicy2",
282 "--user-allowed-to-authenticate-from",
283 sddl)
284 self.assertEqual(result, -1)
285 self.assertIn("Unable to parse SDDL", err)
286 self.assertIn(sddl, err)
287 self.assertIn(f"\n{'^':>76}\n", err)
288 self.assertIn(" unexpected byte 0x73 's' parsing literal", err)
289 self.assertNotIn(" File ", err)
291 def test_create__invalid_sddl_normal_ace(self):
292 """Test creating a new authentication policy with invalid SDDL in a field."""
293 sddl = "O:SYG:SYD:(A;;;;ZZ)(XA;OICI;CR;;;WD;(Member_of {WD}))"
294 result, out, err = self.runcmd("domain", "auth", "policy", "create",
295 "--name", "invalidSDDLPolicy3",
296 "--user-allowed-to-authenticate-from",
297 sddl)
298 self.assertEqual(result, -1)
299 self.assertIn("Unable to parse SDDL", err)
300 self.assertIn(sddl, err)
301 self.assertIn(f"\n{'^':>13}", err)
302 self.assertIn("\n malformed ACE with only 4 ';'\n", err)
303 self.assertNotIn(" File ", err) # traceback marker
305 def test_create__device_attribute_in_sddl_allowed_to(self):
306 """Test creating a new authentication policy that uses
307 user-allowed-to-authenticate-to with a device attribute."""
309 sddl = 'O:SYG:SYD:(XA;OICI;CR;;;WD;(@Device.claim == "foo"))'
311 name = self.unique_name()
312 self.addCleanup(self.delete_authentication_policy, name=name)
313 result, _, err = self.runcmd("domain", "auth", "policy", "create",
314 "--name", name,
315 "--user-allowed-to-authenticate-to",
316 sddl)
317 self.assertIsNone(result, msg=err)
319 def test_create__device_operator_in_sddl_allowed_to(self):
320 """Test creating a new authentication policy that uses
321 user-allowed-to-authenticate-to with a device operator."""
323 sddl = 'O:SYG:SYD:(XA;OICI;CR;;;WD;(Not_Device_Member_of {SID(WD)}))'
325 name = self.unique_name()
326 self.addCleanup(self.delete_authentication_policy, name=name)
327 result, _, err = self.runcmd("domain", "auth", "policy", "create",
328 "--name", name,
329 "--user-allowed-to-authenticate-to",
330 sddl)
331 self.assertIsNone(result, msg=err)
333 def test_create__device_attribute_in_sddl_allowed_from(self):
334 """Test creating a new authentication policy that uses
335 user-allowed-to-authenticate-from with a device attribute."""
337 sddl = 'O:SYG:SYD:(XA;OICI;CR;;;WD;(@Device.claim == "foo"))'
339 name = self.unique_name()
340 result, _, err = self.runcmd("domain", "auth", "policy", "create",
341 "--name", name,
342 "--user-allowed-to-authenticate-from",
343 sddl)
344 self.assertEqual(result, -1)
345 self.assertIn("Unable to parse SDDL", err)
346 self.assertIn(sddl, err)
347 self.assertIn(f"\n{'^':>31}\n", err)
348 self.assertIn(" a device attribute is not applicable in this context "
349 "(did you intend a user attribute?)",
350 err)
351 self.assertNotIn(" File ", err)
353 def test_create__device_operator_in_sddl_allowed_from(self):
354 """Test creating a new authentication policy that uses
355 user-allowed-to-authenticate-from with a device operator."""
357 sddl = 'O:SYG:SYD:(XA;OICI;CR;;;WD;(Not_Device_Member_of {SID(WD)}))'
359 name = self.unique_name()
360 result, _, err = self.runcmd("domain", "auth", "policy", "create",
361 "--name", name,
362 "--user-allowed-to-authenticate-from",
363 sddl)
364 self.assertEqual(result, -1)
365 self.assertIn("Unable to parse SDDL", err)
366 self.assertIn(sddl, err)
367 self.assertIn(f"\n{'^':>30}\n", err)
368 self.assertIn(" a device‐relative expression will never evaluate to "
369 "true in this context (did you intend a user‐relative "
370 "expression?)",
371 err)
372 self.assertNotIn(" File ", err)
374 def test_create__device_attribute_in_sddl_already_exists(self):
375 """Test modifying an existing authentication policy that uses
376 user-allowed-to-authenticate-from with a device attribute."""
378 # The SDDL refers to ‘Device.claim’.
379 sddl = 'O:SYG:SYD:(XA;OICI;CR;;;WD;(@Device.claim == "foo"))'
380 domain_sid = security.dom_sid(self.samdb.get_domain_sid())
381 descriptor = security.descriptor.from_sddl(sddl, domain_sid)
383 # Manually create an authentication policy that refers to a device
384 # attribute.
386 name = self.unique_name()
387 dn = self.get_authn_policies_dn()
388 dn.add_child(f"CN={name}")
389 message = {
390 'dn': dn,
391 'msDS-AuthNPolicyEnforced': b'TRUE',
392 'objectClass': b'msDS-AuthNPolicy',
393 'msDS-UserAllowedToAuthenticateFrom': ndr_pack(descriptor),
396 self.addCleanup(self.delete_authentication_policy, name=name)
397 self.samdb.add(message)
399 # Change the policy description. This should succeed, in spite of the
400 # policy’s referring to a device attribute when it shouldn’t.
401 result, _, err = self.runcmd("domain", "auth", "policy", "modify",
402 "--name", name,
403 "--description", "NewDescription")
404 self.assertIsNone(result, msg=err)
406 def test_create__already_exists(self):
407 """Test creating a new authentication policy that already exists."""
408 result, out, err = self.runcmd("domain", "auth", "policy", "create",
409 "--name", "User Policy")
410 self.assertEqual(result, -1)
411 self.assertIn("Authentication policy User Policy already exists", err)
413 def test_create__name_missing(self):
414 """Test create authentication policy without --name argument."""
415 result, out, err = self.runcmd("domain", "auth", "policy", "create")
416 self.assertEqual(result, -1)
417 self.assertIn("Argument --name is required.", err)
419 def test_create__audit(self):
420 """Test create authentication policy with --audit flag."""
421 name = self.unique_name()
423 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
424 result, out, err = self.runcmd("domain", "auth", "policy", "create",
425 "--name", name,
426 "--audit")
427 self.assertIsNone(result, msg=err)
429 # fetch and check policy
430 policy = self.get_authentication_policy(name)
431 self.assertEqual(str(policy["msDS-AuthNPolicyEnforced"]), "FALSE")
433 def test_create__enforce(self):
434 """Test create authentication policy with --enforce flag."""
435 name = self.unique_name()
437 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
438 result, out, err = self.runcmd("domain", "auth", "policy", "create",
439 "--name", name,
440 "--enforce")
441 self.assertIsNone(result, msg=err)
443 # fetch and check policy
444 policy = self.get_authentication_policy(name)
445 self.assertEqual(str(policy["msDS-AuthNPolicyEnforced"]), "TRUE")
447 def test_create__audit_enforce_together(self):
448 """Test create auth policy using both --audit and --enforce."""
449 name = self.unique_name()
451 result, out, err = self.runcmd("domain", "auth", "policy", "create",
452 "--name", name,
453 "--audit", "--enforce")
455 self.assertEqual(result, -1)
456 self.assertIn("--audit and --enforce cannot be used together.", err)
458 def test_create__protect_unprotect_together(self):
459 """Test create authentication policy using --protect and --unprotect."""
460 name = self.unique_name()
462 result, out, err = self.runcmd("domain", "auth", "policy", "create",
463 "--name", name,
464 "--protect", "--unprotect")
466 self.assertEqual(result, -1)
467 self.assertIn("--protect and --unprotect cannot be used together.", err)
469 def test_user_allowed_to_authenticate_from__set_repeated(self):
470 """Test repeating similar arguments doesn't make sense to use together.
472 user-allowed-to-authenticate-from set --device-group
473 user-allowed-to-authenticate-from set --device-silo
475 name = self.unique_name()
477 self.runcmd("domain", "auth", "policy", "create", "--name", name)
478 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
480 result, out, err = self.runcmd("domain", "auth", "policy",
481 "user-allowed-to-authenticate-from",
482 "set", "--name", name,
483 "--device-group",
484 self.device_group.name,
485 "--device-silo",
486 "Managers")
488 self.assertEqual(result, -1)
489 self.assertIn("Cannot have both --device-group and --device-silo options.", err)
491 def test_user_allowed_to_authenticate_to__set_repeated(self):
492 """Test repeating similar arguments doesn't make sense to use together.
494 user-allowed-to-authenticate-to set --by-group
495 user-allowed-to-authenticate-to set --by-silo
497 name = self.unique_name()
499 self.runcmd("domain", "auth", "policy", "create", "--name", name)
500 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
502 result, out, err = self.runcmd("domain", "auth", "policy",
503 "user-allowed-to-authenticate-to",
504 "set", "--name", name,
505 "--by-group",
506 self.device_group.name,
507 "--by-silo",
508 "Managers")
510 self.assertEqual(result, -1)
511 self.assertIn("Cannot have both --by-group and --by-silo options.", err)
513 def test_service_allowed_to_authenticate_from__set_repeated(self):
514 """Test repeating similar arguments doesn't make sense to use together.
516 service-allowed-to-authenticate-from set --device-group
517 service-allowed-to-authenticate-from set --device-silo
519 name = self.unique_name()
521 self.runcmd("domain", "auth", "policy", "create", "--name", name)
522 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
524 result, out, err = self.runcmd("domain", "auth", "policy",
525 "service-allowed-to-authenticate-from",
526 "set", "--name", name,
527 "--device-group",
528 self.device_group.name,
529 "--device-silo",
530 "QA")
532 self.assertEqual(result, -1)
533 self.assertIn("Cannot have both --device-group and --device-silo options.", err)
535 def test_service_allowed_to_authenticate_to__set_repeated(self):
536 """Test repeating similar arguments doesn't make sense to use together.
538 service-allowed-to-authenticate-to set --by-group
539 service-allowed-to-authenticate-to set --by-silo
541 name = self.unique_name()
543 self.runcmd("domain", "auth", "policy", "create", "--name", name)
544 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
546 result, out, err = self.runcmd("domain", "auth", "policy",
547 "service-allowed-to-authenticate-to",
548 "set", "--name", name,
549 "--by-group",
550 self.device_group.name,
551 "--by-silo",
552 "QA")
554 self.assertEqual(result, -1)
555 self.assertIn("Cannot have both --by-group and --by-silo options.", err)
557 def test_computer_allowed_to_authenticate_to__set_repeated(self):
558 """Test repeating similar arguments doesn't make sense to use together.
560 computer-allowed-to-authenticate-to set --by-group
561 computer-allowed-to-authenticate-to set --by-silo
563 name = self.unique_name()
565 self.runcmd("domain", "auth", "policy", "create", "--name", name)
566 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
568 result, out, err = self.runcmd("domain", "auth", "policy",
569 "computer-allowed-to-authenticate-to",
570 "set", "--name", name,
571 "--by-group",
572 self.device_group.name,
573 "--by-silo",
574 "QA")
576 self.assertEqual(result, -1)
577 self.assertIn("Cannot have both --by-group and --by-silo options.", err)
579 def test_create__fails(self):
580 """Test creating an authentication policy, but it fails."""
581 name = self.unique_name()
583 # Raise ModelError when ldb.add() is called.
584 with patch.object(SamDB, "add") as add_mock:
585 add_mock.side_effect = ModelError("Custom error message")
586 result, out, err = self.runcmd("domain", "auth", "policy", "create",
587 "--name", name)
588 self.assertEqual(result, -1)
589 self.assertIn("Custom error message", err)
591 def test_modify__description(self):
592 """Test modifying an authentication policy description."""
593 name = self.unique_name()
595 # Create a policy to modify for this test.
596 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
597 self.runcmd("domain", "auth", "policy", "create", "--name", name)
599 # Change the policy description.
600 result, out, err = self.runcmd("domain", "auth", "policy", "modify",
601 "--name", name,
602 "--description", "NewDescription")
603 self.assertIsNone(result, msg=err)
605 # Verify fields were changed.
606 policy = self.get_authentication_policy(name)
607 self.assertEqual(str(policy["description"]), "NewDescription")
609 def test_modify__strong_ntlm_policy(self):
610 """Test modify strong ntlm policy on the authentication policy."""
611 name = self.unique_name()
613 # Create a policy to modify for this test.
614 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
615 self.runcmd("domain", "auth", "policy", "create", "--name", name)
617 result, out, err = self.runcmd("domain", "auth", "policy", "modify",
618 "--name", name,
619 "--strong-ntlm-policy", "Required")
620 self.assertIsNone(result, msg=err)
622 # Verify fields were changed.
623 policy = self.get_authentication_policy(name)
624 self.assertEqual(str(policy["msDS-StrongNTLMPolicy"]), "2")
626 # Check an invalid choice.
627 with self.assertRaises((OptionValueError, SystemExit)):
628 self.runcmd("domain", "auth", "policy", "modify",
629 "--name", name,
630 "--strong-ntlm-policy", "Invalid")
632 # It is difficult to test the error message text for invalid
633 # choices because inside optparse it will raise OptionValueError
634 # followed by raising SystemExit(2).
636 def test_modify__user_tgt_lifetime_mins(self):
637 """Test modifying an authentication policy --user-tgt-lifetime-mins.
639 This includes checking the upper and lower bounds.
641 name = self.unique_name()
643 # Create a policy to modify for this test.
644 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
645 self.runcmd("domain", "auth", "policy", "create", "--name", name)
647 result, out, err = self.runcmd("domain", "auth", "policy", "modify",
648 "--name", name,
649 "--user-tgt-lifetime-mins", "120")
650 self.assertIsNone(result, msg=err)
652 # Verify field was changed.
653 policy = self.get_authentication_policy(name)
654 self.assertEqual(str(policy["msDS-UserTGTLifetime"]), str(mins_to_tgt_lifetime(120)))
656 # check lower bounds (45)
657 result, out, err = self.runcmd("domain", "auth", "policy", "modify",
658 "--name", name + "Lower",
659 "--user-tgt-lifetime-mins", "44")
660 self.assertEqual(result, -1)
661 self.assertIn("--user-tgt-lifetime-mins must be between 45 and 2147483647",
662 err)
664 # check upper bounds (2147483647)
665 result, out, err = self.runcmd("domain", "auth", "policy", "modify",
666 "--name", name + "Upper",
667 "--user-tgt-lifetime-mins", "2147483648")
668 self.assertEqual(result, -1)
669 self.assertIn("--user-tgt-lifetime-mins must be between 45 and 2147483647",
670 err)
672 def test_modify__service_tgt_lifetime_mins(self):
673 """Test modifying an authentication policy --service-tgt-lifetime-mins.
675 This includes checking the upper and lower bounds.
677 name = self.unique_name()
679 # Create a policy to modify for this test.
680 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
681 self.runcmd("domain", "auth", "policy", "create", "--name", name)
683 result, out, err = self.runcmd("domain", "auth", "policy", "modify",
684 "--name", name,
685 "--service-tgt-lifetime-mins", "120")
686 self.assertIsNone(result, msg=err)
688 # Verify field was changed.
689 policy = self.get_authentication_policy(name)
690 self.assertEqual(str(policy["msDS-ServiceTGTLifetime"]), str(mins_to_tgt_lifetime(120)))
692 # check lower bounds (45)
693 result, out, err = self.runcmd("domain", "auth", "policy", "modify",
694 "--name", name + "Lower",
695 "--service-tgt-lifetime-mins", "44")
696 self.assertEqual(result, -1)
697 self.assertIn("--service-tgt-lifetime-mins must be between 45 and 2147483647",
698 err)
700 # check upper bounds (2147483647)
701 result, out, err = self.runcmd("domain", "auth", "policy", "modify",
702 "--name", name + "Upper",
703 "--service-tgt-lifetime-mins", "2147483648")
704 self.assertEqual(result, -1)
705 self.assertIn("--service-tgt-lifetime-mins must be between 45 and 2147483647",
706 err)
708 def test_modify__computer_tgt_lifetime_mins(self):
709 """Test modifying an authentication policy --computer-tgt-lifetime-mins.
711 This includes checking the upper and lower bounds.
713 name = self.unique_name()
715 # Create a policy to modify for this test.
716 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
717 self.runcmd("domain", "auth", "policy", "create", "--name", name)
719 result, out, err = self.runcmd("domain", "auth", "policy", "modify",
720 "--name", name,
721 "--computer-tgt-lifetime-mins", "120")
722 self.assertIsNone(result, msg=err)
724 # Verify field was changed.
725 policy = self.get_authentication_policy(name)
726 self.assertEqual(str(policy["msDS-ComputerTGTLifetime"]), str(mins_to_tgt_lifetime(120)))
728 # check lower bounds (45)
729 result, out, err = self.runcmd("domain", "auth", "policy", "modify",
730 "--name", name + "Lower",
731 "--computer-tgt-lifetime-mins", "44")
732 self.assertEqual(result, -1)
733 self.assertIn("--computer-tgt-lifetime-mins must be between 45 and 2147483647",
734 err)
736 # check upper bounds (2147483647)
737 result, out, err = self.runcmd("domain", "auth", "policy", "modify",
738 "--name", name + "Upper",
739 "--computer-tgt-lifetime-mins", "2147483648")
740 self.assertEqual(result, -1)
741 self.assertIn("--computer-tgt-lifetime-mins must be between 45 and 2147483647",
742 err)
744 def test_modify__user_allowed_to_authenticate_from(self):
745 """Modify authentication policy user allowed to authenticate from."""
746 name = self.unique_name()
747 expected = "O:SYG:SYD:(XA;OICI;CR;;;WD;(Member_of {SID(AO)}))"
749 # Create a policy to modify for this test.
750 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
751 self.runcmd("domain", "auth", "policy", "create", "--name", name)
753 # Modify user allowed to authenticate from field
754 result, out, err = self.runcmd("domain", "auth", "policy", "modify",
755 "--name", name,
756 "--user-allowed-to-authenticate-from",
757 expected)
758 self.assertIsNone(result, msg=err)
760 # Check user allowed to authenticate from field was modified.
761 policy = self.get_authentication_policy(name)
762 self.assertEqual(str(policy["cn"]), name)
763 desc = policy["msDS-UserAllowedToAuthenticateFrom"][0]
764 sddl = ndr_unpack(security.descriptor, desc).as_sddl()
765 self.assertEqual(sddl, expected)
767 def test_user_allowed_to_authenticate_from__set_device_group(self):
768 """Tests the user-allowed-to-authenticate-from set --device-group shortcut."""
769 name = self.unique_name()
770 expected = "O:SYG:SYD:(XA;OICI;CR;;;WD;(Member_of_any {SID(%s)}))" % (
771 self.device_group.object_sid)
773 # Create a policy to modify for this test.
774 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
775 self.runcmd("domain", "auth", "policy", "create", "--name", name)
777 # Modify user allowed to authenticate from silo field
778 result, out, err = self.runcmd("domain", "auth", "policy",
779 "user-allowed-to-authenticate-from",
780 "set", "--name", name,
781 "--device-group", self.device_group.name)
782 self.assertIsNone(result, msg=err)
784 # Check generated SDDL.
785 policy = self.get_authentication_policy(name)
786 desc = policy["msDS-UserAllowedToAuthenticateFrom"][0]
787 sddl = ndr_unpack(security.descriptor, desc).as_sddl()
788 self.assertEqual(sddl, expected)
790 def test_user_allowed_to_authenticate_from__set_device_silo(self):
791 """Tests the user-allowed-to-authenticate-from set --device-silo shortcut."""
792 name = self.unique_name()
794 # Create a policy to modify for this test.
795 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
796 self.runcmd("domain", "auth", "policy", "create", "--name", name)
798 # Modify user allowed to authenticate from silo field
799 result, out, err = self.runcmd("domain", "auth", "policy",
800 "user-allowed-to-authenticate-from",
801 "set", "--name", name,
802 "--device-silo", "QA")
803 self.assertIsNone(result, msg=err)
805 # Check generated SDDL.
806 policy = self.get_authentication_policy(name)
807 desc = policy["msDS-UserAllowedToAuthenticateFrom"][0]
808 sddl = ndr_unpack(security.descriptor, desc).as_sddl()
809 self.assertEqual(
810 sddl,
811 'O:SYG:SYD:(XA;OICI;CR;;;WD;(@USER.ad://ext/AuthenticationSilo == "QA"))')
813 def test_modify__user_allowed_to_authenticate_to(self):
814 """Modify authentication policy user allowed to authenticate to."""
815 name = self.unique_name()
816 expected = "O:SYG:SYD:(XA;OICI;CR;;;WD;(Member_of {SID(AO)}))"
818 # Create a policy to modify for this test.
819 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
820 self.runcmd("domain", "auth", "policy", "create", "--name", name)
822 # Modify user allowed to authenticate to field
823 result, out, err = self.runcmd("domain", "auth", "policy", "modify",
824 "--name", name,
825 "--user-allowed-to-authenticate-to",
826 expected)
827 self.assertIsNone(result, msg=err)
829 # Check user allowed to authenticate to field was modified.
830 policy = self.get_authentication_policy(name)
831 self.assertEqual(str(policy["cn"]), name)
832 desc = policy["msDS-UserAllowedToAuthenticateTo"][0]
833 sddl = ndr_unpack(security.descriptor, desc).as_sddl()
834 self.assertEqual(sddl, expected)
836 def test_user_allowed_to_authenticate_to__set_by_group(self):
837 """Tests the user-allowed-to-authenticate-to set --by-group shortcut."""
838 name = self.unique_name()
839 expected = "O:SYG:SYD:(XA;OICI;CR;;;WD;(Member_of_any {SID(%s)}))" % (
840 self.device_group.object_sid)
842 # Create a policy to modify for this test.
843 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
844 self.runcmd("domain", "auth", "policy", "create", "--name", name)
846 # Modify user allowed to authenticate to field
847 result, out, err = self.runcmd("domain", "auth", "policy",
848 "user-allowed-to-authenticate-to",
849 "set", "--name", name,
850 "--by-group", self.device_group.name)
851 self.assertIsNone(result, msg=err)
853 # Check user allowed to authenticate to field was modified.
854 policy = self.get_authentication_policy(name)
855 self.assertEqual(str(policy["cn"]), name)
856 desc = policy["msDS-UserAllowedToAuthenticateTo"][0]
857 sddl = ndr_unpack(security.descriptor, desc).as_sddl()
858 self.assertEqual(sddl, expected)
860 def test_user_allowed_to_authenticate_to__set_by_silo(self):
861 """Tests the user-allowed-to-authenticate-to set --by-silo shortcut."""
862 name = self.unique_name()
863 expected = ('O:SYG:SYD:(XA;OICI;CR;;;WD;(@USER.ad://ext/'
864 'AuthenticationSilo == "Developers"))')
866 # Create a policy to modify for this test.
867 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
868 self.runcmd("domain", "auth", "policy", "create", "--name", name)
870 # Modify user allowed to authenticate to field
871 result, out, err = self.runcmd("domain", "auth", "policy",
872 "user-allowed-to-authenticate-to",
873 "set", "--name", name,
874 "--by-silo", "Developers")
875 self.assertIsNone(result, msg=err)
877 # Check user allowed to authenticate to field was modified.
878 policy = self.get_authentication_policy(name)
879 self.assertEqual(str(policy["cn"]), name)
880 desc = policy["msDS-UserAllowedToAuthenticateTo"][0]
881 sddl = ndr_unpack(security.descriptor, desc).as_sddl()
882 self.assertEqual(sddl, expected)
884 def test_modify__service_allowed_to_authenticate_from(self):
885 """Modify authentication policy service allowed to authenticate from."""
886 name = self.unique_name()
887 expected = "O:SYG:SYD:(XA;OICI;CR;;;WD;(Member_of {SID(AO)}))"
889 # Create a policy to modify for this test.
890 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
891 self.runcmd("domain", "auth", "policy", "create", "--name", name)
893 # Modify service allowed to authenticate from field
894 result, out, err = self.runcmd("domain", "auth", "policy", "modify",
895 "--name", name,
896 "--service-allowed-to-authenticate-from",
897 expected)
898 self.assertIsNone(result, msg=err)
900 # Check service allowed to authenticate from field was modified.
901 policy = self.get_authentication_policy(name)
902 self.assertEqual(str(policy["cn"]), name)
903 desc = policy["msDS-ServiceAllowedToAuthenticateFrom"][0]
904 sddl = ndr_unpack(security.descriptor, desc).as_sddl()
905 self.assertEqual(sddl, expected)
907 def test_service_allowed_to_authenticate_from__set_device_group(self):
908 """Tests the service-allowed-to-authenticate-from set --device-group shortcut."""
909 name = self.unique_name()
910 expected = "O:SYG:SYD:(XA;OICI;CR;;;WD;(Member_of_any {SID(%s)}))" % (
911 self.device_group.object_sid)
913 # Create a policy to modify for this test.
914 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
915 self.runcmd("domain", "auth", "policy", "create", "--name", name)
917 # Modify user allowed to authenticate from silo field
918 result, out, err = self.runcmd("domain", "auth", "policy",
919 "service-allowed-to-authenticate-from",
920 "set", "--name", name,
921 "--device-group", self.device_group.name)
922 self.assertIsNone(result, msg=err)
924 # Check generated SDDL.
925 policy = self.get_authentication_policy(name)
926 desc = policy["msDS-ServiceAllowedToAuthenticateFrom"][0]
927 sddl = ndr_unpack(security.descriptor, desc).as_sddl()
928 self.assertEqual(sddl, expected)
930 def test_service_allowed_to_authenticate_from__set_device_silo(self):
931 """Tests the service-allowed-to-authenticate-from set --device-silo shortcut."""
932 name = self.unique_name()
934 # Create a policy to modify for this test.
935 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
936 self.runcmd("domain", "auth", "policy", "create", "--name", name)
938 # Modify user allowed to authenticate from silo field
939 result, out, err = self.runcmd("domain", "auth", "policy",
940 "service-allowed-to-authenticate-from",
941 "set", "--name", name,
942 "--device-silo", "Developers")
943 self.assertIsNone(result, msg=err)
945 # Check generated SDDL.
946 policy = self.get_authentication_policy(name)
947 desc = policy["msDS-ServiceAllowedToAuthenticateFrom"][0]
948 sddl = ndr_unpack(security.descriptor, desc).as_sddl()
949 self.assertEqual(
950 sddl,
951 'O:SYG:SYD:(XA;OICI;CR;;;WD;(@USER.ad://ext/AuthenticationSilo == "Developers"))')
953 def test_modify__service_allowed_to_authenticate_to(self):
954 """Modify authentication policy service allowed to authenticate to."""
955 name = self.unique_name()
956 expected = "O:SYG:SYD:(XA;OICI;CR;;;WD;(Member_of {SID(AO)}))"
958 # Create a policy to modify for this test.
959 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
960 self.runcmd("domain", "auth", "policy", "create", "--name", name)
962 # Modify service allowed to authenticate to field
963 result, out, err = self.runcmd("domain", "auth", "policy", "modify",
964 "--name", name,
965 "--service-allowed-to-authenticate-to",
966 expected)
967 self.assertIsNone(result, msg=err)
969 # Check service allowed to authenticate to field was modified.
970 policy = self.get_authentication_policy(name)
971 self.assertEqual(str(policy["cn"]), name)
972 desc = policy["msDS-ServiceAllowedToAuthenticateTo"][0]
973 sddl = ndr_unpack(security.descriptor, desc).as_sddl()
974 self.assertEqual(sddl, expected)
976 def test_service_allowed_to_authenticate_to__set_by_group(self):
977 """Tests the service-allowed-to-authenticate-to set --by-group shortcut."""
978 name = self.unique_name()
979 expected = "O:SYG:SYD:(XA;OICI;CR;;;WD;(Member_of_any {SID(%s)}))" % (
980 self.device_group.object_sid)
982 # Create a policy to modify for this test.
983 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
984 self.runcmd("domain", "auth", "policy", "create", "--name", name)
986 # Modify user allowed to authenticate to field
987 result, out, err = self.runcmd("domain", "auth", "policy",
988 "service-allowed-to-authenticate-to",
989 "set", "--name", name,
990 "--by-group", self.device_group.name)
991 self.assertIsNone(result, msg=err)
993 # Check user allowed to authenticate to field was modified.
994 policy = self.get_authentication_policy(name)
995 self.assertEqual(str(policy["cn"]), name)
996 desc = policy["msDS-ServiceAllowedToAuthenticateTo"][0]
997 sddl = ndr_unpack(security.descriptor, desc).as_sddl()
998 self.assertEqual(sddl, expected)
1000 def test_service_allowed_to_authenticate_to__set_by_silo(self):
1001 """Tests the service-allowed-to-authenticate-to set --by-silo shortcut."""
1002 name = self.unique_name()
1003 expected = ('O:SYG:SYD:(XA;OICI;CR;;;WD;(@USER.ad://ext/'
1004 'AuthenticationSilo == "QA"))')
1006 # Create a policy to modify for this test.
1007 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
1008 self.runcmd("domain", "auth", "policy", "create", "--name", name)
1010 # Modify user allowed to authenticate to field
1011 result, out, err = self.runcmd("domain", "auth", "policy",
1012 "service-allowed-to-authenticate-to",
1013 "set", "--name", name,
1014 "--by-silo", "QA")
1015 self.assertIsNone(result, msg=err)
1017 # Check user allowed to authenticate to field was modified.
1018 policy = self.get_authentication_policy(name)
1019 self.assertEqual(str(policy["cn"]), name)
1020 desc = policy["msDS-ServiceAllowedToAuthenticateTo"][0]
1021 sddl = ndr_unpack(security.descriptor, desc).as_sddl()
1022 self.assertEqual(sddl, expected)
1024 def test_modify__computer_allowed_to_authenticate_to(self):
1025 """Modify authentication policy computer allowed to authenticate to."""
1026 name = self.unique_name()
1027 expected = "O:SYG:SYD:(XA;OICI;CR;;;WD;(Member_of {SID(AO)}))"
1029 # Create a policy to modify for this test.
1030 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
1031 self.runcmd("domain", "auth", "policy", "create", "--name", name)
1033 # Modify computer allowed to authenticate to field
1034 result, out, err = self.runcmd("domain", "auth", "policy", "modify",
1035 "--name", name,
1036 "--computer-allowed-to-authenticate-to",
1037 expected)
1038 self.assertIsNone(result, msg=err)
1040 # Check computer allowed to authenticate to field was modified.
1041 policy = self.get_authentication_policy(name)
1042 self.assertEqual(str(policy["cn"]), name)
1043 desc = policy["msDS-ComputerAllowedToAuthenticateTo"][0]
1044 sddl = ndr_unpack(security.descriptor, desc).as_sddl()
1045 self.assertEqual(sddl, expected)
1047 def test_computer_allowed_to_authenticate_to__set_by_group(self):
1048 """Tests the computer-allowed-to-authenticate-to set --by-group shortcut."""
1049 name = self.unique_name()
1050 expected = "O:SYG:SYD:(XA;OICI;CR;;;WD;(Member_of_any {SID(%s)}))" % (
1051 self.device_group.object_sid)
1053 # Create a policy to modify for this test.
1054 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
1055 self.runcmd("domain", "auth", "policy", "create", "--name", name)
1057 # Modify user allowed to authenticate to field
1058 result, out, err = self.runcmd("domain", "auth", "policy",
1059 "computer-allowed-to-authenticate-to",
1060 "set", "--name", name, "--by-group",
1061 self.device_group.name)
1062 self.assertIsNone(result, msg=err)
1064 # Check user allowed to authenticate to field was modified.
1065 policy = self.get_authentication_policy(name)
1066 self.assertEqual(str(policy["cn"]), name)
1067 desc = policy["msDS-ComputerAllowedToAuthenticateTo"][0]
1068 sddl = ndr_unpack(security.descriptor, desc).as_sddl()
1069 self.assertEqual(sddl, expected)
1071 def test_computer_allowed_to_authenticate_to__set_by_silo(self):
1072 """Tests the computer-allowed-to-authenticate-to set --by-silo shortcut."""
1073 name = self.unique_name()
1074 expected = ('O:SYG:SYD:(XA;OICI;CR;;;WD;(@USER.ad://ext/'
1075 'AuthenticationSilo == "QA"))')
1077 # Create a policy to modify for this test.
1078 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
1079 self.runcmd("domain", "auth", "policy", "create", "--name", name)
1081 # Modify user allowed to authenticate to field
1082 result, out, err = self.runcmd("domain", "auth", "policy",
1083 "computer-allowed-to-authenticate-to",
1084 "set", "--name", name, "--by-silo",
1085 "QA")
1086 self.assertIsNone(result, msg=err)
1088 # Check user allowed to authenticate to field was modified.
1089 policy = self.get_authentication_policy(name)
1090 self.assertEqual(str(policy["cn"]), name)
1091 desc = policy["msDS-ComputerAllowedToAuthenticateTo"][0]
1092 sddl = ndr_unpack(security.descriptor, desc).as_sddl()
1093 self.assertEqual(sddl, expected)
1095 def test_modify__name_missing(self):
1096 """Test modify authentication but the --name argument is missing."""
1097 result, out, err = self.runcmd("domain", "auth", "policy", "modify",
1098 "--description", "NewDescription")
1099 self.assertEqual(result, -1)
1100 self.assertIn("Argument --name is required.", err)
1102 def test_modify__notfound(self):
1103 """Test modify an authentication silo that doesn't exist."""
1104 result, out, err = self.runcmd("domain", "auth", "policy", "modify",
1105 "--name", "doesNotExist",
1106 "--description", "NewDescription")
1107 self.assertEqual(result, -1)
1108 self.assertIn("Authentication policy doesNotExist not found.", err)
1110 def test_modify__audit_enforce(self):
1111 """Test modify authentication policy using --audit and --enforce."""
1112 name = self.unique_name()
1114 # Create a policy to modify for this test.
1115 self.addCleanup(self.delete_authentication_policy,
1116 name=name, force=True)
1117 self.runcmd("domain", "auth", "policy", "create", "--name", name)
1119 # Change to audit, the default is --enforce.
1120 result, out, err = self.runcmd("domain", "auth", "policy", "modify",
1121 "--name", name,
1122 "--audit")
1123 self.assertIsNone(result, msg=err)
1125 # Check that the policy was changed to --audit.
1126 policy = self.get_authentication_policy(name)
1127 self.assertEqual(str(policy["msDS-AuthNPolicyEnforced"]), "FALSE")
1129 result, out, err = self.runcmd("domain", "auth", "policy", "modify",
1130 "--name", name,
1131 "--enforce")
1132 self.assertIsNone(result, msg=err)
1134 # Check if the policy was changed back to --enforce.
1135 policy = self.get_authentication_policy(name)
1136 self.assertEqual(str(policy["msDS-AuthNPolicyEnforced"]), "TRUE")
1138 def test_modify__protect_unprotect(self):
1139 """Test modify authentication policy using --protect and --unprotect."""
1140 name = self.unique_name()
1142 # Create a policy to modify for this test.
1143 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
1144 self.runcmd("domain", "auth", "policy", "create", "--name", name)
1146 utils = SDUtils(self.samdb)
1147 result, out, err = self.runcmd("domain", "auth", "policy", "modify",
1148 "--name", name,
1149 "--protect")
1150 self.assertIsNone(result, msg=err)
1152 # Check that claim type was protected.
1153 policy = self.get_authentication_policy(name)
1154 desc = utils.get_sd_as_sddl(policy["dn"])
1155 self.assertIn("(D;;DTSD;;;WD)", desc)
1157 result, out, err = self.runcmd("domain", "auth", "policy", "modify",
1158 "--name", name,
1159 "--unprotect")
1160 self.assertIsNone(result, msg=err)
1162 # Check that claim type was unprotected.
1163 policy = self.get_authentication_policy(name)
1164 desc = utils.get_sd_as_sddl(policy["dn"])
1165 self.assertNotIn("(D;;DTSD;;;WD)", desc)
1167 def test_modify__audit_enforce_together(self):
1168 """Test modify auth policy using both --audit and --enforce."""
1169 result, out, err = self.runcmd("domain", "auth", "policy", "modify",
1170 "--name", "User Policy",
1171 "--audit", "--enforce")
1172 self.assertEqual(result, -1)
1173 self.assertIn("--audit and --enforce cannot be used together.", err)
1175 def test_modify__protect_unprotect_together(self):
1176 """Test modify authentication policy using --protect and --unprotect."""
1177 result, out, err = self.runcmd("domain", "auth", "policy", "modify",
1178 "--name", "User Policy",
1179 "--protect", "--unprotect")
1180 self.assertEqual(result, -1)
1181 self.assertIn("--protect and --unprotect cannot be used together.", err)
1183 def test_modify__fails(self):
1184 """Test modifying an authentication policy, but it fails."""
1185 # Raise ModelError when ldb.add() is called.
1186 with patch.object(SamDB, "modify") as modify_mock:
1187 modify_mock.side_effect = ModelError("Custom error message")
1188 result, out, err = self.runcmd("domain", "auth", "policy", "modify",
1189 "--name", "User Policy",
1190 "--description", "New description")
1191 self.assertEqual(result, -1)
1192 self.assertIn("Custom error message", err)
1194 def test_delete__success(self):
1195 """Test deleting an authentication policy that is not protected."""
1196 # Create non-protected authentication policy.
1197 result, out, err = self.runcmd("domain", "auth", "policy", "create",
1198 "--name=deleteTest")
1199 self.assertIsNone(result, msg=err)
1200 policy = self.get_authentication_policy("deleteTest")
1201 self.assertIsNotNone(policy)
1203 # Do the deletion.
1204 result, out, err = self.runcmd("domain", "auth", "policy", "delete",
1205 "--name", "deleteTest")
1206 self.assertIsNone(result, msg=err)
1208 # Authentication policy shouldn't exist anymore.
1209 policy = self.get_authentication_policy("deleteTest")
1210 self.assertIsNone(policy)
1212 def test_delete__protected(self):
1213 """Test deleting a protected auth policy, with and without --force."""
1214 # Create protected authentication policy.
1215 result, out, err = self.runcmd("domain", "auth", "policy", "create",
1216 "--name=deleteProtected",
1217 "--protect")
1218 self.assertIsNone(result, msg=err)
1219 policy = self.get_authentication_policy("deleteProtected")
1220 self.assertIsNotNone(policy)
1222 # Do the deletion.
1223 result, out, err = self.runcmd("domain", "auth", "policy", "delete",
1224 "--name=deleteProtected")
1225 self.assertEqual(result, -1)
1227 # Authentication silo should still exist.
1228 policy = self.get_authentication_policy("deleteProtected")
1229 self.assertIsNotNone(policy)
1231 # Try a force delete instead.
1232 result, out, err = self.runcmd("domain", "auth", "policy", "delete",
1233 "--name=deleteProtected", "--force")
1234 self.assertIsNone(result, msg=err)
1236 # Authentication silo shouldn't exist anymore.
1237 policy = self.get_authentication_policy("deleteProtected")
1238 self.assertIsNone(policy)
1240 def test_delete__notfound(self):
1241 """Test deleting an authentication policy that doesn't exist."""
1242 result, out, err = self.runcmd("domain", "auth", "policy", "delete",
1243 "--name", "doesNotExist")
1244 self.assertEqual(result, -1)
1245 self.assertIn("Authentication policy doesNotExist not found.", err)
1247 def test_delete__name_required(self):
1248 """Test deleting an authentication policy without --name argument."""
1249 result, out, err = self.runcmd("domain", "auth", "policy", "delete")
1250 self.assertEqual(result, -1)
1251 self.assertIn("Argument --name is required.", err)
1253 def test_delete__force_fails(self):
1254 """Test deleting an authentication policy with --force, but it fails."""
1255 name = self.unique_name()
1257 # Create protected authentication policy.
1258 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
1259 result, out, err = self.runcmd("domain", "auth", "policy", "create",
1260 "--name", name,
1261 "--protect")
1262 self.assertIsNone(result, msg=err)
1264 # Policy exists
1265 policy = self.get_authentication_policy(name)
1266 self.assertIsNotNone(policy)
1268 # Try doing delete with --force.
1269 # Patch SDUtils.dacl_delete_aces with a Mock that raises ModelError.
1270 with patch.object(SDUtils, "dacl_delete_aces") as delete_mock:
1271 delete_mock.side_effect = ModelError("Custom error message")
1272 result, out, err = self.runcmd("domain", "auth", "policy", "delete",
1273 "--name", name,
1274 "--force")
1275 self.assertEqual(result, -1)
1276 self.assertIn("Custom error message", err)
1278 def test_delete__fails(self):
1279 """Test deleting an authentication policy, but it fails."""
1280 name = self.unique_name()
1282 # Create regular authentication policy.
1283 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
1284 result, out, err = self.runcmd("domain", "auth", "policy", "create",
1285 "--name", name)
1286 self.assertIsNone(result, msg=err)
1288 # Policy exists
1289 policy = self.get_authentication_policy(name)
1290 self.assertIsNotNone(policy)
1292 # Raise ModelError when ldb.delete() is called.
1293 with patch.object(SamDB, "delete") as delete_mock:
1294 delete_mock.side_effect = ModelError("Custom error message")
1295 result, out, err = self.runcmd("domain", "auth", "policy", "delete",
1296 "--name", name)
1297 self.assertEqual(result, -1)
1298 self.assertIn("Custom error message", err)
1300 # When not using --force we get a hint.
1301 self.assertIn("Try --force", err)
1303 def test_delete__protected_fails(self):
1304 """Test deleting an authentication policy, but it fails."""
1305 name = self.unique_name()
1307 # Create protected authentication policy.
1308 self.addCleanup(self.delete_authentication_policy, name=name, force=True)
1309 result, out, err = self.runcmd("domain", "auth", "policy", "create",
1310 "--name", name,
1311 "--protect")
1312 self.assertIsNone(result, msg=err)
1314 # Policy exists
1315 policy = self.get_authentication_policy(name)
1316 self.assertIsNotNone(policy)
1318 # Raise ModelError when ldb.delete() is called.
1319 with patch.object(SamDB, "delete") as delete_mock:
1320 delete_mock.side_effect = ModelError("Custom error message")
1321 result, out, err = self.runcmd("domain", "auth", "policy", "delete",
1322 "--name", name,
1323 "--force")
1324 self.assertEqual(result, -1)
1325 self.assertIn("Custom error message", err)
1327 # When using --force we don't get the hint.
1328 self.assertNotIn("Try --force", err)