The branch, master has been updated via 4f0ed9b0038 tests/krb5: Add tests for AllowedToAuthenticateTo with an AS-REQ via eac23954156 s4:auth: Update error messages via 67af86d2ab8 auth:credentials: Remove unused include via 8b86174bd34 auth:credentials: Remove trailing line via 67457394e42 tests/krb5: Allow specifying SamDB to use when creating an account via 0bc8d1469b8 python:tests: Do not have current_time() and current_nt_time() implicitly include clock skew via 96ac8144b43 python: Correct time conversion function name via cd44f8063b2 s4:libnet: Fix code spelling via d8fa0dd62eb python: Type ‘format’ parameter as optional via cd7b0720de7 python: Correctly qualify strptime() via ed5f8af3299 python:tests: Fix code spelling via 2f25c23b7bb s4:auth: Allocate strings on shorter‐lived memory context via 398a555fc26 python:tests: Simplify expression via 86db3056177 python:tests: Use Managed Service Accounts well‐known GUID via 55bc523da7d s4:auth: Fix grammar in error message from 8f1a80147d8 pidl: add "return ENOTSUP" for int return type in s3 template
https://git.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit 4f0ed9b00389fa641a423b88ab5462b32dd7bbca Author: Jo Sutton <josut...@catalyst.net.nz> Date: Tue May 2 15:42:24 2023 +1200 tests/krb5: Add tests for AllowedToAuthenticateTo with an AS-REQ BUG: https://bugzilla.samba.org/show_bug.cgi?id=15607 Signed-off-by: Jo Sutton <josut...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> Autobuild-User(master): Andrew Bartlett <abart...@samba.org> Autobuild-Date(master): Thu Mar 21 04:19:18 UTC 2024 on atb-devel-224 commit eac2395415616595c6163768baa163a83a3cea5a Author: Jo Sutton <josut...@catalyst.net.nz> Date: Tue Mar 12 11:08:30 2024 +1300 s4:auth: Update error messages Signed-off-by: Jo Sutton <josut...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 67af86d2ab8cb1c9f7a253652feb4897389c6e64 Author: Jo Sutton <josut...@catalyst.net.nz> Date: Tue Mar 12 11:08:14 2024 +1300 auth:credentials: Remove unused include Signed-off-by: Jo Sutton <josut...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 8b86174bd3409a651fc4d8c8a5edc55b714502ed Author: Jo Sutton <josut...@catalyst.net.nz> Date: Tue Mar 12 11:07:56 2024 +1300 auth:credentials: Remove trailing line Signed-off-by: Jo Sutton <josut...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 67457394e423598af7b8aa654628af9b7ecea5ee Author: Jo Sutton <josut...@catalyst.net.nz> Date: Fri Mar 8 16:34:49 2024 +1300 tests/krb5: Allow specifying SamDB to use when creating an account Signed-off-by: Jo Sutton <josut...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 0bc8d1469b89ddf4b3f6cd07e0941137e05dff9d Author: Jo Sutton <josut...@catalyst.net.nz> Date: Mon Mar 4 13:38:10 2024 +1300 python:tests: Do not have current_time() and current_nt_time() implicitly include clock skew This is just too error‐prone. current_gkid() will still continue to return the next GKID if it’s within clock skew. Signed-off-by: Jo Sutton <josut...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 96ac8144b4311516bd4acf9be95a86b574f359f4 Author: Jo Sutton <josut...@catalyst.net.nz> Date: Thu Mar 7 17:14:24 2024 +1300 python: Correct time conversion function name Signed-off-by: Jo Sutton <josut...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit cd44f8063b2f7ed6bbcd063e450ec99624308c61 Author: Jo Sutton <josut...@catalyst.net.nz> Date: Tue Mar 5 12:37:11 2024 +1300 s4:libnet: Fix code spelling Signed-off-by: Jo Sutton <josut...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit d8fa0dd62eb158e6f4c2270267421c3a77be6680 Author: Jo Sutton <josut...@catalyst.net.nz> Date: Tue Mar 5 12:32:16 2024 +1300 python: Type ‘format’ parameter as optional Signed-off-by: Jo Sutton <josut...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit cd7b0720de7b85903c5d4dfb74fb66bd29519f1d Author: Jo Sutton <josut...@catalyst.net.nz> Date: Tue Mar 5 12:31:27 2024 +1300 python: Correctly qualify strptime() Signed-off-by: Jo Sutton <josut...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit ed5f8af3299143e020a72916c37a3d54a71f1ccc Author: Jo Sutton <josut...@catalyst.net.nz> Date: Mon Mar 4 13:38:29 2024 +1300 python:tests: Fix code spelling Signed-off-by: Jo Sutton <josut...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 2f25c23b7bb4f935e3b9ebf77fa1309de1e2df48 Author: Jo Sutton <josut...@catalyst.net.nz> Date: Thu Mar 14 15:14:55 2024 +1300 s4:auth: Allocate strings on shorter‐lived memory context Signed-off-by: Jo Sutton <josut...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 398a555fc26b386668c83320ce9898816c717f41 Author: Jo Sutton <josut...@catalyst.net.nz> Date: Wed Mar 13 10:12:33 2024 +1300 python:tests: Simplify expression ‘not keytab_bytes’ is shorter and equivalent. Signed-off-by: Jo Sutton <josut...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 86db3056177115a2b443a8b4c6ff8b2b6086d2c8 Author: Jo Sutton <josut...@catalyst.net.nz> Date: Tue Mar 12 16:24:59 2024 +1300 python:tests: Use Managed Service Accounts well‐known GUID Signed-off-by: Jo Sutton <josut...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> commit 55bc523da7d516a4ed43eafb0f22170ea59d9e32 Author: Jo Sutton <josut...@catalyst.net.nz> Date: Tue Mar 12 16:02:45 2024 +1300 s4:auth: Fix grammar in error message Signed-off-by: Jo Sutton <josut...@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abart...@samba.org> ----------------------------------------------------------------------- Summary of changes: auth/credentials/credentials_gmsa.c | 2 - python/samba/nt_time.py | 8 +- python/samba/tests/dckeytab.py | 11 +- python/samba/tests/gkdi.py | 35 ++- python/samba/tests/krb5/authn_policy_tests.py | 372 ++++++++++++++++++++++++++ python/samba/tests/krb5/kdc_base_test.py | 12 +- selftest/knownfail_mit_kdc | 8 + source4/auth/kerberos/kerberos_util.c | 8 +- source4/auth/kerberos/srv_keytab.c | 6 +- source4/libnet/libnet_become_dc.c | 10 +- 10 files changed, 434 insertions(+), 38 deletions(-) Changeset truncated at 500 lines: diff --git a/auth/credentials/credentials_gmsa.c b/auth/credentials/credentials_gmsa.c index f1c794ba093..86422624f1e 100644 --- a/auth/credentials/credentials_gmsa.c +++ b/auth/credentials/credentials_gmsa.c @@ -20,7 +20,6 @@ */ #include "includes.h" -#include "librpc/gen_ndr/samr.h" /* for struct samrPassword */ #include "librpc/gen_ndr/ndr_gmsa.h" /* for struct MANAGEDPASSWORD_BLOB */ #include "auth/credentials/credentials.h" #include "auth/credentials/credentials_internal.h" @@ -127,4 +126,3 @@ NTSTATUS cli_credentials_set_gmsa_passwords(struct cli_credentials *creds, TALLOC_FREE(frame); return NT_STATUS_OK; } - diff --git a/python/samba/nt_time.py b/python/samba/nt_time.py index 496dde576b4..ff6903c8e68 100644 --- a/python/samba/nt_time.py +++ b/python/samba/nt_time.py @@ -18,7 +18,7 @@ # import datetime -from typing import NewType +from typing import NewType, Optional import re @@ -56,7 +56,7 @@ def datetime_from_nt_time(nt_time: NtTime) -> datetime.datetime: return NT_EPOCH + time_since_epoch -def nt_time_delta_from_datetime(dt: datetime.timedelta) -> NtTimeDelta: +def nt_time_delta_from_timedelta(dt: datetime.timedelta) -> NtTimeDelta: return NtTimeDelta(round(dt.total_seconds() * NT_TICKS_PER_SEC)) @@ -88,7 +88,7 @@ def nt_time_from_string(s: str) -> NtTime: dt = datetime.datetime.now(datetime.timezone.utc) elif re.match(r'^\d{14}\.0Z$', s): # "20230127223641.0Z" - dt = datetime.strptime(s, '%Y%m%d%H%M%S.0Z') + dt = datetime.datetime.strptime(s, '%Y%m%d%H%M%S.0Z') else: dt = datetime.datetime.fromisoformat(s) except ValueError: @@ -107,7 +107,7 @@ def nt_time_from_string(s: str) -> NtTime: return nt_time_from_datetime(dt) -def string_from_nt_time(nttime: NtTime, format:str=None) -> str: +def string_from_nt_time(nttime: NtTime, format: Optional[str] = None) -> str: """Format an NtTime date as a string. If format is not provided, an ISO 8601 string is used. diff --git a/python/samba/tests/dckeytab.py b/python/samba/tests/dckeytab.py index f87b95d9dc5..978e3753cc7 100644 --- a/python/samba/tests/dckeytab.py +++ b/python/samba/tests/dckeytab.py @@ -22,7 +22,7 @@ import string from samba.net import Net from samba import enable_net_export_keytab -from samba import credentials, ntstatus, NTSTATUSError, tests +from samba import credentials, dsdb, ntstatus, NTSTATUSError, tests from samba.dcerpc import krb5ccache, security from samba.dsdb import UF_WORKSTATION_TRUST_ACCOUNT from samba.ndr import ndr_unpack, ndr_pack @@ -76,7 +76,7 @@ class DCKeytabTests(TestCaseInTempDir): keytab_as_set.add(entry_as_tuple) keytab_bytes = multiple_entry.further_entry - if keytab_bytes is None or len(keytab_bytes) == 0: + if not keytab_bytes: break return keytab_as_set @@ -345,7 +345,10 @@ class DCKeytabTests(TestCaseInTempDir): # Create gMSA account gmsa_username = "GMSA_K5KeytabTest$" gmsa_principal = f"{gmsa_username}@{self.samdb.domain_dns_name().upper()}" - gmsa_base_dn = f"CN=Managed Service Accounts,{self.samdb.domain_dn()}" + gmsa_base_dn = self.samdb.get_wellknown_dn( + self.samdb.get_default_basedn(), + dsdb.DS_GUID_MANAGED_SERVICE_ACCOUNTS_CONTAINER, + ) gmsa_user_dn = f"CN={gmsa_username},{gmsa_base_dn}" msg = self.samdb.search(base="", scope=SCOPE_BASE, attrs=["tokenGroups"])[0] @@ -430,7 +433,7 @@ class DCKeytabTests(TestCaseInTempDir): while True: local_keys[local_keytab.entry.enctype] = local_keytab.entry.key.data keytab_bytes = local_keytab.further_entry - if keytab_bytes is None or len(keytab_bytes) == 0: + if not keytab_bytes: break local_keytab = ndr_unpack(krb5ccache.MULTIPLE_KEYTAB_ENTRIES, keytab_bytes) diff --git a/python/samba/tests/gkdi.py b/python/samba/tests/gkdi.py index 30ddd78025a..03ed8d0141e 100644 --- a/python/samba/tests/gkdi.py +++ b/python/samba/tests/gkdi.py @@ -91,17 +91,21 @@ class GkdiBaseTest(TestCase): @staticmethod def current_time(offset: Optional[datetime.timedelta] = None) -> datetime.datetime: - if offset is None: - # Allow for clock skew. - offset = timedelta_from_nt_time_delta(MAX_CLOCK_SKEW) - current_time = datetime.datetime.now(tz=datetime.timezone.utc) - return current_time + offset + + if offset is not None: + current_time += offset + + return current_time def current_nt_time(self, offset: Optional[datetime.timedelta] = None) -> NtTime: return nt_time_from_datetime(self.current_time(offset)) def current_gkid(self, offset: Optional[datetime.timedelta] = None) -> Gkid: + if offset is None: + # Allow for clock skew. + offset = timedelta_from_nt_time_delta(MAX_CLOCK_SKEW) + return Gkid.from_nt_time(self.current_nt_time(offset)) def gkdi_connect( @@ -515,13 +519,18 @@ class GkdiBaseTest(TestCase): # which exists so that the samba-tool tests can borrow that # function. - root_key_guid, root_key_dn = create_root_key(samdb, - domain_dn, - current_nt_time=self.current_nt_time(), - use_start_time=use_start_time, - hash_algorithm=hash_algorithm, - guid=guid, - data=data) + root_key_guid, root_key_dn = create_root_key( + samdb, + domain_dn, + current_nt_time=self.current_nt_time( + # Allow for clock skew. + timedelta_from_nt_time_delta(MAX_CLOCK_SKEW) + ), + use_start_time=use_start_time, + hash_algorithm=hash_algorithm, + guid=guid, + data=data, + ) if guid is not None: # A test may request that a root key have a specific GUID so that @@ -589,7 +598,7 @@ def create_root_key( elif isinstance(use_start_time, int): use_start_nt_time = use_start_time else: - raise ValueError("use_start_time should be a datatime or int") + raise ValueError("use_start_time should be a datetime or int") kdf_parameters = None if hash_algorithm is not None: diff --git a/python/samba/tests/krb5/authn_policy_tests.py b/python/samba/tests/krb5/authn_policy_tests.py index b36fb0a8d38..455ad36d479 100755 --- a/python/samba/tests/krb5/authn_policy_tests.py +++ b/python/samba/tests/krb5/authn_policy_tests.py @@ -294,6 +294,115 @@ class AuthnPolicyBaseTests(AuthLogTestBase, KdcTgsBaseTests): opts=opts, use_cache=cached) + def _fast_as_req(self, + client_creds, + target_creds, + armor_tgt, + expected_error=0, + expect_status=None, + expected_status=None, + expected_groups=None, + expect_device_info=None, + expected_device_groups=None, + expect_device_claims=None, + expected_device_claims=None): + client_username = client_creds.get_username() + client_realm = client_creds.get_realm() + client_cname = self.PrincipalName_create(name_type=NT_PRINCIPAL, + names=[client_username]) + + target_name = target_creds.get_username() + target_sname = self.PrincipalName_create( + name_type=NT_PRINCIPAL, names=[target_name]) + target_realm = target_creds.get_realm() + target_decryption_key = self.TicketDecryptionKey_from_creds( + target_creds) + target_etypes = target_creds.tgs_supported_enctypes + + authenticator_subkey = self.RandomKey(kcrypto.Enctype.AES256) + armor_key = self.generate_armor_key(authenticator_subkey, + armor_tgt.session_key) + + preauth_key = self.PasswordKey_from_creds(client_creds, + kcrypto.Enctype.AES256) + + client_challenge_key = ( + self.generate_client_challenge_key(armor_key, preauth_key)) + fast_padata = [self.get_challenge_pa_data(client_challenge_key)] + + def _generate_fast_padata(kdc_exchange_dict, + _callback_dict, + req_body): + return list(fast_padata), req_body + + etypes = kcrypto.Enctype.AES256, kcrypto.Enctype.RC4 + + if expected_error: + check_error_fn = self.generic_check_kdc_error + check_rep_fn = None + else: + check_error_fn = None + check_rep_fn = self.generic_check_kdc_rep + + pac_options = '1' # claims support + + samdb = self.get_samdb() + domain_sid_str = samdb.get_domain_sid() + + if expected_groups is not None: + expected_groups = self.map_sids(expected_groups, None, domain_sid_str) + + if expected_device_groups is not None: + expected_device_groups = self.map_sids(expected_device_groups, None, domain_sid_str) + + kdc_exchange_dict = self.as_exchange_dict( + creds=client_creds, + expected_crealm=client_realm, + expected_cname=client_cname, + expected_srealm=target_realm, + expected_sname=target_sname, + expected_supported_etypes=target_etypes, + ticket_decryption_key=target_decryption_key, + generate_fast_fn=self.generate_simple_fast, + generate_fast_armor_fn=self.generate_ap_req, + generate_fast_padata_fn=_generate_fast_padata, + fast_armor_type=FX_FAST_ARMOR_AP_REQUEST, + check_error_fn=check_error_fn, + check_rep_fn=check_rep_fn, + check_kdc_private_fn=self.generic_check_kdc_private, + expected_error_mode=expected_error, + expected_salt=client_creds.get_salt(), + expect_status=expect_status, + expected_status=expected_status, + expected_groups=expected_groups, + expect_device_info=expect_device_info, + expected_device_domain_sid=domain_sid_str, + expected_device_groups=expected_device_groups, + expect_device_claims=expect_device_claims, + expected_device_claims=expected_device_claims, + authenticator_subkey=authenticator_subkey, + preauth_key=preauth_key, + armor_key=armor_key, + armor_tgt=armor_tgt, + armor_subkey=authenticator_subkey, + kdc_options='0', + pac_options=pac_options, + # PA-DATA types are not important for these tests. + check_patypes=False) + + rep = self._generic_kdc_exchange( + kdc_exchange_dict, + cname=client_cname, + realm=client_realm, + sname=target_sname, + etypes=etypes) + if expected_error: + self.check_error_rep(rep, expected_error) + return None + else: + self.check_as_reply(rep) + return kdc_exchange_dict['rep_ticket_creds'] + @staticmethod def audit_type(msg): return AuditType(msg['type']) @@ -6531,6 +6640,269 @@ class AuthnPolicyTests(AuthnPolicyBaseTests): self.check_tgs_log(client_creds, target_creds, policy=policy) + def test_authn_policy_allowed_to_computer_allow_as_req(self): + # Create a machine account with which to perform FAST. + mach_creds = self.get_cached_creds( + account_type=self.AccountType.COMPUTER) + mach_tgt = self.get_tgt(mach_creds) + + # Create a user account. + client_creds = self.get_cached_creds( + account_type=self.AccountType.USER) + + # Create an authentication policy that applies to a computer and + # explicitly allows the user account to obtain a service ticket. + allowed = f'O:SYD:(A;;CR;;;{client_creds.get_sid()})' + denied = 'O:SYD:(D;;CR;;;WD)' + policy = self.create_authn_policy(enforced=True, + user_allowed_to=denied, + computer_allowed_to=allowed, + service_allowed_to=denied) + + # Create a computer account with the assigned policy. + target_creds = self._get_creds(account_type=self.AccountType.COMPUTER, + assigned_policy=policy) + + # Show that obtaining a service ticket with an AS-REQ is allowed. + self._fast_as_req(client_creds, target_creds, mach_tgt) + + self.check_as_log(client_creds, + server_policy=policy) + + def test_authn_policy_allowed_to_computer_deny_as_req(self): + # Create a machine account with which to perform FAST. + mach_creds = self.get_cached_creds( + account_type=self.AccountType.COMPUTER) + mach_tgt = self.get_tgt(mach_creds) + + # Create a user account. + client_creds = self.get_cached_creds( + account_type=self.AccountType.USER) + + # Create an authentication policy that applies to a computer and + # explicitly denies the user account to obtain a service ticket. + denied = f'O:SYD:(D;;CR;;;{client_creds.get_sid()})' + allowed = 'O:SYD:(A;;CR;;;WD)' + policy = self.create_authn_policy(enforced=True, + user_allowed_to=allowed, + computer_allowed_to=denied, + service_allowed_to=allowed) + + # Create a computer account with the assigned policy. + target_creds = self._get_creds(account_type=self.AccountType.COMPUTER, + assigned_policy=policy) + + # Show that obtaining a service ticket with an AS-REQ is denied. + self._fast_as_req( + client_creds, target_creds, mach_tgt, + expected_error=KDC_ERR_POLICY, + # We aren’t particular about whether or not we get an NTSTATUS. + expect_status=None, + expected_status=ntstatus.NT_STATUS_AUTHENTICATION_FIREWALL_FAILED) + + self.check_as_log( + client_creds, + server_policy=policy, + server_policy_status=ntstatus.NT_STATUS_AUTHENTICATION_FIREWALL_FAILED, + event=AuditEvent.KERBEROS_SERVER_RESTRICTION, + reason=AuditReason.ACCESS_DENIED, + status=ntstatus.NT_STATUS_INVALID_WORKSTATION) + + def test_authn_policy_allowed_to_user_allow_as_req(self): + # Create a machine account with which to perform FAST. + mach_creds = self.get_cached_creds( + account_type=self.AccountType.COMPUTER) + mach_tgt = self.get_tgt(mach_creds) + + # Create a user account. + client_creds = self.get_cached_creds( + account_type=self.AccountType.USER) + + # Create an authentication policy that applies to a user and explicitly + # allows the user account to obtain a service ticket. + allowed = f'O:SYD:(A;;CR;;;{client_creds.get_sid()})' + denied = 'O:SYD:(D;;CR;;;WD)' + policy = self.create_authn_policy(enforced=True, + user_allowed_to=allowed, + computer_allowed_to=denied, + service_allowed_to=denied) + + # Create a user account with the assigned policy. + target_creds = self._get_creds(account_type=self.AccountType.USER, + assigned_policy=policy, + spn='host/{account}') + + # Show that obtaining a service ticket with an AS-REQ is allowed. + self._fast_as_req(client_creds, target_creds, mach_tgt) + + self.check_as_log(client_creds, + server_policy=policy) + + def test_authn_policy_allowed_to_user_deny_as_req(self): + # Create a machine account with which to perform FAST. + mach_creds = self.get_cached_creds( + account_type=self.AccountType.COMPUTER) + mach_tgt = self.get_tgt(mach_creds) + + # Create a user account. + client_creds = self.get_cached_creds( + account_type=self.AccountType.USER) + + # Create an authentication policy that applies to a user and + # explicitly denies the user account to obtain a service ticket. + denied = f'O:SYD:(D;;CR;;;{client_creds.get_sid()})' + allowed = 'O:SYD:(A;;CR;;;WD)' + policy = self.create_authn_policy(enforced=True, + user_allowed_to=denied, + computer_allowed_to=allowed, + service_allowed_to=allowed) + + # Create a user account with the assigned policy. + target_creds = self._get_creds(account_type=self.AccountType.USER, + assigned_policy=policy, + spn='host/{account}') + + # Show that obtaining a service ticket with an AS-REQ is denied. + self._fast_as_req( + client_creds, target_creds, mach_tgt, + expected_error=KDC_ERR_POLICY, + # We aren’t particular about whether or not we get an NTSTATUS. + expect_status=None, + expected_status=ntstatus.NT_STATUS_AUTHENTICATION_FIREWALL_FAILED) + + self.check_as_log( + client_creds, + server_policy=policy, + server_policy_status=ntstatus.NT_STATUS_AUTHENTICATION_FIREWALL_FAILED, + event=AuditEvent.KERBEROS_SERVER_RESTRICTION, + reason=AuditReason.ACCESS_DENIED, + status=ntstatus.NT_STATUS_INVALID_WORKSTATION) + + def test_authn_policy_allowed_to_service_allow_as_req(self): + # Create a machine account with which to perform FAST. + mach_creds = self.get_cached_creds( + account_type=self.AccountType.COMPUTER) + mach_tgt = self.get_tgt(mach_creds) + + # Create a user account. + client_creds = self.get_cached_creds( + account_type=self.AccountType.USER) + + # Create an authentication policy that applies to a managed service and + # explicitly allows the user account to obtain a service ticket. + allowed = f'O:SYD:(A;;CR;;;{client_creds.get_sid()})' + denied = 'O:SYD:(D;;CR;;;WD)' + policy = self.create_authn_policy(enforced=True, + user_allowed_to=denied, + computer_allowed_to=denied, + service_allowed_to=allowed) + + # Create a managed service account with the assigned policy. + target_creds = self._get_creds( + account_type=self.AccountType.MANAGED_SERVICE, + assigned_policy=policy) + + # Show that obtaining a service ticket with an AS-REQ is allowed. + self._fast_as_req(client_creds, target_creds, mach_tgt) + + self.check_as_log(client_creds, + server_policy=policy) + + def test_authn_policy_allowed_to_service_deny_as_req(self): + # Create a machine account with which to perform FAST. + mach_creds = self.get_cached_creds( + account_type=self.AccountType.COMPUTER) + mach_tgt = self.get_tgt(mach_creds) + + # Create a user account. + client_creds = self.get_cached_creds( + account_type=self.AccountType.USER) + + # Create an authentication policy that applies to a managed service and + # explicitly denies the user account to obtain a service ticket. + denied = f'O:SYD:(D;;CR;;;{client_creds.get_sid()})' + allowed = 'O:SYD:(A;;CR;;;WD)' + policy = self.create_authn_policy(enforced=True, + user_allowed_to=allowed, + computer_allowed_to=allowed, + service_allowed_to=denied) + + # Create a managed service account with the assigned policy. + target_creds = self._get_creds( + account_type=self.AccountType.MANAGED_SERVICE, + assigned_policy=policy) + + # Show that obtaining a service ticket with an AS-REQ is denied. + self._fast_as_req( + client_creds, target_creds, mach_tgt, + expected_error=KDC_ERR_POLICY, + # We aren’t particular about whether or not we get an NTSTATUS. + expect_status=None, + expected_status=ntstatus.NT_STATUS_AUTHENTICATION_FIREWALL_FAILED) + + self.check_as_log( + client_creds, + server_policy=policy, + server_policy_status=ntstatus.NT_STATUS_AUTHENTICATION_FIREWALL_FAILED, + event=AuditEvent.KERBEROS_SERVER_RESTRICTION, + reason=AuditReason.ACCESS_DENIED, + status=ntstatus.NT_STATUS_INVALID_WORKSTATION) + + def test_authn_policy_allowed_to_computer_allow_as_req_no_fast(self): + # Create a user account. -- Samba Shared Repository