Path: blob/main/crypto/krb5/src/tests/t_crossrealm.py
34878 views
# Copyright (C) 2011 by the Massachusetts Institute of Technology.1# All rights reserved.2#3# Export of this software from the United States of America may4# require a specific license from the United States Government.5# It is the responsibility of any person or organization contemplating6# export to obtain such a license before exporting.7#8# WITHIN THAT CONSTRAINT, permission to use, copy, modify, and9# distribute this software and its documentation for any purpose and10# without fee is hereby granted, provided that the above copyright11# notice appear in all copies and that both that copyright notice and12# this permission notice appear in supporting documentation, and that13# the name of M.I.T. not be used in advertising or publicity pertaining14# to distribution of the software without specific, written prior15# permission. Furthermore if you modify this software you must label16# your software as modified software and not distribute it in such a17# fashion that it might be confused with the original M.I.T. software.18# M.I.T. makes no representations about the suitability of19# this software for any purpose. It is provided "as is" without express20# or implied warranty.2122from k5test import *2324def test_kvno(r, princ, test, env=None):25r.run([kvno, princ], env=env, expected_msg=princ)262728def stop(*realms):29for r in realms:30r.stop()313233# Verify that the princs appear as the service principals in the klist34# output for the realm r, in order.35def check_klist(r, princs):36out = r.run([klist])37count = 038seen_header = False39for l in out.split('\n'):40if l.startswith('Valid starting'):41seen_header = True42continue43if not seen_header or l == '':44continue45if count >= len(princs):46fail('too many entries in klist output')47svcprinc = l.split()[4]48if svcprinc != princs[count]:49fail('saw service princ %s in klist output, expected %s' %50(svcprinc, princs[count]))51count += 152if count != len(princs):53fail('not enough entries in klist output')545556def tgt(r1, r2):57return 'krbtgt/%s@%s' % (r1.realm, r2.realm)585960# Basic two-realm test with cross TGTs in both directions.61mark('two realms')62r1, r2 = cross_realms(2)63test_kvno(r1, r2.host_princ, 'basic r1->r2')64check_klist(r1, (tgt(r1, r1), tgt(r2, r1), r2.host_princ))65test_kvno(r2, r1.host_princ, 'basic r2->r1')66check_klist(r2, (tgt(r2, r2), tgt(r1, r2), r1.host_princ))67stop(r1, r2)6869# Test the KDC domain walk for hierarchically arranged realms. The70# client in A.X will ask for a cross TGT to B.X, but A.X's KDC only71# has a TGT for the intermediate realm X, so it will return that72# instead. The client will use that to get a TGT for B.X.73mark('hierarchical realms')74r1, r2, r3 = cross_realms(3, xtgts=((0,1), (1,2)),75args=({'realm': 'A.X'}, {'realm': 'X'},76{'realm': 'B.X'}))77test_kvno(r1, r3.host_princ, 'KDC domain walk')78check_klist(r1, (tgt(r1, r1), r3.host_princ))7980# Test start_realm in this setup.81r1.run([kvno, '--out-cache', r1.ccache, r2.krbtgt_princ])82r1.run([klist, '-C'], expected_msg='config: start_realm = X')83msgs = ('Requesting TGT krbtgt/B.X@X using TGT krbtgt/X@X',84'Received TGT for service realm: krbtgt/B.X@X')85r1.run([kvno, r3.host_princ], expected_trace=msgs)8687stop(r1, r2, r3)8889# Test client capaths. The client in A will ask for a cross TGT to D,90# but A's KDC won't have it and won't know an intermediate to return.91# The client will walk its A->D capaths to get TGTs for B, then C,92# then D. The KDCs for C and D need capaths settings to avoid failing93# transited checks, including a capaths for A->C.94mark('client capaths')95capaths = {'capaths': {'A': {'D': ['B', 'C'], 'C': 'B'}}}96r1, r2, r3, r4 = cross_realms(4, xtgts=((0,1), (1,2), (2,3)),97args=({'realm': 'A'},98{'realm': 'B'},99{'realm': 'C', 'krb5_conf': capaths},100{'realm': 'D', 'krb5_conf': capaths}))101r1client = r1.special_env('client', False, krb5_conf=capaths)102test_kvno(r1, r4.host_princ, 'client capaths', r1client)103check_klist(r1, (tgt(r1, r1), tgt(r2, r1), tgt(r3, r2), tgt(r4, r3),104r4.host_princ))105stop(r1, r2, r3, r4)106107# Test KDC capaths. The KDCs for A and B have appropriate capaths108# settings to determine intermediate TGTs to return, but the client109# has no idea.110mark('kdc capaths')111capaths = {'capaths': {'A': {'D': ['B', 'C'], 'C': 'B'}, 'B': {'D': 'C'}}}112r1, r2, r3, r4 = cross_realms(4, xtgts=((0,1), (1,2), (2,3)),113args=({'realm': 'A', 'krb5_conf': capaths},114{'realm': 'B', 'krb5_conf': capaths},115{'realm': 'C', 'krb5_conf': capaths},116{'realm': 'D', 'krb5_conf': capaths}))117r1client = r1.special_env('client', False, krb5_conf={'capaths': None})118test_kvno(r1, r4.host_princ, 'KDC capaths', r1client)119check_klist(r1, (tgt(r1, r1), r4.host_princ))120stop(r1, r2, r3, r4)121122# A capaths value of '.' should enforce direct cross-realm, with no123# intermediate.124mark('direct cross-realm enforcement')125capaths = {'capaths': {'A.X': {'B.X': '.'}}}126r1, r2, r3 = cross_realms(3, xtgts=((0,1), (1,2)),127args=({'realm': 'A.X', 'krb5_conf': capaths},128{'realm': 'X'}, {'realm': 'B.X'}))129r1.run([kvno, r3.host_princ], expected_code=1,130expected_msg='Server krbtgt/[email protected] not found in Kerberos database')131stop(r1, r2, r3)132133# Test transited error. The KDC for C does not recognize B as an134# intermediate realm for A->C, so it refuses to issue a service135# ticket.136mark('transited error (three realms)')137capaths = {'capaths': {'A': {'C': 'B'}}}138r1, r2, r3 = cross_realms(3, xtgts=((0,1), (1,2)),139args=({'realm': 'A', 'krb5_conf': capaths},140{'realm': 'B'}, {'realm': 'C'}))141r1.run([kvno, r3.host_princ], expected_code=1,142expected_msg='KDC policy rejects request')143check_klist(r1, (tgt(r1, r1), tgt(r3, r2)))144stop(r1, r2, r3)145146# Test server transited checking. The KDC for C recognizes B as an147# intermediate realm for A->C, but the server environment does not.148# The server should honor the ticket if the transited-policy-checked149# flag is set, but not if it isn't. (It is only possible for our KDC150# to issue a ticket without the transited-policy-checked flag with151# reject_bad_transit=false.)152mark('server transited checking')153capaths = {'capaths': {'A': {'C': 'B'}}}154noreject = {'realms': {'$realm': {'reject_bad_transit': 'false'}}}155r1, r2, r3 = cross_realms(3, xtgts=((0,1), (1,2)),156args=({'realm': 'A', 'krb5_conf': capaths},157{'realm': 'B'},158{'realm': 'C', 'krb5_conf': capaths,159'kdc_conf': noreject}))160r3server = r3.special_env('server', False, krb5_conf={'capaths': None})161# Process a ticket with the transited-policy-checked flag set.162shutil.copy(r1.ccache, r1.ccache + '.copy')163r1.run(['./gcred', 'principal', r3.host_princ])164os.rename(r1.ccache, r3.ccache)165r3.run(['./rdreq', r3.host_princ], env=r3server, expected_msg='0 success')166# Try again with the transited-policy-checked flag unset.167os.rename(r1.ccache + '.copy', r1.ccache)168r1.run(['./gcred', '-t', 'principal', r3.host_princ])169os.rename(r1.ccache, r3.ccache)170r3.run(['./rdreq', r3.host_princ], env=r3server,171expected_msg='43 Illegal cross-realm ticket')172stop(r1, r2, r3)173174# Test a four-realm scenario. This test used to result in an "Illegal175# cross-realm ticket" error as the KDC for D would refuse to process176# the cross-realm ticket from C. Now that we honor the177# transited-policy-checked flag in krb5_rd_req(), it instead issues a178# policy error as in the three-realm scenario.179mark('transited error (four realms)')180capaths = {'capaths': {'A': {'D': ['B', 'C'], 'C': 'B'}, 'B': {'D': 'C'}}}181r1, r2, r3, r4 = cross_realms(4, xtgts=((0,1), (1,2), (2,3)),182args=({'realm': 'A', 'krb5_conf': capaths},183{'realm': 'B', 'krb5_conf': capaths},184{'realm': 'C', 'krb5_conf': capaths},185{'realm': 'D'}))186r1.run([kvno, r4.host_princ], expected_code=1,187expected_msg='KDC policy rejects request')188check_klist(r1, (tgt(r1, r1), tgt(r4, r3)))189stop(r1, r2, r3, r4)190191success('Cross-realm tests')192193194