summaryrefslogtreecommitdiffstats
path: root/python/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py')
-rwxr-xr-xpython/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py818
1 files changed, 818 insertions, 0 deletions
diff --git a/python/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py b/python/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py
new file mode 100755
index 0000000..4feb3bb
--- /dev/null
+++ b/python/samba/tests/krb5/ms_kile_client_principal_lookup_tests.py
@@ -0,0 +1,818 @@
+#!/usr/bin/env python3
+# Unix SMB/CIFS implementation.
+# Copyright (C) Stefan Metzmacher 2020
+# Copyright (C) 2020 Catalyst.Net Ltd
+#
+# 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"
+
+from samba.dsdb import UF_DONT_REQUIRE_PREAUTH
+from samba.tests.krb5.kdc_base_test import KDCBaseTest
+from samba.tests.krb5.rfc4120_constants import (
+ AES256_CTS_HMAC_SHA1_96,
+ ARCFOUR_HMAC_MD5,
+ NT_ENTERPRISE_PRINCIPAL,
+ NT_PRINCIPAL,
+ NT_SRV_INST,
+ KDC_ERR_C_PRINCIPAL_UNKNOWN,
+ KDC_ERR_TGT_REVOKED,
+)
+
+global_asn1_print = False
+global_hexdump = False
+
+
+class MS_Kile_Client_Principal_Lookup_Tests(KDCBaseTest):
+ """ Tests for MS-KILE client principal look-up
+ See [MS-KILE]: Kerberos Protocol Extensions
+ section 3.3.5.6.1 Client Principal Lookup
+ """
+
+ def setUp(self):
+ super().setUp()
+ self.do_asn1_print = global_asn1_print
+ self.do_hexdump = global_hexdump
+
+ def check_pac(self, samdb, auth_data, uc, name, upn=None):
+
+ pac_data = self.get_pac_data(auth_data)
+ if upn is None:
+ upn = "%s@%s" % (name, uc.get_realm().lower())
+ if name.endswith('$'):
+ name = name[:-1]
+
+ self.assertEqual(
+ uc.get_username(),
+ str(pac_data.account_name),
+ "pac_data = {%s}" % str(pac_data))
+ self.assertEqual(
+ name,
+ pac_data.logon_name,
+ "pac_data = {%s}" % str(pac_data))
+ self.assertEqual(
+ uc.get_realm(),
+ pac_data.domain_name,
+ "pac_data = {%s}" % str(pac_data))
+ self.assertEqual(
+ upn,
+ pac_data.upn,
+ "pac_data = {%s}" % str(pac_data))
+ self.assertEqual(
+ uc.get_sid(),
+ pac_data.account_sid,
+ "pac_data = {%s}" % str(pac_data))
+
+ def test_nt_principal_step_1(self):
+ """ Step 1
+ For an NT_PRINCIPAL cname with no realm or the realm matches the
+ DC's domain
+ search for an account with the
+ sAMAccountName matching the cname.
+ """
+
+ # Create user and machine accounts for the test.
+ #
+ samdb = self.get_samdb()
+ user_name = "mskileusr"
+ (uc, dn) = self.create_account(samdb, user_name)
+ realm = uc.get_realm().lower()
+
+ mach_name = "mskilemac"
+ (mc, _) = self.create_account(samdb, mach_name,
+ account_type=self.AccountType.COMPUTER)
+
+ # Do the initial AS-REQ, should get a pre-authentication required
+ # response
+ etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
+ cname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL, names=[user_name])
+ sname = self.PrincipalName_create(
+ name_type=NT_SRV_INST, names=["krbtgt", realm])
+
+ rep = self.as_req(cname, sname, realm, etype)
+ self.check_pre_authentication(rep)
+
+ # Do the next AS-REQ
+ padata = self.get_enc_timestamp_pa_data(uc, rep)
+ key = self.get_as_rep_key(uc, rep)
+ rep = self.as_req(cname, sname, realm, etype, padata=[padata])
+ self.check_as_reply(rep)
+
+ # Request a ticket to the host service on the machine account
+ ticket = rep['ticket']
+ enc_part2 = self.get_as_rep_enc_data(key, rep)
+ key = self.EncryptionKey_import(enc_part2['key'])
+ cname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL,
+ names=[user_name])
+ sname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL,
+ names=[mc.get_username()])
+
+ (rep, enc_part) = self.tgs_req(
+ cname, sname, uc.get_realm(), ticket, key, etype,
+ creds=uc, service_creds=mc)
+ self.check_tgs_reply(rep)
+
+ # Check the contents of the pac, and the ticket
+ ticket = rep['ticket']
+ enc_part = self.decode_service_ticket(mc, ticket)
+ self.check_pac(samdb, enc_part['authorization-data'], uc, user_name)
+ # check the crealm and cname
+ cname = enc_part['cname']
+ self.assertEqual(NT_PRINCIPAL, cname['name-type'])
+ self.assertEqual(user_name.encode('UTF8'), cname['name-string'][0])
+ self.assertEqual(realm.upper().encode('UTF8'), enc_part['crealm'])
+
+ def test_nt_principal_step_2(self):
+ """ Step 2
+ If not found
+ search for sAMAccountName equal to the cname + "$"
+
+ """
+
+ # Create a machine account for the test.
+ #
+ samdb = self.get_samdb()
+ mach_name = "mskilemac"
+ (mc, dn) = self.create_account(samdb, mach_name,
+ account_type=self.AccountType.COMPUTER)
+ realm = mc.get_realm().lower()
+
+ # Do the initial AS-REQ, should get a pre-authentication required
+ # response
+ etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
+ cname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL, names=[mach_name])
+ sname = self.PrincipalName_create(
+ name_type=NT_SRV_INST, names=["krbtgt", realm])
+
+ rep = self.as_req(cname, sname, realm, etype)
+ self.check_pre_authentication(rep)
+
+ # Do the next AS-REQ
+ padata = self.get_enc_timestamp_pa_data(mc, rep)
+ key = self.get_as_rep_key(mc, rep)
+ rep = self.as_req(cname, sname, realm, etype, padata=[padata])
+ self.check_as_reply(rep)
+
+ # Request a ticket to the host service on the machine account
+ ticket = rep['ticket']
+ enc_part2 = self.get_as_rep_enc_data(key, rep)
+ key = self.EncryptionKey_import(enc_part2['key'])
+ cname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL,
+ names=[mach_name])
+ sname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL,
+ names=[mc.get_username()])
+
+ (rep, enc_part) = self.tgs_req(
+ cname, sname, mc.get_realm(), ticket, key, etype,
+ creds=mc, service_creds=mc)
+ self.check_tgs_reply(rep)
+
+ # Check the contents of the pac, and the ticket
+ ticket = rep['ticket']
+ enc_part = self.decode_service_ticket(mc, ticket)
+ self.check_pac(samdb, enc_part['authorization-data'], mc, mach_name + '$')
+ # check the crealm and cname
+ cname = enc_part['cname']
+ self.assertEqual(NT_PRINCIPAL, cname['name-type'])
+ self.assertEqual(mach_name.encode('UTF8'), cname['name-string'][0])
+ self.assertEqual(realm.upper().encode('UTF8'), enc_part['crealm'])
+
+ def test_nt_principal_step_3(self):
+ """ Step 3
+
+ If not found
+ search for a matching UPN name where the UPN is set to
+ cname@realm or cname@DC's domain name
+
+ """
+ # Create a user account for the test.
+ #
+ samdb = self.get_samdb()
+ user_name = "mskileusr"
+ upn_name = "mskileupn"
+ upn = upn_name + "@" + self.get_user_creds().get_realm().lower()
+ (uc, dn) = self.create_account(samdb, user_name, upn=upn)
+ realm = uc.get_realm().lower()
+
+ mach_name = "mskilemac"
+ (mc, _) = self.create_account(samdb, mach_name,
+ account_type=self.AccountType.COMPUTER)
+
+ # Do the initial AS-REQ, should get a pre-authentication required
+ # response
+ etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
+ cname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL, names=[upn_name])
+ sname = self.PrincipalName_create(
+ name_type=NT_SRV_INST, names=["krbtgt", realm])
+
+ rep = self.as_req(cname, sname, realm, etype)
+ self.check_pre_authentication(rep)
+
+ # Do the next AS-REQ
+ padata = self.get_enc_timestamp_pa_data(uc, rep)
+ key = self.get_as_rep_key(uc, rep)
+ rep = self.as_req(cname, sname, realm, etype, padata=[padata])
+ self.check_as_reply(rep)
+
+ # Request a ticket to the host service on the machine account
+ ticket = rep['ticket']
+ enc_part2 = self.get_as_rep_enc_data(key, rep)
+ key = self.EncryptionKey_import(enc_part2['key'])
+ cname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL,
+ names=[upn_name])
+ sname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL,
+ names=[mc.get_username()])
+
+ (rep, enc_part) = self.tgs_req(
+ cname, sname, uc.get_realm(), ticket, key, etype,
+ creds=uc, service_creds=mc)
+ self.check_tgs_reply(rep)
+
+ # Check the contents of the service ticket
+ ticket = rep['ticket']
+ enc_part = self.decode_service_ticket(mc, ticket)
+ self.check_pac(samdb, enc_part['authorization-data'], uc, upn_name)
+ # check the crealm and cname
+ cname = enc_part['cname']
+ self.assertEqual(NT_PRINCIPAL, cname['name-type'])
+ self.assertEqual(upn_name.encode('UTF8'), cname['name-string'][0])
+ self.assertEqual(realm.upper().encode('UTF8'), enc_part['crealm'])
+
+ def test_nt_principal_step_4_a(self):
+ """ Step 4, no pre-authentication
+ If not found and no pre-authentication
+ search for a matching altSecurityIdentity
+ """
+ # Create a user account for the test.
+ # with an altSecurityIdentity, and with UF_DONT_REQUIRE_PREAUTH
+ # set.
+ #
+ # note that in this case IDL_DRSCrackNames is called with
+ # pmsgIn.formatOffered set to
+ # DS_USER_PRINCIPAL_NAME_AND_ALTSECID
+ #
+ # setting UF_DONT_REQUIRE_PREAUTH seems to be the only way
+ # to trigger the no pre-auth step
+
+ samdb = self.get_samdb()
+ user_name = "mskileusr"
+ alt_name = "mskilealtsec"
+ (uc, dn) = self.create_account(samdb, user_name,
+ account_control=UF_DONT_REQUIRE_PREAUTH)
+ realm = uc.get_realm().lower()
+ alt_sec = "Kerberos:%s@%s" % (alt_name, realm)
+ self.add_attribute(samdb, dn, "altSecurityIdentities", alt_sec)
+
+ mach_name = "mskilemac"
+ (mc, _) = self.create_account(samdb, mach_name,
+ account_type=self.AccountType.COMPUTER)
+
+ # Do the initial AS-REQ, as we've set UF_DONT_REQUIRE_PREAUTH
+ # we should get a valid AS-RESP
+ # response
+ etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
+ cname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL, names=[alt_name])
+ sname = self.PrincipalName_create(
+ name_type=NT_SRV_INST, names=["krbtgt", realm])
+
+ rep = self.as_req(cname, sname, realm, etype)
+ self.check_as_reply(rep)
+ salt = "%s%s" % (realm.upper(), user_name)
+ key = self.PasswordKey_create(
+ rep['enc-part']['etype'],
+ uc.get_password(),
+ salt.encode('UTF8'),
+ rep['enc-part']['kvno'])
+
+ # Request a ticket to the host service on the machine account
+ ticket = rep['ticket']
+ enc_part2 = self.get_as_rep_enc_data(key, rep)
+ key = self.EncryptionKey_import(enc_part2['key'])
+ cname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL, names=[alt_name])
+ sname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL,
+ names=[mc.get_username()])
+
+ (rep, enc_part) = self.tgs_req(
+ cname, sname, uc.get_realm(), ticket, key, etype,
+ creds=uc, service_creds=mc, expect_pac=False,
+ expect_edata=False,
+ expected_error_mode=KDC_ERR_TGT_REVOKED)
+ self.check_error_rep(rep, KDC_ERR_TGT_REVOKED)
+
+ def test_nt_principal_step_4_b(self):
+ """ Step 4, pre-authentication
+ If not found and pre-authentication
+ search for a matching user principal name
+ """
+
+ # Create user and machine accounts for the test.
+ #
+ samdb = self.get_samdb()
+ user_name = "mskileusr"
+ alt_name = "mskilealtsec"
+ (uc, dn) = self.create_account(samdb, user_name)
+ realm = uc.get_realm().lower()
+ alt_sec = "Kerberos:%s@%s" % (alt_name, realm)
+ self.add_attribute(samdb, dn, "altSecurityIdentities", alt_sec)
+
+ mach_name = "mskilemac"
+ (mc, _) = self.create_account(samdb, mach_name,
+ account_type=self.AccountType.COMPUTER)
+
+ # Do the initial AS-REQ, should get a pre-authentication required
+ # response
+ etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
+ cname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL, names=[alt_name])
+ sname = self.PrincipalName_create(
+ name_type=NT_SRV_INST, names=["krbtgt", realm])
+
+ rep = self.as_req(cname, sname, realm, etype)
+ self.check_pre_authentication(rep)
+
+ # Do the next AS-REQ
+ padata = self.get_enc_timestamp_pa_data(uc, rep)
+ key = self.get_as_rep_key(uc, rep)
+ # Note: although we used the alt security id for the pre-auth
+ # we need to use the username for the auth
+ cname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL, names=[user_name])
+ rep = self.as_req(cname, sname, realm, etype, padata=[padata])
+ self.check_as_reply(rep)
+
+ # Request a ticket to the host service on the machine account
+ ticket = rep['ticket']
+ enc_part2 = self.get_as_rep_enc_data(key, rep)
+ key = self.EncryptionKey_import(enc_part2['key'])
+ cname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL,
+ names=[user_name])
+ sname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL,
+ names=[mc.get_username()])
+
+ (rep, enc_part) = self.tgs_req(
+ cname, sname, uc.get_realm(), ticket, key, etype,
+ creds=uc, service_creds=mc)
+ self.check_tgs_reply(rep)
+
+ # Check the contents of the pac, and the ticket
+ ticket = rep['ticket']
+ enc_part = self.decode_service_ticket(mc, ticket)
+ self.check_pac(samdb,
+ enc_part['authorization-data'], uc, user_name)
+ # check the crealm and cname
+ cname = enc_part['cname']
+ self.assertEqual(NT_PRINCIPAL, cname['name-type'])
+ self.assertEqual(user_name.encode('UTF8'), cname['name-string'][0])
+ self.assertEqual(realm.upper().encode('UTF8'), enc_part['crealm'])
+
+ def test_nt_principal_step_4_c(self):
+ """ Step 4, pre-authentication
+ If not found and pre-authentication
+ search for a matching user principal name
+
+ This test uses the altsecid, so the AS-REQ should fail.
+ """
+
+ # Create user and machine accounts for the test.
+ #
+ samdb = self.get_samdb()
+ user_name = "mskileusr"
+ alt_name = "mskilealtsec"
+ (uc, dn) = self.create_account(samdb, user_name)
+ realm = uc.get_realm().lower()
+ alt_sec = "Kerberos:%s@%s" % (alt_name, realm)
+ self.add_attribute(samdb, dn, "altSecurityIdentities", alt_sec)
+
+ mach_name = "mskilemac"
+ (mc, _) = self.create_account(samdb, mach_name,
+ account_type=self.AccountType.COMPUTER)
+
+ # Do the initial AS-REQ, should get a pre-authentication required
+ # response
+ etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
+ cname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL, names=[alt_name])
+ sname = self.PrincipalName_create(
+ name_type=NT_SRV_INST, names=["krbtgt", realm])
+
+ rep = self.as_req(cname, sname, realm, etype)
+ self.check_pre_authentication(rep)
+
+ # Do the next AS-REQ
+ padata = self.get_enc_timestamp_pa_data(uc, rep)
+ # Use the alternate security identifier
+ # this should fail
+ cname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL, names=[alt_sec])
+ rep = self.as_req(cname, sname, realm, etype, padata=[padata])
+ self.check_error_rep(rep, KDC_ERR_C_PRINCIPAL_UNKNOWN)
+
+ def test_enterprise_principal_step_1_3(self):
+ """ Steps 1-3
+ For an NT_ENTERPRISE_PRINCIPAL cname
+ search for a user principal name matching the cname
+
+ """
+
+ # Create a user account for the test.
+ #
+ samdb = self.get_samdb()
+ user_name = "mskileusr"
+ upn_name = "mskileupn"
+ upn = upn_name + "@" + self.get_user_creds().get_realm().lower()
+ (uc, dn) = self.create_account(samdb, user_name, upn=upn)
+ realm = uc.get_realm().lower()
+
+ mach_name = "mskilemac"
+ (mc, _) = self.create_account(samdb, mach_name,
+ account_type=self.AccountType.COMPUTER)
+
+ # Do the initial AS-REQ, should get a pre-authentication required
+ # response
+ etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
+ cname = self.PrincipalName_create(
+ name_type=NT_ENTERPRISE_PRINCIPAL, names=[upn])
+ sname = self.PrincipalName_create(
+ name_type=NT_SRV_INST, names=["krbtgt", realm])
+
+ rep = self.as_req(cname, sname, realm, etype)
+ self.check_pre_authentication(rep)
+
+ # Do the next AS-REQ
+ padata = self.get_enc_timestamp_pa_data(uc, rep)
+ key = self.get_as_rep_key(uc, rep)
+ rep = self.as_req(cname, sname, realm, etype, padata=[padata])
+ self.check_as_reply(rep)
+
+ # Request a ticket to the host service on the machine account
+ ticket = rep['ticket']
+ enc_part2 = self.get_as_rep_enc_data(key, rep)
+ key = self.EncryptionKey_import(enc_part2['key'])
+ cname = self.PrincipalName_create(
+ name_type=NT_ENTERPRISE_PRINCIPAL, names=[upn])
+ sname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL,
+ names=[mc.get_username()])
+
+ (rep, enc_part) = self.tgs_req(
+ cname, sname, uc.get_realm(), ticket, key, etype,
+ creds=uc, service_creds=mc)
+ self.check_tgs_reply(rep)
+
+ # Check the contents of the pac, and the ticket
+ ticket = rep['ticket']
+ enc_part = self.decode_service_ticket(mc, ticket)
+ self.check_pac(
+ samdb, enc_part['authorization-data'], uc, upn, upn=upn)
+ # check the crealm and cname
+ cname = enc_part['cname']
+ crealm = enc_part['crealm']
+ self.assertEqual(NT_ENTERPRISE_PRINCIPAL, cname['name-type'])
+ self.assertEqual(upn.encode('UTF8'), cname['name-string'][0])
+ self.assertEqual(realm.upper().encode('UTF8'), crealm)
+
+ def test_enterprise_principal_step_4(self):
+ """ Step 4
+
+ If that fails
+ search for an account where the sAMAccountName matches
+ the name before the @
+
+ """
+
+ # Create a user account for the test.
+ #
+ samdb = self.get_samdb()
+ user_name = "mskileusr"
+ (uc, dn) = self.create_account(samdb, user_name)
+ realm = uc.get_realm().lower()
+ ename = user_name + "@" + realm
+
+ mach_name = "mskilemac"
+ (mc, _) = self.create_account(samdb, mach_name,
+ account_type=self.AccountType.COMPUTER)
+
+ # Do the initial AS-REQ, should get a pre-authentication required
+ # response
+ etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
+ cname = self.PrincipalName_create(
+ name_type=NT_ENTERPRISE_PRINCIPAL, names=[ename])
+ sname = self.PrincipalName_create(
+ name_type=NT_SRV_INST, names=["krbtgt", realm])
+
+ rep = self.as_req(cname, sname, realm, etype)
+ self.check_pre_authentication(rep)
+
+ # Do the next AS-REQ
+ padata = self.get_enc_timestamp_pa_data(uc, rep)
+ key = self.get_as_rep_key(uc, rep)
+ rep = self.as_req(cname, sname, realm, etype, padata=[padata])
+ self.check_as_reply(rep)
+
+ # Request a ticket to the host service on the machine account
+ ticket = rep['ticket']
+ enc_part2 = self.get_as_rep_enc_data(key, rep)
+ key = self.EncryptionKey_import(enc_part2['key'])
+ cname = self.PrincipalName_create(
+ name_type=NT_ENTERPRISE_PRINCIPAL, names=[ename])
+ sname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL,
+ names=[mc.get_username()])
+
+ (rep, enc_part) = self.tgs_req(
+ cname, sname, uc.get_realm(), ticket, key, etype,
+ creds=uc, service_creds=mc)
+ self.check_tgs_reply(rep)
+
+ # Check the contents of the pac, and the ticket
+ ticket = rep['ticket']
+ enc_part = self.decode_service_ticket(mc, ticket)
+ self.check_pac(
+ samdb, enc_part['authorization-data'], uc, ename, upn=ename)
+ # check the crealm and cname
+ cname = enc_part['cname']
+ crealm = enc_part['crealm']
+ self.assertEqual(NT_ENTERPRISE_PRINCIPAL, cname['name-type'])
+ self.assertEqual(ename.encode('UTF8'), cname['name-string'][0])
+ self.assertEqual(realm.upper().encode('UTF8'), crealm)
+
+ def test_enterprise_principal_step_5(self):
+ """ Step 5
+
+ If that fails
+ search for an account where the sAMAccountName matches
+ the name before the @ with a $ appended.
+
+ """
+
+ # Create a user account for the test.
+ #
+ samdb = self.get_samdb()
+ user_name = "mskileusr"
+ (uc, _) = self.create_account(samdb, user_name)
+ realm = uc.get_realm().lower()
+
+ mach_name = "mskilemac"
+ (mc, dn) = self.create_account(samdb, mach_name,
+ account_type=self.AccountType.COMPUTER)
+ ename = mach_name + "@" + realm
+ uname = mach_name + "$@" + realm
+
+ # Do the initial AS-REQ, should get a pre-authentication required
+ # response
+ etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
+ cname = self.PrincipalName_create(
+ name_type=NT_ENTERPRISE_PRINCIPAL, names=[ename])
+ sname = self.PrincipalName_create(
+ name_type=NT_SRV_INST, names=["krbtgt", realm])
+
+ rep = self.as_req(cname, sname, realm, etype)
+ self.check_pre_authentication(rep)
+
+ # Do the next AS-REQ
+ padata = self.get_enc_timestamp_pa_data(mc, rep)
+ key = self.get_as_rep_key(mc, rep)
+ rep = self.as_req(cname, sname, realm, etype, padata=[padata])
+ self.check_as_reply(rep)
+
+ # Request a ticket to the host service on the machine account
+ ticket = rep['ticket']
+ enc_part2 = self.get_as_rep_enc_data(key, rep)
+ key = self.EncryptionKey_import(enc_part2['key'])
+ cname = self.PrincipalName_create(
+ name_type=NT_ENTERPRISE_PRINCIPAL, names=[ename])
+ sname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL,
+ names=[mc.get_username()])
+
+ (rep, enc_part) = self.tgs_req(
+ cname, sname, uc.get_realm(), ticket, key, etype,
+ creds=uc, service_creds=mc)
+ self.check_tgs_reply(rep)
+
+ # Check the contents of the pac, and the ticket
+ ticket = rep['ticket']
+ enc_part = self.decode_service_ticket(mc, ticket)
+ self.check_pac(
+ samdb, enc_part['authorization-data'], mc, ename, upn=uname)
+ # check the crealm and cname
+ cname = enc_part['cname']
+ crealm = enc_part['crealm']
+ self.assertEqual(NT_ENTERPRISE_PRINCIPAL, cname['name-type'])
+ self.assertEqual(ename.encode('UTF8'), cname['name-string'][0])
+ self.assertEqual(realm.upper().encode('UTF8'), crealm)
+
+ def test_enterprise_principal_step_6_a(self):
+ """ Step 6, no pre-authentication
+ If not found and no pre-authentication
+ search for a matching altSecurityIdentity
+ """
+ # Create a user account for the test.
+ # with an altSecurityIdentity, and with UF_DONT_REQUIRE_PREAUTH
+ # set.
+ #
+ # note that in this case IDL_DRSCrackNames is called with
+ # pmsgIn.formatOffered set to
+ # DS_USER_PRINCIPAL_NAME_AND_ALTSECID
+ #
+ # setting UF_DONT_REQUIRE_PREAUTH seems to be the only way
+ # to trigger the no pre-auth step
+
+ samdb = self.get_samdb()
+ user_name = "mskileusr"
+ alt_name = "mskilealtsec"
+ (uc, dn) = self.create_account(samdb, user_name,
+ account_control=UF_DONT_REQUIRE_PREAUTH)
+ realm = uc.get_realm().lower()
+ alt_sec = "Kerberos:%s@%s" % (alt_name, realm)
+ self.add_attribute(samdb, dn, "altSecurityIdentities", alt_sec)
+ ename = alt_name + "@" + realm
+
+ mach_name = "mskilemac"
+ (mc, _) = self.create_account(samdb, mach_name,
+ account_type=self.AccountType.COMPUTER)
+
+ # Do the initial AS-REQ, as we've set UF_DONT_REQUIRE_PREAUTH
+ # we should get a valid AS-RESP
+ # response
+ etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
+ cname = self.PrincipalName_create(
+ name_type=NT_ENTERPRISE_PRINCIPAL, names=[ename])
+ sname = self.PrincipalName_create(
+ name_type=NT_SRV_INST, names=["krbtgt", realm])
+
+ rep = self.as_req(cname, sname, realm, etype)
+ self.check_as_reply(rep)
+ salt = "%s%s" % (realm.upper(), user_name)
+ key = self.PasswordKey_create(
+ rep['enc-part']['etype'],
+ uc.get_password(),
+ salt.encode('UTF8'),
+ rep['enc-part']['kvno'])
+
+ # Request a ticket to the host service on the machine account
+ ticket = rep['ticket']
+ enc_part2 = self.get_as_rep_enc_data(key, rep)
+ key = self.EncryptionKey_import(enc_part2['key'])
+ cname = self.PrincipalName_create(
+ name_type=NT_ENTERPRISE_PRINCIPAL, names=[ename])
+ sname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL,
+ names=[mc.get_username()])
+
+ (rep, enc_part) = self.tgs_req(
+ cname, sname, uc.get_realm(), ticket, key, etype,
+ creds=uc, service_creds=mc, expect_pac=False,
+ expect_edata=False,
+ expected_error_mode=KDC_ERR_TGT_REVOKED)
+ self.check_error_rep(rep, KDC_ERR_TGT_REVOKED)
+
+ def test_nt_enterprise_principal_step_6_b(self):
+ """ Step 4, pre-authentication
+ If not found and pre-authentication
+ search for a matching user principal name
+ """
+
+ # Create user and machine accounts for the test.
+ #
+ samdb = self.get_samdb()
+ user_name = "mskileusr"
+ alt_name = "mskilealtsec"
+ (uc, dn) = self.create_account(samdb, user_name)
+ realm = uc.get_realm().lower()
+ alt_sec = "Kerberos:%s@%s" % (alt_name, realm)
+ self.add_attribute(samdb, dn, "altSecurityIdentities", alt_sec)
+ ename = alt_name + "@" + realm
+ uname = user_name + "@" + realm
+
+ mach_name = "mskilemac"
+ (mc, _) = self.create_account(samdb, mach_name,
+ account_type=self.AccountType.COMPUTER)
+
+ # Do the initial AS-REQ, should get a pre-authentication required
+ # response
+ etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
+ cname = self.PrincipalName_create(
+ name_type=NT_ENTERPRISE_PRINCIPAL, names=[ename])
+ sname = self.PrincipalName_create(
+ name_type=NT_SRV_INST, names=["krbtgt", realm])
+
+ rep = self.as_req(cname, sname, realm, etype)
+ self.check_pre_authentication(rep)
+
+ # Do the next AS-REQ
+ padata = self.get_enc_timestamp_pa_data(uc, rep)
+ key = self.get_as_rep_key(uc, rep)
+ # Note: although we used the alt security id for the pre-auth
+ # we need to use the username for the auth
+ cname = self.PrincipalName_create(
+ name_type=NT_ENTERPRISE_PRINCIPAL, names=[uname])
+ rep = self.as_req(cname, sname, realm, etype, padata=[padata])
+ self.check_as_reply(rep)
+
+ # Request a ticket to the host service on the machine account
+ ticket = rep['ticket']
+ enc_part2 = self.get_as_rep_enc_data(key, rep)
+ key = self.EncryptionKey_import(enc_part2['key'])
+ cname = self.PrincipalName_create(
+ name_type=NT_ENTERPRISE_PRINCIPAL,
+ names=[uname])
+ sname = self.PrincipalName_create(
+ name_type=NT_PRINCIPAL,
+ names=[mc.get_username()])
+
+ (rep, enc_part) = self.tgs_req(
+ cname, sname, uc.get_realm(), ticket, key, etype,
+ creds=uc, service_creds=mc)
+ self.check_tgs_reply(rep)
+
+ # Check the contents of the pac, and the ticket
+ ticket = rep['ticket']
+ enc_part = self.decode_service_ticket(mc, ticket)
+ self.check_pac(
+ samdb, enc_part['authorization-data'], uc, uname, upn=uname)
+ # check the crealm and cname
+ cname = enc_part['cname']
+ self.assertEqual(NT_ENTERPRISE_PRINCIPAL, cname['name-type'])
+ self.assertEqual(uname.encode('UTF8'), cname['name-string'][0])
+ self.assertEqual(realm.upper().encode('UTF8'), enc_part['crealm'])
+
+ def test_nt_principal_step_6_c(self):
+ """ Step 4, pre-authentication
+ If not found and pre-authentication
+ search for a matching user principal name
+
+ This test uses the altsecid, so the AS-REQ should fail.
+ """
+
+ # Create user and machine accounts for the test.
+ #
+ samdb = self.get_samdb()
+ user_name = "mskileusr"
+ alt_name = "mskilealtsec"
+ (uc, dn) = self.create_account(samdb, user_name)
+ realm = uc.get_realm().lower()
+ alt_sec = "Kerberos:%s@%s" % (alt_name, realm)
+ self.add_attribute(samdb, dn, "altSecurityIdentities", alt_sec)
+ ename = alt_name + "@" + realm
+
+ mach_name = "mskilemac"
+ (mc, _) = self.create_account(samdb, mach_name,
+ account_type=self.AccountType.COMPUTER)
+
+ # Do the initial AS-REQ, should get a pre-authentication required
+ # response
+ etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
+ cname = self.PrincipalName_create(
+ name_type=NT_ENTERPRISE_PRINCIPAL, names=[ename])
+ sname = self.PrincipalName_create(
+ name_type=NT_SRV_INST, names=["krbtgt", realm])
+
+ rep = self.as_req(cname, sname, realm, etype)
+ self.check_pre_authentication(rep)
+
+ # Do the next AS-REQ
+ padata = self.get_enc_timestamp_pa_data(uc, rep)
+ # Use the alternate security identifier
+ # this should fail
+ cname = self.PrincipalName_create(
+ name_type=NT_ENTERPRISE_PRINCIPAL, names=[ename])
+ rep = self.as_req(cname, sname, realm, etype, padata=[padata])
+ self.check_error_rep(rep, KDC_ERR_C_PRINCIPAL_UNKNOWN)
+
+
+if __name__ == "__main__":
+ global_asn1_print = False
+ global_hexdump = False
+ import unittest
+ unittest.main()