--- /dev/null
+#!/usr/bin/env python3
+# Unix SMB/CIFS implementation.
+# Copyright (C) Stefan Metzmacher 2020
+# Copyright (C) Catalyst.Net Ltd 2022
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import sys
+import os
+
+sys.path.insert(0, 'bin/python')
+os.environ['PYTHONUNBUFFERED'] = '1'
+
+import random
+import re
+
+from samba.dcerpc import netlogon, security
+from samba.tests import DynamicTestCase, env_get_var_value
+from samba.tests.krb5 import kcrypto
+from samba.tests.krb5.kdc_base_test import GroupType, KDCBaseTest, Principal
+from samba.tests.krb5.raw_testcase import Krb5EncryptionKey, RawKerberosTest
+from samba.tests.krb5.rfc4120_constants import (
+ AES256_CTS_HMAC_SHA1_96,
+ ARCFOUR_HMAC_MD5,
+ KRB_TGS_REP,
+)
+
+SidType = RawKerberosTest.SidType
+
+global_asn1_print = False
+global_hexdump = False
+
+
+@DynamicTestCase
+class DeviceTests(KDCBaseTest):
+ # Placeholder objects that represent accounts undergoing testing.
+ user = object()
+ mach = object()
+ trust_user = object()
+ trust_mach = object()
+
+ # Constants for group SID attributes.
+ default_attrs = security.SE_GROUP_DEFAULT_FLAGS
+ resource_attrs = default_attrs | security.SE_GROUP_RESOURCE
+
+ asserted_identity = security.SID_AUTHENTICATION_AUTHORITY_ASSERTED_IDENTITY
+ compounded_auth = security.SID_COMPOUNDED_AUTHENTICATION
+
+ user_trust_domain = 'S-1-5-21-123-456-111'
+ mach_trust_domain = 'S-1-5-21-123-456-222'
+
+ def setUp(self):
+ super().setUp()
+ self.do_asn1_print = global_asn1_print
+ self.do_hexdump = global_hexdump
+
+ # Some general information on how Windows handles device info:
+
+ # All the SIDs in the computer's info3.sids end up in device.domain_groups
+ # (if they are in any domain), or in device.sids (if they are not). Even if
+ # netlogon.NETLOGON_EXTRA_SIDS is not set.
+
+ # The remainder of the SIDs in device.domain_groups come from an LDAP
+ # search of the computer's domain-local groups.
+
+ # None of the SIDs in the computer's logon_info.resource_groups.groups go
+ # anywhere. Even if netlogon.NETLOGON_RESOURCE_GROUPS is set.
+
+ # In summary:
+ # info3.base.groups => device.groups
+ # info3.sids => device.sids (if not in a domain)
+ # info3.sids => device.domain_groups (if in a domain)
+ # searched-for domain-local groups => device.domain_groups
+
+ # These searched-for domain-local groups are based on _all_ the groups in
+ # info3.base.groups and info3.sids. So if the account is no longer a member
+ # of a (universal or global) group that belongs to a domain-local group,
+ # but has that universal or global group in info3.base.groups or
+ # info3.sids, then the domain-local group will still get added to the
+ # PAC. But the resource groups don't affect this (presumably, they are
+ # being filtered out). Also, those groups the search is based on do not go
+ # in themselves, even if they are domain-local groups.
+
+ cases = [
+ {
+ # Make a TGS request to the krbtgt.
+ 'test': 'basic to krbtgt',
+ 'as:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'as:mach:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ # Indicate this request is to the krbtgt.
+ 'tgs:to_krbtgt': True,
+ 'tgs:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ },
+ {
+ # Make a TGS request to a service that supports SID compression.
+ 'test': 'device to service compressed',
+ 'as:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'as:mach:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:to_krbtgt': False,
+ 'tgs:compression': True,
+ 'tgs:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ # The compounded authentication SID indicates that we used FAST
+ # with a device's TGT.
+ (compounded_auth, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:device:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ frozenset([(security.SID_CLAIMS_VALID, SidType.RESOURCE_SID, default_attrs)]),
+ },
+ },
+ {
+ # Make a TGS request to a service that lacks support for SID
+ # compression.
+ 'test': 'device to service uncompressed',
+ 'as:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'as:mach:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:to_krbtgt': False,
+ # SID compression is unsupported.
+ 'tgs:compression': False,
+ # There is no change in the reply PAC.
+ 'tgs:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (compounded_auth, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:device:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ frozenset([(security.SID_CLAIMS_VALID, SidType.RESOURCE_SID, default_attrs)]),
+ },
+ },
+ {
+ # Make a TGS request to a service that lacks support for compound
+ # identity.
+ 'test': 'device to service no compound id',
+ 'as:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'as:mach:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:to_krbtgt': False,
+ # Compound identity is unsupported.
+ 'tgs:compound_id': False,
+ 'tgs:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (compounded_auth, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ # The device info is still generated.
+ 'tgs:device:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ frozenset([(security.SID_CLAIMS_VALID, SidType.RESOURCE_SID, default_attrs)]),
+ },
+ },
+ {
+ 'test': 'universal groups to krbtgt',
+ 'groups': {
+ # The user and computer each belong to a couple of universal
+ # groups.
+ 'group0': (GroupType.UNIVERSAL, {'group1'}),
+ 'group1': (GroupType.UNIVERSAL, {user}),
+ 'group2': (GroupType.UNIVERSAL, {'group3'}),
+ 'group3': (GroupType.UNIVERSAL, {mach}),
+ },
+ 'as:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ # The user's groups appear in the PAC of the TGT.
+ ('group0', SidType.BASE_SID, default_attrs),
+ ('group1', SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'as:mach:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ # So too for the computer's groups.
+ ('group2', SidType.BASE_SID, default_attrs),
+ ('group3', SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:to_krbtgt': True,
+ 'tgs:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ # The user's groups appear in the TGS reply PAC.
+ ('group0', SidType.BASE_SID, default_attrs),
+ ('group1', SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ },
+ {
+ 'test': 'universal groups to service',
+ 'groups': {
+ 'group0': (GroupType.UNIVERSAL, {'group1'}),
+ 'group1': (GroupType.UNIVERSAL, {user}),
+ 'group2': (GroupType.UNIVERSAL, {'group3'}),
+ 'group3': (GroupType.UNIVERSAL, {mach}),
+ },
+ 'as:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ ('group0', SidType.BASE_SID, default_attrs),
+ ('group1', SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'as:mach:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ ('group2', SidType.BASE_SID, default_attrs),
+ ('group3', SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:to_krbtgt': False,
+ 'tgs:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ ('group0', SidType.BASE_SID, default_attrs),
+ ('group1', SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (compounded_auth, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:device:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ # The computer's groups appear in the device info structure of
+ # the TGS reply PAC.
+ ('group2', SidType.BASE_SID, default_attrs),
+ ('group3', SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ frozenset([(security.SID_CLAIMS_VALID, SidType.RESOURCE_SID, default_attrs)]),
+ },
+ },
+ {
+ 'test': 'domain-local groups to krbtgt',
+ 'groups': {
+ # The user and computer each belong to a couple of domain-local
+ # groups.
+ 'group0': (GroupType.DOMAIN_LOCAL, {'group1'}),
+ 'group1': (GroupType.DOMAIN_LOCAL, {user}),
+ 'group2': (GroupType.DOMAIN_LOCAL, {'group3'}),
+ 'group3': (GroupType.DOMAIN_LOCAL, {mach}),
+ },
+ 'as:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ # The user's domain-local group memberships do not appear.
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'as:mach:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ # Nor do the computer's.
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:to_krbtgt': True,
+ 'tgs:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ # The user's groups do not appear in the TGS reply PAC.
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ },
+ {
+ 'test': 'domain-local groups to service compressed',
+ 'groups': {
+ 'group0': (GroupType.DOMAIN_LOCAL, {'group1'}),
+ 'group1': (GroupType.DOMAIN_LOCAL, {user}),
+ 'group2': (GroupType.DOMAIN_LOCAL, {'group3'}),
+ 'group3': (GroupType.DOMAIN_LOCAL, {mach}),
+ },
+ 'as:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'as:mach:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:to_krbtgt': False,
+ 'tgs:compression': True,
+ 'tgs:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ # These groups appear as resource SIDs.
+ ('group0', SidType.RESOURCE_SID, resource_attrs),
+ ('group1', SidType.RESOURCE_SID, resource_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (compounded_auth, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:device:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ # The computer's groups appear together as resource SIDs.
+ frozenset([
+ ('group2', SidType.RESOURCE_SID, resource_attrs),
+ ('group3', SidType.RESOURCE_SID, resource_attrs),
+ ]),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ frozenset([(security.SID_CLAIMS_VALID, SidType.RESOURCE_SID, default_attrs)]),
+ },
+ },
+ {
+ 'test': 'domain-local groups to service uncompressed',
+ 'groups': {
+ 'group0': (GroupType.DOMAIN_LOCAL, {'group1'}),
+ 'group1': (GroupType.DOMAIN_LOCAL, {user}),
+ 'group2': (GroupType.DOMAIN_LOCAL, {'group3'}),
+ 'group3': (GroupType.DOMAIN_LOCAL, {mach}),
+ },
+ 'as:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'as:mach:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:to_krbtgt': False,
+ 'tgs:compression': False,
+ 'tgs:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ # The user's groups now appear as extra SIDs.
+ ('group0', SidType.EXTRA_SID, resource_attrs),
+ ('group1', SidType.EXTRA_SID, resource_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (compounded_auth, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:device:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ # The computer's groups are still resource SIDs.
+ frozenset([
+ ('group2', SidType.RESOURCE_SID, resource_attrs),
+ ('group3', SidType.RESOURCE_SID, resource_attrs),
+ ]),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ frozenset([(security.SID_CLAIMS_VALID, SidType.RESOURCE_SID, default_attrs)]),
+ },
+ },
+ # Test what happens if the computer is removed from a group prior to
+ # the TGS request.
+ {
+ 'test': 'remove transitive domain-local groups to krbtgt',
+ 'groups': {
+ # The computer is transitively a member of a couple of
+ # domain-local groups...
+ 'dom-local-outer-0': (GroupType.DOMAIN_LOCAL, {'dom-local-inner'}),
+ 'dom-local-outer-1': (GroupType.DOMAIN_LOCAL, {'universal-inner'}),
+ # ...via another domain-local group and a universal group.
+ 'dom-local-inner': (GroupType.DOMAIN_LOCAL, {mach}),
+ 'universal-inner': (GroupType.UNIVERSAL, {mach}),
+ },
+ # Just prior to the TGS request, the computer is removed from both
+ # inner groups. Domain-local groups will have not been added to the
+ # PAC at this point.
+ 'tgs:mach:removed': {
+ 'dom-local-inner',
+ 'universal-inner',
+ },
+ 'as:mach:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ # Only the universal group appears in the PAC.
+ ('universal-inner', SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:to_krbtgt': True,
+ 'tgs:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ },
+ {
+ 'test': 'remove transitive domain-local groups to service compressed',
+ 'groups': {
+ 'dom-local-outer-0': (GroupType.DOMAIN_LOCAL, {'dom-local-inner'}),
+ 'dom-local-outer-1': (GroupType.DOMAIN_LOCAL, {'universal-inner'}),
+ 'dom-local-inner': (GroupType.DOMAIN_LOCAL, {mach}),
+ 'universal-inner': (GroupType.UNIVERSAL, {mach}),
+ },
+ 'tgs:mach:removed': {
+ 'dom-local-inner',
+ 'universal-inner',
+ },
+ 'as:mach:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ ('universal-inner', SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:to_krbtgt': False,
+ 'tgs:compression': True,
+ 'tgs:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (compounded_auth, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:device:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ # The universal group appears in the device info...
+ ('universal-inner', SidType.BASE_SID, default_attrs),
+ # ...along with the second domain-local group, even though the
+ # computer no longer belongs to it.
+ frozenset([
+ ('dom-local-outer-1', SidType.RESOURCE_SID, resource_attrs),
+ ]),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ frozenset([(security.SID_CLAIMS_VALID, SidType.RESOURCE_SID, default_attrs)]),
+ },
+ },
+ {
+ 'test': 'remove transitive domain-local groups to service uncompressed',
+ 'groups': {
+ 'dom-local-outer-0': (GroupType.DOMAIN_LOCAL, {'dom-local-inner'}),
+ 'dom-local-outer-1': (GroupType.DOMAIN_LOCAL, {'universal-inner'}),
+ 'dom-local-inner': (GroupType.DOMAIN_LOCAL, {mach}),
+ 'universal-inner': (GroupType.UNIVERSAL, {mach}),
+ },
+ 'tgs:mach:removed': {
+ 'dom-local-inner',
+ 'universal-inner',
+ },
+ 'as:mach:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ ('universal-inner', SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:to_krbtgt': False,
+ 'tgs:compression': False,
+ 'tgs:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (compounded_auth, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:device:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ ('universal-inner', SidType.BASE_SID, default_attrs),
+ frozenset([
+ ('dom-local-outer-1', SidType.RESOURCE_SID, resource_attrs),
+ ]),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ frozenset([(security.SID_CLAIMS_VALID, SidType.RESOURCE_SID, default_attrs)]),
+ },
+ },
+ # Test what happens if the computer is added to a group prior to the
+ # TGS request.
+ {
+ 'test': 'add transitive domain-local groups to krbtgt',
+ 'groups': {
+ # We create a pair of groups, to be used presently.
+ 'dom-local-outer': (GroupType.DOMAIN_LOCAL, {'universal-inner'}),
+ 'universal-inner': (GroupType.UNIVERSAL, {}),
+ },
+ # Just prior to the TGS request, the computer is added to the inner
+ # group.
+ 'tgs:mach:added': {
+ 'universal-inner',
+ },
+ 'as:mach:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:to_krbtgt': True,
+ 'tgs:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ },
+ {
+ 'test': 'add transitive domain-local groups to service compressed',
+ 'groups': {
+ 'dom-local-outer': (GroupType.DOMAIN_LOCAL, {'universal-inner'}),
+ 'universal-inner': (GroupType.UNIVERSAL, {}),
+ },
+ 'tgs:mach:added': {
+ 'universal-inner',
+ },
+ 'as:mach:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:to_krbtgt': False,
+ 'tgs:compression': True,
+ 'tgs:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (compounded_auth, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:device:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ # The computer was not a member of the universal group at the
+ # time of obtaining a TGT, and said group did not make it into
+ # the PAC. Group expansion is only concerned with domain-local
+ # groups, none of which the machine currently belongs
+ # to. Therefore, neither group is present in the device info
+ # structure.
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ frozenset([(security.SID_CLAIMS_VALID, SidType.RESOURCE_SID, default_attrs)]),
+ },
+ },
+ {
+ 'test': 'add transitive domain-local groups to service uncompressed',
+ 'groups': {
+ 'dom-local-outer': (GroupType.DOMAIN_LOCAL, {'universal-inner'}),
+ 'universal-inner': (GroupType.UNIVERSAL, {}),
+ },
+ 'tgs:mach:added': {
+ 'universal-inner',
+ },
+ 'as:mach:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:to_krbtgt': False,
+ 'tgs:compression': False,
+ 'tgs:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (compounded_auth, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:device:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ frozenset([(security.SID_CLAIMS_VALID, SidType.RESOURCE_SID, default_attrs)]),
+ },
+ },
+ # Simulate a machine ticket coming in over a trust.
+ {
+ 'test': 'from trust domain-local groups to service compressed',
+ 'groups': {
+ # The machine belongs to a couple of domain-local groups in our
+ # domain.
+ 'foo': (GroupType.DOMAIN_LOCAL, {trust_mach}),
+ 'bar': (GroupType.DOMAIN_LOCAL, {'foo'}),
+ },
+ 'tgs:to_krbtgt': False,
+ 'tgs:compression': True,
+ # The machine SID is from a different domain.
+ 'tgs:mach_sid': trust_mach,
+ 'tgs:mach:sids': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ # This dummy resource SID comes from the trusted domain.
+ (f'{mach_trust_domain}-333', SidType.RESOURCE_SID, resource_attrs),
+ },
+ 'tgs:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (compounded_auth, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:device:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ # The domain-local groups end up in the device info.
+ frozenset([
+ ('foo', SidType.RESOURCE_SID, resource_attrs),
+ ('bar', SidType.RESOURCE_SID, resource_attrs),
+ ]),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ frozenset([(security.SID_CLAIMS_VALID, SidType.RESOURCE_SID, default_attrs)]),
+ },
+ },
+ {
+ 'test': 'from trust domain-local groups to service uncompressed',
+ 'groups': {
+ 'foo': (GroupType.DOMAIN_LOCAL, {trust_mach}),
+ 'bar': (GroupType.DOMAIN_LOCAL, {'foo'}),
+ },
+ 'tgs:to_krbtgt': False,
+ 'tgs:compression': False,
+ 'tgs:mach_sid': trust_mach,
+ 'tgs:mach:sids': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ (f'{mach_trust_domain}-333', SidType.RESOURCE_SID, resource_attrs),
+ },
+ 'tgs:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (compounded_auth, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:device:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ frozenset([
+ ('foo', SidType.RESOURCE_SID, resource_attrs),
+ ('bar', SidType.RESOURCE_SID, resource_attrs),
+ ]),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ frozenset([(security.SID_CLAIMS_VALID, SidType.RESOURCE_SID, default_attrs)]),
+ },
+ },
+ # Simulate the user ticket coming in over a trust.
+ {
+ 'test': 'user from trust domain-local groups to krbtgt',
+ 'groups': {
+ # The user belongs to a couple of domain-local groups in our
+ # domain.
+ 'group0': (GroupType.DOMAIN_LOCAL, {trust_user}),
+ 'group1': (GroupType.DOMAIN_LOCAL, {'group0'}),
+ },
+ 'tgs:to_krbtgt': True,
+ # Both SIDs are from a different domain.
+ 'tgs:user_sid': trust_user,
+ 'tgs:user:sids': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ # This dummy resource SID comes from the trusted domain.
+ (f'{mach_trust_domain}-333', SidType.RESOURCE_SID, resource_attrs),
+ },
+ 'tgs:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ # The dummy resource SID remains in the PAC.
+ (f'{mach_trust_domain}-333', SidType.RESOURCE_SID, resource_attrs),
+ },
+ },
+ {
+ 'test': 'user from trust domain-local groups to service compressed',
+ 'groups': {
+ 'group0': (GroupType.DOMAIN_LOCAL, {trust_user}),
+ 'group1': (GroupType.DOMAIN_LOCAL, {'group0'}),
+ },
+ 'tgs:to_krbtgt': False,
+ 'tgs:compression': True,
+ 'tgs:user_sid': trust_user,
+ 'tgs:user:sids': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ # This dummy resource SID comes from the trusted domain.
+ (f'{mach_trust_domain}-333', SidType.RESOURCE_SID, resource_attrs),
+ },
+ 'tgs:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (compounded_auth, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ ('group0', SidType.RESOURCE_SID, resource_attrs),
+ ('group1', SidType.RESOURCE_SID, resource_attrs),
+ },
+ 'tgs:device:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ frozenset([(security.SID_CLAIMS_VALID, SidType.RESOURCE_SID, default_attrs)]),
+ },
+ },
+ {
+ 'test': 'user from trust domain-local groups to service uncompressed',
+ 'groups': {
+ 'group0': (GroupType.DOMAIN_LOCAL, {trust_user}),
+ 'group1': (GroupType.DOMAIN_LOCAL, {'group0'}),
+ },
+ 'tgs:to_krbtgt': False,
+ 'tgs:compression': False,
+ 'tgs:user_sid': trust_user,
+ 'tgs:user:sids': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ # This dummy resource SID comes from the trusted domain.
+ (f'{mach_trust_domain}-333', SidType.RESOURCE_SID, resource_attrs),
+ },
+ 'tgs:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (compounded_auth, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ ('group0', SidType.EXTRA_SID, resource_attrs),
+ ('group1', SidType.EXTRA_SID, resource_attrs),
+ },
+ 'tgs:device:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ frozenset([(security.SID_CLAIMS_VALID, SidType.RESOURCE_SID, default_attrs)]),
+ },
+ },
+ # Simulate both tickets coming in over a trust.
+ {
+ 'test': 'both from trust domain-local groups to krbtgt',
+ 'groups': {
+ # The user and machine each belong to a couple of domain-local
+ # groups in our domain.
+ 'group0': (GroupType.DOMAIN_LOCAL, {trust_user}),
+ 'group1': (GroupType.DOMAIN_LOCAL, {'group0'}),
+ 'group2': (GroupType.DOMAIN_LOCAL, {trust_mach}),
+ 'group3': (GroupType.DOMAIN_LOCAL, {'group2'}),
+ },
+ 'tgs:to_krbtgt': True,
+ # Both SIDs are from a different domain.
+ 'tgs:user_sid': trust_user,
+ 'tgs:mach_sid': trust_mach,
+ 'tgs:user:sids': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ # This dummy resource SID comes from the trusted domain.
+ (f'{mach_trust_domain}-333', SidType.RESOURCE_SID, resource_attrs),
+ },
+ 'tgs:mach:sids': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ # This dummy resource SID comes from the trusted domain.
+ (f'{mach_trust_domain}-444', SidType.RESOURCE_SID, resource_attrs),
+ },
+ 'tgs:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ # The dummy resource SID remains in the PAC.
+ (f'{mach_trust_domain}-333', SidType.RESOURCE_SID, resource_attrs),
+ },
+ },
+ {
+ 'test': 'both from trust domain-local groups to service compressed',
+ 'groups': {
+ # The machine belongs to a couple of domain-local groups in our
+ # domain.
+ 'group0': (GroupType.DOMAIN_LOCAL, {trust_user}),
+ 'group1': (GroupType.DOMAIN_LOCAL, {'group0'}),
+ 'group2': (GroupType.DOMAIN_LOCAL, {trust_mach}),
+ 'group3': (GroupType.DOMAIN_LOCAL, {'group2'}),
+ },
+ 'tgs:to_krbtgt': False,
+ 'tgs:compression': True,
+ 'tgs:user_sid': trust_user,
+ 'tgs:mach_sid': trust_mach,
+ 'tgs:user:sids': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ # This dummy resource SID comes from the trusted domain.
+ (f'{mach_trust_domain}-333', SidType.RESOURCE_SID, resource_attrs),
+ },
+ 'tgs:mach:sids': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ # This dummy resource SID comes from the trusted domain.
+ (f'{mach_trust_domain}-444', SidType.RESOURCE_SID, resource_attrs),
+ },
+ 'tgs:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (compounded_auth, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ ('group0', SidType.RESOURCE_SID, resource_attrs),
+ ('group1', SidType.RESOURCE_SID, resource_attrs),
+ },
+ 'tgs:device:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ # The domain-local groups end up in the device info.
+ frozenset([
+ ('group2', SidType.RESOURCE_SID, resource_attrs),
+ ('group3', SidType.RESOURCE_SID, resource_attrs),
+ ]),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ frozenset([(security.SID_CLAIMS_VALID, SidType.RESOURCE_SID, default_attrs)]),
+ },
+ },
+ {
+ 'test': 'both from trust domain-local groups to service uncompressed',
+ 'groups': {
+ 'group0': (GroupType.DOMAIN_LOCAL, {trust_user}),
+ 'group1': (GroupType.DOMAIN_LOCAL, {'group0'}),
+ 'group2': (GroupType.DOMAIN_LOCAL, {trust_mach}),
+ 'group3': (GroupType.DOMAIN_LOCAL, {'group2'}),
+ },
+ 'tgs:to_krbtgt': False,
+ 'tgs:compression': False,
+ 'tgs:user_sid': trust_user,
+ 'tgs:mach_sid': trust_mach,
+ 'tgs:user:sids': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ # This dummy resource SID comes from the trusted domain.
+ (f'{mach_trust_domain}-333', SidType.RESOURCE_SID, resource_attrs),
+ },
+ 'tgs:mach:sids': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ # This dummy resource SID comes from the trusted domain.
+ (f'{mach_trust_domain}-444', SidType.RESOURCE_SID, resource_attrs),
+ },
+ 'tgs:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (compounded_auth, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ ('group0', SidType.EXTRA_SID, resource_attrs),
+ ('group1', SidType.EXTRA_SID, resource_attrs),
+ },
+ 'tgs:device:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ frozenset([
+ ('group2', SidType.RESOURCE_SID, resource_attrs),
+ ('group3', SidType.RESOURCE_SID, resource_attrs),
+ ]),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ frozenset([(security.SID_CLAIMS_VALID, SidType.RESOURCE_SID, default_attrs)]),
+ },
+ },
+ # Test how resource SIDs are propagated into the device info structure.
+ {
+ 'test': 'mach resource sids',
+ 'tgs:mach:sids': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ # Of these SIDs, the Base SIDs and Extra SIDs are all
+ # propagated into the device info structure, regardless of
+ # their attrs, while the Resource SIDs are all dropped.
+ (123, SidType.BASE_SID, default_attrs),
+ (333, SidType.BASE_SID, default_attrs),
+ (333, SidType.BASE_SID, resource_attrs),
+ (1000, SidType.BASE_SID, resource_attrs),
+ (497, SidType.EXTRA_SID, resource_attrs), # the Claims Valid RID.
+ (333, SidType.RESOURCE_SID, default_attrs),
+ (498, SidType.RESOURCE_SID, resource_attrs),
+ (99999, SidType.RESOURCE_SID, default_attrs),
+ (12345678, SidType.RESOURCE_SID, resource_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:to_krbtgt': False,
+ 'tgs:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (compounded_auth, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:device:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ (123, SidType.BASE_SID, default_attrs),
+ (333, SidType.BASE_SID, default_attrs),
+ (333, SidType.BASE_SID, resource_attrs),
+ (1000, SidType.BASE_SID, resource_attrs),
+ frozenset({
+ (497, SidType.RESOURCE_SID, resource_attrs),
+ }),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ frozenset([(security.SID_CLAIMS_VALID, SidType.RESOURCE_SID, default_attrs)]),
+ },
+ },
+ # Add a Base SID to the user's PAC, and confirm it is propagated into
+ # the PAC of the service ticket.
+ {
+ 'test': 'base sid to krbtgt',
+ 'tgs:user:sids': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (123, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:to_krbtgt': True,
+ 'tgs:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (123, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ },
+ {
+ 'test': 'base sid to service',
+ 'tgs:user:sids': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (123, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:to_krbtgt': False,
+ 'tgs:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (123, SidType.BASE_SID, default_attrs),
+ (compounded_auth, SidType.EXTRA_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:device:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ frozenset([(security.SID_CLAIMS_VALID, SidType.RESOURCE_SID, default_attrs)]),
+ },
+ },
+ # Add a Base SID with resource attrs to the user's PAC, and confirm it
+ # is propagated into the PAC of the service ticket.
+ {
+ 'test': 'base sid resource attrs to krbtgt',
+ 'tgs:user:sids': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (123, SidType.BASE_SID, resource_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:to_krbtgt': True,
+ 'tgs:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (123, SidType.BASE_SID, resource_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ },
+ {
+ 'test': 'base sid resource attrs to service',
+ 'tgs:user:sids': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (123, SidType.BASE_SID, resource_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:to_krbtgt': False,
+ 'tgs:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (123, SidType.BASE_SID, resource_attrs),
+ (compounded_auth, SidType.EXTRA_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:device:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ frozenset([(security.SID_CLAIMS_VALID, SidType.RESOURCE_SID, default_attrs)]),
+ },
+ },
+ # Add a couple of Extra SIDs to the user's PAC, and confirm they are
+ # propagated into the PAC of the service ticket.
+ {
+ 'test': 'extra sids to krbtgt',
+ 'tgs:user:sids': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ ('S-1-5-2-3-4', SidType.EXTRA_SID, default_attrs),
+ ('S-1-5-2-3-5', SidType.EXTRA_SID, resource_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:to_krbtgt': True,
+ 'tgs:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ ('S-1-5-2-3-4', SidType.EXTRA_SID, default_attrs),
+ ('S-1-5-2-3-5', SidType.EXTRA_SID, resource_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ },
+ {
+ 'test': 'extra sids to service',
+ 'tgs:user:sids': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ ('S-1-5-2-3-4', SidType.EXTRA_SID, default_attrs),
+ ('S-1-5-2-3-5', SidType.EXTRA_SID, resource_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:to_krbtgt': False,
+ 'tgs:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ ('S-1-5-2-3-4', SidType.EXTRA_SID, default_attrs),
+ ('S-1-5-2-3-5', SidType.EXTRA_SID, resource_attrs),
+ (compounded_auth, SidType.EXTRA_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:device:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ frozenset([(security.SID_CLAIMS_VALID, SidType.RESOURCE_SID, default_attrs)]),
+ },
+ },
+ # Test what happens if we remove the CLAIMS_VALID and ASSERTED_IDENTITY
+ # SIDs from either of the PACs, so we can see at what point these SIDs
+ # are added.
+ {
+ 'test': 'removed special sids to krbtgt',
+ 'tgs:user:sids': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ ('S-1-5-2-3-4', SidType.EXTRA_SID, default_attrs),
+ # We don't specify asserted identity or claims valid SIDs for
+ # the user...
+ },
+ 'tgs:mach:sids': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ # ...nor for the computer.
+ },
+ 'tgs:to_krbtgt': True,
+ 'tgs:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ ('S-1-5-2-3-4', SidType.EXTRA_SID, default_attrs),
+ # They don't show up in the service ticket.
+ },
+ },
+ {
+ 'test': 'removed special sids to service',
+ 'tgs:user:sids': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ ('S-1-5-2-3-4', SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:mach:sids': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ },
+ 'tgs:to_krbtgt': False,
+ 'tgs:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ ('S-1-5-2-3-4', SidType.EXTRA_SID, default_attrs),
+ (compounded_auth, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:device:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ # These special SIDs don't show up in the device info either.
+ },
+ },
+ # Test a group being the primary one for the user and machine.
+ {
+ 'test': 'primary universal to krbtgt',
+ 'groups': {
+ 'primary-user': (GroupType.UNIVERSAL, {user}),
+ 'primary-mach': (GroupType.UNIVERSAL, {mach}),
+ },
+ # Set these groups as the account's primary groups.
+ 'primary_group': 'primary-user',
+ 'mach:primary_group': 'primary-mach',
+ 'as:expected': {
+ # They appear in the PAC as normal.
+ ('primary-user', SidType.BASE_SID, default_attrs),
+ ('primary-user', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'as:mach:expected': {
+ ('primary-mach', SidType.BASE_SID, default_attrs),
+ ('primary-mach', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:to_krbtgt': True,
+ 'tgs:expected': {
+ ('primary-user', SidType.BASE_SID, default_attrs),
+ ('primary-user', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ },
+ {
+ 'test': 'primary universal to service compressed',
+ 'groups': {
+ 'primary-user': (GroupType.UNIVERSAL, {user}),
+ 'primary-mach': (GroupType.UNIVERSAL, {mach}),
+ },
+ 'primary_group': 'primary-user',
+ 'mach:primary_group': 'primary-mach',
+ 'as:expected': {
+ ('primary-user', SidType.BASE_SID, default_attrs),
+ ('primary-user', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'as:mach:expected': {
+ ('primary-mach', SidType.BASE_SID, default_attrs),
+ ('primary-mach', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:to_krbtgt': False,
+ 'tgs:compression': True,
+ 'tgs:expected': {
+ ('primary-user', SidType.BASE_SID, default_attrs),
+ ('primary-user', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (compounded_auth, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:device:expected': {
+ ('primary-mach', SidType.BASE_SID, default_attrs),
+ ('primary-mach', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ frozenset([(security.SID_CLAIMS_VALID, SidType.RESOURCE_SID, default_attrs)]),
+ },
+ },
+ {
+ 'test': 'primary universal to service uncompressed',
+ 'groups': {
+ 'primary-user': (GroupType.UNIVERSAL, {user}),
+ 'primary-mach': (GroupType.UNIVERSAL, {mach}),
+ },
+ 'primary_group': 'primary-user',
+ 'mach:primary_group': 'primary-mach',
+ 'as:expected': {
+ ('primary-user', SidType.BASE_SID, default_attrs),
+ ('primary-user', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'as:mach:expected': {
+ ('primary-mach', SidType.BASE_SID, default_attrs),
+ ('primary-mach', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:to_krbtgt': False,
+ # SID compression is unsupported.
+ 'tgs:compression': False,
+ 'tgs:expected': {
+ ('primary-user', SidType.BASE_SID, default_attrs),
+ ('primary-user', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (compounded_auth, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:device:expected': {
+ ('primary-mach', SidType.BASE_SID, default_attrs),
+ ('primary-mach', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ frozenset([(security.SID_CLAIMS_VALID, SidType.RESOURCE_SID, default_attrs)]),
+ },
+ },
+ # Test domain-local primary groups.
+ {
+ 'test': 'primary domain-local to krbtgt',
+ 'groups': {
+ 'primary-user': (GroupType.DOMAIN_LOCAL, {user}),
+ 'primary-mach': (GroupType.DOMAIN_LOCAL, {mach}),
+ },
+ # Though Windows normally disallows setting domain-locals group as
+ # primary groups, Samba does not.
+ 'primary_group': 'primary-user',
+ 'mach:primary_group': 'primary-mach',
+ 'as:expected': {
+ # The domain-local groups appear as our primary GIDs, but do
+ # not appear in the base SIDs.
+ ('primary-user', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'as:mach:expected': {
+ ('primary-mach', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:to_krbtgt': True,
+ 'tgs:expected': {
+ ('primary-user', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ },
+ {
+ 'test': 'primary domain-local to service compressed',
+ 'groups': {
+ 'primary-user': (GroupType.DOMAIN_LOCAL, {user}),
+ 'primary-mach': (GroupType.DOMAIN_LOCAL, {mach}),
+ },
+ 'primary_group': 'primary-user',
+ 'mach:primary_group': 'primary-mach',
+ 'as:expected': {
+ ('primary-user', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'as:mach:expected': {
+ ('primary-mach', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:to_krbtgt': False,
+ 'tgs:compression': True,
+ 'tgs:expected': {
+ ('primary-user', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (compounded_auth, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:device:expected': {
+ ('primary-mach', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ frozenset([(security.SID_CLAIMS_VALID, SidType.RESOURCE_SID, default_attrs)]),
+ },
+ },
+ {
+ 'test': 'primary domain-local to service uncompressed',
+ 'groups': {
+ 'primary-user': (GroupType.DOMAIN_LOCAL, {user}),
+ 'primary-mach': (GroupType.DOMAIN_LOCAL, {mach}),
+ },
+ 'primary_group': 'primary-user',
+ 'mach:primary_group': 'primary-mach',
+ 'as:expected': {
+ ('primary-user', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'as:mach:expected': {
+ ('primary-mach', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:to_krbtgt': False,
+ # SID compression is unsupported.
+ 'tgs:compression': False,
+ 'tgs:expected': {
+ ('primary-user', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (compounded_auth, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:device:expected': {
+ ('primary-mach', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ frozenset([(security.SID_CLAIMS_VALID, SidType.RESOURCE_SID, default_attrs)]),
+ },
+ },
+ # Test the scenario where we belong to a now-domain-local group, and
+ # possess an old TGT issued when the group was still our primary one.
+ {
+ 'test': 'old primary domain-local to krbtgt',
+ 'groups': {
+ # Domain-local groups to which the accounts belong.
+ 'primary-user': (GroupType.DOMAIN_LOCAL, {user}),
+ 'primary-mach': (GroupType.DOMAIN_LOCAL, {mach}),
+ },
+ 'tgs:user:sids': {
+ # In the PACs, the groups have the attributes of an ordinary
+ # group...
+ ('primary-user', SidType.BASE_SID, default_attrs),
+ # ...and remain our primary ones.
+ ('primary-user', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:mach:sids': {
+ ('primary-mach', SidType.BASE_SID, default_attrs),
+ ('primary-mach', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:to_krbtgt': True,
+ 'tgs:expected': {
+ # The groups don't change.
+ ('primary-user', SidType.BASE_SID, default_attrs),
+ ('primary-user', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ },
+ {
+ 'test': 'old primary domain-local to service compressed',
+ 'groups': {
+ 'primary-user': (GroupType.DOMAIN_LOCAL, {user}),
+ 'primary-mach': (GroupType.DOMAIN_LOCAL, {mach}),
+ },
+ 'tgs:user:sids': {
+ ('primary-user', SidType.BASE_SID, default_attrs),
+ ('primary-user', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:mach:sids': {
+ ('primary-mach', SidType.BASE_SID, default_attrs),
+ ('primary-mach', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:to_krbtgt': False,
+ 'tgs:compression': True,
+ 'tgs:expected': {
+ ('primary-user', SidType.BASE_SID, default_attrs),
+ ('primary-user', SidType.PRIMARY_GID, None),
+ # The groups are added a second time to the PAC, now as
+ # resource groups.
+ ('primary-user', SidType.RESOURCE_SID, resource_attrs),
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (compounded_auth, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:device:expected': {
+ ('primary-mach', SidType.BASE_SID, default_attrs),
+ ('primary-mach', SidType.PRIMARY_GID, None),
+ frozenset([('primary-mach', SidType.RESOURCE_SID, resource_attrs)]),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ frozenset([(security.SID_CLAIMS_VALID, SidType.RESOURCE_SID, default_attrs)]),
+ },
+ },
+ {
+ 'test': 'old primary domain-local to service uncompressed',
+ 'groups': {
+ 'primary-user': (GroupType.DOMAIN_LOCAL, {user}),
+ 'primary-mach': (GroupType.DOMAIN_LOCAL, {mach}),
+ },
+ 'tgs:user:sids': {
+ ('primary-user', SidType.BASE_SID, default_attrs),
+ ('primary-user', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:mach:sids': {
+ ('primary-mach', SidType.BASE_SID, default_attrs),
+ ('primary-mach', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:to_krbtgt': False,
+ # SID compression is unsupported.
+ 'tgs:compression': False,
+ 'tgs:expected': {
+ ('primary-user', SidType.BASE_SID, default_attrs),
+ ('primary-user', SidType.PRIMARY_GID, None),
+ # This time, the group is added to Extra SIDs.
+ ('primary-user', SidType.EXTRA_SID, resource_attrs),
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (compounded_auth, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:device:expected': {
+ ('primary-mach', SidType.BASE_SID, default_attrs),
+ ('primary-mach', SidType.PRIMARY_GID, None),
+ frozenset([('primary-mach', SidType.RESOURCE_SID, resource_attrs)]),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ frozenset([(security.SID_CLAIMS_VALID, SidType.RESOURCE_SID, default_attrs)]),
+ },
+ },
+ # Test the scenario where each account possesses an old TGT issued when
+ # a now-domain-local group was still its primary one. The accounts no
+ # longer belong to those groups, which themselves belong to other
+ # domain-local groups.
+ {
+ 'test': 'old primary domain-local transitive to krbtgt',
+ 'groups': {
+ 'user-outer': (GroupType.DOMAIN_LOCAL, {'user-inner'}),
+ 'user-inner': (GroupType.DOMAIN_LOCAL, {}),
+ 'mach-outer': (GroupType.DOMAIN_LOCAL, {'mach-inner'}),
+ 'mach-inner': (GroupType.DOMAIN_LOCAL, {}),
+ },
+ 'tgs:user:sids': {
+ # In the PACs, the groups have the attributes of an ordinary
+ # group...
+ ('user-inner', SidType.BASE_SID, default_attrs),
+ # ...and remain our primary ones.
+ ('user-inner', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:mach:sids': {
+ ('mach-inner', SidType.BASE_SID, default_attrs),
+ ('mach-inner', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:to_krbtgt': True,
+ 'tgs:expected': {
+ # The groups don't change.
+ ('user-inner', SidType.BASE_SID, default_attrs),
+ ('user-inner', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ },
+ {
+ 'test': 'old primary domain-local transitive to service compressed',
+ 'groups': {
+ 'user-outer': (GroupType.DOMAIN_LOCAL, {'user-inner'}),
+ 'user-inner': (GroupType.DOMAIN_LOCAL, {}),
+ 'mach-outer': (GroupType.DOMAIN_LOCAL, {'mach-inner'}),
+ 'mach-inner': (GroupType.DOMAIN_LOCAL, {}),
+ },
+ 'tgs:user:sids': {
+ ('user-inner', SidType.BASE_SID, default_attrs),
+ ('user-inner', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:mach:sids': {
+ ('mach-inner', SidType.BASE_SID, default_attrs),
+ ('mach-inner', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:to_krbtgt': False,
+ 'tgs:compression': True,
+ 'tgs:expected': {
+ ('user-inner', SidType.BASE_SID, default_attrs),
+ ('user-inner', SidType.PRIMARY_GID, None),
+ # The second resource groups are added a second time to the PAC
+ # as resource groups.
+ ('user-outer', SidType.RESOURCE_SID, resource_attrs),
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (compounded_auth, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:device:expected': {
+ ('mach-inner', SidType.BASE_SID, default_attrs),
+ ('mach-inner', SidType.PRIMARY_GID, None),
+ frozenset([('mach-outer', SidType.RESOURCE_SID, resource_attrs)]),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ frozenset([(security.SID_CLAIMS_VALID, SidType.RESOURCE_SID, default_attrs)]),
+ },
+ },
+ {
+ 'test': 'old primary domain-local transitive to service uncompressed',
+ 'groups': {
+ 'user-outer': (GroupType.DOMAIN_LOCAL, {'user-inner'}),
+ 'user-inner': (GroupType.DOMAIN_LOCAL, {}),
+ 'mach-outer': (GroupType.DOMAIN_LOCAL, {'mach-inner'}),
+ 'mach-inner': (GroupType.DOMAIN_LOCAL, {}),
+ },
+ 'tgs:user:sids': {
+ ('user-inner', SidType.BASE_SID, default_attrs),
+ ('user-inner', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:mach:sids': {
+ ('mach-inner', SidType.BASE_SID, default_attrs),
+ ('mach-inner', SidType.PRIMARY_GID, None),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:to_krbtgt': False,
+ # SID compression is unsupported.
+ 'tgs:compression': False,
+ 'tgs:expected': {
+ ('user-inner', SidType.BASE_SID, default_attrs),
+ ('user-inner', SidType.PRIMARY_GID, None),
+ # This time, the group is added to Extra SIDs.
+ ('user-outer', SidType.EXTRA_SID, resource_attrs),
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (compounded_auth, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:device:expected': {
+ ('mach-inner', SidType.BASE_SID, default_attrs),
+ ('mach-inner', SidType.PRIMARY_GID, None),
+ frozenset([('mach-outer', SidType.RESOURCE_SID, resource_attrs)]),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ frozenset([(security.SID_CLAIMS_VALID, SidType.RESOURCE_SID, default_attrs)]),
+ },
+ },
+ # Test how the various categories of SIDs are propagated into the
+ # device info structure.
+ {
+ 'test': 'device info sid grouping',
+ 'tgs:mach:sids': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ # These base SIDs are simply propagated into the device info,
+ # irrespective of whatever attributes they have.
+ (1, SidType.BASE_SID, default_attrs),
+ (2, SidType.BASE_SID, 12345),
+ # Extra SIDs not from a domain are also propagated.
+ ('S-1-5-2-3-4', SidType.EXTRA_SID, 789),
+ ('S-1-5-20', SidType.EXTRA_SID, 999),
+ ('S-1-5-21', SidType.EXTRA_SID, 999),
+ ('S-1-6-0', SidType.EXTRA_SID, 999),
+ ('S-1-6-2-3-4', SidType.EXTRA_SID, 789),
+ # Extra SIDs from our own domain are collated into a group.
+ (3, SidType.EXTRA_SID, default_attrs),
+ (4, SidType.EXTRA_SID, 12345),
+ # Extra SIDs from other domains are collated into separate groups.
+ ('S-1-5-21-0-0-0-490', SidType.EXTRA_SID, 5),
+ ('S-1-5-21-0-0-0-491', SidType.EXTRA_SID, 6),
+ ('S-1-5-21-0-0-1-492', SidType.EXTRA_SID, 7),
+ ('S-1-5-21-0-0-1-493', SidType.EXTRA_SID, 8),
+ ('S-1-5-21-0-0-1-494', SidType.EXTRA_SID, 9),
+ # A non-domain SID (too few subauths), ...
+ ('S-1-5-21-242424-12345-2', SidType.EXTRA_SID, 1111111111),
+ # ... a domain SID, ...
+ ('S-1-5-21-242424-12345-321321-2', SidType.EXTRA_SID, 1111111111),
+ # ... and a non-domain SID (too many subauths).
+ ('S-1-5-21-242424-12345-321321-654321-2', SidType.EXTRA_SID, default_attrs),
+ # Special SIDs.
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:to_krbtgt': False,
+ 'tgs:expected': {
+ (security.DOMAIN_RID_USERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_USERS, SidType.PRIMARY_GID, None),
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ (compounded_auth, SidType.EXTRA_SID, default_attrs),
+ (security.SID_CLAIMS_VALID, SidType.EXTRA_SID, default_attrs),
+ },
+ 'tgs:device:expected': {
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.BASE_SID, default_attrs),
+ (security.DOMAIN_RID_DOMAIN_MEMBERS, SidType.PRIMARY_GID, None),
+ # Base SIDs.
+ (1, SidType.BASE_SID, default_attrs),
+ (2, SidType.BASE_SID, 12345),
+ # Extra SIDs from other domains.
+ ('S-1-5-2-3-4', SidType.EXTRA_SID, 789),
+ ('S-1-5-20', SidType.EXTRA_SID, 999),
+ ('S-1-5-21', SidType.EXTRA_SID, 999),
+ ('S-1-6-0', SidType.EXTRA_SID, 999),
+ ('S-1-6-2-3-4', SidType.EXTRA_SID, 789),
+ # Extra SIDs from our own domain.
+ frozenset({
+ (3, SidType.RESOURCE_SID, default_attrs),
+ (4, SidType.RESOURCE_SID, 12345),
+ }),
+ # Extra SIDs from other domains.
+ frozenset({
+ ('S-1-5-21-0-0-0-490', SidType.RESOURCE_SID, 5),
+ ('S-1-5-21-0-0-0-491', SidType.RESOURCE_SID, 6),
+ # These SIDs end up placed with the CLAIMS_VALID SID.
+ (security.SID_CLAIMS_VALID, SidType.RESOURCE_SID, default_attrs),
+ }),
+ frozenset({
+ ('S-1-5-21-0-0-1-492', SidType.RESOURCE_SID, 7),
+ ('S-1-5-21-0-0-1-493', SidType.RESOURCE_SID, 8),
+ ('S-1-5-21-0-0-1-494', SidType.RESOURCE_SID, 9),
+ }),
+ # Non-domain SID.
+ ('S-1-5-21-242424-12345-2', SidType.EXTRA_SID, 1111111111),
+ # Domain SID.
+ frozenset({
+ ('S-1-5-21-242424-12345-321321-2', SidType.RESOURCE_SID, 1111111111),
+ }),
+ # Non-domain SID.
+ ('S-1-5-21-242424-12345-321321-654321-2', SidType.EXTRA_SID, default_attrs),
+ # Special SIDs.
+ (asserted_identity, SidType.EXTRA_SID, default_attrs),
+ },
+ },
+ ]
+
+ @classmethod
+ def setUpDynamicTestCases(cls):
+ FILTER = env_get_var_value('FILTER', allow_missing=True)
+ SKIP_INVALID = env_get_var_value('SKIP_INVALID', allow_missing=True)
+
+ for case in cls.cases:
+ invalid = case.pop('configuration_invalid', False)
+ if SKIP_INVALID and invalid:
+ # Some group setups are invalid on Windows, so we allow them to
+ # be skipped.
+ continue
+ name = case.pop('test')
+ if FILTER and not re.search(FILTER, name):
+ continue
+ name = re.sub(r'\W+', '_', name)
+
+ cls.generate_dynamic_test('test_device_info', name,
+ dict(case))
+
+ def _test_device_info_with_args(self, case):
+ # The group arrangement for the test.
+ group_setup = case.pop('groups', None)
+
+ # Groups that should be the primary group for the user and machine
+ # respectively.
+ primary_group = case.pop('primary_group', None)
+ mach_primary_group = case.pop('mach:primary_group', None)
+
+ # Whether the TGS-REQ should be directed to the krbtgt.
+ tgs_to_krbtgt = case.pop('tgs:to_krbtgt', None)
+
+ # Whether the target server of the TGS-REQ should support compound
+ # identity or resource SID compression.
+ tgs_compound_id = case.pop('tgs:compound_id', None)
+ tgs_compression = case.pop('tgs:compression', None)
+
+ # Optional SIDs to replace those in the PACs prior to a TGS-REQ.
+ tgs_user_sids = case.pop('tgs:user:sids', None)
+ tgs_mach_sids = case.pop('tgs:mach:sids', None)
+
+ # Optional groups which the machine is added to or removed from prior
+ # to a TGS-REQ , to test how the groups in the device PAC are expanded.
+ tgs_mach_added = case.pop('tgs:mach:added', None)
+ tgs_mach_removed = case.pop('tgs:mach:removed', None)
+
+ # Optional account SIDs to replace those in the PACs prior to a
+ # TGS-REQ.
+ tgs_user_sid = case.pop('tgs:user_sid', None)
+ tgs_mach_sid = case.pop('tgs:mach_sid', None)
+
+ # User flags that may be set or reset in the PAC prior to a TGS-REQ.
+ tgs_mach_set_user_flags = case.pop('tgs:mach:set_user_flags', None)
+ tgs_mach_reset_user_flags = case.pop('tgs:mach:reset_user_flags', None)
+
+ # The SIDs we expect to see in the PAC after a AS-REQ or a TGS-REQ.
+ as_expected = case.pop('as:expected', None)
+ as_mach_expected = case.pop('as:mach:expected', None)
+ tgs_expected = case.pop('tgs:expected', None)
+ tgs_device_expected = case.pop('tgs:device:expected', None)
+
+ # There should be no parameters remaining in the testcase.
+ self.assertFalse(case, 'unexpected parameters in testcase')
+
+ if as_expected is None:
+ self.assertIsNotNone(tgs_expected,
+ 'no set of expected SIDs is provided')
+
+ if as_mach_expected is None:
+ self.assertIsNotNone(tgs_expected,
+ 'no set of expected machine SIDs is provided')
+
+ if tgs_to_krbtgt is None:
+ tgs_to_krbtgt = False
+
+ if tgs_compound_id is None and not tgs_to_krbtgt:
+ # Assume the service supports compound identity by default.
+ tgs_compound_id = True
+
+ if tgs_to_krbtgt:
+ self.assertIsNone(tgs_device_expected,
+ 'device SIDs are not added for a krbtgt request')
+
+ self.assertIsNotNone(tgs_expected,
+ 'no set of expected TGS SIDs is provided')
+
+ if tgs_user_sid is not None:
+ self.assertIsNotNone(tgs_user_sids,
+ 'specified TGS-REQ user SID, but no '
+ 'accompanying user SIDs provided')
+
+ if tgs_mach_sid is not None:
+ self.assertIsNotNone(tgs_mach_sids,
+ 'specified TGS-REQ mach SID, but no '
+ 'accompanying machine SIDs provided')
+
+ if tgs_mach_set_user_flags is None:
+ tgs_mach_set_user_flags = 0
+ else:
+ self.assertIsNotNone(tgs_mach_sids,
+ 'specified TGS-REQ set user flags, but no '
+ 'accompanying machine SIDs provided')
+
+ if tgs_mach_reset_user_flags is None:
+ tgs_mach_reset_user_flags = 0
+ else:
+ self.assertIsNotNone(tgs_mach_sids,
+ 'specified TGS-REQ reset user flags, but no '
+ 'accompanying machine SIDs provided')
+
+ user_use_cache = not group_setup and (
+ not primary_group)
+ mach_use_cache = not group_setup and (
+ not mach_primary_group) and (
+ not tgs_mach_added) and (
+ not tgs_mach_removed)
+
+ samdb = self.get_samdb()
+
+ domain_sid = samdb.get_domain_sid()
+
+ # Create the user account. It needs to be freshly created rather than
+ # cached if there is a possibility of adding it to one or more groups.
+ user_creds = self.get_cached_creds(
+ account_type=self.AccountType.USER,
+ use_cache=user_use_cache)
+ user_dn = user_creds.get_dn()
+ user_sid = self.get_objectSid(samdb, user_dn)
+ user_name = user_creds.get_username()
+
+ trust_user_rid = random.randint(2000, 0xfffffffe)
+ trust_user_sid = f'{self.user_trust_domain}-{trust_user_rid}'
+
+ trust_mach_rid = random.randint(2000, 0xfffffffe)
+ trust_mach_sid = f'{self.mach_trust_domain}-{trust_mach_rid}'
+
+ # Create the machine account. It needs to be freshly created rather
+ # than cached if there is a possibility of adding it to one or more
+ # groups.
+ mach_creds = self.get_cached_creds(
+ account_type=self.AccountType.COMPUTER,
+ use_cache=mach_use_cache)
+ mach_dn = mach_creds.get_dn()
+ mach_dn_str = str(mach_dn)
+ mach_sid = self.get_objectSid(samdb, mach_dn)
+
+ user_principal = Principal(user_dn, user_sid)
+ mach_principal = Principal(mach_dn, mach_sid)
+ trust_user_principal = Principal(None, trust_user_sid)
+ trust_mach_principal = Principal(None, trust_mach_sid)
+ preexisting_groups = {
+ self.user: user_principal,
+ self.mach: mach_principal,
+ self.trust_user: trust_user_principal,
+ self.trust_mach: trust_mach_principal,
+ }
+ primary_groups = {}
+ if primary_group is not None:
+ primary_groups[user_principal] = primary_group
+ if mach_primary_group is not None:
+ primary_groups[mach_principal] = mach_primary_group
+ groups = self.setup_groups(samdb,
+ preexisting_groups,
+ group_setup,
+ primary_groups)
+ del group_setup
+
+ if tgs_user_sid is None:
+ tgs_user_sid = user_sid
+ elif tgs_user_sid in groups:
+ tgs_user_sid = groups[tgs_user_sid].sid
+
+ tgs_user_domain_sid, tgs_user_rid = tgs_user_sid.rsplit('-', 1)
+
+ if tgs_mach_sid is None:
+ tgs_mach_sid = mach_sid
+ elif tgs_mach_sid in groups:
+ tgs_mach_sid = groups[tgs_mach_sid].sid
+
+ tgs_mach_domain_sid, tgs_mach_rid = tgs_mach_sid.rsplit('-', 1)
+
+ expected_groups = self.map_sids(as_expected, groups,
+ domain_sid)
+ mach_expected_groups = self.map_sids(as_mach_expected, groups,
+ domain_sid)
+ tgs_user_sids_mapped = self.map_sids(tgs_user_sids, groups,
+ tgs_user_domain_sid)
+ tgs_mach_sids_mapped = self.map_sids(tgs_mach_sids, groups,
+ tgs_mach_domain_sid)
+ tgs_expected_mapped = self.map_sids(tgs_expected, groups,
+ tgs_user_domain_sid)
+ tgs_device_expected_mapped = self.map_sids(tgs_device_expected, groups,
+ tgs_mach_domain_sid)
+
+ user_tgt = self.get_tgt(user_creds,
+ expected_groups=expected_groups,
+ unexpected_groups=None)
+
+ mach_tgt = self.get_tgt(mach_creds,
+ expected_groups=mach_expected_groups,
+ unexpected_groups=None)
+
+ if tgs_user_sids is not None:
+ # Replace the SIDs in the user's PAC with the ones provided by the
+ # test.
+ user_tgt = self.ticket_with_sids(user_tgt,
+ tgs_user_sids_mapped,
+ tgs_user_domain_sid,
+ tgs_user_rid)
+
+ if tgs_mach_sids is not None:
+ # Replace the SIDs in the machine's PAC with the ones provided by
+ # the test.
+ mach_tgt = self.ticket_with_sids(mach_tgt,
+ tgs_mach_sids_mapped,
+ tgs_mach_domain_sid,
+ tgs_mach_rid,
+ set_user_flags=tgs_mach_set_user_flags,
+ reset_user_flags=tgs_mach_reset_user_flags)
+
+ if tgs_mach_removed is not None:
+ for removed in tgs_mach_removed:
+ group_dn = self.map_to_dn(removed, groups, domain_sid=None)
+ self.remove_from_group(mach_dn, group_dn)
+
+ if tgs_mach_added is not None:
+ for added in tgs_mach_added:
+ group_dn = self.map_to_dn(added, groups, domain_sid=None)
+ self.add_to_group(mach_dn_str, group_dn, 'member',
+ expect_attr=False)
+
+ subkey = self.RandomKey(user_tgt.session_key.etype)
+
+ armor_subkey = self.RandomKey(subkey.etype)
+ explicit_armor_key = self.generate_armor_key(armor_subkey,
+ mach_tgt.session_key)
+ armor_key = kcrypto.cf2(explicit_armor_key.key,
+ subkey.key,
+ b'explicitarmor',
+ b'tgsarmor')
+ armor_key = Krb5EncryptionKey(armor_key, None)
+
+ target_creds, sname = self.get_target(
+ to_krbtgt=tgs_to_krbtgt,
+ compound_id=tgs_compound_id,
+ compression=tgs_compression)
+ srealm = target_creds.get_realm()
+
+ decryption_key = self.TicketDecryptionKey_from_creds(
+ target_creds)
+
+ target_supported_etypes = target_creds.tgs_supported_enctypes
+
+ etypes = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
+
+ kdc_options = '0'
+ pac_options = '1' # claims support
+
+ requester_sid = None
+ if tgs_to_krbtgt:
+ requester_sid = user_sid
+
+ expect_resource_groups_flag = None
+ if tgs_mach_reset_user_flags & netlogon.NETLOGON_RESOURCE_GROUPS:
+ expect_resource_groups_flag = False
+ elif tgs_mach_set_user_flags & netlogon.NETLOGON_RESOURCE_GROUPS:
+ expect_resource_groups_flag = True
+
+ # Perform a TGS-REQ with the user account.
+
+ kdc_exchange_dict = self.tgs_exchange_dict(
+ expected_crealm=user_tgt.crealm,
+ expected_cname=user_tgt.cname,
+ expected_srealm=srealm,
+ expected_sname=sname,
+ expected_account_name=user_name,
+ ticket_decryption_key=decryption_key,
+ generate_fast_fn=self.generate_simple_fast,
+ generate_fast_armor_fn=self.generate_ap_req,
+ check_rep_fn=self.generic_check_kdc_rep,
+ check_kdc_private_fn=self.generic_check_kdc_private,
+ tgt=user_tgt,
+ armor_key=armor_key,
+ armor_tgt=mach_tgt,
+ armor_subkey=armor_subkey,
+ pac_options=pac_options,
+ authenticator_subkey=subkey,
+ kdc_options=kdc_options,
+ expect_pac=True,
+ expect_pac_attrs=tgs_to_krbtgt,
+ expect_pac_attrs_pac_request=tgs_to_krbtgt,
+ expected_sid=tgs_user_sid,
+ expected_requester_sid=requester_sid,
+ expected_domain_sid=tgs_user_domain_sid,
+ expected_device_domain_sid=tgs_mach_domain_sid,
+ expected_supported_etypes=target_supported_etypes,
+ expect_resource_groups_flag=expect_resource_groups_flag,
+ expected_groups=tgs_expected_mapped,
+ unexpected_groups=None,
+ expect_device_claims=None,
+ expect_device_info=not tgs_to_krbtgt,
+ expected_device_groups=tgs_device_expected_mapped)
+
+ rep = self._generic_kdc_exchange(kdc_exchange_dict,
+ cname=None,
+ realm=srealm,
+ sname=sname,
+ etypes=etypes)
+ self.check_reply(rep, KRB_TGS_REP)
+
+
+if __name__ == '__main__':
+ global_asn1_print = False
+ global_hexdump = False
+ import unittest
+ unittest.main()