2 # Unix SMB/CIFS implementation.
3 # Copyright (C) Stefan Metzmacher 2020
4 # Copyright (C) 2020 Catalyst.Net Ltd
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
23 sys.path.insert(0, "bin/python")
24 os.environ["PYTHONUNBUFFERED"] = "1"
26 from samba.dsdb import UF_NORMAL_ACCOUNT, UF_DONT_REQUIRE_PREAUTH
27 from samba.tests.krb5.kdc_base_test import KDCBaseTest
28 from samba.tests.krb5.rfc4120_constants import (
29 AES256_CTS_HMAC_SHA1_96,
31 NT_ENTERPRISE_PRINCIPAL,
34 KDC_ERR_C_PRINCIPAL_UNKNOWN,
37 global_asn1_print = False
38 global_hexdump = False
41 class MS_Kile_Client_Principal_Lookup_Tests(KDCBaseTest):
42 ''' Tests for MS-KILE client principal look-up
43 See [MS-KILE]: Kerberos Protocol Extensions
44 secion 3.3.5.6.1 Client Principal Lookup
49 self.do_asn1_print = global_asn1_print
50 self.do_hexdump = global_hexdump
52 def check_pac(self, samdb, auth_data, dn, uc, name, upn=None):
54 pac_data = self.get_pac_data(auth_data)
55 sid = self.get_objectSid(samdb, dn)
57 upn = "%s@%s" % (name, uc.get_realm().lower())
58 if name.endswith('$'):
63 str(pac_data.account_name),
64 "pac_data = {%s}" % str(pac_data))
68 "pac_data = {%s}" % str(pac_data))
72 "pac_data = {%s}" % str(pac_data))
76 "pac_data = {%s}" % str(pac_data))
80 "pac_data = {%s}" % str(pac_data))
82 def test_nt_principal_step_1(self):
84 For an NT_PRINCIPAL cname with no realm or the realm matches the
86 search for an account with the
87 sAMAccountName matching the cname.
90 # Create user and machine accounts for the test.
92 samdb = self.get_samdb()
93 user_name = "mskileusr"
94 (uc, dn) = self.create_account(samdb, user_name)
95 realm = uc.get_realm().lower()
97 mach_name = "mskilemac"
98 (mc, _) = self.create_account(samdb, mach_name,
99 account_type=self.AccountType.COMPUTER)
101 # Do the initial AS-REQ, should get a pre-authentication required
103 etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
104 cname = self.PrincipalName_create(
105 name_type=NT_PRINCIPAL, names=[user_name])
106 sname = self.PrincipalName_create(
107 name_type=NT_SRV_INST, names=["krbtgt", realm])
109 rep = self.as_req(cname, sname, realm, etype)
110 self.check_pre_authentication(rep)
113 padata = self.get_enc_timestamp_pa_data(uc, rep)
114 key = self.get_as_rep_key(uc, rep)
115 rep = self.as_req(cname, sname, realm, etype, padata=[padata])
116 self.check_as_reply(rep)
118 # Request a ticket to the host service on the machine account
119 ticket = rep['ticket']
120 enc_part2 = self.get_as_rep_enc_data(key, rep)
121 key = self.EncryptionKey_import(enc_part2['key'])
122 cname = self.PrincipalName_create(
123 name_type=NT_PRINCIPAL,
125 sname = self.PrincipalName_create(
126 name_type=NT_PRINCIPAL,
127 names=[mc.get_username()])
129 (rep, enc_part) = self.tgs_req(
130 cname, sname, uc.get_realm(), ticket, key, etype,
132 self.check_tgs_reply(rep)
134 # Check the contents of the pac, and the ticket
135 ticket = rep['ticket']
136 enc_part = self.decode_service_ticket(mc, ticket)
137 self.check_pac(samdb, enc_part['authorization-data'], dn, uc, user_name)
138 # check the crealm and cname
139 cname = enc_part['cname']
140 self.assertEqual(NT_PRINCIPAL, cname['name-type'])
141 self.assertEqual(user_name.encode('UTF8'), cname['name-string'][0])
142 self.assertEqual(realm.upper().encode('UTF8'), enc_part['crealm'])
144 def test_nt_principal_step_2(self):
147 search for sAMAccountName equal to the cname + "$"
151 # Create a machine account for the test.
153 samdb = self.get_samdb()
154 mach_name = "mskilemac"
155 (mc, dn) = self.create_account(samdb, mach_name,
156 account_type=self.AccountType.COMPUTER)
157 realm = mc.get_realm().lower()
159 # Do the initial AS-REQ, should get a pre-authentication required
161 etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
162 cname = self.PrincipalName_create(
163 name_type=NT_PRINCIPAL, names=[mach_name])
164 sname = self.PrincipalName_create(
165 name_type=NT_SRV_INST, names=["krbtgt", realm])
167 rep = self.as_req(cname, sname, realm, etype)
168 self.check_pre_authentication(rep)
171 padata = self.get_enc_timestamp_pa_data(mc, rep)
172 key = self.get_as_rep_key(mc, rep)
173 rep = self.as_req(cname, sname, realm, etype, padata=[padata])
174 self.check_as_reply(rep)
176 # Request a ticket to the host service on the machine account
177 ticket = rep['ticket']
178 enc_part2 = self.get_as_rep_enc_data(key, rep)
179 key = self.EncryptionKey_import(enc_part2['key'])
180 cname = self.PrincipalName_create(
181 name_type=NT_PRINCIPAL,
183 sname = self.PrincipalName_create(
184 name_type=NT_PRINCIPAL,
185 names=[mc.get_username()])
187 (rep, enc_part) = self.tgs_req(
188 cname, sname, mc.get_realm(), ticket, key, etype,
190 self.check_tgs_reply(rep)
192 # Check the contents of the pac, and the ticket
193 ticket = rep['ticket']
194 enc_part = self.decode_service_ticket(mc, ticket)
195 self.check_pac(samdb, enc_part['authorization-data'], dn, mc, mach_name + '$')
196 # check the crealm and cname
197 cname = enc_part['cname']
198 self.assertEqual(NT_PRINCIPAL, cname['name-type'])
199 self.assertEqual(mach_name.encode('UTF8'), cname['name-string'][0])
200 self.assertEqual(realm.upper().encode('UTF8'), enc_part['crealm'])
202 def test_nt_principal_step_3(self):
206 search for a matching UPN name where the UPN is set to
207 cname@realm or cname@DC's domain name
210 # Create a user account for the test.
212 samdb = self.get_samdb()
213 user_name = "mskileusr"
214 upn_name = "mskileupn"
215 upn = upn_name + "@" + self.get_user_creds().get_realm().lower()
216 (uc, dn) = self.create_account(samdb, user_name, upn=upn)
217 realm = uc.get_realm().lower()
219 mach_name = "mskilemac"
220 (mc, _) = self.create_account(samdb, mach_name,
221 account_type=self.AccountType.COMPUTER)
223 # Do the initial AS-REQ, should get a pre-authentication required
225 etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
226 cname = self.PrincipalName_create(
227 name_type=NT_PRINCIPAL, names=[upn_name])
228 sname = self.PrincipalName_create(
229 name_type=NT_SRV_INST, names=["krbtgt", realm])
231 rep = self.as_req(cname, sname, realm, etype)
232 self.check_pre_authentication(rep)
235 padata = self.get_enc_timestamp_pa_data(uc, rep)
236 key = self.get_as_rep_key(uc, rep)
237 rep = self.as_req(cname, sname, realm, etype, padata=[padata])
238 self.check_as_reply(rep)
240 # Request a ticket to the host service on the machine account
241 ticket = rep['ticket']
242 enc_part2 = self.get_as_rep_enc_data(key, rep)
243 key = self.EncryptionKey_import(enc_part2['key'])
244 cname = self.PrincipalName_create(
245 name_type=NT_PRINCIPAL,
247 sname = self.PrincipalName_create(
248 name_type=NT_PRINCIPAL,
249 names=[mc.get_username()])
251 (rep, enc_part) = self.tgs_req(
252 cname, sname, uc.get_realm(), ticket, key, etype,
254 self.check_tgs_reply(rep)
256 # Check the contents of the service ticket
257 ticket = rep['ticket']
258 enc_part = self.decode_service_ticket(mc, ticket)
259 self.check_pac(samdb, enc_part['authorization-data'], dn, uc, upn_name)
260 # check the crealm and cname
261 cname = enc_part['cname']
262 self.assertEqual(NT_PRINCIPAL, cname['name-type'])
263 self.assertEqual(upn_name.encode('UTF8'), cname['name-string'][0])
264 self.assertEqual(realm.upper().encode('UTF8'), enc_part['crealm'])
266 def test_nt_principal_step_4_a(self):
267 ''' Step 4, no pre-authentication
268 If not found and no pre-authentication
269 search for a matching altSecurityIdentity
271 # Create a user account for the test.
272 # with an altSecurityIdentity, and with UF_DONT_REQUIRE_PREAUTH
275 # note that in this case IDL_DRSCrackNames is called with
276 # pmsgIn.formatOffered set to
277 # DS_USER_PRINCIPAL_NAME_AND_ALTSECID
279 # setting UF_DONT_REQUIRE_PREAUTH seems to be the only way
280 # to trigger the no pre-auth step
282 samdb = self.get_samdb()
283 user_name = "mskileusr"
284 alt_name = "mskilealtsec"
285 (uc, dn) = self.create_account(samdb, user_name,
286 account_control=UF_DONT_REQUIRE_PREAUTH)
287 realm = uc.get_realm().lower()
288 alt_sec = "Kerberos:%s@%s" % (alt_name, realm)
289 self.add_attribute(samdb, dn, "altSecurityIdentities", alt_sec)
291 mach_name = "mskilemac"
292 (mc, _) = self.create_account(samdb, mach_name,
293 account_type=self.AccountType.COMPUTER)
295 # Do the initial AS-REQ, as we've set UF_DONT_REQUIRE_PREAUTH
296 # we should get a valid AS-RESP
298 etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
299 cname = self.PrincipalName_create(
300 name_type=NT_PRINCIPAL, names=[alt_name])
301 sname = self.PrincipalName_create(
302 name_type=NT_SRV_INST, names=["krbtgt", realm])
304 rep = self.as_req(cname, sname, realm, etype)
305 self.check_as_reply(rep)
306 salt = "%s%s" % (realm.upper(), user_name)
307 key = self.PasswordKey_create(
308 rep['enc-part']['etype'],
311 rep['enc-part']['kvno'])
313 # Request a ticket to the host service on the machine account
314 ticket = rep['ticket']
315 enc_part2 = self.get_as_rep_enc_data(key, rep)
316 key = self.EncryptionKey_import(enc_part2['key'])
317 cname = self.PrincipalName_create(
318 name_type=NT_PRINCIPAL, names=[alt_name])
319 sname = self.PrincipalName_create(
320 name_type=NT_PRINCIPAL,
321 names=[mc.get_username()])
323 (rep, enc_part) = self.tgs_req(
324 cname, sname, uc.get_realm(), ticket, key, etype,
325 service_creds=mc, expect_pac=False)
326 self.check_tgs_reply(rep)
328 # Check the contents of the service ticket
329 ticket = rep['ticket']
330 enc_part = self.decode_service_ticket(mc, ticket)
332 # We get an empty authorization-data element in the ticket.
334 self.assertEqual([], enc_part['authorization-data'])
335 # check the crealm and cname
336 cname = enc_part['cname']
337 self.assertEqual(NT_PRINCIPAL, cname['name-type'])
338 self.assertEqual(alt_name.encode('UTF8'), cname['name-string'][0])
339 self.assertEqual(realm.upper().encode('UTF8'), enc_part['crealm'])
341 def test_nt_principal_step_4_b(self):
342 ''' Step 4, pre-authentication
343 If not found and pre-authentication
344 search for a matching user principal name
347 # Create user and machine accounts for the test.
349 samdb = self.get_samdb()
350 user_name = "mskileusr"
351 alt_name = "mskilealtsec"
352 (uc, dn) = self.create_account(samdb, user_name)
353 realm = uc.get_realm().lower()
354 alt_sec = "Kerberos:%s@%s" % (alt_name, realm)
355 self.add_attribute(samdb, dn, "altSecurityIdentities", alt_sec)
357 mach_name = "mskilemac"
358 (mc, _) = self.create_account(samdb, mach_name,
359 account_type=self.AccountType.COMPUTER)
361 # Do the initial AS-REQ, should get a pre-authentication required
363 etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
364 cname = self.PrincipalName_create(
365 name_type=NT_PRINCIPAL, names=[alt_name])
366 sname = self.PrincipalName_create(
367 name_type=NT_SRV_INST, names=["krbtgt", realm])
369 rep = self.as_req(cname, sname, realm, etype)
370 self.check_pre_authentication(rep)
373 padata = self.get_enc_timestamp_pa_data(uc, rep)
374 key = self.get_as_rep_key(uc, rep)
375 # Note: although we used the alt security id for the pre-auth
376 # we need to use the username for the auth
377 cname = self.PrincipalName_create(
378 name_type=NT_PRINCIPAL, names=[user_name])
379 rep = self.as_req(cname, sname, realm, etype, padata=[padata])
380 self.check_as_reply(rep)
382 # Request a ticket to the host service on the machine account
383 ticket = rep['ticket']
384 enc_part2 = self.get_as_rep_enc_data(key, rep)
385 key = self.EncryptionKey_import(enc_part2['key'])
386 cname = self.PrincipalName_create(
387 name_type=NT_PRINCIPAL,
389 sname = self.PrincipalName_create(
390 name_type=NT_PRINCIPAL,
391 names=[mc.get_username()])
393 (rep, enc_part) = self.tgs_req(
394 cname, sname, uc.get_realm(), ticket, key, etype,
396 self.check_tgs_reply(rep)
398 # Check the contents of the pac, and the ticket
399 ticket = rep['ticket']
400 enc_part = self.decode_service_ticket(mc, ticket)
401 self.check_pac(samdb,
402 enc_part['authorization-data'], dn, uc, user_name)
403 # check the crealm and cname
404 cname = enc_part['cname']
405 self.assertEqual(NT_PRINCIPAL, cname['name-type'])
406 self.assertEqual(user_name.encode('UTF8'), cname['name-string'][0])
407 self.assertEqual(realm.upper().encode('UTF8'), enc_part['crealm'])
409 def test_nt_principal_step_4_c(self):
410 ''' Step 4, pre-authentication
411 If not found and pre-authentication
412 search for a matching user principal name
414 This test uses the altsecid, so the AS-REQ should fail.
417 # Create user and machine accounts for the test.
419 samdb = self.get_samdb()
420 user_name = "mskileusr"
421 alt_name = "mskilealtsec"
422 (uc, dn) = self.create_account(samdb, user_name)
423 realm = uc.get_realm().lower()
424 alt_sec = "Kerberos:%s@%s" % (alt_name, realm)
425 self.add_attribute(samdb, dn, "altSecurityIdentities", alt_sec)
427 mach_name = "mskilemac"
428 (mc, _) = self.create_account(samdb, mach_name,
429 account_type=self.AccountType.COMPUTER)
431 # Do the initial AS-REQ, should get a pre-authentication required
433 etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
434 cname = self.PrincipalName_create(
435 name_type=NT_PRINCIPAL, names=[alt_name])
436 sname = self.PrincipalName_create(
437 name_type=NT_SRV_INST, names=["krbtgt", realm])
439 rep = self.as_req(cname, sname, realm, etype)
440 self.check_pre_authentication(rep)
443 padata = self.get_enc_timestamp_pa_data(uc, rep)
444 # Use the alternate security identifier
446 cname = self.PrincipalName_create(
447 name_type=NT_PRINCIPAL, names=[alt_sec])
448 rep = self.as_req(cname, sname, realm, etype, padata=[padata])
449 self.check_error_rep(rep, KDC_ERR_C_PRINCIPAL_UNKNOWN)
451 def test_enterprise_principal_step_1_3(self):
453 For an NT_ENTERPRISE_PRINCIPAL cname
454 search for a user principal name matching the cname
458 # Create a user account for the test.
460 samdb = self.get_samdb()
461 user_name = "mskileusr"
462 upn_name = "mskileupn"
463 upn = upn_name + "@" + self.get_user_creds().get_realm().lower()
464 (uc, dn) = self.create_account(samdb, user_name, upn=upn)
465 realm = uc.get_realm().lower()
467 mach_name = "mskilemac"
468 (mc, _) = self.create_account(samdb, mach_name,
469 account_type=self.AccountType.COMPUTER)
471 # Do the initial AS-REQ, should get a pre-authentication required
473 etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
474 cname = self.PrincipalName_create(
475 name_type=NT_ENTERPRISE_PRINCIPAL, names=[upn])
476 sname = self.PrincipalName_create(
477 name_type=NT_SRV_INST, names=["krbtgt", realm])
479 rep = self.as_req(cname, sname, realm, etype)
480 self.check_pre_authentication(rep)
483 padata = self.get_enc_timestamp_pa_data(uc, rep)
484 key = self.get_as_rep_key(uc, rep)
485 rep = self.as_req(cname, sname, realm, etype, padata=[padata])
486 self.check_as_reply(rep)
488 # Request a ticket to the host service on the machine account
489 ticket = rep['ticket']
490 enc_part2 = self.get_as_rep_enc_data(key, rep)
491 key = self.EncryptionKey_import(enc_part2['key'])
492 cname = self.PrincipalName_create(
493 name_type=NT_ENTERPRISE_PRINCIPAL, names=[upn])
494 sname = self.PrincipalName_create(
495 name_type=NT_PRINCIPAL,
496 names=[mc.get_username()])
498 (rep, enc_part) = self.tgs_req(
499 cname, sname, uc.get_realm(), ticket, key, etype,
501 self.check_tgs_reply(rep)
503 # Check the contents of the pac, and the ticket
504 ticket = rep['ticket']
505 enc_part = self.decode_service_ticket(mc, ticket)
507 samdb, enc_part['authorization-data'], dn, uc, upn, upn=upn)
508 # check the crealm and cname
509 cname = enc_part['cname']
510 crealm = enc_part['crealm']
511 self.assertEqual(NT_ENTERPRISE_PRINCIPAL, cname['name-type'])
512 self.assertEqual(upn.encode('UTF8'), cname['name-string'][0])
513 self.assertEqual(realm.upper().encode('UTF8'), crealm)
515 def test_enterprise_principal_step_4(self):
519 search for an account where the sAMAccountName matches
520 the name before the @
524 # Create a user account for the test.
526 samdb = self.get_samdb()
527 user_name = "mskileusr"
528 (uc, dn) = self.create_account(samdb, user_name)
529 realm = uc.get_realm().lower()
530 ename = user_name + "@" + realm
532 mach_name = "mskilemac"
533 (mc, _) = self.create_account(samdb, mach_name,
534 account_type=self.AccountType.COMPUTER)
536 # Do the initial AS-REQ, should get a pre-authentication required
538 etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
539 cname = self.PrincipalName_create(
540 name_type=NT_ENTERPRISE_PRINCIPAL, names=[ename])
541 sname = self.PrincipalName_create(
542 name_type=NT_SRV_INST, names=["krbtgt", realm])
544 rep = self.as_req(cname, sname, realm, etype)
545 self.check_pre_authentication(rep)
548 padata = self.get_enc_timestamp_pa_data(uc, rep)
549 key = self.get_as_rep_key(uc, rep)
550 rep = self.as_req(cname, sname, realm, etype, padata=[padata])
551 self.check_as_reply(rep)
553 # Request a ticket to the host service on the machine account
554 ticket = rep['ticket']
555 enc_part2 = self.get_as_rep_enc_data(key, rep)
556 key = self.EncryptionKey_import(enc_part2['key'])
557 cname = self.PrincipalName_create(
558 name_type=NT_ENTERPRISE_PRINCIPAL, names=[ename])
559 sname = self.PrincipalName_create(
560 name_type=NT_PRINCIPAL,
561 names=[mc.get_username()])
563 (rep, enc_part) = self.tgs_req(
564 cname, sname, uc.get_realm(), ticket, key, etype,
566 self.check_tgs_reply(rep)
568 # Check the contents of the pac, and the ticket
569 ticket = rep['ticket']
570 enc_part = self.decode_service_ticket(mc, ticket)
572 samdb, enc_part['authorization-data'], dn, uc, ename, upn=ename)
573 # check the crealm and cname
574 cname = enc_part['cname']
575 crealm = enc_part['crealm']
576 self.assertEqual(NT_ENTERPRISE_PRINCIPAL, cname['name-type'])
577 self.assertEqual(ename.encode('UTF8'), cname['name-string'][0])
578 self.assertEqual(realm.upper().encode('UTF8'), crealm)
580 def test_enterprise_principal_step_5(self):
584 search for an account where the sAMAccountName matches
585 the name before the @ with a $ appended.
589 # Create a user account for the test.
591 samdb = self.get_samdb()
592 user_name = "mskileusr"
593 (uc, _) = self.create_account(samdb, user_name)
594 realm = uc.get_realm().lower()
596 mach_name = "mskilemac"
597 (mc, dn) = self.create_account(samdb, mach_name,
598 account_type=self.AccountType.COMPUTER)
599 ename = mach_name + "@" + realm
600 uname = mach_name + "$@" + realm
602 # Do the initial AS-REQ, should get a pre-authentication required
604 etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
605 cname = self.PrincipalName_create(
606 name_type=NT_ENTERPRISE_PRINCIPAL, names=[ename])
607 sname = self.PrincipalName_create(
608 name_type=NT_SRV_INST, names=["krbtgt", realm])
610 rep = self.as_req(cname, sname, realm, etype)
611 self.check_pre_authentication(rep)
614 padata = self.get_enc_timestamp_pa_data(mc, rep)
615 key = self.get_as_rep_key(mc, rep)
616 rep = self.as_req(cname, sname, realm, etype, padata=[padata])
617 self.check_as_reply(rep)
619 # Request a ticket to the host service on the machine account
620 ticket = rep['ticket']
621 enc_part2 = self.get_as_rep_enc_data(key, rep)
622 key = self.EncryptionKey_import(enc_part2['key'])
623 cname = self.PrincipalName_create(
624 name_type=NT_ENTERPRISE_PRINCIPAL, names=[ename])
625 sname = self.PrincipalName_create(
626 name_type=NT_PRINCIPAL,
627 names=[mc.get_username()])
629 (rep, enc_part) = self.tgs_req(
630 cname, sname, uc.get_realm(), ticket, key, etype,
632 self.check_tgs_reply(rep)
634 # Check the contents of the pac, and the ticket
635 ticket = rep['ticket']
636 enc_part = self.decode_service_ticket(mc, ticket)
638 samdb, enc_part['authorization-data'], dn, mc, ename, upn=uname)
639 # check the crealm and cname
640 cname = enc_part['cname']
641 crealm = enc_part['crealm']
642 self.assertEqual(NT_ENTERPRISE_PRINCIPAL, cname['name-type'])
643 self.assertEqual(ename.encode('UTF8'), cname['name-string'][0])
644 self.assertEqual(realm.upper().encode('UTF8'), crealm)
646 def test_enterprise_principal_step_6_a(self):
647 ''' Step 6, no pre-authentication
648 If not found and no pre-authentication
649 search for a matching altSecurityIdentity
651 # Create a user account for the test.
652 # with an altSecurityIdentity, and with UF_DONT_REQUIRE_PREAUTH
655 # note that in this case IDL_DRSCrackNames is called with
656 # pmsgIn.formatOffered set to
657 # DS_USER_PRINCIPAL_NAME_AND_ALTSECID
659 # setting UF_DONT_REQUIRE_PREAUTH seems to be the only way
660 # to trigger the no pre-auth step
662 samdb = self.get_samdb()
663 user_name = "mskileusr"
664 alt_name = "mskilealtsec"
665 (uc, dn) = self.create_account(samdb, user_name,
666 account_control=UF_DONT_REQUIRE_PREAUTH)
667 realm = uc.get_realm().lower()
668 alt_sec = "Kerberos:%s@%s" % (alt_name, realm)
669 self.add_attribute(samdb, dn, "altSecurityIdentities", alt_sec)
670 ename = alt_name + "@" + realm
672 mach_name = "mskilemac"
673 (mc, _) = self.create_account(samdb, mach_name,
674 account_type=self.AccountType.COMPUTER)
676 # Do the initial AS-REQ, as we've set UF_DONT_REQUIRE_PREAUTH
677 # we should get a valid AS-RESP
679 etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
680 cname = self.PrincipalName_create(
681 name_type=NT_ENTERPRISE_PRINCIPAL, names=[ename])
682 sname = self.PrincipalName_create(
683 name_type=NT_SRV_INST, names=["krbtgt", realm])
685 rep = self.as_req(cname, sname, realm, etype)
686 self.check_as_reply(rep)
687 salt = "%s%s" % (realm.upper(), user_name)
688 key = self.PasswordKey_create(
689 rep['enc-part']['etype'],
692 rep['enc-part']['kvno'])
694 # Request a ticket to the host service on the machine account
695 ticket = rep['ticket']
696 enc_part2 = self.get_as_rep_enc_data(key, rep)
697 key = self.EncryptionKey_import(enc_part2['key'])
698 cname = self.PrincipalName_create(
699 name_type=NT_ENTERPRISE_PRINCIPAL, names=[ename])
700 sname = self.PrincipalName_create(
701 name_type=NT_PRINCIPAL,
702 names=[mc.get_username()])
704 (rep, enc_part) = self.tgs_req(
705 cname, sname, uc.get_realm(), ticket, key, etype,
706 service_creds=mc, expect_pac=False)
707 self.check_tgs_reply(rep)
709 # Check the contents of the service ticket
710 ticket = rep['ticket']
711 enc_part = self.decode_service_ticket(mc, ticket)
713 # We get an empty authorization-data element in the ticket.
715 self.assertEqual([], enc_part['authorization-data'])
716 # check the crealm and cname
717 cname = enc_part['cname']
718 self.assertEqual(NT_ENTERPRISE_PRINCIPAL, cname['name-type'])
719 self.assertEqual(ename.encode('UTF8'), cname['name-string'][0])
720 self.assertEqual(realm.upper().encode('UTF8'), enc_part['crealm'])
722 def test_nt_enterprise_principal_step_6_b(self):
723 ''' Step 4, pre-authentication
724 If not found and pre-authentication
725 search for a matching user principal name
728 # Create user and machine accounts for the test.
730 samdb = self.get_samdb()
731 user_name = "mskileusr"
732 alt_name = "mskilealtsec"
733 (uc, dn) = self.create_account(samdb, user_name)
734 realm = uc.get_realm().lower()
735 alt_sec = "Kerberos:%s@%s" % (alt_name, realm)
736 self.add_attribute(samdb, dn, "altSecurityIdentities", alt_sec)
737 ename = alt_name + "@" + realm
738 uname = user_name + "@" + realm
740 mach_name = "mskilemac"
741 (mc, _) = self.create_account(samdb, mach_name,
742 account_type=self.AccountType.COMPUTER)
744 # Do the initial AS-REQ, should get a pre-authentication required
746 etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
747 cname = self.PrincipalName_create(
748 name_type=NT_ENTERPRISE_PRINCIPAL, names=[ename])
749 sname = self.PrincipalName_create(
750 name_type=NT_SRV_INST, names=["krbtgt", realm])
752 rep = self.as_req(cname, sname, realm, etype)
753 self.check_pre_authentication(rep)
756 padata = self.get_enc_timestamp_pa_data(uc, rep)
757 key = self.get_as_rep_key(uc, rep)
758 # Note: although we used the alt security id for the pre-auth
759 # we need to use the username for the auth
760 cname = self.PrincipalName_create(
761 name_type=NT_ENTERPRISE_PRINCIPAL, names=[uname])
762 rep = self.as_req(cname, sname, realm, etype, padata=[padata])
763 self.check_as_reply(rep)
765 # Request a ticket to the host service on the machine account
766 ticket = rep['ticket']
767 enc_part2 = self.get_as_rep_enc_data(key, rep)
768 key = self.EncryptionKey_import(enc_part2['key'])
769 cname = self.PrincipalName_create(
770 name_type=NT_ENTERPRISE_PRINCIPAL,
772 sname = self.PrincipalName_create(
773 name_type=NT_PRINCIPAL,
774 names=[mc.get_username()])
776 (rep, enc_part) = self.tgs_req(
777 cname, sname, uc.get_realm(), ticket, key, etype,
779 self.check_tgs_reply(rep)
781 # Check the contents of the pac, and the ticket
782 ticket = rep['ticket']
783 enc_part = self.decode_service_ticket(mc, ticket)
785 samdb, enc_part['authorization-data'], dn, uc, uname, upn=uname)
786 # check the crealm and cname
787 cname = enc_part['cname']
788 self.assertEqual(NT_ENTERPRISE_PRINCIPAL, cname['name-type'])
789 self.assertEqual(uname.encode('UTF8'), cname['name-string'][0])
790 self.assertEqual(realm.upper().encode('UTF8'), enc_part['crealm'])
792 def test_nt_principal_step_6_c(self):
793 ''' Step 4, pre-authentication
794 If not found and pre-authentication
795 search for a matching user principal name
797 This test uses the altsecid, so the AS-REQ should fail.
800 # Create user and machine accounts for the test.
802 samdb = self.get_samdb()
803 user_name = "mskileusr"
804 alt_name = "mskilealtsec"
805 (uc, dn) = self.create_account(samdb, user_name)
806 realm = uc.get_realm().lower()
807 alt_sec = "Kerberos:%s@%s" % (alt_name, realm)
808 self.add_attribute(samdb, dn, "altSecurityIdentities", alt_sec)
809 ename = alt_name + "@" + realm
811 mach_name = "mskilemac"
812 (mc, _) = self.create_account(samdb, mach_name,
813 account_type=self.AccountType.COMPUTER)
815 # Do the initial AS-REQ, should get a pre-authentication required
817 etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
818 cname = self.PrincipalName_create(
819 name_type=NT_ENTERPRISE_PRINCIPAL, names=[ename])
820 sname = self.PrincipalName_create(
821 name_type=NT_SRV_INST, names=["krbtgt", realm])
823 rep = self.as_req(cname, sname, realm, etype)
824 self.check_pre_authentication(rep)
827 padata = self.get_enc_timestamp_pa_data(uc, rep)
828 # Use the alternate security identifier
830 cname = self.PrincipalName_create(
831 name_type=NT_ENTERPRISE_PRINCIPAL, names=[ename])
832 rep = self.as_req(cname, sname, realm, etype, padata=[padata])
833 self.check_error_rep(rep, KDC_ERR_C_PRINCIPAL_UNKNOWN)
836 if __name__ == "__main__":
837 global_asn1_print = False
838 global_hexdump = False