import samba.getopt as options
from samba.netcmd import Command, CommandError, Option, SuperCommand
-from samba.netcmd.domain.models import AuthenticationPolicy
+from samba.netcmd.domain.models import AuthenticationPolicy, AuthenticationSilo
from samba.netcmd.domain.models.auth_policy import MIN_TGT_LIFETIME,\
MAX_TGT_LIFETIME, StrongNTLMPolicy
from samba.netcmd.domain.models.exceptions import ModelError
from samba.netcmd.validators import Range
+def check_similar_args(option, args):
+ """Helper method for checking similar mutually exclusive args.
+
+ Example: --user-allowed-to-authenticate-from and
+ --user-allowed-to-authenticate-from-silo
+ """
+ num = sum(arg is not None for arg in args)
+ if num > 1:
+ raise CommandError(f"{option} argument repeated {num} times.")
+
+
class UserOptions(options.OptionGroup):
"""User options used by policy create and policy modify commands."""
help="Conditions user is allowed to authenticate from.",
type=str, dest="allowed_to_authenticate_from",
action="callback", callback=self.set_option)
+ self.add_option("--user-allowed-to-authenticate-from-silo",
+ help="User is allowed to authenticate from silo.",
+ type=str, dest="allowed_to_authenticate_from_silo",
+ action="callback", callback=self.set_option)
self.add_option("--user-allowed-to-authenticate-to",
help="Conditions user is allowed to authenticate to.",
type=str, dest="allowed_to_authenticate_to",
help="Conditions service is allowed to authenticate from.",
type=str, dest="allowed_to_authenticate_from",
action="callback", callback=self.set_option)
+ self.add_option("--service-allowed-to-authenticate-from-silo",
+ help="Service is allowed to authenticate from silo.",
+ type=str, dest="allowed_to_authenticate_from_silo",
+ action="callback", callback=self.set_option)
self.add_option("--service-allowed-to-authenticate-to",
help="Conditions service is allowed to authenticate to.",
type=str, dest="allowed_to_authenticate_to",
if audit and enforce:
raise CommandError("--audit and --enforce cannot be used together.")
+ # Check for repeated, similar arguments.
+ check_similar_args("--user-allowed-to-authenticate-from",
+ [useropts.allowed_to_authenticate_from,
+ useropts.allowed_to_authenticate_from_silo])
+ check_similar_args("--service-allowed-to-authenticate-from",
+ [serviceopts.allowed_to_authenticate_from,
+ serviceopts.allowed_to_authenticate_from_silo])
+
ldb = self.ldb_connect(hostopts, sambaopts, credopts)
+ # Generate SDDL for authenticating users from a silo
+ if useropts.allowed_to_authenticate_from_silo:
+ silo = AuthenticationSilo.get(
+ ldb, cn=useropts.allowed_to_authenticate_from_silo)
+ useropts.allowed_to_authenticate_from = 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()
+
try:
policy = AuthenticationPolicy.get(ldb, cn=name)
except ModelError as e:
if audit and enforce:
raise CommandError("--audit and --enforce cannot be used together.")
+ # Check for repeated, similar arguments.
+ check_similar_args("--user-allowed-to-authenticate-from",
+ [useropts.allowed_to_authenticate_from,
+ useropts.allowed_to_authenticate_from_silo])
+ check_similar_args("--service-allowed-to-authenticate-from",
+ [serviceopts.allowed_to_authenticate_from,
+ serviceopts.allowed_to_authenticate_from_silo])
+
ldb = self.ldb_connect(hostopts, sambaopts, credopts)
+ # Generate SDDL for authenticating users from a silo
+ if useropts.allowed_to_authenticate_from_silo:
+ silo = AuthenticationSilo.get(
+ ldb, cn=useropts.allowed_to_authenticate_from_silo)
+ useropts.allowed_to_authenticate_from = 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()
+
try:
policy = AuthenticationPolicy.get(ldb, cn=name)
except ModelError as e:
self.assertIn("--user-tgt-lifetime-mins must be between 45 and 2147483647",
err)
+ def test_create__user_allowed_to_authenticate_from_silo(self):
+ """Tests the --user-allowed-to-authenticate-from-silo shortcut."""
+ name = self.unique_name()
+
+ 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-from-silo",
+ "Developers")
+ self.assertIsNone(result, msg=err)
+
+ # Check policy fields.
+ policy = self.get_authentication_policy(name)
+ self.assertEqual(str(policy["cn"]), name)
+
+ # Check generated SDDL.
+ desc = policy["msDS-UserAllowedToAuthenticateFrom"][0]
+ sddl = ndr_unpack(security.descriptor, desc).as_sddl()
+ self.assertEqual(
+ sddl,
+ "O:SYG:SYD:(XA;OICI;CR;;;WD;(@USER.ad://ext/AuthenticationSilo/Developers))")
+
def test_create__service_tgt_lifetime_mins(self):
"""Test create a new authentication policy with --service-tgt-lifetime-mins.
self.assertIn("--service-tgt-lifetime-mins must be between 45 and 2147483647",
err)
+ def test_create__service_allowed_to_authenticate_from_silo(self):
+ """Tests the --service-allowed-to-authenticate-from-silo shortcut."""
+ name = self.unique_name()
+
+ 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-from-silo",
+ "Managers")
+ self.assertIsNone(result, msg=err)
+
+ # Check policy fields.
+ policy = self.get_authentication_policy(name)
+ self.assertEqual(str(policy["cn"]), name)
+ desc = policy["msDS-ServiceAllowedToAuthenticateFrom"][0]
+
+ # Check generated SDDL.
+ sddl = ndr_unpack(security.descriptor, desc).as_sddl()
+ self.assertEqual(
+ sddl,
+ "O:SYG:SYD:(XA;OICI;CR;;;WD;(@USER.ad://ext/AuthenticationSilo/Managers))")
+
def test_create__computer_tgt_lifetime_mins(self):
"""Test create a new authentication policy with --computer-tgt-lifetime-mins.
self.assertEqual(result, -1)
self.assertIn("--protect and --unprotect cannot be used together.", err)
+ def test_create__user_allowed_to_authenticate_from_repeated(self):
+ """Test repeating similar arguments doesn't make sense to use together.
+
+ --user-allowed-to-authenticate-from
+ --user-allowed-to-authenticate-from-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-from",
+ sddl,
+ "--user-allowed-to-authenticate-from-silo",
+ "Managers")
+
+ self.assertEqual(result, -1)
+ self.assertIn("--user-allowed-to-authenticate-from 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.
+
+ --service-allowed-to-authenticate-from
+ --service-allowed-to-authenticate-from-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-from",
+ sddl,
+ "--service-allowed-to-authenticate-from-silo",
+ "QA")
+
+ self.assertEqual(result, -1)
+ self.assertIn("--service-allowed-to-authenticate-from argument repeated 2 times.", err)
+
def test_create__fails(self):
"""Test creating an authentication policy, but it fails."""
name = self.unique_name()
sddl = ndr_unpack(security.descriptor, desc).as_sddl()
self.assertEqual(sddl, expected)
+ def test_modify__user_allowed_to_authenticate_from_silo(self):
+ """Test the --user-allowed-to-authenticate-from-silo shortcut."""
+ name = self.unique_name()
+
+ # 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 from silo field
+ result, out, err = self.runcmd("domain", "auth", "policy", "modify",
+ "--name", name,
+ "--user-allowed-to-authenticate-from-silo",
+ "QA")
+ self.assertIsNone(result, msg=err)
+
+ # Check generated SDDL.
+ policy = self.get_authentication_policy(name)
+ desc = policy["msDS-UserAllowedToAuthenticateFrom"][0]
+ sddl = ndr_unpack(security.descriptor, desc).as_sddl()
+ self.assertEqual(
+ sddl,
+ "O:SYG:SYD:(XA;OICI;CR;;;WD;(@USER.ad://ext/AuthenticationSilo/QA))")
+
def test_modify__user_allowed_to_authenticate_to(self):
"""Modify authentication policy user allowed to authenticate to."""
name = self.unique_name()
sddl = ndr_unpack(security.descriptor, desc).as_sddl()
self.assertEqual(sddl, expected)
+ def test_modify__service_allowed_to_authenticate_from_silo(self):
+ """Test the --service-allowed-to-authenticate-from-silo shortcut."""
+ name = self.unique_name()
+
+ # 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 from silo field
+ result, out, err = self.runcmd("domain", "auth", "policy", "modify",
+ "--name", name,
+ "--service-allowed-to-authenticate-from-silo",
+ "Developers")
+ self.assertIsNone(result, msg=err)
+
+ # Check generated SDDL.
+ policy = self.get_authentication_policy(name)
+ desc = policy["msDS-ServiceAllowedToAuthenticateFrom"][0]
+ sddl = ndr_unpack(security.descriptor, desc).as_sddl()
+ self.assertEqual(
+ sddl,
+ "O:SYG:SYD:(XA;OICI;CR;;;WD;(@USER.ad://ext/AuthenticationSilo/Developers))")
+
def test_modify__service_allowed_to_authenticate_to(self):
"""Modify authentication policy service allowed to authenticate to."""
name = self.unique_name()