]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
netcmd: auth policy: add allowed-to-authenticate-to-by-group attributes
authorRob van der Linde <rob@catalyst.net.nz>
Tue, 21 Nov 2023 02:09:05 +0000 (15:09 +1300)
committerDouglas Bagnall <dbagnall@samba.org>
Wed, 22 Nov 2023 23:35:33 +0000 (23:35 +0000)
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
python/samba/tests/samba_tool/silo_base.py

index ad6bfe14c9e18bc5589eb6e7c8c443739541b8f1..8acd54617d51e28c9f9f9478c8a57c90422edabb 100644 (file)
@@ -22,7 +22,8 @@
 
 import samba.getopt as options
 from samba.netcmd import Command, CommandError, Option, SuperCommand
-from samba.netcmd.domain.models import AuthenticationPolicy, AuthenticationSilo
+from samba.netcmd.domain.models import AuthenticationPolicy,\
+    AuthenticationSilo, Group
 from samba.netcmd.domain.models.auth_policy import MIN_TGT_LIFETIME,\
     MAX_TGT_LIFETIME, StrongNTLMPolicy
 from samba.netcmd.domain.models.exceptions import ModelError
@@ -68,6 +69,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-group",
+                        help="User is allowed to authenticate to by group.",
+                        type=str, dest="allowed_to_authenticate_to_by_group",
+                        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",
@@ -102,6 +107,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-group",
+                        help="Service is allowed to authenticate to by group.",
+                        type=str, dest="allowed_to_authenticate_to_by_group",
+                        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",
@@ -123,6 +132,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-group",
+                        help="Computer is allowed to authenticate to group.",
+                        type=str, dest="allowed_to_authenticate_to_by_group",
+                        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",
@@ -254,15 +267,18 @@ class cmd_domain_auth_policy_create(Command):
                             useropts.allowed_to_authenticate_from_device_silo])
         check_similar_args("--user-allowed-to-authenticate-to",
                            [useropts.allowed_to_authenticate_to,
+                            useropts.allowed_to_authenticate_to_by_group,
                             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_device_silo])
         check_similar_args("--service-allowed-to-authenticate-to",
                            [serviceopts.allowed_to_authenticate_to,
+                            serviceopts.allowed_to_authenticate_to_by_group,
                             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_group,
                             computeropts.allowed_to_authenticate_to_by_silo])
 
         ldb = self.ldb_connect(hostopts, sambaopts, credopts)
@@ -273,6 +289,12 @@ class cmd_domain_auth_policy_create(Command):
                 ldb, cn=useropts.allowed_to_authenticate_from_device_silo)
             useropts.allowed_to_authenticate_from = silo.get_authentication_sddl()
 
+        # Generate SDDL for authenticating user accounts to a group
+        if useropts.allowed_to_authenticate_to_by_group:
+            group = Group.get(
+                ldb, cn=useropts.allowed_to_authenticate_to_by_group)
+            useropts.allowed_to_authenticate_to = group.get_authentication_sddl()
+
         # Generate SDDL for authenticating user accounts to a silo
         if useropts.allowed_to_authenticate_to_by_silo:
             silo = AuthenticationSilo.get(
@@ -285,12 +307,24 @@ class cmd_domain_auth_policy_create(Command):
                 ldb, cn=serviceopts.allowed_to_authenticate_from_device_silo)
             serviceopts.allowed_to_authenticate_from = silo.get_authentication_sddl()
 
+        # Generate SDDL for authenticating service accounts to a group
+        if serviceopts.allowed_to_authenticate_to_by_group:
+            group = Group.get(
+                ldb, cn=serviceopts.allowed_to_authenticate_to_by_group)
+            serviceopts.allowed_to_authenticate_to = group.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 group
+        if computeropts.allowed_to_authenticate_to_by_group:
+            group = Group.get(
+                ldb, cn=computeropts.allowed_to_authenticate_to_by_group)
+            computeropts.allowed_to_authenticate_to = group.get_authentication_sddl()
+
         # Generate SDDL for authenticating computer accounts to a silo
         if computeropts.allowed_to_authenticate_to_by_silo:
             silo = AuthenticationSilo.get(
@@ -397,15 +431,18 @@ class cmd_domain_auth_policy_modify(Command):
                             useropts.allowed_to_authenticate_from_device_silo])
         check_similar_args("--user-allowed-to-authenticate-to",
                            [useropts.allowed_to_authenticate_to,
+                            useropts.allowed_to_authenticate_to_by_group,
                             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_device_silo])
         check_similar_args("--service-allowed-to-authenticate-to",
                            [serviceopts.allowed_to_authenticate_to,
+                            serviceopts.allowed_to_authenticate_to_by_group,
                             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_group,
                             computeropts.allowed_to_authenticate_to_by_silo])
 
         ldb = self.ldb_connect(hostopts, sambaopts, credopts)
@@ -416,6 +453,12 @@ class cmd_domain_auth_policy_modify(Command):
                 ldb, cn=useropts.allowed_to_authenticate_from_device_silo)
             useropts.allowed_to_authenticate_from = silo.get_authentication_sddl()
 
+        # Generate SDDL for authenticating user accounts to a group
+        if useropts.allowed_to_authenticate_to_by_group:
+            group = Group.get(
+                ldb, cn=useropts.allowed_to_authenticate_to_by_group)
+            useropts.allowed_to_authenticate_to = group.get_authentication_sddl()
+
         # Generate SDDL for authenticating user accounts to a silo
         if useropts.allowed_to_authenticate_to_by_silo:
             silo = AuthenticationSilo.get(
@@ -428,12 +471,24 @@ class cmd_domain_auth_policy_modify(Command):
                 ldb, cn=serviceopts.allowed_to_authenticate_from_device_silo)
             serviceopts.allowed_to_authenticate_from = silo.get_authentication_sddl()
 
+        # Generate SDDL for authenticating service accounts to a group
+        if serviceopts.allowed_to_authenticate_to_by_group:
+            group = Group.get(
+                ldb, cn=serviceopts.allowed_to_authenticate_to_by_group)
+            serviceopts.allowed_to_authenticate_to = group.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 group
+        if computeropts.allowed_to_authenticate_to_by_group:
+            group = Group.get(
+                ldb, cn=computeropts.allowed_to_authenticate_to_by_group)
+            computeropts.allowed_to_authenticate_to = group.get_authentication_sddl()
+
         # Generate SDDL for authenticating computer accounts to a silo
         if computeropts.allowed_to_authenticate_to_by_silo:
             silo = AuthenticationSilo.get(
index 84de6bd9cf40b907349f89b75822cd82d330a412..5f68b627d88fe141005f3e46297faa4e82c318ec 100644 (file)
@@ -175,6 +175,27 @@ 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_group(self):
+        """Tests the --user-allowed-to-authenticate-to-by-group shortcut."""
+        name = self.unique_name()
+        expected = "O:SYG:SYD:(XA;OICI;CR;;;WD;(Member_of_any {SID(%s)}))" % (
+            self.device_group.object_sid)
+
+        # Create a user with authenticate to by group 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-group",
+            self.device_group.name)
+        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__user_allowed_to_authenticate_to_by_silo(self):
         """Tests the --user-allowed-to-authenticate-to-by-silo shortcut."""
         name = self.unique_name()
@@ -251,6 +272,27 @@ 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_group(self):
+        """Tests the --service-allowed-to-authenticate-to-by-group shortcut."""
+        name = self.unique_name()
+        expected = "O:SYG:SYD:(XA;OICI;CR;;;WD;(Member_of_any {SID(%s)}))" % (
+            self.device_group.object_sid)
+
+        # Create a user with authenticate to by group 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-group",
+            self.device_group.name)
+        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__service_allowed_to_authenticate_to_by_silo(self):
         """Tests the --service-allowed-to-authenticate-to-by-silo shortcut."""
         name = self.unique_name()
@@ -305,6 +347,27 @@ 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_group(self):
+        """Tests the --computer-allowed-to-authenticate-to-by-group shortcut."""
+        name = self.unique_name()
+        expected = "O:SYG:SYD:(XA;OICI;CR;;;WD;(Member_of_any {SID(%s)}))" % (
+            self.device_group.object_sid)
+
+        # Create a user with authenticate to by group 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-group",
+            self.device_group.name)
+        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__computer_allowed_to_authenticate_to_by_silo(self):
         """Tests the --computer-allowed-to-authenticate-to-by-silo shortcut."""
         name = self.unique_name()
@@ -892,6 +955,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_group(self):
+        """Tests the --user-allowed-to-authenticate-to-by-group shortcut."""
+        name = self.unique_name()
+        expected = "O:SYG:SYD:(XA;OICI;CR;;;WD;(Member_of_any {SID(%s)}))" % (
+            self.device_group.object_sid)
+
+        # 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-group",
+                                       self.device_group.name)
+        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__user_allowed_to_authenticate_to_by_silo(self):
         """Tests the --user-allowed-to-authenticate-to-by-silo shortcut."""
         name = self.unique_name()
@@ -985,6 +1072,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_group(self):
+        """Tests the --service-allowed-to-authenticate-to-by-group shortcut."""
+        name = self.unique_name()
+        expected = "O:SYG:SYD:(XA;OICI;CR;;;WD;(Member_of_any {SID(%s)}))" % (
+            self.device_group.object_sid)
+
+        # 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-group",
+                                       self.device_group.name)
+        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__service_allowed_to_authenticate_to_by_silo(self):
         """Tests the --service-allowed-to-authenticate-to-by-silo shortcut."""
         name = self.unique_name()
@@ -1032,6 +1143,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_group(self):
+        """Tests the --computer-allowed-to-authenticate-to-by-group shortcut."""
+        name = self.unique_name()
+        expected = "O:SYG:SYD:(XA;OICI;CR;;;WD;(Member_of_any {SID(%s)}))" % (
+            self.device_group.object_sid)
+
+        # 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-group",
+                                       self.device_group.name)
+        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__computer_allowed_to_authenticate_to_by_silo(self):
         """Tests the --computer-allowed-to-authenticate-to-by-silo shortcut."""
         name = self.unique_name()
index d514bbc360e726bb1939e591bd6fc4471645d014..451d330850c0a3e27a5a4a14f5dc545950c4566a 100644 (file)
@@ -24,6 +24,8 @@ import os
 
 from ldb import SCOPE_ONELEVEL
 
+from samba.netcmd.domain.models import Group
+
 from .base import SambaToolCmdTest
 
 HOST = "ldap://{DC_SERVER}".format(**os.environ)
@@ -59,6 +61,10 @@ class SiloTest(SambaToolCmdTest):
             service_authentication_policy="Service Policy",
             computer_authentication_policy="Computer Policy")
 
+        cls.device_group = Group(name="device-group")
+        cls.device_group.save(cls.samdb)
+        cls.addClassCleanup(cls.device_group.delete, cls.samdb)
+
     def get_services_dn(self):
         """Returns Services DN."""
         services_dn = self.samdb.get_config_basedn()