1# Copyright (C) 2011 by the Massachusetts Institute of Technology. 2# All rights reserved. 3# 4# Export of this software from the United States of America may 5# require a specific license from the United States Government. 6# It is the responsibility of any person or organization contemplating 7# export to obtain such a license before exporting. 8# 9# WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 10# distribute this software and its documentation for any purpose and 11# without fee is hereby granted, provided that the above copyright 12# notice appear in all copies and that both that copyright notice and 13# this permission notice appear in supporting documentation, and that 14# the name of M.I.T. not be used in advertising or publicity pertaining 15# to distribution of the software without specific, written prior 16# permission. Furthermore if you modify this software you must label 17# your software as modified software and not distribute it in such a 18# fashion that it might be confused with the original M.I.T. software. 19# M.I.T. makes no representations about the suitability of 20# this software for any purpose. It is provided "as is" without express 21# or implied warranty. 22 23from k5test import * 24 25def test_kvno(r, princ, test, env=None): 26 r.run([kvno, princ], env=env, expected_msg=princ) 27 28 29def stop(*realms): 30 for r in realms: 31 r.stop() 32 33 34# Verify that the princs appear as the service principals in the klist 35# output for the realm r, in order. 36def check_klist(r, princs): 37 out = r.run([klist]) 38 count = 0 39 seen_header = False 40 for l in out.split('\n'): 41 if l.startswith('Valid starting'): 42 seen_header = True 43 continue 44 if not seen_header or l == '': 45 continue 46 if count >= len(princs): 47 fail('too many entries in klist output') 48 svcprinc = l.split()[4] 49 if svcprinc != princs[count]: 50 fail('saw service princ %s in klist output, expected %s' % 51 (svcprinc, princs[count])) 52 count += 1 53 if count != len(princs): 54 fail('not enough entries in klist output') 55 56 57def tgt(r1, r2): 58 return 'krbtgt/%s@%s' % (r1.realm, r2.realm) 59 60 61# Basic two-realm test with cross TGTs in both directions. 62mark('two realms') 63r1, r2 = cross_realms(2) 64test_kvno(r1, r2.host_princ, 'basic r1->r2') 65check_klist(r1, (tgt(r1, r1), tgt(r2, r1), r2.host_princ)) 66test_kvno(r2, r1.host_princ, 'basic r2->r1') 67check_klist(r2, (tgt(r2, r2), tgt(r1, r2), r1.host_princ)) 68stop(r1, r2) 69 70# Test the KDC domain walk for hierarchically arranged realms. The 71# client in A.X will ask for a cross TGT to B.X, but A.X's KDC only 72# has a TGT for the intermediate realm X, so it will return that 73# instead. The client will use that to get a TGT for B.X. 74mark('hierarchical realms') 75r1, r2, r3 = cross_realms(3, xtgts=((0,1), (1,2)), 76 args=({'realm': 'A.X'}, {'realm': 'X'}, 77 {'realm': 'B.X'})) 78test_kvno(r1, r3.host_princ, 'KDC domain walk') 79check_klist(r1, (tgt(r1, r1), r3.host_princ)) 80 81# Test start_realm in this setup. 82r1.run([kvno, '--out-cache', r1.ccache, r2.krbtgt_princ]) 83r1.run([klist, '-C'], expected_msg='config: start_realm = X') 84msgs = ('Requesting TGT krbtgt/B.X@X using TGT krbtgt/X@X', 85 'Received TGT for service realm: krbtgt/B.X@X') 86r1.run([kvno, r3.host_princ], expected_trace=msgs) 87 88stop(r1, r2, r3) 89 90# Test client capaths. The client in A will ask for a cross TGT to D, 91# but A's KDC won't have it and won't know an intermediate to return. 92# The client will walk its A->D capaths to get TGTs for B, then C, 93# then D. The KDCs for C and D need capaths settings to avoid failing 94# transited checks, including a capaths for A->C. 95mark('client capaths') 96capaths = {'capaths': {'A': {'D': ['B', 'C'], 'C': 'B'}}} 97r1, r2, r3, r4 = cross_realms(4, xtgts=((0,1), (1,2), (2,3)), 98 args=({'realm': 'A'}, 99 {'realm': 'B'}, 100 {'realm': 'C', 'krb5_conf': capaths}, 101 {'realm': 'D', 'krb5_conf': capaths})) 102r1client = r1.special_env('client', False, krb5_conf=capaths) 103test_kvno(r1, r4.host_princ, 'client capaths', r1client) 104check_klist(r1, (tgt(r1, r1), tgt(r2, r1), tgt(r3, r2), tgt(r4, r3), 105 r4.host_princ)) 106stop(r1, r2, r3, r4) 107 108# Test KDC capaths. The KDCs for A and B have appropriate capaths 109# settings to determine intermediate TGTs to return, but the client 110# has no idea. 111mark('kdc capaths') 112capaths = {'capaths': {'A': {'D': ['B', 'C'], 'C': 'B'}, 'B': {'D': 'C'}}} 113r1, r2, r3, r4 = cross_realms(4, xtgts=((0,1), (1,2), (2,3)), 114 args=({'realm': 'A', 'krb5_conf': capaths}, 115 {'realm': 'B', 'krb5_conf': capaths}, 116 {'realm': 'C', 'krb5_conf': capaths}, 117 {'realm': 'D', 'krb5_conf': capaths})) 118r1client = r1.special_env('client', False, krb5_conf={'capaths': None}) 119test_kvno(r1, r4.host_princ, 'KDC capaths', r1client) 120check_klist(r1, (tgt(r1, r1), r4.host_princ)) 121stop(r1, r2, r3, r4) 122 123# A capaths value of '.' should enforce direct cross-realm, with no 124# intermediate. 125mark('direct cross-realm enforcement') 126capaths = {'capaths': {'A.X': {'B.X': '.'}}} 127r1, r2, r3 = cross_realms(3, xtgts=((0,1), (1,2)), 128 args=({'realm': 'A.X', 'krb5_conf': capaths}, 129 {'realm': 'X'}, {'realm': 'B.X'})) 130r1.run([kvno, r3.host_princ], expected_code=1, 131 expected_msg='Server krbtgt/B.X@A.X not found in Kerberos database') 132stop(r1, r2, r3) 133 134# Test transited error. The KDC for C does not recognize B as an 135# intermediate realm for A->C, so it refuses to issue a service 136# ticket. 137mark('transited error (three realms)') 138capaths = {'capaths': {'A': {'C': 'B'}}} 139r1, r2, r3 = cross_realms(3, xtgts=((0,1), (1,2)), 140 args=({'realm': 'A', 'krb5_conf': capaths}, 141 {'realm': 'B'}, {'realm': 'C'})) 142r1.run([kvno, r3.host_princ], expected_code=1, 143 expected_msg='KDC policy rejects request') 144check_klist(r1, (tgt(r1, r1), tgt(r3, r2))) 145stop(r1, r2, r3) 146 147# Test server transited checking. The KDC for C recognizes B as an 148# intermediate realm for A->C, but the server environment does not. 149# The server should honor the ticket if the transited-policy-checked 150# flag is set, but not if it isn't. (It is only possible for our KDC 151# to issue a ticket without the transited-policy-checked flag with 152# reject_bad_transit=false.) 153mark('server transited checking') 154capaths = {'capaths': {'A': {'C': 'B'}}} 155noreject = {'realms': {'$realm': {'reject_bad_transit': 'false'}}} 156r1, r2, r3 = cross_realms(3, xtgts=((0,1), (1,2)), 157 args=({'realm': 'A', 'krb5_conf': capaths}, 158 {'realm': 'B'}, 159 {'realm': 'C', 'krb5_conf': capaths, 160 'kdc_conf': noreject})) 161r3server = r3.special_env('server', False, krb5_conf={'capaths': None}) 162# Process a ticket with the transited-policy-checked flag set. 163shutil.copy(r1.ccache, r1.ccache + '.copy') 164r1.run(['./gcred', 'principal', r3.host_princ]) 165os.rename(r1.ccache, r3.ccache) 166r3.run(['./rdreq', r3.host_princ], env=r3server, expected_msg='0 success') 167# Try again with the transited-policy-checked flag unset. 168os.rename(r1.ccache + '.copy', r1.ccache) 169r1.run(['./gcred', '-t', 'principal', r3.host_princ]) 170os.rename(r1.ccache, r3.ccache) 171r3.run(['./rdreq', r3.host_princ], env=r3server, 172 expected_msg='43 Illegal cross-realm ticket') 173stop(r1, r2, r3) 174 175# Test a four-realm scenario. This test used to result in an "Illegal 176# cross-realm ticket" error as the KDC for D would refuse to process 177# the cross-realm ticket from C. Now that we honor the 178# transited-policy-checked flag in krb5_rd_req(), it instead issues a 179# policy error as in the three-realm scenario. 180mark('transited error (four realms)') 181capaths = {'capaths': {'A': {'D': ['B', 'C'], 'C': 'B'}, 'B': {'D': 'C'}}} 182r1, r2, r3, r4 = cross_realms(4, xtgts=((0,1), (1,2), (2,3)), 183 args=({'realm': 'A', 'krb5_conf': capaths}, 184 {'realm': 'B', 'krb5_conf': capaths}, 185 {'realm': 'C', 'krb5_conf': capaths}, 186 {'realm': 'D'})) 187r1.run([kvno, r4.host_princ], expected_code=1, 188 expected_msg='KDC policy rejects request') 189check_klist(r1, (tgt(r1, r1), tgt(r4, r3))) 190stop(r1, r2, r3, r4) 191 192success('Cross-realm tests') 193