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 <r...@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 <r...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> Autobuild-User(master): Andrew Bartlett <abart...@samba.org> Autobuild-Date(master): Wed Nov 29 04:15:27 UTC 2023 on atb-devel-224 commit 834fc223e2e3a9c07e1df57cf7f4ae39afb13db2 Author: Rob van der Linde <r...@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 <r...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> commit 0d907a021415d1a94469faf3fcd301022979fefc Author: Rob van der Linde <r...@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 <r...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> commit dc74cabaa4d7ec52c9d33b19aaafe4272de249a5 Author: Rob van der Linde <r...@catalyst.net.nz> Date: Tue Nov 21 16:27:09 2023 +1300 tests: claims: blackbox device tests Signed-off-by: Rob van der Linde <r...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> commit 64212a371be2c262338d604944cc73b397913fdb Author: Andrew Bartlett <abart...@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 <abart...@samba.org> Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> commit c49fd98ed7a547fe37b354d93671a9d2f05c8b34 Author: Andrew Bartlett <abart...@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 <abart...@samba.org> Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> commit 0293d233bf206fabe1e209548c0c44d511f9e73f Author: Andrew Bartlett <abart...@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 <abart...@samba.org> Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> commit ebdb1f6b43af4141bf598f6dffdc47df94401336 Author: Andrew Bartlett <abart...@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 <abart...@samba.org> Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> commit 61b0397de2031813bdcf35a742eeba2dc9c5f9b9 Author: Andrew Bartlett <abart...@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 <abart...@samba.org> Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> commit cc2c9b2a1e72802675a6e0494679774b920abe8c Author: Andrew Bartlett <abart...@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 <abart...@samba.org> Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> commit bed1893a75e7bf5e7b607fb1bc5712e3175d17a9 Author: Andrew Bartlett <abart...@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 <abart...@samba.org> Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> commit dbb682f5fac1094bfd5ad70c35bfe9e9c877b935 Author: Andrew Bartlett <abart...@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 <abart...@samba.org> Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz> commit 6222d572eecb958174e7795e2dc8143188c6ae2e Author: Andrew Bartlett <abart...@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 <abart...@samba.org> Reviewed-by: Joseph Sutton <josephsut...@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