tests/krb5: Provide ticket enc-part key to tgs_req()
[samba.git] / python / samba / tests / krb5 / kdc_tgs_tests.py
1 #!/usr/bin/env python3
2 # Unix SMB/CIFS implementation.
3 # Copyright (C) Stefan Metzmacher 2020
4 # Copyright (C) 2020 Catalyst.Net Ltd
5 #
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.
10 #
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.
15 #
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/>.
18 #
19
20 import sys
21 import os
22
23 sys.path.insert(0, "bin/python")
24 os.environ["PYTHONUNBUFFERED"] = "1"
25
26 from samba.tests.krb5.kdc_base_test import KDCBaseTest
27 from samba.tests.krb5.rfc4120_constants import (
28     AES256_CTS_HMAC_SHA1_96,
29     ARCFOUR_HMAC_MD5,
30     KRB_ERROR,
31     KDC_ERR_BADMATCH,
32     NT_PRINCIPAL,
33     NT_SRV_INST,
34 )
35
36 global_asn1_print = False
37 global_hexdump = False
38
39
40 class KdcTgsTests(KDCBaseTest):
41
42     def setUp(self):
43         super().setUp()
44         self.do_asn1_print = global_asn1_print
45         self.do_hexdump = global_hexdump
46
47     def test_tgs_req_cname_does_not_not_match_authenticator_cname(self):
48         ''' Try and obtain a ticket from the TGS, but supply a cname
49             that differs from that provided to the krbtgt
50         '''
51         # Create the user account
52         samdb = self.get_samdb()
53         user_name = "tsttktusr"
54         (uc, _) = self.create_account(samdb, user_name)
55         realm = uc.get_realm().lower()
56
57         # Do the initial AS-REQ, should get a pre-authentication required
58         # response
59         etype = (AES256_CTS_HMAC_SHA1_96,)
60         cname = self.PrincipalName_create(
61             name_type=NT_PRINCIPAL, names=[user_name])
62         sname = self.PrincipalName_create(
63             name_type=NT_SRV_INST, names=["krbtgt", realm])
64
65         rep = self.as_req(cname, sname, realm, etype)
66         self.check_pre_authentication(rep)
67
68         # Do the next AS-REQ
69         padata = self.get_enc_timestamp_pa_data(uc, rep)
70         key = self.get_as_rep_key(uc, rep)
71         rep = self.as_req(cname, sname, realm, etype, padata=[padata])
72         self.check_as_reply(rep)
73
74         # Request a service ticket, but use a cname that does not match
75         # that in the original AS-REQ
76         enc_part2 = self.get_as_rep_enc_data(key, rep)
77         key = self.EncryptionKey_import(enc_part2['key'])
78         ticket = rep['ticket']
79
80         cname = self.PrincipalName_create(
81             name_type=NT_PRINCIPAL,
82             names=["Administrator"])
83         sname = self.PrincipalName_create(
84             name_type=NT_PRINCIPAL,
85             names=["host", samdb.host_dns_name()])
86
87         (rep, enc_part) = self.tgs_req(cname, sname, realm, ticket, key, etype,
88                                        expected_error_mode=KDC_ERR_BADMATCH)
89
90         self.assertIsNone(
91             enc_part,
92             "rep = {%s}, enc_part = {%s}" % (rep, enc_part))
93         self.assertEqual(KRB_ERROR, rep['msg-type'], "rep = {%s}" % rep)
94         self.assertEqual(
95             KDC_ERR_BADMATCH,
96             rep['error-code'],
97             "rep = {%s}" % rep)
98
99     def test_ldap_service_ticket(self):
100         '''Get a ticket to the ldap service
101         '''
102         # Create the user account
103         samdb = self.get_samdb()
104         user_name = "tsttktusr"
105         (uc, _) = self.create_account(samdb, user_name)
106         realm = uc.get_realm().lower()
107
108         # Do the initial AS-REQ, should get a pre-authentication required
109         # response
110         etype = (AES256_CTS_HMAC_SHA1_96,)
111         cname = self.PrincipalName_create(
112             name_type=NT_PRINCIPAL, names=[user_name])
113         sname = self.PrincipalName_create(
114             name_type=NT_SRV_INST, names=["krbtgt", realm])
115
116         rep = self.as_req(cname, sname, realm, etype)
117         self.check_pre_authentication(rep)
118
119         # Do the next AS-REQ
120         padata = self.get_enc_timestamp_pa_data(uc, rep)
121         key = self.get_as_rep_key(uc, rep)
122         rep = self.as_req(cname, sname, realm, etype, padata=[padata])
123         self.check_as_reply(rep)
124
125         enc_part2 = self.get_as_rep_enc_data(key, rep)
126         key = self.EncryptionKey_import(enc_part2['key'])
127         ticket = rep['ticket']
128
129         # Request a ticket to the ldap service
130         sname = self.PrincipalName_create(
131             name_type=NT_SRV_INST,
132             names=["ldap", samdb.host_dns_name()])
133
134         (rep, _) = self.tgs_req(
135             cname, sname, uc.get_realm(), ticket, key, etype,
136             service_creds=self.get_dc_creds())
137
138         self.check_tgs_reply(rep)
139
140     def test_get_ticket_for_host_service_of_machine_account(self):
141
142         # Create a user and machine account for the test.
143         #
144         samdb = self.get_samdb()
145         user_name = "tsttktusr"
146         (uc, dn) = self.create_account(samdb, user_name)
147         (mc, _) = self.create_account(samdb, "tsttktmac", machine_account=True)
148         realm = uc.get_realm().lower()
149
150         # Do the initial AS-REQ, should get a pre-authentication required
151         # response
152         etype = (AES256_CTS_HMAC_SHA1_96, ARCFOUR_HMAC_MD5)
153         cname = self.PrincipalName_create(
154             name_type=NT_PRINCIPAL, names=[user_name])
155         sname = self.PrincipalName_create(
156             name_type=NT_SRV_INST, names=["krbtgt", realm])
157
158         rep = self.as_req(cname, sname, realm, etype)
159         self.check_pre_authentication(rep)
160
161         # Do the next AS-REQ
162         padata = self.get_enc_timestamp_pa_data(uc, rep)
163         key = self.get_as_rep_key(uc, rep)
164         rep = self.as_req(cname, sname, realm, etype, padata=[padata])
165         self.check_as_reply(rep)
166
167         # Request a ticket to the host service on the machine account
168         ticket = rep['ticket']
169         enc_part2 = self.get_as_rep_enc_data(key, rep)
170         key = self.EncryptionKey_import(enc_part2['key'])
171         cname = self.PrincipalName_create(
172             name_type=NT_PRINCIPAL,
173             names=[user_name])
174         sname = self.PrincipalName_create(
175             name_type=NT_PRINCIPAL,
176             names=[mc.get_username()])
177
178         (rep, enc_part) = self.tgs_req(
179             cname, sname, uc.get_realm(), ticket, key, etype,
180             service_creds=mc)
181         self.check_tgs_reply(rep)
182
183         # Check the contents of the service ticket
184         ticket = rep['ticket']
185         enc_part = self.decode_service_ticket(mc, ticket)
186
187         pac_data = self.get_pac_data(enc_part['authorization-data'])
188         sid = self.get_objectSid(samdb, dn)
189         upn = "%s@%s" % (uc.get_username(), realm)
190         self.assertEqual(
191             uc.get_username(),
192             str(pac_data.account_name),
193             "rep = {%s},%s" % (rep, pac_data))
194         self.assertEqual(
195             uc.get_username(),
196             pac_data.logon_name,
197             "rep = {%s},%s" % (rep, pac_data))
198         self.assertEqual(
199             uc.get_realm(),
200             pac_data.domain_name,
201             "rep = {%s},%s" % (rep, pac_data))
202         self.assertEqual(
203             upn,
204             pac_data.upn,
205             "rep = {%s},%s" % (rep, pac_data))
206         self.assertEqual(
207             sid,
208             pac_data.account_sid,
209             "rep = {%s},%s" % (rep, pac_data))
210
211
212 if __name__ == "__main__":
213     global_asn1_print = True
214     global_hexdump = True
215     import unittest
216     unittest.main()