[SCM] Samba Shared Repository - branch master updated

Andrew Bartlett abartlet at samba.org
Wed Nov 29 04:16:02 UTC 2023


The branch, master has been updated
       via  e2651628844 tests: claims blackbox: add device and server silo restrictions test
       via  834fc223e2e python: tests: claims blackbox tests use ntstatus constants
       via  0d907a02141 tests: claims blackbox: use raw strings rather than escaping \
       via  dc74cabaa4d tests: claims: blackbox device tests
       via  64212a371be selftest: Run samba.tests.gensec in an enviroment build also with MIT Krb5
       via  c49fd98ed7a s4-auth/kerberos: Use FAST credentials for armor if specified in cli_credentials
       via  0293d233bf2 python/tests: Add test for creds.set_krb5_fast_credentials()
       via  ebdb1f6b43a python/tests: Lock in key-word arguments as key-word only in samba.tests.gssapi
       via  61b0397de20 python/tests: Import samba.gensec, not gensec
       via  cc2c9b2a1e7 auth/credentials: Add Python bindings for association of a connection for FAST
       via  bed1893a75e auth/credentials: Add API to allow requesting a Kerberos ticket to be protected with FAST
       via  dbb682f5fac build: Add build time detection for the MIT FAST ccache API
       via  6222d572eec third_party/heimdal: Provide krb5_init_creds_opt_set_fast_ccache() and krb5_init_creds_opt_set_fast_flags() (import lorikeet-heimdal-202311290114 (commit 4c8517e161396330c76240bf09609a0dd5f9ea20))
      from  a757a51a26f libcli/security: note suboptimality of conditional ACE Contains operators

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit e2651628844d6a4262de4093770d958fc1ee4535
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Tue Nov 28 13:05:33 2023 +1300

    tests: claims blackbox: add device and server silo restrictions test
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    
    Autobuild-User(master): Andrew Bartlett <abartlet at samba.org>
    Autobuild-Date(master): Wed Nov 29 04:15:27 UTC 2023 on atb-devel-224

commit 834fc223e2e3a9c07e1df57cf7f4ae39afb13db2
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Wed Nov 29 11:37:42 2023 +1300

    python: tests: claims blackbox tests use ntstatus constants
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 0d907a021415d1a94469faf3fcd301022979fefc
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Tue Nov 28 12:46:53 2023 +1300

    tests: claims blackbox: use raw strings rather than escaping \
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit dc74cabaa4d7ec52c9d33b19aaafe4272de249a5
Author: Rob van der Linde <rob at catalyst.net.nz>
Date:   Tue Nov 21 16:27:09 2023 +1300

    tests: claims: blackbox device tests
    
    Signed-off-by: Rob van der Linde <rob at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 64212a371be2c262338d604944cc73b397913fdb
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Tue Nov 28 17:07:15 2023 +1300

    selftest: Run samba.tests.gensec in an enviroment build also with MIT Krb5
    
    We would like confidence that the FAST hooks work with both implementations.
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit c49fd98ed7a547fe37b354d93671a9d2f05c8b34
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Mon Nov 20 14:12:19 2023 +1300

    s4-auth/kerberos: Use FAST credentials for armor if specified in cli_credentials
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 0293d233bf206fabe1e209548c0c44d511f9e73f
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Mon Nov 20 12:17:57 2023 +1300

    python/tests: Add test for creds.set_krb5_fast_credentials()
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit ebdb1f6b43af4141bf598f6dffdc47df94401336
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Mon Nov 20 12:42:15 2023 +1300

    python/tests: Lock in key-word arguments as key-word only in samba.tests.gssapi
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 61b0397de2031813bdcf35a742eeba2dc9c5f9b9
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Mon Nov 20 13:02:21 2023 +1300

    python/tests: Import samba.gensec, not gensec
    
    This allows this function to be used by gensec.py (a test) without collision.
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit cc2c9b2a1e72802675a6e0494679774b920abe8c
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Mon Nov 20 12:16:04 2023 +1300

    auth/credentials: Add Python bindings for association of a connection for FAST
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit bed1893a75e7bf5e7b607fb1bc5712e3175d17a9
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Fri Nov 17 17:41:53 2023 +1300

    auth/credentials: Add API to allow requesting a Kerberos ticket to be protected with FAST
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit dbb682f5fac1094bfd5ad70c35bfe9e9c877b935
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Tue Nov 28 13:51:07 2023 +1300

    build: Add build time detection for the MIT FAST ccache API
    
    This will allow us to link against an older system Heimdal.
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 6222d572eecb958174e7795e2dc8143188c6ae2e
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Wed Nov 29 14:16:16 2023 +1300

    third_party/heimdal: Provide krb5_init_creds_opt_set_fast_ccache() and krb5_init_creds_opt_set_fast_flags() (import lorikeet-heimdal-202311290114 (commit 4c8517e161396330c76240bf09609a0dd5f9ea20))
    
    It is easier for external callers to manipulate the krb5_get_init_creds_opt
    (via the helpers) as this is passed down from higher up than the krb5_init_creds_context.
    
    And just as importantly, alignment with MIT makes end-user callers happier.
    
    Finally, this resolves the ambiguity as to which layer owns the
    krb5_ccache, because now we match the MIT behaviour the init_creds code
    re-opens a private copy inside libkrb5, meaning the caller closes the
    cache it opened, rather than handing it over to the library.
    
    (The unrelated changes are fixes to the test_pac test, also included in this import,
    but in distinct lorikeet-heimdal commits, to allow it to compile)
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Joseph Sutton <josephsutton at catalyst.net.nz>

-----------------------------------------------------------------------

Summary of changes:
 auth/credentials/credentials.h                     |  12 +
 auth/credentials/credentials_internal.h            |   6 +
 auth/credentials/credentials_krb5.c                |  51 +++-
 auth/credentials/pycredentials.c                   |  94 +++++++
 python/samba/tests/__init__.py                     |   4 +-
 python/samba/tests/blackbox/claims.py              | 305 ++++++++++++++++++++-
 python/samba/tests/gensec.py                       |  39 ++-
 source4/auth/kerberos/kerberos_credentials.h       |   1 +
 source4/auth/kerberos/kerberos_util.c              |  47 ++++
 source4/selftest/tests.py                          |   6 +-
 third_party/heimdal/kdc/kdc-tester.c               |  16 +-
 third_party/heimdal/kuser/kinit.c                  |  50 ++--
 third_party/heimdal/lib/krb5/init_creds.c          |  46 ++++
 third_party/heimdal/lib/krb5/init_creds_pw.c       |  19 ++
 third_party/heimdal/lib/krb5/krb5.h                |   2 +
 third_party/heimdal/lib/krb5/krb5_locl.h           |  37 +--
 .../heimdal/lib/krb5/libkrb5-exports.def.in        |   3 +
 third_party/heimdal/lib/krb5/test_pac.c            |  38 ++-
 third_party/heimdal/lib/krb5/version-script.map    |   3 +
 third_party/heimdal_build/wscript_configure        |   2 +
 wscript_configure_system_heimdal                   |   7 +
 wscript_configure_system_mitkrb5                   |   2 +
 22 files changed, 720 insertions(+), 70 deletions(-)


Changeset truncated at 500 lines:

diff --git a/auth/credentials/credentials.h b/auth/credentials/credentials.h
index c3a048ecc8d..3ad40267e2e 100644
--- a/auth/credentials/credentials.h
+++ b/auth/credentials/credentials.h
@@ -351,4 +351,16 @@ int cli_credentials_get_aes256_key(struct cli_credentials *cred,
 				   const char *salt,
 				   DATA_BLOB *aes_256);
 
+/**
+ * Kerberos FAST handling
+ */
+
+NTSTATUS cli_credentials_set_krb5_fast_armor_credentials(struct cli_credentials *creds,
+							 struct cli_credentials *armor_creds,
+							 bool require_fast_armor);
+
+struct cli_credentials *cli_credentials_get_krb5_fast_armor_credentials(struct cli_credentials *creds);
+
+bool cli_credentials_get_krb5_require_fast_armor(struct cli_credentials *creds);
+
 #endif /* __CREDENTIALS_H__ */
diff --git a/auth/credentials/credentials_internal.h b/auth/credentials/credentials_internal.h
index 966926919b0..cda361e1dd0 100644
--- a/auth/credentials/credentials_internal.h
+++ b/auth/credentials/credentials_internal.h
@@ -131,6 +131,12 @@ struct cli_credentials {
 	enum smb_signing_setting ipc_signing_state;
 
 	enum smb_encryption_setting encryption_state;
+
+	/* Credentials to use for FAST */
+	struct cli_credentials *krb5_fast_armor_credentials;
+
+	/* Should we require FAST? */
+	bool krb5_require_fast_armor;
 };
 
 #endif /* __CREDENTIALS_INTERNAL_H__ */
diff --git a/auth/credentials/credentials_krb5.c b/auth/credentials/credentials_krb5.c
index 7d7d0248cb4..4463401a767 100644
--- a/auth/credentials/credentials_krb5.c
+++ b/auth/credentials/credentials_krb5.c
@@ -726,7 +726,14 @@ _PUBLIC_ int cli_credentials_get_named_ccache(struct cli_credentials *cred,
 		return ret;
 	}
 
-	ret = kinit_to_ccache(cred, cred, (*ccc)->smb_krb5_context, event_ctx, (*ccc)->ccache, &obtained, error_string);
+	ret = kinit_to_ccache(cred,
+			      cred,
+			      (*ccc)->smb_krb5_context,
+			      lp_ctx,
+			      event_ctx,
+			      (*ccc)->ccache,
+			      &obtained,
+			      error_string);
 	if (ret) {
 		return ret;
 	}
@@ -1125,7 +1132,7 @@ static int cli_credentials_shallow_ccache(struct cli_credentials *cred)
 _PUBLIC_ struct cli_credentials *cli_credentials_shallow_copy(TALLOC_CTX *mem_ctx,
 						struct cli_credentials *src)
 {
-	struct cli_credentials *dst;
+	struct cli_credentials *dst, *armor_credentials;
 	int ret;
 
 	dst = talloc(mem_ctx, struct cli_credentials);
@@ -1135,6 +1142,14 @@ _PUBLIC_ struct cli_credentials *cli_credentials_shallow_copy(TALLOC_CTX *mem_ct
 
 	*dst = *src;
 
+	if (dst->krb5_fast_armor_credentials != NULL) {
+		armor_credentials = talloc_reference(dst, dst->krb5_fast_armor_credentials);
+		if (armor_credentials == NULL) {
+			TALLOC_FREE(dst);
+			return NULL;
+		}
+	}
+
 	ret = cli_credentials_shallow_ccache(dst);
 	if (ret != 0) {
 		TALLOC_FREE(dst);
@@ -1532,3 +1547,35 @@ _PUBLIC_ int cli_credentials_get_aes256_key(struct cli_credentials *cred,
 
 	return 0;
 }
+
+/* This take a reference to the armor credentials to ensure the lifetime is appropriate */
+
+NTSTATUS cli_credentials_set_krb5_fast_armor_credentials(struct cli_credentials *creds,
+							 struct cli_credentials *armor_creds,
+							 bool require_fast_armor)
+{
+	talloc_unlink(creds, creds->krb5_fast_armor_credentials);
+	if (armor_creds == NULL) {
+		creds->krb5_fast_armor_credentials = NULL;
+		return NT_STATUS_OK;
+	}
+
+	creds->krb5_fast_armor_credentials = talloc_reference(creds, armor_creds);
+	if (creds->krb5_fast_armor_credentials == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	creds->krb5_require_fast_armor = require_fast_armor;
+
+	return NT_STATUS_OK;
+}
+
+struct cli_credentials *cli_credentials_get_krb5_fast_armor_credentials(struct cli_credentials *creds)
+{
+	return creds->krb5_fast_armor_credentials;
+}
+
+bool cli_credentials_get_krb5_require_fast_armor(struct cli_credentials *creds)
+{
+	return creds->krb5_require_fast_armor;
+}
diff --git a/auth/credentials/pycredentials.c b/auth/credentials/pycredentials.c
index 3687050bde9..8e7d8ae7b56 100644
--- a/auth/credentials/pycredentials.c
+++ b/auth/credentials/pycredentials.c
@@ -41,6 +41,11 @@ static PyObject *py_creds_new(PyTypeObject *type, PyObject *args, PyObject *kwar
 	return pytalloc_steal(type, cli_credentials_init(NULL));
 }
 
+static PyObject *PyCredentials_from_cli_credentials(struct cli_credentials *creds)
+{
+	return pytalloc_reference(&PyCredentials, creds);
+}
+
 static PyObject *py_creds_get_username(PyObject *self, PyObject *unused)
 {
 	struct cli_credentials *creds = PyCredentials_AsCliCredentials(self);
@@ -1219,6 +1224,74 @@ static PyObject *py_creds_set_smb_encryption(PyObject *self, PyObject *args)
 	Py_RETURN_NONE;
 }
 
+static PyObject *py_creds_get_krb5_fast_armor_credentials(PyObject *self, PyObject *unused)
+{
+	struct cli_credentials *creds = NULL;
+	struct cli_credentials *fast_creds = NULL;
+
+	creds = PyCredentials_AsCliCredentials(self);
+	if (creds == NULL) {
+		PyErr_Format(PyExc_TypeError, "Credentials expected");
+		return NULL;
+	}
+
+	fast_creds = cli_credentials_get_krb5_fast_armor_credentials(creds);
+	if (fast_creds == NULL) {
+		Py_RETURN_NONE;
+	}
+
+	return PyCredentials_from_cli_credentials(fast_creds);
+}
+
+static PyObject *py_creds_set_krb5_fast_armor_credentials(PyObject *self, PyObject *args)
+{
+	struct cli_credentials *creds = NULL;
+	PyObject *pyfast_creds;
+	struct cli_credentials *fast_creds = NULL;
+	int fast_armor_required = 0;
+	NTSTATUS status;
+
+	creds = PyCredentials_AsCliCredentials(self);
+	if (creds == NULL) {
+		PyErr_Format(PyExc_TypeError, "Credentials expected");
+		return NULL;
+	}
+	if (!PyArg_ParseTuple(args, "Op", &pyfast_creds, &fast_armor_required)) {
+		return NULL;
+	}
+	if (pyfast_creds == Py_None) {
+		fast_creds = NULL;
+	} else {
+		fast_creds = PyCredentials_AsCliCredentials(pyfast_creds);
+		if (fast_creds == NULL) {
+			PyErr_Format(PyExc_TypeError, "Credentials expected");
+			return NULL;
+		}
+	}
+
+	status = cli_credentials_set_krb5_fast_armor_credentials(creds,
+								 fast_creds,
+								 fast_armor_required);
+
+	PyErr_NTSTATUS_IS_ERR_RAISE(status);
+	Py_RETURN_NONE;
+}
+
+static PyObject *py_creds_get_krb5_require_fast_armor(PyObject *self, PyObject *unused)
+{
+	bool krb5_fast_armor_required;
+	struct cli_credentials *creds = NULL;
+
+	creds = PyCredentials_AsCliCredentials(self);
+	if (creds == NULL) {
+		PyErr_Format(PyExc_TypeError, "Credentials expected");
+		return NULL;
+	}
+
+	krb5_fast_armor_required = cli_credentials_get_krb5_require_fast_armor(creds);
+	return PyBool_FromLong(krb5_fast_armor_required);
+}
+
 static PyMethodDef py_creds_methods[] = {
 	{
 		.ml_name  = "get_username",
@@ -1558,6 +1631,27 @@ static PyMethodDef py_creds_methods[] = {
 		.ml_meth  = py_creds_set_smb_encryption,
 		.ml_flags = METH_VARARGS,
 	},
+	{
+		.ml_name  = "get_krb5_fast_armor_credentials",
+		.ml_meth  = py_creds_get_krb5_fast_armor_credentials,
+		.ml_flags = METH_NOARGS,
+		.ml_doc   = "S.get_krb5_fast_armor_credentials() -> Credentials\n"
+			    "Get the Kerberos FAST credentials set on this credentials object"
+	},
+	{
+		.ml_name  = "set_krb5_fast_armor_credentials",
+		.ml_meth  = py_creds_set_krb5_fast_armor_credentials,
+		.ml_flags = METH_VARARGS,
+		.ml_doc   = "S.set_krb5_fast_armor_credentials(credentials, required) -> None\n"
+			    "Set Kerberos FAST credentials for this credentials object, and if FAST armoring must be used."
+	},
+	{
+		.ml_name  = "get_krb5_require_fast_armor",
+		.ml_meth  = py_creds_get_krb5_require_fast_armor,
+		.ml_flags = METH_NOARGS,
+		.ml_doc   = "S.get_krb5_fast_armor() -> bool\n"
+			    "Indicate if Kerberos FAST armor is required"
+	},
 	{ .ml_name = NULL }
 };
 
diff --git a/python/samba/tests/__init__.py b/python/samba/tests/__init__.py
index 5ba18c9fdcb..9981e1390a2 100644
--- a/python/samba/tests/__init__.py
+++ b/python/samba/tests/__init__.py
@@ -26,13 +26,13 @@ import samba
 from samba import param
 from samba import credentials
 from samba.credentials import Credentials
-from samba import gensec
 import subprocess
 import sys
 import unittest
 import re
 from enum import IntEnum, unique
 import samba.auth
+import samba.gensec
 import samba.dcerpc.base
 from random import randint
 from random import SystemRandom
@@ -256,7 +256,7 @@ class TestCase(unittest.TestCase):
         c.set_realm(template.get_realm())
         c.set_workstation(template.get_workstation())
         c.set_gensec_features(c.get_gensec_features()
-                              | gensec.FEATURE_SEAL)
+                              | samba.gensec.FEATURE_SEAL)
         c.set_kerberos_state(kerberos_state)
         if simple_bind_dn:
             c.set_bind_dn(simple_bind_dn)
diff --git a/python/samba/tests/blackbox/claims.py b/python/samba/tests/blackbox/claims.py
index 135595eec24..1c6cddcec24 100755
--- a/python/samba/tests/blackbox/claims.py
+++ b/python/samba/tests/blackbox/claims.py
@@ -27,6 +27,7 @@ from samba import NTSTATUSError
 from samba.auth import AuthContext
 from samba.credentials import Credentials
 from samba.gensec import FEATURE_SEAL, Security
+from samba.ntstatus import NT_STATUS_LOGON_FAILURE, NT_STATUS_UNSUCCESSFUL
 from samba.tests import BlackboxTestCase
 
 SERVER = os.environ["SERVER"]
@@ -46,6 +47,286 @@ class ClaimsSupportTests(BlackboxTestCase):
     order after the tests finishes, they don't execute straight away.
     """
 
+    def test_device_group_restrictions(self):
+        client_password = "T3stPassword0nly"
+        target_password = "T3stC0mputerPassword"
+        device_password = "T3stD3vicePassword"
+
+        # Create target computer.
+        self.check_run("computer create claims-server")
+        self.addCleanup(self.run_command, "computer delete claims-server")
+        self.check_run(rf"user setpassword claims-server\$ --newpassword={target_password}")
+
+        # Create device computer.
+        self.check_run("computer create claims-device")
+        self.addCleanup(self.run_command, "computer delete claims-device")
+        self.check_run(rf"user setpassword claims-device\$ --newpassword={device_password}")
+
+        # Create a user.
+        self.check_run(f"user create claimstestuser {client_password}")
+        self.addCleanup(self.run_command, "user delete claimstestuser")
+
+        # Create an authentication policy.
+        self.check_run("domain auth policy create --enforce --name=device-restricted-users-pol")
+        self.addCleanup(self.run_command,
+                        "domain auth policy delete --name=device-restricted-users-pol")
+
+        self.check_run("group add allowed-devices")
+        self.addCleanup(self.run_command, "group delete allowed-devices")
+
+        # Set allowed to authenticate from.
+        self.check_run(f"domain auth policy modify --name=device-restricted-users-pol "
+                       "--user-allowed-to-authenticate-from-device-group=allowed-devices")
+
+        self.check_run("user auth policy assign claimstestuser --policy=device-restricted-users-pol")
+
+        with self.assertRaises(NTSTATUSError) as error:
+            self.verify_access(
+                client_username="claimstestuser",
+                client_password=client_password,
+                target_hostname="claims-server",
+                target_username="claims-server",
+                target_password=target_password,
+                device_username="claims-device",
+                device_password=device_password,
+            )
+
+            self.assertEqual(error.exception.args[0], NT_STATUS_LOGON_FAILURE)
+            self.assertEqual(
+                error.exception.args[1],
+                "The attempted logon is invalid. This is either due to a "
+                "bad username or authentication information.")
+
+        self.check_run("group addmembers allowed-devices claims-device")
+
+        self.verify_access(
+            client_username="claimstestuser",
+            client_password=client_password,
+            target_hostname="claims-server",
+            target_username="claims-server",
+            target_password=target_password,
+            device_username="claims-device",
+            device_password=device_password,
+        )
+
+    def test_device_silo_restrictions(self):
+        client_password = "T3stPassword0nly"
+        target_password = "T3stC0mputerPassword"
+        device_password = "T3stD3vicePassword"
+
+        # Create target computer.
+        self.check_run("computer create claims-server")
+        self.addCleanup(self.run_command, "computer delete claims-server")
+        self.check_run(rf"user setpassword claims-server\$ --newpassword={target_password}")
+
+        # Create device computer.
+        self.check_run("computer create claims-device")
+        self.addCleanup(self.run_command, "computer delete claims-device")
+        self.check_run(rf"user setpassword claims-device\$ --newpassword={device_password}")
+
+        # Create a user.
+        self.check_run(f"user create claimstestuser {client_password}")
+        self.addCleanup(self.run_command, "user delete claimstestuser")
+
+        # Create an authentication policy.
+        self.check_run("domain auth policy create --enforce --name=allowed-devices-only-pol")
+        self.addCleanup(self.run_command,
+                        "domain auth policy delete --name=allowed-devices-only-pol")
+
+        # Create an authentication silo.
+        self.check_run("domain auth silo create --enforce --name=allowed-devices-only-silo "
+                       "--user-authentication-policy=allowed-devices-only-pol "
+                       "--computer-authentication-policy=allowed-devices-only-pol "
+                       "--service-authentication-policy=allowed-devices-only-pol")
+        self.addCleanup(self.run_command,
+                        "domain auth silo delete --name=allowed-devices-only-silo")
+
+        # Set allowed to authenticate from (where the login can happen) and to
+        # (server requires silo that in term has this rule, so knows the user
+        # was required to authenticate from).
+        self.check_run(f"domain auth policy modify --name=allowed-devices-only-pol "
+                       "--user-allowed-to-authenticate-from-device-silo=allowed-devices-only-silo")
+
+        # Grant access to silo.
+        self.check_run(r"domain auth silo member grant --name=allowed-devices-only-silo --member=claims-device\$")
+        self.check_run("domain auth silo member grant --name=allowed-devices-only-silo --member=claimstestuser")
+
+        # However with nothing assigned, allow-by-default still applies
+        self.verify_access(
+            client_username="claimstestuser",
+            client_password=client_password,
+            target_hostname="claims-server",
+            target_username="claims-server",
+            target_password=target_password,
+        )
+
+        # Show that adding a FAST armor from the device doesn't change
+        # things either way
+        self.verify_access(
+            client_username="claimstestuser",
+            client_password=client_password,
+            target_hostname="claims-server",
+            target_username="claims-server",
+            target_password=target_password,
+            device_username="claims-device",
+            device_password=device_password,
+        )
+
+        # Assign silo to the user.
+        self.check_run("user auth silo assign claimstestuser --silo=allowed-devices-only-silo")
+
+        # We fail, as the KDC now requires the silo but the client is not using an approved device
+        with self.assertRaises(NTSTATUSError) as error:
+            self.verify_access(
+                client_username="claimstestuser",
+                client_password=client_password,
+                target_hostname="claims-server",
+                target_username="claims-server",
+                target_password=target_password,
+                device_username="claims-device",
+                device_password=device_password,
+            )
+
+        self.assertEqual(error.exception.args[0], NT_STATUS_UNSUCCESSFUL)
+        self.assertIn(
+            "The requested operation was unsuccessful.",
+            error.exception.args[1])
+
+        # Assign silo to the device.
+        self.check_run(r"user auth silo assign claims-device\$ --silo=allowed-devices-only-silo")
+
+        self.verify_access(
+            client_username="claimstestuser",
+            client_password=client_password,
+            target_hostname="claims-server",
+            target_username="claims-server",
+            target_password=target_password,
+            device_username="claims-device",
+            device_password=device_password,
+        )
+
+    def test_device_and_server_silo_restrictions(self):
+        client_password = "T3stPassword0nly"
+        target_password = "T3stC0mputerPassword"
+        device_password = "T3stD3vicePassword"
+
+        # Create target computer.
+        self.check_run("computer create claims-server")
+        self.addCleanup(self.run_command, "computer delete claims-server")
+        self.check_run(rf"user setpassword claims-server\$ --newpassword={target_password}")
+
+        # Create device computer.
+        self.check_run("computer create claims-device")
+        self.addCleanup(self.run_command, "computer delete claims-device")
+        self.check_run(rf"user setpassword claims-device\$ --newpassword={device_password}")
+
+        # Create a user.
+        self.check_run(f"user create claimstestuser {client_password}")
+        self.addCleanup(self.run_command, "user delete claimstestuser")
+
+        # Create an authentication policy.
+        self.check_run("domain auth policy create --enforce --name=allowed-devices-only-pol")
+        self.addCleanup(self.run_command,
+                        "domain auth policy delete --name=allowed-devices-only-pol")
+
+        # Create an authentication silo.
+        self.check_run("domain auth silo create --enforce --name=allowed-devices-only-silo "
+                       "--user-authentication-policy=allowed-devices-only-pol "
+                       "--computer-authentication-policy=allowed-devices-only-pol "
+                       "--service-authentication-policy=allowed-devices-only-pol")
+        self.addCleanup(self.run_command,
+                        "domain auth silo delete --name=allowed-devices-only-silo")
+
+        # Set allowed to authenticate from (where the login can happen) and to
+        # (server requires silo that in term has this rule, so knows the user
+        # was required to authenticate from).
+        # If we assigned services to the silo we would need to add
+        # --service-allowed-to-authenticate-to/from options as well.
+        # Likewise, if there are services running in user accounts, we need
+        # --user-allowed-to-authenticate-to
+        self.check_run(f"domain auth policy modify --name=allowed-devices-only-pol "
+                       "--user-allowed-to-authenticate-from-device-silo=allowed-devices-only-silo "
+                       "--computer-allowed-to-authenticate-to-by-silo=allowed-devices-only-silo")
+
+        # Grant access to silo.
+        self.check_run(r"domain auth silo member grant --name=allowed-devices-only-silo --member=claims-device\$")
+        self.check_run(r"domain auth silo member grant --name=allowed-devices-only-silo --member=claims-server\$")
+        self.check_run("domain auth silo member grant --name=allowed-devices-only-silo --member=claimstestuser")
+
+        # However with nothing assigned, allow-by-default still applies
+        self.verify_access(
+            client_username="claimstestuser",
+            client_password=client_password,
+            target_hostname="claims-server",
+            target_username="claims-server",
+            target_password=target_password,
+        )
+
+        # Show that adding a FAST armor from the device doesn't change
+        # things either way
+        self.verify_access(
+            client_username="claimstestuser",


-- 
Samba Shared Repository



More information about the samba-cvs mailing list