]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
netcmd: auth policy: add allowed to authenticate to by silo attributes
authorRob van der Linde <rob@catalyst.net.nz>
Mon, 13 Nov 2023 10:48:36 +0000 (23:48 +1300)
committerDouglas Bagnall <dbagnall@samba.org>
Wed, 22 Nov 2023 23:35:33 +0000 (23:35 +0000)
--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 <rob@catalyst.net.nz>
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
python/samba/netcmd/domain/auth/policy.py
python/samba/tests/samba_tool/domain_auth_policy.py

index d0ca96b677a4526c611c03212ddd9eaa432c492a..1eb3acf3273181be117152f38a8434afb590e5d8 100644 (file)
@@ -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:
index 6d7804dd4f334de40d72989dce34cc4af9e2e8c9..f6062f1b46cbf1dfa2603ebfabd061d56788dc90 100644 (file)
@@ -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",