xref: /freebsd/crypto/krb5/src/tests/gssapi/t_gssapi.py (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1from k5test import *
2
3# Test krb5 negotiation under SPNEGO for all enctype configurations.  Also
4# test IOV wrap/unwrap with and without SPNEGO.
5for realm in multipass_realms():
6    realm.run(['./t_spnego','p:' + realm.host_princ, realm.keytab])
7    realm.run(['./t_iov', 'p:' + realm.host_princ])
8    realm.run(['./t_iov', '-s', 'p:' + realm.host_princ])
9    realm.run(['./t_pcontok', 'p:' + realm.host_princ])
10
11realm = K5Realm()
12
13# Test gss_add_cred().
14realm.run(['./t_add_cred'])
15
16### Test acceptor name behavior.
17
18# Create some host-based principals and put most of them into the
19# keytab.  Rename one principal so that the keytab name matches the
20# key but not the client name.
21realm.run([kadminl, 'addprinc', '-randkey', 'service1/abraham'])
22realm.run([kadminl, 'addprinc', '-randkey', 'service1/barack'])
23realm.run([kadminl, 'addprinc', '-randkey', 'service2/calvin'])
24realm.run([kadminl, 'addprinc', '-randkey', 'service2/dwight'])
25realm.run([kadminl, 'addprinc', '-randkey', 'host/-nomatch-'])
26realm.run([kadminl, 'addprinc', '-randkey', 'http/localhost'])
27realm.run([kadminl, 'xst', 'service1/abraham'])
28realm.run([kadminl, 'xst', 'service1/barack'])
29realm.run([kadminl, 'xst', 'service2/calvin'])
30realm.run([kadminl, 'xst', 'http/localhost'])
31realm.run([kadminl, 'renprinc', 'service1/abraham', 'service1/andrew'])
32
33# Test with no default realm and no dots in the server name.
34realm.run(['./t_accname', 'h:http@localhost'], expected_msg='http/localhost')
35remove_default = {'libdefaults': {'default_realm': None}}
36no_default = realm.special_env('no_default', False, krb5_conf=remove_default)
37realm.run(['./t_accname', 'h:http@localhost'], expected_msg='http/localhost',
38          env=no_default)
39
40# Test with no acceptor name, including client/keytab principal
41# mismatch (non-fatal) and missing keytab entry (fatal).
42realm.run(['./t_accname', 'p:service1/andrew'],
43          expected_msg='service1/abraham')
44realm.run(['./t_accname', 'p:service1/barack'], expected_msg='service1/barack')
45realm.run(['./t_accname', 'p:service2/calvin'], expected_msg='service2/calvin')
46realm.run(['./t_accname', 'p:service2/dwight'], expected_code=1,
47          expected_msg=' not found in keytab')
48
49# Test with acceptor name containing service only, including
50# client/keytab hostname mismatch (non-fatal) and service name
51# mismatch (fatal).
52realm.run(['./t_accname', 'p:service1/andrew', 'h:service1'],
53          expected_msg='service1/abraham')
54realm.run(['./t_accname', 'p:service1/andrew', 'h:service2'], expected_code=1,
55          expected_msg=' not found in keytab')
56realm.run(['./t_accname', 'p:service2/calvin', 'h:service2'],
57          expected_msg='service2/calvin')
58realm.run(['./t_accname', 'p:service2/calvin', 'h:service1'], expected_code=1,
59          expected_msg=' found in keytab but does not match server principal')
60# Regression test for #8892 (trailing @ in name).
61realm.run(['./t_accname', 'p:service1/andrew', 'h:service1@'],
62          expected_msg='service1/abraham')
63
64# Test with acceptor name containing service and host.  Use the
65# client's un-canonicalized hostname as acceptor input to mirror what
66# many servers do.
67realm.run(['./t_accname', 'p:' + realm.host_princ,
68           'h:host@%s' % socket.gethostname()], expected_msg=realm.host_princ)
69realm.run(['./t_accname', 'p:host/-nomatch-',
70           'h:host@%s' % socket.gethostname()], expected_code=1,
71          expected_msg=' not found in keytab')
72
73# If possible, test with an acceptor name requiring fallback to match
74# against a keytab entry.
75canonname = canonicalize_hostname(hostname)
76if canonname != hostname:
77    os.rename(realm.keytab, realm.keytab + '.save')
78    canonprinc = 'host/' + canonname
79    realm.run([kadminl, 'addprinc', '-randkey', canonprinc])
80    realm.extract_keytab(canonprinc, realm.keytab)
81    # Use the canonical name for the initiator's target name, since
82    # host/hostname exists in the KDB (but not the keytab).
83    realm.run(['./t_accname', 'h:host@' + canonname, 'h:host@' + hostname])
84    os.rename(realm.keytab + '.save', realm.keytab)
85else:
86    skipped('GSS acceptor name fallback test',
87            '%s does not canonicalize to a different name' % hostname)
88
89# Test krb5_gss_import_cred.
90realm.run(['./t_imp_cred', 'p:service1/barack'])
91realm.run(['./t_imp_cred', 'p:service1/barack', 'service1/barack'])
92realm.run(['./t_imp_cred', 'p:service1/andrew', 'service1/abraham'])
93realm.run(['./t_imp_cred', 'p:service2/dwight'], expected_code=1,
94          expected_msg=' not found in keytab')
95
96# Verify that we can't acquire acceptor creds without a keytab.
97os.remove(realm.keytab)
98out = realm.run(['./t_accname', 'p:abc'], expected_code=1)
99if ('gss_acquire_cred: Keytab' not in out or
100    'nonexistent or empty' not in out):
101    fail('Expected error message not seen for nonexistent keytab')
102
103realm.stop()
104
105# Re-run the last acceptor name test with ignore_acceptor_hostname set
106# and the principal for the mismatching hostname in the keytab.
107ignore_conf = {'libdefaults': {'ignore_acceptor_hostname': 'true'}}
108realm = K5Realm(krb5_conf=ignore_conf)
109realm.run([kadminl, 'addprinc', '-randkey', 'host/-nomatch-'])
110realm.run([kadminl, 'xst', 'host/-nomatch-'])
111realm.run(['./t_accname', 'p:host/-nomatch-',
112           'h:host@%s' % socket.gethostname()], expected_msg='host/-nomatch-')
113
114realm.stop()
115
116# Make sure a GSSAPI acceptor can handle cross-realm tickets with a
117# transited field.  (Regression test for #7639.)
118r1, r2, r3 = cross_realms(3, xtgts=((0,1), (1,2)),
119                          create_user=False, create_host=False,
120                          args=[{'realm': 'A.X', 'create_user': True},
121                                {'realm': 'X'},
122                                {'realm': 'B.X', 'create_host': True}])
123os.rename(r3.keytab, r1.keytab)
124r1.run(['./t_accname', 'p:' + r3.host_princ, 'h:host'])
125r1.stop()
126r2.stop()
127r3.stop()
128
129### Test gss_inquire_cred behavior.
130
131realm = K5Realm()
132
133# Test deferred resolution of the default ccache for initiator creds.
134realm.run(['./t_inq_cred'], expected_msg=realm.user_princ)
135realm.run(['./t_inq_cred', '-k'], expected_msg=realm.user_princ)
136realm.run(['./t_inq_cred', '-s'], expected_msg=realm.user_princ)
137
138# Test picking a name from the keytab for acceptor creds.
139realm.run(['./t_inq_cred', '-a'], expected_msg=realm.host_princ)
140realm.run(['./t_inq_cred', '-k', '-a'], expected_msg=realm.host_princ)
141realm.run(['./t_inq_cred', '-s', '-a'], expected_msg=realm.host_princ)
142
143# Test client keytab initiation (non-deferred) with a specified name.
144realm.extract_keytab(realm.user_princ, realm.client_keytab)
145os.remove(realm.ccache)
146realm.run(['./t_inq_cred', '-k'], expected_msg=realm.user_princ)
147
148# Test deferred client keytab initiation and GSS_C_BOTH cred usage.
149os.remove(realm.client_keytab)
150os.remove(realm.ccache)
151shutil.copyfile(realm.keytab, realm.client_keytab)
152realm.run(['./t_inq_cred', '-k', '-b'], expected_msg=realm.host_princ)
153
154# Test gss_export_name behavior.
155realm.run(['./t_export_name', 'u:x'], expected_msg=\
156          '0401000B06092A864886F7120102020000000D78404B5242544553542E434F4D\n')
157realm.run(['./t_export_name', '-s', 'u:xyz'],
158          expected_msg='0401000806062B06010505020000000378797A\n')
159realm.run(['./t_export_name', 'p:a@b'],
160          expected_msg='0401000B06092A864886F71201020200000003614062\n')
161realm.run(['./t_export_name', '-s', 'p:a@b'],
162          expected_msg='0401000806062B060105050200000003614062\n')
163
164# Test that composite-export tokens can be imported.
165realm.run(['./t_export_name', '-c', 'p:a@b'], expected_msg=
166          '0402000B06092A864886F7120102020000000361406200000000\n')
167
168# Test gss_inquire_mechs_for_name behavior.
169krb5_mech = '{ 1 2 840 113554 1 2 2 }'
170spnego_mech = '{ 1 3 6 1 5 5 2 }'
171out = realm.run(['./t_inq_mechs_name', 'p:a@b'])
172if krb5_mech not in out:
173    fail('t_inq_mechs_name (principal)')
174out = realm.run(['./t_inq_mechs_name', 'u:x'])
175if krb5_mech not in out or spnego_mech not in out:
176    fail('t_inq_mecs_name (user)')
177out = realm.run(['./t_inq_mechs_name', 'h:host'])
178if krb5_mech not in out or spnego_mech not in out:
179    fail('t_inq_mecs_name (hostbased)')
180
181# Test that accept_sec_context can produce an error token and
182# init_sec_context can interpret it.
183realm.run(['./t_err', 'p:' + realm.host_princ])
184realm.run(['./t_err', '--spnego', 'p:' + realm.host_princ])
185
186# Test the GSS_KRB5_CRED_NO_CI_FLAGS_X cred option.
187realm.run(['./t_ciflags', 'p:' + realm.host_princ])
188
189# Test that inquire_context works properly, even on incomplete
190# contexts.
191realm.run(['./t_inq_ctx', 'user', password('user'), 'p:%s' % realm.host_princ])
192
193if runenv.sizeof_time_t <= 4:
194    skip_rest('y2038 GSSAPI tests', 'platform has 32-bit time_t')
195
196# Test lifetime results, using a realm with a large maximum lifetime
197# so that we can test ticket end dates after y2038.
198realm.stop()
199conf = {'realms': {'$realm': {'max_life': '9000d'}}}
200realm = K5Realm(kdc_conf=conf, get_creds=False)
201
202# Check a lifetime string result against an expected number value (or None).
203# Allow some variance due to time elapsed during the tests.
204def check_lifetime(msg, val, expected):
205    if expected is None and val != 'indefinite':
206        fail('%s: expected indefinite, got %s' % (msg, val))
207    if expected is not None and val == 'indefinite':
208        fail('%s: expected %d, got indefinite' % (msg, expected))
209    if expected is not None and abs(int(val) - expected) > 100:
210        fail('%s: expected %d, got %s' % (msg, expected, val))
211
212realm.kinit(realm.user_princ, password('user'), flags=['-l', '8500d'])
213out = realm.run(['./t_lifetime', 'p:' + realm.host_princ, str(8000 * 86400)])
214ln = out.split('\n')
215check_lifetime('icred gss_acquire_cred', ln[0], 8500 * 86400)
216check_lifetime('icred gss_inquire_cred', ln[1], 8500 * 86400)
217check_lifetime('acred gss_acquire_cred', ln[2], None)
218check_lifetime('acred gss_inquire_cred', ln[3], None)
219check_lifetime('ictx gss_init_sec_context', ln[4], 8000 * 86400)
220check_lifetime('ictx gss_inquire_context', ln[5], 8000 * 86400)
221check_lifetime('ictx gss_context_time', ln[6], 8000 * 86400)
222check_lifetime('actx gss_accept_sec_context', ln[7], 8000 * 86400 + 300)
223check_lifetime('actx gss_inquire_context', ln[8], 8000 * 86400 + 300)
224check_lifetime('actx gss_context_time', ln[9], 8000 * 86400 + 300)
225
226success('GSSAPI tests')
227