From: Rob van der Linde Date: Mon, 13 Nov 2023 10:48:36 +0000 (+1300) Subject: netcmd: auth policy: add allowed to authenticate to by silo attributes X-Git-Tag: talloc-2.4.2~569 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=42de24d73a96ed574fbbe5af938e15e06fc6eac1;p=thirdparty%2Fsamba.git netcmd: auth policy: add allowed to authenticate to by silo attributes --user-allowed-to-authenticate-to-by-silo --service-allowed-to-authenticate-to-by-silo --computer-allowed-to-authenticate-to-by-silo Signed-off-by: Rob van der Linde Reviewed-by: Douglas Bagnall Reviewed-by: Andrew Bartlett --- diff --git a/python/samba/netcmd/domain/auth/policy.py b/python/samba/netcmd/domain/auth/policy.py index d0ca96b677a..1eb3acf3273 100644 --- a/python/samba/netcmd/domain/auth/policy.py +++ b/python/samba/netcmd/domain/auth/policy.py @@ -68,6 +68,10 @@ class UserOptions(options.OptionGroup): help="Conditions user is allowed to authenticate to.", type=str, dest="allowed_to_authenticate_to", action="callback", callback=self.set_option) + self.add_option("--user-allowed-to-authenticate-to-by-silo", + help="User is allowed to authenticate to by silo.", + type=str, dest="allowed_to_authenticate_to_by_silo", + action="callback", callback=self.set_option) class ServiceOptions(options.OptionGroup): @@ -98,6 +102,10 @@ class ServiceOptions(options.OptionGroup): help="Conditions service is allowed to authenticate to.", type=str, dest="allowed_to_authenticate_to", action="callback", callback=self.set_option) + self.add_option("--service-allowed-to-authenticate-to-by-silo", + help="Service is allowed to authenticate to by silo.", + type=str, dest="allowed_to_authenticate_to_by_silo", + action="callback", callback=self.set_option) class ComputerOptions(options.OptionGroup): @@ -115,6 +123,10 @@ class ComputerOptions(options.OptionGroup): help="Conditions computer is allowed to authenticate to.", type=str, dest="allowed_to_authenticate_to", action="callback", callback=self.set_option) + self.add_option("--computer-allowed-to-authenticate-to-by-silo", + help="Computer is allowed to authenticate to silo.", + type=str, dest="allowed_to_authenticate_to_by_silo", + action="callback", callback=self.set_option) class cmd_domain_auth_policy_list(Command): @@ -240,9 +252,18 @@ class cmd_domain_auth_policy_create(Command): check_similar_args("--user-allowed-to-authenticate-from", [useropts.allowed_to_authenticate_from, useropts.allowed_to_authenticate_from_silo]) + check_similar_args("--user-allowed-to-authenticate-to", + [useropts.allowed_to_authenticate_to, + useropts.allowed_to_authenticate_to_by_silo]) check_similar_args("--service-allowed-to-authenticate-from", [serviceopts.allowed_to_authenticate_from, serviceopts.allowed_to_authenticate_from_silo]) + check_similar_args("--service-allowed-to-authenticate-to", + [serviceopts.allowed_to_authenticate_to, + serviceopts.allowed_to_authenticate_to_by_silo]) + check_similar_args("--computer-allowed-to-authenticate-to", + [computeropts.allowed_to_authenticate_to, + computeropts.allowed_to_authenticate_to_by_silo]) ldb = self.ldb_connect(hostopts, sambaopts, credopts) @@ -252,12 +273,30 @@ class cmd_domain_auth_policy_create(Command): ldb, cn=useropts.allowed_to_authenticate_from_silo) useropts.allowed_to_authenticate_from = silo.get_authentication_sddl() + # Generate SDDL for authenticating user accounts to a silo + if useropts.allowed_to_authenticate_to_by_silo: + silo = AuthenticationSilo.get( + ldb, cn=useropts.allowed_to_authenticate_to_by_silo) + useropts.allowed_to_authenticate_to = silo.get_authentication_sddl() + # Generate SDDL for authenticating service accounts from a silo if serviceopts.allowed_to_authenticate_from_silo: silo = AuthenticationSilo.get( ldb, cn=serviceopts.allowed_to_authenticate_from_silo) serviceopts.allowed_to_authenticate_from = silo.get_authentication_sddl() + # Generate SDDL for authenticating service accounts to a silo + if serviceopts.allowed_to_authenticate_to_by_silo: + silo = AuthenticationSilo.get( + ldb, cn=serviceopts.allowed_to_authenticate_to_by_silo) + serviceopts.allowed_to_authenticate_to = silo.get_authentication_sddl() + + # Generate SDDL for authenticating computer accounts to a silo + if computeropts.allowed_to_authenticate_to_by_silo: + silo = AuthenticationSilo.get( + ldb, cn=computeropts.allowed_to_authenticate_to_by_silo) + computeropts.allowed_to_authenticate_to = silo.get_authentication_sddl() + try: policy = AuthenticationPolicy.get(ldb, cn=name) except ModelError as e: @@ -356,9 +395,18 @@ class cmd_domain_auth_policy_modify(Command): check_similar_args("--user-allowed-to-authenticate-from", [useropts.allowed_to_authenticate_from, useropts.allowed_to_authenticate_from_silo]) + check_similar_args("--user-allowed-to-authenticate-to", + [useropts.allowed_to_authenticate_to, + useropts.allowed_to_authenticate_to_by_silo]) check_similar_args("--service-allowed-to-authenticate-from", [serviceopts.allowed_to_authenticate_from, serviceopts.allowed_to_authenticate_from_silo]) + check_similar_args("--service-allowed-to-authenticate-to", + [serviceopts.allowed_to_authenticate_to, + serviceopts.allowed_to_authenticate_to_by_silo]) + check_similar_args("--computer-allowed-to-authenticate-to", + [computeropts.allowed_to_authenticate_to, + computeropts.allowed_to_authenticate_to_by_silo]) ldb = self.ldb_connect(hostopts, sambaopts, credopts) @@ -368,12 +416,30 @@ class cmd_domain_auth_policy_modify(Command): ldb, cn=useropts.allowed_to_authenticate_from_silo) useropts.allowed_to_authenticate_from = silo.get_authentication_sddl() + # Generate SDDL for authenticating user accounts to a silo + if useropts.allowed_to_authenticate_to_by_silo: + silo = AuthenticationSilo.get( + ldb, cn=useropts.allowed_to_authenticate_to_by_silo) + useropts.allowed_to_authenticate_to = silo.get_authentication_sddl() + # Generate SDDL for authenticating service accounts from a silo if serviceopts.allowed_to_authenticate_from_silo: silo = AuthenticationSilo.get( ldb, cn=serviceopts.allowed_to_authenticate_from_silo) serviceopts.allowed_to_authenticate_from = silo.get_authentication_sddl() + # Generate SDDL for authenticating service accounts to a silo + if serviceopts.allowed_to_authenticate_to_by_silo: + silo = AuthenticationSilo.get( + ldb, cn=serviceopts.allowed_to_authenticate_to_by_silo) + serviceopts.allowed_to_authenticate_to = silo.get_authentication_sddl() + + # Generate SDDL for authenticating computer accounts to a silo + if computeropts.allowed_to_authenticate_to_by_silo: + silo = AuthenticationSilo.get( + ldb, cn=computeropts.allowed_to_authenticate_to_by_silo) + computeropts.allowed_to_authenticate_to = silo.get_authentication_sddl() + try: policy = AuthenticationPolicy.get(ldb, cn=name) except ModelError as e: diff --git a/python/samba/tests/samba_tool/domain_auth_policy.py b/python/samba/tests/samba_tool/domain_auth_policy.py index 6d7804dd4f3..f6062f1b46c 100644 --- a/python/samba/tests/samba_tool/domain_auth_policy.py +++ b/python/samba/tests/samba_tool/domain_auth_policy.py @@ -175,6 +175,26 @@ class AuthPolicyCmdTestCase(SiloTest): sddl, 'O:SYG:SYD:(XA;OICI;CR;;;WD;(@USER.ad://ext/AuthenticationSilo == "Developers"))') + def test_create__user_allowed_to_authenticate_to_by_silo(self): + """Tests the --user-allowed-to-authenticate-to-by-silo shortcut.""" + name = self.unique_name() + expected = ('O:SYG:SYD:(XA;OICI;CR;;;WD;(@USER.ad://ext/' + 'AuthenticationSilo == "QA"))') + + # Create a user with authenticate to by silo attribute. + self.addCleanup(self.delete_authentication_policy, name=name, force=True) + result, out, err = self.runcmd( + "domain", "auth", "policy", "create", "--name", name, + "--user-allowed-to-authenticate-to-by-silo", "QA") + self.assertIsNone(result, msg=err) + + # Check user allowed to authenticate to field was modified. + policy = self.get_authentication_policy(name) + self.assertEqual(str(policy["cn"]), name) + desc = policy["msDS-UserAllowedToAuthenticateTo"][0] + sddl = ndr_unpack(security.descriptor, desc).as_sddl() + self.assertEqual(sddl, expected) + def test_create__service_tgt_lifetime_mins(self): """Test create a new authentication policy with --service-tgt-lifetime-mins. @@ -231,6 +251,26 @@ class AuthPolicyCmdTestCase(SiloTest): sddl, 'O:SYG:SYD:(XA;OICI;CR;;;WD;(@USER.ad://ext/AuthenticationSilo == "Managers"))') + def test_create__service_allowed_to_authenticate_to_by_silo(self): + """Tests the --service-allowed-to-authenticate-to-by-silo shortcut.""" + name = self.unique_name() + expected = ('O:SYG:SYD:(XA;OICI;CR;;;WD;(@USER.ad://ext/' + 'AuthenticationSilo == "Managers"))') + + # Create a user with authenticate to by silo attribute. + self.addCleanup(self.delete_authentication_policy, name=name, force=True) + result, out, err = self.runcmd( + "domain", "auth", "policy", "create", "--name", name, + "--service-allowed-to-authenticate-to-by-silo", "Managers") + self.assertIsNone(result, msg=err) + + # Check user allowed to authenticate to field was modified. + policy = self.get_authentication_policy(name) + self.assertEqual(str(policy["cn"]), name) + desc = policy["msDS-ServiceAllowedToAuthenticateTo"][0] + sddl = ndr_unpack(security.descriptor, desc).as_sddl() + self.assertEqual(sddl, expected) + def test_create__computer_tgt_lifetime_mins(self): """Test create a new authentication policy with --computer-tgt-lifetime-mins. @@ -265,6 +305,26 @@ class AuthPolicyCmdTestCase(SiloTest): self.assertIn("--computer-tgt-lifetime-mins must be between 45 and 2147483647", err) + def test_create__computer_allowed_to_authenticate_to_by_silo(self): + """Tests the --computer-allowed-to-authenticate-to-by-silo shortcut.""" + name = self.unique_name() + expected = ('O:SYG:SYD:(XA;OICI;CR;;;WD;(@USER.ad://ext/' + 'AuthenticationSilo == "QA"))') + + # Create a user with authenticate to by silo attribute. + self.addCleanup(self.delete_authentication_policy, name=name, force=True) + result, out, err = self.runcmd( + "domain", "auth", "policy", "create", "--name", name, + "--computer-allowed-to-authenticate-to-by-silo", "QA") + self.assertIsNone(result, msg=err) + + # Check user allowed to authenticate to field was modified. + policy = self.get_authentication_policy(name) + self.assertEqual(str(policy["cn"]), name) + desc = policy["msDS-ComputerAllowedToAuthenticateTo"][0] + sddl = ndr_unpack(security.descriptor, desc).as_sddl() + self.assertEqual(sddl, expected) + def test_create__valid_sddl(self): """Test creating a new authentication policy with valid SDDL in a field.""" name = self.unique_name() @@ -522,6 +582,25 @@ class AuthPolicyCmdTestCase(SiloTest): self.assertEqual(result, -1) self.assertIn("--user-allowed-to-authenticate-from argument repeated 2 times.", err) + def test_create__user_allowed_to_authenticate_to_repeated(self): + """Test repeating similar arguments doesn't make sense to use together. + + --user-allowed-to-authenticate-to + --user-allowed-to-authenticate-to-by-silo + """ + sddl = 'O:SYG:SYD:(XA;OICI;CR;;;WD;(@USER.ad://ext/AuthenticationSilo == "Developers"))' + name = self.unique_name() + + result, out, err = self.runcmd("domain", "auth", "policy", "create", + "--name", name, + "--user-allowed-to-authenticate-to", + sddl, + "--user-allowed-to-authenticate-to-by-silo", + "Managers") + + self.assertEqual(result, -1) + self.assertIn("--user-allowed-to-authenticate-to argument repeated 2 times.", err) + def test_create__service_allowed_to_authenticate_from_repeated(self): """Test repeating similar arguments doesn't make sense to use together. @@ -541,6 +620,44 @@ class AuthPolicyCmdTestCase(SiloTest): self.assertEqual(result, -1) self.assertIn("--service-allowed-to-authenticate-from argument repeated 2 times.", err) + def test_create__service_allowed_to_authenticate_to_repeated(self): + """Test repeating similar arguments doesn't make sense to use together. + + --service-allowed-to-authenticate-to + --service-allowed-to-authenticate-to-by-silo + """ + sddl = 'O:SYG:SYD:(XA;OICI;CR;;;WD;(@USER.ad://ext/AuthenticationSilo == "Managers"))' + name = self.unique_name() + + result, out, err = self.runcmd("domain", "auth", "policy", "create", + "--name", name, + "--service-allowed-to-authenticate-to", + sddl, + "--service-allowed-to-authenticate-to-by-silo", + "QA") + + self.assertEqual(result, -1) + self.assertIn("--service-allowed-to-authenticate-to argument repeated 2 times.", err) + + def test_create__computer_allowed_to_authenticate_to_repeated(self): + """Test repeating similar arguments doesn't make sense to use together. + + --computer-allowed-to-authenticate-to + --computer-allowed-to-authenticate-to-by-silo + """ + sddl = 'O:SYG:SYD:(XA;OICI;CR;;;WD;(@USER.ad://ext/AuthenticationSilo == "Managers"))' + name = self.unique_name() + + result, out, err = self.runcmd("domain", "auth", "policy", "create", + "--name", name, + "--computer-allowed-to-authenticate-to", + sddl, + "--computer-allowed-to-authenticate-to-by-silo", + "QA") + + self.assertEqual(result, -1) + self.assertIn("--computer-allowed-to-authenticate-to argument repeated 2 times.", err) + def test_create__fails(self): """Test creating an authentication policy, but it fails.""" name = self.unique_name() @@ -775,6 +892,30 @@ class AuthPolicyCmdTestCase(SiloTest): sddl = ndr_unpack(security.descriptor, desc).as_sddl() self.assertEqual(sddl, expected) + def test_modify__user_allowed_to_authenticate_to_by_silo(self): + """Tests the --user-allowed-to-authenticate-to-by-silo shortcut.""" + name = self.unique_name() + expected = ('O:SYG:SYD:(XA;OICI;CR;;;WD;(@USER.ad://ext/' + 'AuthenticationSilo == "Developers"))') + + # Create a policy to modify for this test. + self.addCleanup(self.delete_authentication_policy, name=name, force=True) + self.runcmd("domain", "auth", "policy", "create", "--name", name) + + # Modify user allowed to authenticate to field + result, out, err = self.runcmd("domain", "auth", "policy", "modify", + "--name", name, + "--user-allowed-to-authenticate-to-by-silo", + "Developers") + self.assertIsNone(result, msg=err) + + # Check user allowed to authenticate to field was modified. + policy = self.get_authentication_policy(name) + self.assertEqual(str(policy["cn"]), name) + desc = policy["msDS-UserAllowedToAuthenticateTo"][0] + sddl = ndr_unpack(security.descriptor, desc).as_sddl() + self.assertEqual(sddl, expected) + def test_modify__service_allowed_to_authenticate_from(self): """Modify authentication policy service allowed to authenticate from.""" name = self.unique_name() @@ -844,6 +985,30 @@ class AuthPolicyCmdTestCase(SiloTest): sddl = ndr_unpack(security.descriptor, desc).as_sddl() self.assertEqual(sddl, expected) + def test_modify__service_allowed_to_authenticate_to_by_silo(self): + """Tests the --service-allowed-to-authenticate-to-by-silo shortcut.""" + name = self.unique_name() + expected = ('O:SYG:SYD:(XA;OICI;CR;;;WD;(@USER.ad://ext/' + 'AuthenticationSilo == "QA"))') + + # Create a policy to modify for this test. + self.addCleanup(self.delete_authentication_policy, name=name, force=True) + self.runcmd("domain", "auth", "policy", "create", "--name", name) + + # Modify user allowed to authenticate to field + result, out, err = self.runcmd("domain", "auth", "policy", "modify", + "--name", name, + "--service-allowed-to-authenticate-to-by-silo", + "QA") + self.assertIsNone(result, msg=err) + + # Check user allowed to authenticate to field was modified. + policy = self.get_authentication_policy(name) + self.assertEqual(str(policy["cn"]), name) + desc = policy["msDS-ServiceAllowedToAuthenticateTo"][0] + sddl = ndr_unpack(security.descriptor, desc).as_sddl() + self.assertEqual(sddl, expected) + def test_modify__computer_allowed_to_authenticate_to(self): """Modify authentication policy computer allowed to authenticate to.""" name = self.unique_name() @@ -867,6 +1032,30 @@ class AuthPolicyCmdTestCase(SiloTest): sddl = ndr_unpack(security.descriptor, desc).as_sddl() self.assertEqual(sddl, expected) + def test_modify__computer_allowed_to_authenticate_to_by_silo(self): + """Tests the --computer-allowed-to-authenticate-to-by-silo shortcut.""" + name = self.unique_name() + expected = ('O:SYG:SYD:(XA;OICI;CR;;;WD;(@USER.ad://ext/' + 'AuthenticationSilo == "QA"))') + + # Create a policy to modify for this test. + self.addCleanup(self.delete_authentication_policy, name=name, force=True) + self.runcmd("domain", "auth", "policy", "create", "--name", name) + + # Modify user allowed to authenticate to field + result, out, err = self.runcmd("domain", "auth", "policy", "modify", + "--name", name, + "--computer-allowed-to-authenticate-to-by-silo", + "QA") + self.assertIsNone(result, msg=err) + + # Check user allowed to authenticate to field was modified. + policy = self.get_authentication_policy(name) + self.assertEqual(str(policy["cn"]), name) + desc = policy["msDS-ComputerAllowedToAuthenticateTo"][0] + sddl = ndr_unpack(security.descriptor, desc).as_sddl() + self.assertEqual(sddl, expected) + def test_modify__name_missing(self): """Test modify authentication but the --name argument is missing.""" result, out, err = self.runcmd("domain", "auth", "policy", "modify",