Path: blob/main/crypto/krb5/src/tests/gssapi/t_s4u.py
34889 views
from k5test import *1from base64 import b64encode2import shutil34realm = K5Realm(create_host=False, get_creds=False)5usercache = 'FILE:' + os.path.join(realm.testdir, 'usercache')6storagecache = 'FILE:' + os.path.join(realm.testdir, 'save')78# Create two service principals with keys in the default keytab.9service1 = 'service/1@%s' % realm.realm10realm.addprinc(service1)11realm.extract_keytab(service1, realm.keytab)12service2 = 'service/2@%s' % realm.realm13realm.addprinc(service2)14realm.extract_keytab(service2, realm.keytab)1516puser = 'p:' + realm.user_princ17pservice1 = 'p:' + service118pservice2 = 'p:' + service21920# Get forwardable creds for service1 in the default cache.21realm.kinit(service1, None, ['-f', '-k'])2223# Try S4U2Self for user with a restricted password.24realm.run([kadminl, 'modprinc', '+needchange', realm.user_princ])25realm.run(['./t_s4u', 'e:user', '-'])26realm.run([kadminl, 'modprinc', '-needchange',27'-pwexpire', '1/1/2000', realm.user_princ])28realm.run(['./t_s4u', 'e:user', '-'])29realm.run([kadminl, 'modprinc', '-pwexpire', 'never', realm.user_princ])3031# Try krb5 -> S4U2Proxy with forwardable user creds. This should fail32# at the S4U2Proxy step since the DB2 back end currently has no33# support for allowing it.34realm.kinit(realm.user_princ, password('user'), ['-f', '-c', usercache])35output = realm.run(['./t_s4u2proxy_krb5', usercache, storagecache, '-',36pservice1, pservice2], expected_code=1)37if ('auth1: ' + realm.user_princ not in output or38'KDC can\'t fulfill requested option' not in output):39fail('krb5 -> s4u2proxy')4041# Again with SPNEGO.42output = realm.run(['./t_s4u2proxy_krb5', '--spnego', usercache, storagecache,43'-', pservice1, pservice2],44expected_code=1)45if ('auth1: ' + realm.user_princ not in output or46'KDC can\'t fulfill requested option' not in output):47fail('krb5 -> s4u2proxy (SPNEGO)')4849# Try krb5 -> S4U2Proxy without forwardable user creds.50realm.kinit(realm.user_princ, password('user'), ['-c', usercache])51output = realm.run(['./t_s4u2proxy_krb5', usercache, storagecache, pservice1,52pservice1, pservice2], expected_code=1)53if ('auth1: ' + realm.user_princ not in output or54'KDC can\'t fulfill requested option' not in output):55fail('krb5 -> s4u2proxy not-forwardable')5657# Try S4U2Self. Ask for an S4U2Proxy step; this won't succeed because58# service/1 isn't allowed to get a forwardable S4U2Self ticket.59realm.run(['./t_s4u', puser, pservice2], expected_code=1,60expected_msg='KDC can\'t fulfill requested option')61realm.run(['./t_s4u', '--spnego', puser, pservice2], expected_code=1,62expected_msg='KDC can\'t fulfill requested option')6364# Correct that problem and try again. As above, the S4U2Proxy step65# won't actually succeed since we don't support that in DB2.66realm.run([kadminl, 'modprinc', '+ok_to_auth_as_delegate', service1])67realm.run(['./t_s4u', puser, pservice2], expected_code=1,68expected_msg='KDC can\'t fulfill requested option')6970# Again with SPNEGO. This uses SPNEGO for the initial authentication,71# but still uses krb5 for S4U2Proxy--the delegated cred is returned as72# a krb5 cred, not a SPNEGO cred, and t_s4u uses the delegated cred73# directly rather than saving and reacquiring it.74realm.run(['./t_s4u', '--spnego', puser, pservice2], expected_code=1,75expected_msg='KDC can\'t fulfill requested option')7677realm.stop()7879# Set up a realm using the test KDB module so that we can do80# successful S4U2Proxy delegations.81testprincs = {'krbtgt/KRBTEST.COM': {'keys': 'aes128-cts'},82'user': {'keys': 'aes128-cts'},83'service/1': {'flags': '+ok-to-auth-as-delegate',84'keys': 'aes128-cts'},85'service/2': {'keys': 'aes128-cts'}}86conf = {'realms': {'$realm': {'database_module': 'test'}},87'dbmodules': {'test': {'db_library': 'test',88'princs': testprincs,89'delegation': {'service/1': 'service/2'}}}}90realm = K5Realm(create_kdb=False, kdc_conf=conf)91userkeytab = 'FILE:' + os.path.join(realm.testdir, 'userkeytab')92realm.extract_keytab(realm.user_princ, userkeytab)93realm.extract_keytab(service1, realm.keytab)94realm.extract_keytab(service2, realm.keytab)95realm.start_kdc()9697# Get forwardable creds for service1 in the default cache.98realm.kinit(service1, None, ['-f', '-k'])99100# Successful krb5 -> S4U2Proxy, with krb5 and SPNEGO mechs.101realm.kinit(realm.user_princ, None, ['-f', '-k', '-c', usercache,102'-t', userkeytab])103out = realm.run(['./t_s4u2proxy_krb5', usercache, storagecache, '-',104pservice1, pservice2])105if 'auth1: user@' not in out or 'auth2: user@' not in out:106fail('krb5 -> s4u2proxy')107out = realm.run(['./t_s4u2proxy_krb5', '--spnego', usercache, storagecache,108'-', pservice1, pservice2])109if 'auth1: user@' not in out or 'auth2: user@' not in out:110fail('krb5 -> s4u2proxy')111112# Successful S4U2Self -> S4U2Proxy.113out = realm.run(['./t_s4u', puser, pservice2])114115# Regression test for #8139: get a user ticket directly for service1 and116# try krb5 -> S4U2Proxy.117realm.kinit(realm.user_princ, None, ['-f', '-k', '-c', usercache,118'-t', userkeytab, '-S', service1])119out = realm.run(['./t_s4u2proxy_krb5', usercache, storagecache, '-',120pservice1, pservice2])121if 'auth1: user@' not in out or 'auth2: user@' not in out:122fail('krb5 -> s4u2proxy')123124# Simulate a krbtgt rollover and verify that the user ticket can still125# be validated.126realm.stop_kdc()127newtgt_keys = ['2 aes128-cts', '1 aes128-cts']128newtgt_princs = {'krbtgt/KRBTEST.COM': {'keys': newtgt_keys}}129newtgt_conf = {'dbmodules': {'test': {'princs': newtgt_princs}}}130newtgt_env = realm.special_env('newtgt', True, kdc_conf=newtgt_conf)131realm.start_kdc(env=newtgt_env)132out = realm.run(['./t_s4u2proxy_krb5', usercache, storagecache, '-',133pservice1, pservice2])134if 'auth1: user@' not in out or 'auth2: user@' not in out:135fail('krb5 -> s4u2proxy')136137# Get a user ticket after the krbtgt rollover and verify that138# S4U2Proxy delegation works (also a #8139 regression test).139realm.kinit(realm.user_princ, None, ['-f', '-k', '-c', usercache,140'-t', userkeytab])141out = realm.run(['./t_s4u2proxy_krb5', usercache, storagecache, '-',142pservice1, pservice2])143if 'auth1: user@' not in out or 'auth2: user@' not in out:144fail('krb5 -> s4u2proxy')145146realm.stop()147148mark('S4U2Self with various enctypes')149for realm in multipass_realms(create_host=False, get_creds=False):150service1 = 'service/1@%s' % realm.realm151realm.addprinc(service1)152realm.extract_keytab(service1, realm.keytab)153realm.kinit(service1, None, ['-k'])154realm.run(['./t_s4u', 'e:user', '-'])155156# Test cross realm S4U2Self using server referrals.157mark('cross-realm S4U2Self')158testprincs = {'krbtgt/SREALM': {'keys': 'aes128-cts'},159'krbtgt/UREALM': {'keys': 'aes128-cts'},160'user': {'keys': 'aes128-cts', 'flags': '+preauth'},161'other': {'keys': 'aes128-cts'}}162kdcconf1 = {'realms': {'$realm': {'database_module': 'test'}},163'dbmodules': {'test': {'db_library': 'test',164'princs': testprincs,165'alias': {'enterprise@abc': '@UREALM',166'user@UREALM': '@UREALM'}}}}167kdcconf2 = {'realms': {'$realm': {'database_module': 'test'}},168'dbmodules': {'test': {'db_library': 'test',169'princs': testprincs,170'alias': {'user@SREALM': '@SREALM',171'user@UREALM': 'user',172'enterprise@abc': 'user'}}}}173r1, r2 = cross_realms(2, xtgts=(),174args=({'realm': 'SREALM', 'kdc_conf': kdcconf1},175{'realm': 'UREALM', 'kdc_conf': kdcconf2}),176create_kdb=False)177178r1.start_kdc()179r2.start_kdc()180r1.extract_keytab(r1.user_princ, r1.keytab)181r1.kinit(r1.user_princ, None, ['-k', '-t', r1.keytab])182savefile = r1.ccache + '.save'183shutil.copyfile(r1.ccache, savefile)184185# Include a regression test for #8741 by unsetting the default realm.186remove_default = {'libdefaults': {'default_realm': None}}187no_default = r1.special_env('no_default', False, krb5_conf=remove_default)188msgs = ('Getting credentials user@UREALM -> user@SREALM',189'/Matching credential not found',190'Getting credentials user@SREALM -> krbtgt/UREALM@SREALM',191'Received creds for desired service krbtgt/UREALM@SREALM',192'via TGT krbtgt/UREALM@SREALM after requesting user\\@SREALM@UREALM',193'krbtgt/SREALM@UREALM differs from requested user\\@SREALM@UREALM',194'via TGT krbtgt/SREALM@UREALM after requesting user@SREALM',195'TGS reply is for user@UREALM -> user@SREALM')196r1.run(['./t_s4u', 'p:' + r2.user_princ, '-', r1.keytab], env=no_default,197expected_trace=msgs)198199# Test realm identification of enterprise principal names ([MS-SFU]200# 3.1.5.1.1.1). Attach a bogus realm to the enterprise name to verify201# that we start at the server realm.202mark('cross-realm S4U2Self with enterprise name')203msgs = ('Getting initial credentials for enterprise\\@abc@SREALM',204'Sending unauthenticated request',205'/Realm not local to KDC',206'Following referral to realm UREALM',207'Sending unauthenticated request',208'/Additional pre-authentication required',209'Identified realm of client principal as UREALM',210'Getting credentials enterprise\\@abc@UREALM -> user@SREALM',211'TGS reply is for enterprise\\@abc@UREALM -> user@SREALM')212r1.run(['./t_s4u', 'e:enterprise@abc@NOREALM', '-', r1.keytab],213expected_trace=msgs)214215mark('S4U2Self using X509 certificate')216217# Encode name as a PEM certificate file (sort of) for use by kvno.218def princ_cert(name):219enc = b64encode(name.encode('ascii')).decode('ascii')220return '-----BEGIN CERTIFICATE-----\n%s\n-----END y\n' % enc221222cert_path = os.path.join(r1.testdir, 'fake_cert')223with open(cert_path, "w") as cert_file:224cert_file.write(princ_cert('other'))225226shutil.copyfile(savefile, r1.ccache)227msgs = ('Getting initial credentials for @SREALM',228'Identified realm of client principal as SREALM',229'TGS reply is for other@SREALM',230'Getting credentials other@SREALM',231'Storing other@SREALM')232r1.run([kvno, '-F', cert_path, r1.user_princ], expected_trace=msgs)233234shutil.copyfile(savefile, r1.ccache)235msgs = ('Getting credentials other@SREALM',236'TGS reply is for other@SREALM',237'Storing other@SREALM')238r1.run([kvno, '-I', 'other', '-F', cert_path, r1.user_princ],239expected_trace=msgs)240241shutil.copyfile(savefile, r1.ccache)242msgs = ('Getting initial credentials for other@SREALM',243'Identified realm of client principal as SREALM',244'Getting credentials other@SREALM',245'TGS reply is for other@SREALM',246'Storing other@SREALM')247r1.run([kvno, '-U', 'other', '-F', cert_path, r1.user_princ],248expected_trace=msgs)249250mark('cross-realm S4U2Self using X509 certificate')251252with open(cert_path, "w") as cert_file:253cert_file.write(princ_cert('user@UREALM'))254255shutil.copyfile(savefile, r1.ccache)256msgs = ('Getting initial credentials for @SREALM',257'Identified realm of client principal as UREALM',258'TGS reply is for user@UREALM',259'Getting credentials user@UREALM',260'Storing user@UREALM')261r1.run([kvno, '-F', cert_path, r1.user_princ], expected_trace=msgs)262263shutil.copyfile(savefile, r1.ccache)264msgs = ('Getting credentials user@UREALM',265'TGS reply is for user@UREALM',266'Storing user@UREALM')267r1.run([kvno, '-I', 'user@UREALM', '-F', cert_path, r1.user_princ],268expected_trace=msgs)269270shutil.copyfile(savefile, r1.ccache)271msgs = ('Getting initial credentials for enterprise\\@abc@SREALM',272'Identified realm of client principal as UREALM',273'Getting credentials enterprise\\@abc@UREALM',274'TGS reply is for enterprise\\@abc@UREALM',275'Storing enterprise\\@abc@UREALM')276r1.run([kvno, '-U', 'enterprise@abc', '-F', cert_path, r1.user_princ],277expected_trace=msgs)278279shutil.copyfile(savefile, r1.ccache)280281mark('S4U2Self using X509 certificate (GSSAPI)')282283r1.run(['./t_s4u', 'c:other', '-', r1.keytab])284r1.run(['./t_s4u', 'c:user@UREALM', '-', r1.keytab])285286r1.run(['./t_s4u', '--spnego', 'c:other', '-', r1.keytab])287r1.run(['./t_s4u', '--spnego', 'c:user@UREALM', '-', r1.keytab])288289r1.stop()290r2.stop()291292mark('Resource-based constrained delegation')293294a_princs = {'krbtgt/A': {'keys': 'aes128-cts'},295'krbtgt/B': {'keys': 'aes128-cts'},296'user': {'keys': 'aes128-cts', 'flags': '+preauth'},297'sensitive': {'keys': 'aes128-cts',298'flags': '+disallow_forwardable'},299'impersonator': {'keys': 'aes128-cts'},300'service1': {'keys': 'aes128-cts'},301'rb2': {'keys': 'aes128-cts'},302'rb': {'keys': 'aes128-cts'}}303a_kconf = {'realms': {'$realm': {'database_module': 'test'}},304'dbmodules': {'test': {'db_library': 'test',305'princs': a_princs,306'rbcd': {'rb@A': 'impersonator@A',307'rb2@A': 'service1@A'},308'delegation': {'service1': 'rb2'},309'alias': {'rb@A': 'rb',310'rb@B': '@B',311'rb@C': '@B',312'service/rb.a': 'rb',313'service/rb.b': '@B',314'service/rb.c': '@B' }}}}315316b_princs = {'krbtgt/B': {'keys': 'aes128-cts'},317'krbtgt/A': {'keys': 'aes128-cts'},318'krbtgt/C': {'keys': 'aes128-cts'},319'user': {'keys': 'aes128-cts', 'flags': '+preauth'},320'rb': {'keys': 'aes128-cts'}}321b_kconf = {'realms': {'$realm': {'database_module': 'test'}},322'dbmodules': {'test': {'db_library': 'test',323'princs': b_princs,324'rbcd': {'rb@B': 'impersonator@A'},325'alias': {'rb@B': 'rb',326'service/rb.b': 'rb',327'rb@C': '@C',328'impersonator@A': '@A',329'service/rb.c': '@C'}}}}330331c_princs = {'krbtgt/C': {'keys': 'aes128-cts'},332'krbtgt/B': {'keys': 'aes128-cts'},333'rb': {'keys': 'aes128-cts'}}334c_kconf = {'realms': {'$realm': {'database_module': 'test'}},335'capaths': { 'A' : { 'C' : 'B' }},336'dbmodules': {'test': {'db_library': 'test',337'princs': c_princs,338'rbcd': {'rb@C': ['impersonator@A',339'service1@A']},340'alias': {'rb@C': 'rb',341'service/rb.c': 'rb' }}}}342343ra, rb, rc = cross_realms(3, xtgts=(),344args=({'realm': 'A', 'kdc_conf': a_kconf},345{'realm': 'B', 'kdc_conf': b_kconf},346{'realm': 'C', 'kdc_conf': c_kconf}),347create_kdb=False)348349ra.start_kdc()350rb.start_kdc()351rc.start_kdc()352353domain_realm = {'domain_realm': {'.a':'A', '.b':'B', '.c':'C'}}354domain_conf = ra.special_env('domain_conf', False, krb5_conf=domain_realm)355356ra.extract_keytab('impersonator@A', ra.keytab)357ra.kinit('impersonator@A', None, ['-f', '-k', '-t', ra.keytab])358359mark('Local-realm RBCD')360ra.run(['./t_s4u', 'p:' + ra.user_princ, 'p:rb'])361ra.run(['./t_s4u', 'p:' + ra.user_princ, 'e:rb'])362ra.run(['./t_s4u', 'p:' + ra.user_princ, 'p:rb@A'])363ra.run(['./t_s4u', 'p:' + ra.user_princ, 'e:rb@A'])364ra.run(['./t_s4u', 'p:' + ra.user_princ, 'e:rb@A@'])365ra.run(['./t_s4u', 'p:' + ra.user_princ, 'e:rb@A@A'])366ra.run(['./t_s4u', 'p:' + ra.user_princ, 'h:[email protected]'])367ra.run(['./t_s4u', 'p:' + ra.user_princ, 'h:[email protected]'], env=domain_conf)368ra.run(['./t_s4u', 'p:' + 'sensitive@A', 'h:[email protected]'], expected_code=1)369ra.run(['./t_s4u', 'p:' + rb.user_princ, 'h:[email protected]'])370371mark('Cross-realm RBCD')372ra.run(['./t_s4u', 'p:' + ra.user_princ, 'e:rb@B'])373ra.run(['./t_s4u', 'p:' + ra.user_princ, 'e:rb@B@'])374ra.run(['./t_s4u', 'p:' + ra.user_princ, 'e:rb@B@A'])375ra.run(['./t_s4u', 'p:' + ra.user_princ, 'h:[email protected]'])376ra.run(['./t_s4u', 'p:' + ra.user_princ, 'h:[email protected]'], env=domain_conf)377ra.run(['./t_s4u', 'p:' + 'sensitive@A', 'h:[email protected]'], expected_code=1)378ra.run(['./t_s4u', 'p:' + rb.user_princ, 'h:[email protected]'])379380mark('RBCD transitive trust')381ra.run(['./t_s4u', 'p:' + ra.user_princ, 'e:rb@C'])382ra.run(['./t_s4u', 'p:' + ra.user_princ, 'e:rb@C@'])383ra.run(['./t_s4u', 'p:' + ra.user_princ, 'e:rb@C@A'])384ra.run(['./t_s4u', 'p:' + ra.user_princ, 'h:[email protected]'])385ra.run(['./t_s4u', 'p:' + ra.user_princ, 'h:[email protected]'], env=domain_conf)386ra.run(['./t_s4u', 'p:' + 'sensitive@A', 'h:[email protected]'], expected_code=1)387ra.run(['./t_s4u', 'p:' + rb.user_princ, 'h:[email protected]'])388389# Although service1 has RBCD delegation privileges to rb2@A, it does390# not have ok-to-auth-as-delegate and does have traditional delegation391# privileges, so it cannot get a forwardable S4U2Self ticket.392mark('RBCD forwardable blocked by forward delegation privileges')393ra.extract_keytab('service1@A', ra.keytab)394ra.kinit('service1@A', None, ['-f', '-k', '-t', ra.keytab])395ra.run(['./t_s4u', 'p:' + ra.user_princ, 'e:rb2@A'], expected_code=1,396expected_msg='KDC can\'t fulfill requested option')397398ra.stop()399rb.stop()400rc.stop()401402success('S4U test cases')403404405