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

Reply via email to