ad5d2437e056894c73e813adbff800272b54a538
[dmulder/samba-autobuild/.git] / python / samba / tests / samba_tool / domain_auth_policy.py
1 # Unix SMB/CIFS implementation.
2 #
3 # Tests for samba-tool domain auth policy command
4 #
5 # Copyright (C) Catalyst.Net Ltd. 2023
6 #
7 # Written by Rob van der Linde <rob@catalyst.net.nz>
8 #
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.
13 #
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.
18 #
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/>.
21 #
22
23 import json
24 from optparse import OptionValueError
25 from unittest.mock import patch
26
27 from samba.dcerpc import security
28 from samba.ndr import ndr_unpack
29 from samba.netcmd.domain.models.exceptions import ModelError
30 from samba.samdb import SamDB
31 from samba.sd_utils import SDUtils
32
33 from .domain_auth_base import BaseAuthCmdTest
34
35
36 class AuthPolicyCmdTestCase(BaseAuthCmdTest):
37
38     def test_list(self):
39         """Test listing authentication policies in list format."""
40         result, out, err = self.runcmd("domain", "auth", "policy", "list")
41         self.assertIsNone(result, msg=err)
42
43         expected_policies = ["User Policy", "Service Policy", "Computer Policy"]
44
45         for policy in expected_policies:
46             self.assertIn(policy, out)
47
48     def test_list__json(self):
49         """Test listing authentication policies in JSON format."""
50         result, out, err = self.runcmd("domain", "auth", "policy",
51                                        "list", "--json")
52         self.assertIsNone(result, msg=err)
53
54         # we should get valid json
55         policies = json.loads(out)
56
57         expected_policies = ["User Policy", "Service Policy", "Computer Policy"]
58
59         for name in expected_policies:
60             policy = policies[name]
61             self.assertIn("name", policy)
62             self.assertIn("msDS-AuthNPolicy", list(policy["objectClass"]))
63             self.assertIn("msDS-AuthNPolicyEnforced", policy)
64             self.assertIn("msDS-StrongNTLMPolicy", policy)
65             self.assertIn("objectGUID", policy)
66
67     def test_view(self):
68         """Test viewing a single authentication policy."""
69         result, out, err = self.runcmd("domain", "auth", "policy", "view",
70                                        "--name", "User Policy")
71         self.assertIsNone(result, msg=err)
72
73         # we should get valid json
74         policy = json.loads(out)
75
76         # check a few fields only
77         self.assertEqual(policy["cn"], "User Policy")
78         self.assertEqual(policy["msDS-AuthNPolicyEnforced"], True)
79
80     def test_view__notfound(self):
81         """Test viewing an authentication policy that doesn't exist."""
82         result, out, err = self.runcmd("domain", "auth", "policy", "view",
83                                        "--name", "doesNotExist")
84         self.assertEqual(result, -1)
85         self.assertIn("Authentication policy doesNotExist not found.", err)
86
87     def test_view__name_required(self):
88         """Test view authentication policy without --name argument."""
89         result, out, err = self.runcmd("domain", "auth", "policy", "view")
90         self.assertEqual(result, -1)
91         self.assertIn("Argument --name is required.", err)
92
93     def test_create__success(self):
94         """Test creating a new authentication policy."""
95         self.addCleanup(self.delete_authentication_policy,
96                         name="createTest", force=True)
97
98         result, out, err = self.runcmd("domain", "auth", "policy", "create",
99                                        "--name", "createTest")
100         self.assertIsNone(result, msg=err)
101
102         # Check policy that was created
103         policy = self.get_authentication_policy("createTest")
104         self.assertEqual(str(policy["cn"]), "createTest")
105         self.assertEqual(str(policy["msDS-AuthNPolicyEnforced"]), "TRUE")
106
107     def test_create__description(self):
108         """Test creating a new authentication policy with description set."""
109         self.addCleanup(self.delete_authentication_policy,
110                         name="descriptionTest", force=True)
111
112         result, out, err = self.runcmd("domain", "auth", "policy", "create",
113                                        "--name", "descriptionTest",
114                                        "--description", "Custom Description")
115         self.assertIsNone(result, msg=err)
116
117         # Check policy description
118         policy = self.get_authentication_policy("descriptionTest")
119         self.assertEqual(str(policy["cn"]), "descriptionTest")
120         self.assertEqual(str(policy["description"]), "Custom Description")
121
122     def test_create__user_tgt_lifetime_mins(self):
123         """Test create a new authentication policy with --user-tgt-lifetime-mins.
124
125         Also checks the upper and lower bounds are handled.
126         """
127         self.addCleanup(self.delete_authentication_policy,
128                         name="userTGTLifetime", force=True)
129
130         result, out, err = self.runcmd("domain", "auth", "policy", "create",
131                                        "--name", "userTGTLifetime",
132                                        "--user-tgt-lifetime-mins", "60")
133         self.assertIsNone(result, msg=err)
134
135         # Check policy fields.
136         policy = self.get_authentication_policy("userTGTLifetime")
137         self.assertEqual(str(policy["cn"]), "userTGTLifetime")
138         self.assertEqual(str(policy["msDS-UserTGTLifetime"]), "60")
139
140         # check lower bounds (45)
141         result, out, err = self.runcmd("domain", "auth", "policy", "create",
142                                        "--name", "userTGTLifetimeLower",
143                                        "--user-tgt-lifetime-mins", "44")
144         self.assertEqual(result, -1)
145         self.assertIn("--user-tgt-lifetime-mins must be between 45 and 2147483647",
146                       err)
147
148         # check upper bounds (2147483647)
149         result, out, err = self.runcmd("domain", "auth", "policy", "create",
150                                        "--name", "userTGTLifetimeUpper",
151                                        "--user-tgt-lifetime-mins", "2147483648")
152         self.assertEqual(result, -1)
153         self.assertIn("--user-tgt-lifetime-mins must be between 45 and 2147483647",
154                       err)
155
156     def test_create__service_tgt_lifetime_mins(self):
157         """Test create a new authentication policy with --service-tgt-lifetime-mins.
158
159         Also checks the upper and lower bounds are handled.
160         """
161         self.addCleanup(self.delete_authentication_policy,
162                         name="serviceTGTLifetime", force=True)
163
164         result, out, err = self.runcmd("domain", "auth", "policy", "create",
165                                        "--name", "serviceTGTLifetime",
166                                        "--service-tgt-lifetime-mins", "60")
167         self.assertIsNone(result, msg=err)
168
169         # Check policy fields.
170         policy = self.get_authentication_policy("serviceTGTLifetime")
171         self.assertEqual(str(policy["cn"]), "serviceTGTLifetime")
172         self.assertEqual(str(policy["msDS-ServiceTGTLifetime"]), "60")
173
174         # check lower bounds (45)
175         result, out, err = self.runcmd("domain", "auth", "policy", "create",
176                                        "--name", "serviceTGTLifetimeLower",
177                                        "--service-tgt-lifetime-mins", "44")
178         self.assertEqual(result, -1)
179         self.assertIn("--service-tgt-lifetime-mins must be between 45 and 2147483647",
180                       err)
181
182         # check upper bounds (2147483647)
183         result, out, err = self.runcmd("domain", "auth", "policy", "create",
184                                        "--name", "serviceTGTLifetimeUpper",
185                                        "--service-tgt-lifetime-mins", "2147483648")
186         self.assertEqual(result, -1)
187         self.assertIn("--service-tgt-lifetime-mins must be between 45 and 2147483647",
188                       err)
189
190     def test_create__computer_tgt_lifetime_mins(self):
191         """Test create a new authentication policy with --computer-tgt-lifetime-mins.
192
193         Also checks the upper and lower bounds are handled.
194         """
195         self.addCleanup(self.delete_authentication_policy,
196                         name="computerTGTLifetime", force=True)
197
198         result, out, err = self.runcmd("domain", "auth", "policy", "create",
199                                        "--name", "computerTGTLifetime",
200                                        "--computer-tgt-lifetime-mins", "60")
201         self.assertIsNone(result, msg=err)
202
203         # Check policy fields.
204         policy = self.get_authentication_policy("computerTGTLifetime")
205         self.assertEqual(str(policy["cn"]), "computerTGTLifetime")
206         self.assertEqual(str(policy["msDS-ComputerTGTLifetime"]), "60")
207
208         # check lower bounds (45)
209         result, out, err = self.runcmd("domain", "auth", "policy", "create",
210                                        "--name", "computerTGTLifetimeLower",
211                                        "--computer-tgt-lifetime-mins", "44")
212         self.assertEqual(result, -1)
213         self.assertIn("--computer-tgt-lifetime-mins must be between 45 and 2147483647",
214                       err)
215
216         # check upper bounds (2147483647)
217         result, out, err = self.runcmd("domain", "auth", "policy", "create",
218                                        "--name", "computerTGTLifetimeUpper",
219                                        "--computer-tgt-lifetime-mins", "2147483648")
220         self.assertEqual(result, -1)
221         self.assertIn("--computer-tgt-lifetime-mins must be between 45 and 2147483647",
222                       err)
223
224     def test_create__valid_sddl(self):
225         """Test creating a new authentication policy with valid SDDL in a field."""
226         expected = "O:SYG:SYD:(XA;OICI;CR;;;WD;(Member_of {SID(AO)}))"
227
228         self.addCleanup(self.delete_authentication_policy,
229                         name="validSDDLPolicy", force=True)
230
231         result, out, err = self.runcmd("domain", "auth", "policy", "create",
232                                        "--name", "validSDDLPolicy",
233                                        "--user-allowed-to-authenticate-from",
234                                        expected)
235         self.assertIsNone(result, msg=err)
236
237         # Check policy fields.
238         policy = self.get_authentication_policy("validSDDLPolicy")
239         self.assertEqual(str(policy["cn"]), "validSDDLPolicy")
240         desc = policy["msDS-UserAllowedToAuthenticateFrom"][0]
241         sddl = ndr_unpack(security.descriptor, desc).as_sddl()
242         self.assertEqual(sddl, expected)
243
244     def test_create__invalid_sddl(self):
245         """Test creating a new authentication policy with invalid SDDL in a field."""
246         result, out, err = self.runcmd("domain", "auth", "policy", "create",
247                                        "--name", "invalidSDDLPolicy",
248                                        "--user-allowed-to-authenticate-from",
249                                        "*INVALID SDDL*")
250         self.assertEqual(result, -1)
251         self.assertIn(
252             "msDS-UserAllowedToAuthenticateFrom: Unable to parse SDDL", err)
253
254     def test_create__already_exists(self):
255         """Test creating a new authentication policy that already exists."""
256         result, out, err = self.runcmd("domain", "auth", "policy", "create",
257                                        "--name", "User Policy")
258         self.assertEqual(result, -1)
259         self.assertIn("Authentication policy User Policy already exists", err)
260
261     def test_create__name_missing(self):
262         """Test create authentication policy without --name argument."""
263         result, out, err = self.runcmd("domain", "auth", "policy", "create")
264         self.assertEqual(result, -1)
265         self.assertIn("Argument --name is required.", err)
266
267     def test_create__audit(self):
268         """Test create authentication policy with --audit flag."""
269         result, out, err = self.runcmd("domain", "auth", "policy", "create",
270                                        "--name", "auditPolicy",
271                                        "--audit")
272         self.assertIsNone(result, msg=err)
273
274         # fetch and check policy
275         policy = self.get_authentication_policy("auditPolicy")
276         self.assertEqual(str(policy["msDS-AuthNPolicyEnforced"]), "FALSE")
277
278     def test_create__enforce(self):
279         """Test create authentication policy with --enforce flag."""
280         result, out, err = self.runcmd("domain", "auth", "policy", "create",
281                                        "--name", "enforcePolicy",
282                                        "--enforce")
283         self.assertIsNone(result, msg=err)
284
285         # fetch and check policy
286         policy = self.get_authentication_policy("enforcePolicy")
287         self.assertEqual(str(policy["msDS-AuthNPolicyEnforced"]), "TRUE")
288
289     def test_create__audit_enforce_together(self):
290         """Test create auth policy using both --audit and --enforce."""
291         result, out, err = self.runcmd("domain", "auth", "policy", "create",
292                                        "--name", "enforceTogether",
293                                        "--audit", "--enforce")
294         self.assertEqual(result, -1)
295         self.assertIn("--audit and --enforce cannot be used together.", err)
296
297     def test_create__protect_unprotect_together(self):
298         """Test create authentication policy using --protect and --unprotect."""
299         result, out, err = self.runcmd("domain", "auth", "policy", "create",
300                                        "--name", "protectTogether",
301                                        "--protect", "--unprotect")
302         self.assertEqual(result, -1)
303         self.assertIn("--protect and --unprotect cannot be used together.", err)
304
305     def test_create__fails(self):
306         """Test creating an authentication policy, but it fails."""
307         # Raise ModelError when ldb.add() is called.
308         with patch.object(SamDB, "add") as add_mock:
309             add_mock.side_effect = ModelError("Custom error message")
310             result, out, err = self.runcmd("domain", "auth", "policy", "create",
311                                            "--name", "createFails")
312             self.assertEqual(result, -1)
313             self.assertIn("Custom error message", err)
314
315     def test_modify__description(self):
316         """Test modifying an authentication policy description."""
317         # Create a policy to modify for this test.
318         name = "modifyDescription"
319         self.runcmd("domain", "auth", "policy", "create", "--name", name)
320         self.addCleanup(self.delete_authentication_policy,
321                         name=name, force=True)
322
323         # Change the policy description.
324         result, out, err = self.runcmd("domain", "auth", "policy", "modify",
325                                        "--name", name,
326                                        "--description", "NewDescription")
327         self.assertIsNone(result, msg=err)
328
329         # Verify fields were changed.
330         policy = self.get_authentication_policy(name)
331         self.assertEqual(str(policy["description"]), "NewDescription")
332
333     def test_modify__strong_ntlm_policy(self):
334         """Test modify strong ntlm policy on the authentication policy."""
335         # Create a policy to modify for this test.
336         name = "modifyStrongNTLMPolicy"
337         self.runcmd("domain", "auth", "policy", "create", "--name", name)
338         self.addCleanup(self.delete_authentication_policy,
339                         name=name, force=True)
340
341         result, out, err = self.runcmd("domain", "auth", "policy", "modify",
342                                        "--name", name,
343                                        "--strong-ntlm-policy", "Required")
344         self.assertIsNone(result, msg=err)
345
346         # Verify fields were changed.
347         policy = self.get_authentication_policy(name)
348         self.assertEqual(str(policy["msDS-StrongNTLMPolicy"]), "2")
349
350         # Check an invalid choice.
351         with self.assertRaises((OptionValueError, SystemExit)):
352             self.runcmd("domain", "auth", "policy", "modify",
353                         "--name", name,
354                         "--strong-ntlm-policy", "Invalid")
355
356         # It is difficult to test the error message text for invalid
357         # choices because inside optparse it will raise OptionValueError
358         # followed by raising SystemExit(2).
359
360     def test_modify__user_tgt_lifetime_mins(self):
361         """Test modifying an authentication policy --user-tgt-lifetime-mins.
362
363         This includes checking the upper and lower bounds.
364         """
365         # Create a policy to modify for this test.
366         name = "modifyUserTGTLifetime"
367         self.runcmd("domain", "auth", "policy", "create", "--name", name)
368         self.addCleanup(self.delete_authentication_policy,
369                         name=name, force=True)
370
371         result, out, err = self.runcmd("domain", "auth", "policy", "modify",
372                                        "--name", name,
373                                        "--user-tgt-lifetime-mins", "120")
374         self.assertIsNone(result, msg=err)
375
376         # Verify field was changed.
377         policy = self.get_authentication_policy(name)
378         self.assertEqual(str(policy["msDS-UserTGTLifetime"]), "120")
379
380         # check lower bounds (45)
381         result, out, err = self.runcmd("domain", "auth", "policy", "modify",
382                                        "--name", name,
383                                        "--user-tgt-lifetime-mins", "44")
384         self.assertEqual(result, -1)
385         self.assertIn("--user-tgt-lifetime-mins must be between 45 and 2147483647",
386                       err)
387
388         # check upper bounds (2147483647)
389         result, out, err = self.runcmd("domain", "auth", "policy", "modify",
390                                        "--name", name,
391                                        "--user-tgt-lifetime-mins", "2147483648")
392         self.assertEqual(result, -1)
393         self.assertIn("--user-tgt-lifetime-mins must be between 45 and 2147483647",
394                       err)
395
396     def test_modify__service_tgt_lifetime_mins(self):
397         """Test modifying an authentication policy --service-tgt-lifetime-mins.
398
399         This includes checking the upper and lower bounds.
400         """
401         # Create a policy to modify for this test.
402         name = "modifyServiceTGTLifetime"
403         self.runcmd("domain", "auth", "policy", "create", "--name", name)
404         self.addCleanup(self.delete_authentication_policy,
405                         name=name, force=True)
406
407         result, out, err = self.runcmd("domain", "auth", "policy", "modify",
408                                        "--name", name,
409                                        "--service-tgt-lifetime-mins", "120")
410         self.assertIsNone(result, msg=err)
411
412         # Verify field was changed.
413         policy = self.get_authentication_policy(name)
414         self.assertEqual(str(policy["msDS-ServiceTGTLifetime"]), "120")
415
416         # check lower bounds (45)
417         result, out, err = self.runcmd("domain", "auth", "policy", "modify",
418                                        "--name", name,
419                                        "--service-tgt-lifetime-mins", "44")
420         self.assertEqual(result, -1)
421         self.assertIn("--service-tgt-lifetime-mins must be between 45 and 2147483647",
422                       err)
423
424         # check upper bounds (2147483647)
425         result, out, err = self.runcmd("domain", "auth", "policy", "modify",
426                                        "--name", name,
427                                        "--service-tgt-lifetime-mins", "2147483648")
428         self.assertEqual(result, -1)
429         self.assertIn("--service-tgt-lifetime-mins must be between 45 and 2147483647",
430                       err)
431
432     def test_modify__computer_tgt_lifetime_mins(self):
433         """Test modifying an authentication policy --computer-tgt-lifetime-mins.
434
435         This includes checking the upper and lower bounds.
436         """
437         # Create a policy to modify for this test.
438         name = "modifyComputerTGTLifetime"
439         self.runcmd("domain", "auth", "policy", "create", "--name", name)
440         self.addCleanup(self.delete_authentication_policy,
441                         name=name, force=True)
442
443         result, out, err = self.runcmd("domain", "auth", "policy", "modify",
444                                        "--name", name,
445                                        "--computer-tgt-lifetime-mins", "120")
446         self.assertIsNone(result, msg=err)
447
448         # Verify field was changed.
449         policy = self.get_authentication_policy(name)
450         self.assertEqual(str(policy["msDS-ComputerTGTLifetime"]), "120")
451
452         # check lower bounds (45)
453         result, out, err = self.runcmd("domain", "auth", "policy", "modify",
454                                        "--name", name,
455                                        "--computer-tgt-lifetime-mins", "44")
456         self.assertEqual(result, -1)
457         self.assertIn("--computer-tgt-lifetime-mins must be between 45 and 2147483647",
458                       err)
459
460         # check upper bounds (2147483647)
461         result, out, err = self.runcmd("domain", "auth", "policy", "modify",
462                                        "--name", name,
463                                        "--computer-tgt-lifetime-mins", "2147483648")
464         self.assertEqual(result, -1)
465         self.assertIn("--computer-tgt-lifetime-mins must be between 45 and 2147483647",
466                       err)
467
468     def test_modify__name_missing(self):
469         """Test modify authentication but the --name argument is missing."""
470         result, out, err = self.runcmd("domain", "auth", "policy", "modify",
471                                        "--description", "NewDescription")
472         self.assertEqual(result, -1)
473         self.assertIn("Argument --name is required.", err)
474
475     def test_modify__notfound(self):
476         """Test modify an authentication silo that doesn't exist."""
477         result, out, err = self.runcmd("domain", "auth", "policy", "modify",
478                                        "--name", "doesNotExist",
479                                        "--description", "NewDescription")
480         self.assertEqual(result, -1)
481         self.assertIn("Authentication policy doesNotExist not found.", err)
482
483     def test_modify__audit_enforce(self):
484         """Test modify authentication policy using --audit and --enforce."""
485         # Create a policy to modify for this test.
486         name = "modifyEnforce"
487         self.runcmd("domain", "auth", "policy", "create", "--name", name)
488         self.addCleanup(self.delete_authentication_policy,
489                         name=name, force=True)
490
491         # Change to audit, the default is --enforce.
492         result, out, err = self.runcmd("domain", "auth", "policy", "modify",
493                                        "--name", name,
494                                        "--audit")
495         self.assertIsNone(result, msg=err)
496
497         # Check that the policy was changed to --audit.
498         policy = self.get_authentication_policy(name)
499         self.assertEqual(str(policy["msDS-AuthNPolicyEnforced"]), "FALSE")
500
501         result, out, err = self.runcmd("domain", "auth", "policy", "modify",
502                                        "--name", name,
503                                        "--enforce")
504         self.assertIsNone(result, msg=err)
505
506         # Check if the policy was changed back to --enforce.
507         policy = self.get_authentication_policy(name)
508         self.assertEqual(str(policy["msDS-AuthNPolicyEnforced"]), "TRUE")
509
510     def test_modify__protect_unprotect(self):
511         """Test modify authentication policy using --protect and --unprotect."""
512         # Create a policy to modify for this test.
513         name = "modifyProtect"
514         self.runcmd("domain", "auth", "policy", "create", "--name", name)
515         self.addCleanup(self.delete_authentication_policy,
516                         name=name, force=True)
517
518         utils = SDUtils(self.samdb)
519         result, out, err = self.runcmd("domain", "auth", "policy", "modify",
520                                        "--name", name,
521                                        "--protect")
522         self.assertIsNone(result, msg=err)
523
524         # Check that claim type was protected.
525         policy = self.get_authentication_policy(name)
526         desc = utils.get_sd_as_sddl(policy["dn"])
527         self.assertIn("(D;;DTSD;;;WD)", desc)
528
529         result, out, err = self.runcmd("domain", "auth", "policy", "modify",
530                                        "--name", name,
531                                        "--unprotect")
532         self.assertIsNone(result, msg=err)
533
534         # Check that claim type was unprotected.
535         policy = self.get_authentication_policy(name)
536         desc = utils.get_sd_as_sddl(policy["dn"])
537         self.assertNotIn("(D;;DTSD;;;WD)", desc)
538
539     def test_modify__audit_enforce_together(self):
540         """Test modify auth policy using both --audit and --enforce."""
541         result, out, err = self.runcmd("domain", "auth", "policy", "modify",
542                                        "--name", "User Policy",
543                                        "--audit", "--enforce")
544         self.assertEqual(result, -1)
545         self.assertIn("--audit and --enforce cannot be used together.", err)
546
547     def test_modify__protect_unprotect_together(self):
548         """Test modify authentication policy using --protect and --unprotect."""
549         result, out, err = self.runcmd("domain", "auth", "policy", "modify",
550                                        "--name", "User Policy",
551                                        "--protect", "--unprotect")
552         self.assertEqual(result, -1)
553         self.assertIn("--protect and --unprotect cannot be used together.", err)
554
555     def test_modify__fails(self):
556         """Test modifying an authentication policy, but it fails."""
557         # Raise ModelError when ldb.add() is called.
558         with patch.object(SamDB, "modify") as modify_mock:
559             modify_mock.side_effect = ModelError("Custom error message")
560             result, out, err = self.runcmd("domain", "auth", "policy", "modify",
561                                            "--name", "User Policy",
562                                            "--description", "New description")
563             self.assertEqual(result, -1)
564             self.assertIn("Custom error message", err)
565
566     def test_delete__success(self):
567         """Test deleting an authentication policy that is not protected."""
568         # Create non-protected authentication policy.
569         result, out, err = self.runcmd("domain", "auth", "policy", "create",
570                                        "--name=deleteTest")
571         self.assertIsNone(result, msg=err)
572         policy = self.get_authentication_policy("deleteTest")
573         self.assertIsNotNone(policy)
574
575         # Do the deletion.
576         result, out, err = self.runcmd("domain", "auth", "policy", "delete",
577                                        "--name", "deleteTest")
578         self.assertIsNone(result, msg=err)
579
580         # Authentication policy shouldn't exist anymore.
581         policy = self.get_authentication_policy("deleteTest")
582         self.assertIsNone(policy)
583
584     def test_delete__protected(self):
585         """Test deleting a protected auth policy, with and without --force."""
586         # Create protected authentication policy.
587         result, out, err = self.runcmd("domain", "auth", "policy", "create",
588                                        "--name=deleteProtected",
589                                        "--protect")
590         self.assertIsNone(result, msg=err)
591         policy = self.get_authentication_policy("deleteProtected")
592         self.assertIsNotNone(policy)
593
594         # Do the deletion.
595         result, out, err = self.runcmd("domain", "auth", "policy", "delete",
596                                        "--name=deleteProtected")
597         self.assertEqual(result, -1)
598
599         # Authentication silo should still exist.
600         policy = self.get_authentication_policy("deleteProtected")
601         self.assertIsNotNone(policy)
602
603         # Try a force delete instead.
604         result, out, err = self.runcmd("domain", "auth", "policy", "delete",
605                                        "--name=deleteProtected", "--force")
606         self.assertIsNone(result, msg=err)
607
608         # Authentication silo shouldn't exist anymore.
609         policy = self.get_authentication_policy("deleteProtected")
610         self.assertIsNone(policy)
611
612     def test_delete__notfound(self):
613         """Test deleting an authentication policy that doesn't exist."""
614         result, out, err = self.runcmd("domain", "auth", "policy", "delete",
615                                        "--name", "doesNotExist")
616         self.assertEqual(result, -1)
617         self.assertIn("Authentication policy doesNotExist not found.", err)
618
619     def test_delete__name_required(self):
620         """Test deleting an authentication policy without --name argument."""
621         result, out, err = self.runcmd("domain", "auth", "policy", "delete")
622         self.assertEqual(result, -1)
623         self.assertIn("Argument --name is required.", err)
624
625     def test_delete__force_fails(self):
626         """Test deleting an authentication policy with --force, but it fails."""
627         # Create protected authentication policy.
628         result, out, err = self.runcmd("domain", "auth", "policy", "create",
629                                        "--name=deleteForceFail",
630                                        "--protect")
631         self.assertIsNone(result, msg=err)
632         policy = self.get_authentication_policy("deleteForceFail")
633         self.assertIsNotNone(policy)
634
635         # Try delete with --force.
636         # Patch SDUtils.dacl_delete_aces with a Mock that raises ModelError.
637         with patch.object(SDUtils, "dacl_delete_aces") as delete_mock:
638             delete_mock.side_effect = ModelError("Custom error message")
639             result, out, err = self.runcmd("domain", "auth", "policy", "delete",
640                                            "--name", "deleteForceFail",
641                                            "--force")
642             self.assertEqual(result, -1)
643             self.assertIn("Custom error message", err)
644
645     def test_delete__fails(self):
646         """Test deleting an authentication policy, but it fails."""
647         # Create regular authentication policy.
648         result, out, err = self.runcmd("domain", "auth", "policy", "create",
649                                        "--name=regularPolicy")
650         self.assertIsNone(result, msg=err)
651         policy = self.get_authentication_policy("regularPolicy")
652         self.assertIsNotNone(policy)
653
654         # Raise ModelError when ldb.delete() is called.
655         with patch.object(SamDB, "delete") as delete_mock:
656             delete_mock.side_effect = ModelError("Custom error message")
657             result, out, err = self.runcmd("domain", "auth", "policy", "delete",
658                                            "--name", "regularPolicy")
659             self.assertEqual(result, -1)
660             self.assertIn("Custom error message", err)
661
662             # When not using --force we get a hint.
663             self.assertIn("Try --force", err)
664
665     def test_delete__protected_fails(self):
666         """Test deleting an authentication policy, but it fails."""
667         # Create protected authentication policy.
668         result, out, err = self.runcmd("domain", "auth", "policy", "create",
669                                        "--name=protectedPolicy",
670                                        "--protect")
671         self.assertIsNone(result, msg=err)
672         policy = self.get_authentication_policy("protectedPolicy")
673         self.assertIsNotNone(policy)
674
675         # Raise ModelError when ldb.delete() is called.
676         with patch.object(SamDB, "delete") as delete_mock:
677             delete_mock.side_effect = ModelError("Custom error message")
678             result, out, err = self.runcmd("domain", "auth", "policy", "delete",
679                                            "--name", "protectedPolicy",
680                                            "--force")
681             self.assertEqual(result, -1)
682             self.assertIn("Custom error message", err)
683
684             # When using --force we don't get the hint.
685             self.assertNotIn("Try --force", err)