1from k5test import * 2 3# Load the sample KDC authdata module. Allow renewable tickets. 4greet_path = os.path.join(buildtop, 'plugins', 'authdata', 'greet_server', 5 'greet_server.so') 6conf = {'realms': {'$realm': {'max_life': '20h', 'max_renewable_life': '20h'}}, 7 'plugins': {'kdcauthdata': {'module': 'greet:' + greet_path}}} 8realm = K5Realm(krb5_conf=conf) 9 10# With no requested authdata, we expect to see PAC (128) in an 11# if-relevant container and the greet authdata in a kdc-issued 12# container. 13mark('baseline authdata') 14out = realm.run(['./adata', realm.host_princ]) 15if '?128: [6, 7, 10, 16, 19]' not in out or '^-42: Hello' not in out: 16 fail('expected authdata not seen for basic request') 17 18# Requested authdata is copied into the ticket, with KDC-only types 19# filtered out. (128 is win2k-pac, which should be filtered.) 20mark('request authdata') 21out = realm.run(['./adata', realm.host_princ, '-5', 'test1', '?-6', 'test2', 22 '128', 'fakepac', '?128', 'ifrelfakepac', 23 '^-8', 'fakekdcissued', '?^-8', 'ifrelfakekdcissued']) 24if ' -5: test1' not in out or '?-6: test2' not in out: 25 fail('expected authdata not seen for request with authdata') 26if 'fake' in out: 27 fail('KDC-only authdata not filtered for request with authdata') 28 29mark('AD-MANDATORY-FOR-KDC') 30realm.run(['./adata', realm.host_princ, '!-1', 'mandatoryforkdc'], 31 expected_code=1, expected_msg='KDC policy rejects request') 32 33# The no_auth_data_required server flag should suppress the PAC, but 34# not module or request authdata. 35mark('no_auth_data_required server flag') 36realm.run([kadminl, 'ank', '-randkey', '+no_auth_data_required', 'noauth']) 37realm.extract_keytab('noauth', realm.keytab) 38out = realm.run(['./adata', 'noauth', '-2', 'test']) 39if '^-42: Hello' not in out or ' -2: test' not in out: 40 fail('expected authdata not seen for no_auth_data_required request') 41if '128: ' in out: 42 fail('PAC authdata seen for no_auth_data_required request') 43 44# Cross-realm TGT requests should not suppress PAC or request 45# authdata. 46mark('cross-realm') 47realm.addprinc('krbtgt/XREALM') 48realm.extract_keytab('krbtgt/XREALM', realm.keytab) 49out = realm.run(['./adata', 'krbtgt/XREALM', '-3', 'test']) 50if '128:' not in out or '^-42: Hello' not in out or ' -3: test' not in out: 51 fail('expected authdata not seen for cross-realm TGT request') 52 53mark('pac_privsvr_enctype') 54# Change the privsvr enctype and make sure we can still verify the PAC 55# on a service ticket in a TGS request. 56realm.run([kadminl, 'setstr', realm.host_princ, 57 'pac_privsvr_enctype', 'aes128-sha1']) 58realm.kinit(realm.user_princ, password('user'), 59 ['-S', realm.host_princ, '-r', '1h']) 60realm.kinit(realm.user_princ, None, ['-S', realm.host_princ, '-R']) 61# Remove the attribute and make sure the previously-issued service 62# ticket PAC no longer verifies. 63realm.run([kadminl, 'delstr', realm.host_princ, 'pac_privsvr_enctype']) 64realm.kinit(realm.user_princ, None, ['-S', realm.host_princ, '-R'], 65 expected_code=1, expected_msg='Message stream modified') 66 67realm.stop() 68 69if not pkinit_enabled: 70 skipped('anonymous ticket authdata tests', 'PKINIT not built') 71else: 72 # Set up a realm with PKINIT support and get anonymous tickets. 73 realm = K5Realm(krb5_conf=conf, get_creds=False, pkinit=True) 74 realm.addprinc('WELLKNOWN/ANONYMOUS') 75 realm.kinit('@%s' % realm.realm, flags=['-n']) 76 77 # PAC and module authdata should be suppressed for anonymous 78 # tickets, but not request authdata. 79 mark('anonymous') 80 out = realm.run(['./adata', realm.host_princ, '-4', 'test']) 81 if ' -4: test' not in out: 82 fail('expected authdata not seen for anonymous request') 83 if '128: ' in out or '-42: ' in out: 84 fail('PAC or greet authdata seen for anonymous request') 85 86realm.stop() 87 88# Test authentication indicators. Load the test preauth module so we 89# can control the indicators asserted. 90testpreauth = os.path.join(buildtop, 'plugins', 'preauth', 'test', 'test.so') 91krb5conf = {'plugins': {'kdcpreauth': {'module': 'test:' + testpreauth}, 92 'clpreauth': {'module': 'test:' + testpreauth}}} 93realm, realm2 = cross_realms(2, args=({'realm': 'LOCAL'}, 94 {'realm': 'FOREIGN'}), 95 krb5_conf=krb5conf, get_creds=False) 96realm.run([kadminl, 'modprinc', '+requires_preauth', '-maxrenewlife', '2 days', 97 realm.user_princ]) 98realm.run([kadminl, 'modprinc', '-maxrenewlife', '2 days', realm.host_princ]) 99realm.run([kadminl, 'modprinc', '-maxrenewlife', '2 days', realm.krbtgt_princ]) 100realm.extract_keytab(realm.krbtgt_princ, realm.keytab) 101realm.extract_keytab(realm.host_princ, realm.keytab) 102realm.extract_keytab('krbtgt/FOREIGN', realm.keytab) 103realm2.extract_keytab(realm2.krbtgt_princ, realm.keytab) 104realm2.extract_keytab(realm2.host_princ, realm.keytab) 105realm2.extract_keytab('krbtgt/LOCAL', realm.keytab) 106 107# AS request to local-realm service 108mark('AS-REQ to local service auth indicator') 109realm.kinit(realm.user_princ, password('user'), 110 ['-X', 'indicators=indcl', '-r', '2d', '-S', realm.host_princ]) 111realm.run(['./adata', realm.host_princ], expected_msg='+97: [indcl]') 112 113# Ticket modification request 114mark('ticket modification auth indicator') 115realm.kinit(realm.user_princ, None, ['-R', '-S', realm.host_princ]) 116realm.run(['./adata', realm.host_princ], expected_msg='+97: [indcl]') 117 118# AS request to cross TGT 119mark('AS-REQ to cross TGT auth indicator') 120realm.kinit(realm.user_princ, password('user'), 121 ['-X', 'indicators=indcl', '-S', 'krbtgt/FOREIGN']) 122realm.run(['./adata', 'krbtgt/FOREIGN'], expected_msg='+97: [indcl]') 123 124# Multiple indicators 125mark('AS multiple indicators') 126realm.kinit(realm.user_princ, password('user'), 127 ['-X', 'indicators=indcl indcl2 indcl3']) 128realm.run(['./adata', realm.krbtgt_princ], 129 expected_msg='+97: [indcl, indcl2, indcl3]') 130 131# AS request to local TGT (resulting creds are used for TGS tests) 132mark('AS-REQ to local TGT auth indicator') 133realm.kinit(realm.user_princ, password('user'), ['-X', 'indicators=indcl']) 134realm.run(['./adata', realm.krbtgt_princ], expected_msg='+97: [indcl]') 135 136# Local TGS request for local realm service 137mark('TGS-REQ to local service auth indicator') 138realm.run(['./adata', realm.host_princ], expected_msg='+97: [indcl]') 139 140# Local TGS request for cross TGT service 141mark('TGS-REQ to cross TGT auth indicator') 142realm.run(['./adata', 'krbtgt/FOREIGN'], expected_msg='+97: [indcl]') 143 144# We don't yet have support for passing auth indicators across realms, 145# so just verify that indicators don't survive cross-realm requests. 146mark('TGS-REQ to foreign service auth indicator') 147out = realm.run(['./adata', realm2.krbtgt_princ]) 148if '97:' in out: 149 fail('auth-indicator seen in cross TGT request to local TGT') 150out = realm.run(['./adata', 'krbtgt/LOCAL@FOREIGN']) 151if '97:' in out: 152 fail('auth-indicator seen in cross TGT request to cross TGT') 153out = realm.run(['./adata', realm2.host_princ]) 154if '97:' in out: 155 fail('auth-indicator seen in cross TGT request to service') 156 157# Test that the CAMMAC signature still works during a krbtgt rollover. 158mark('CAMMAC signature across krbtgt rollover') 159realm.run([kadminl, 'cpw', '-randkey', '-keepold', realm.krbtgt_princ]) 160realm.run(['./adata', realm.host_princ], expected_msg='+97: [indcl]') 161 162# Test indicator enforcement. 163mark('auth indicator enforcement') 164realm.addprinc('restricted') 165realm.run([kadminl, 'setstr', 'restricted', 'require_auth', 'superstrong']) 166realm.kinit(realm.user_princ, password('user'), ['-S', 'restricted'], 167 expected_code=1, expected_msg='KDC policy rejects request') 168realm.run([kvno, 'restricted'], expected_code=1, 169 expected_msg='KDC policy rejects request') 170realm.run([kadminl, 'setstr', 'restricted', 'require_auth', 'indcl']) 171realm.run([kvno, 'restricted']) 172realm.kinit(realm.user_princ, password('user'), ['-X', 'indicators=ind1 ind2']) 173realm.run([kvno, 'restricted'], expected_code=1) 174realm.run([kadminl, 'setstr', 'restricted', 'require_auth', 'a b c ind2']) 175realm.run([kvno, 'restricted']) 176 177# Regression test for one manifestation of #8139: ensure that 178# forwarded TGTs obtained across a TGT re-key still work when the 179# preferred krbtgt enctype changes. 180mark('#8139 regression test') 181realm.kinit(realm.user_princ, password('user'), ['-f']) 182realm.run([kadminl, 'cpw', '-randkey', '-keepold', '-e', 'des3-cbc-sha1', 183 realm.krbtgt_princ]) 184realm.run(['./forward']) 185realm.run([kvno, realm.host_princ]) 186 187# Repeat the above test using a renewed TGT. 188mark('#8139 regression test (renewed TGT)') 189realm.kinit(realm.user_princ, password('user'), ['-r', '2d']) 190realm.run([kadminl, 'cpw', '-randkey', '-keepold', '-e', 'aes128-cts', 191 realm.krbtgt_princ]) 192realm.kinit(realm.user_princ, None, ['-R']) 193realm.run([kvno, realm.host_princ]) 194 195realm.stop() 196realm2.stop() 197 198# Load the test KDB module to allow successful S4U2Proxy 199# auth-indicator requests and to detect whether replaced_reply_key is 200# set. 201testprincs = {'krbtgt/KRBTEST.COM': {'keys': 'aes128-cts'}, 202 'krbtgt/FOREIGN': {'keys': 'aes128-cts'}, 203 'user': {'keys': 'aes128-cts', 'flags': '+preauth'}, 204 'user2': {'keys': 'aes128-cts', 'flags': '+preauth'}, 205 'rservice': {'keys': 'aes128-cts', 206 'strings': 'require_auth:strong'}, 207 'service/1': {'keys': 'aes128-cts', 208 'flags': '+ok_to_auth_as_delegate'}, 209 'service/2': {'keys': 'aes128-cts'}, 210 'noauthdata': {'keys': 'aes128-cts', 211 'flags': '+no_auth_data_required'}} 212kdcconf = {'realms': {'$realm': {'database_module': 'test'}}, 213 'dbmodules': {'test': {'db_library': 'test', 214 'princs': testprincs, 215 'delegation': {'service/1': 'service/2'}}}} 216realm = K5Realm(krb5_conf=krb5conf, kdc_conf=kdcconf, create_kdb=False, 217 pkinit=True) 218usercache = 'FILE:' + os.path.join(realm.testdir, 'usercache') 219realm.extract_keytab(realm.krbtgt_princ, realm.keytab) 220realm.extract_keytab('krbtgt/FOREIGN', realm.keytab) 221realm.extract_keytab(realm.user_princ, realm.keytab) 222realm.extract_keytab('ruser', realm.keytab) 223realm.extract_keytab('service/1', realm.keytab) 224realm.extract_keytab('service/2', realm.keytab) 225realm.extract_keytab('noauthdata', realm.keytab) 226realm.start_kdc() 227 228if not pkinit_enabled: 229 skipped('replaced_reply_key test', 'PKINIT not built') 230else: 231 # Check that replaced_reply_key is set in issue_pac() when PKINIT 232 # is used. The test KDB module will indicate this by including a 233 # fake PAC_CREDENTIAL_INFO(2) buffer in the PAC. 234 mark('PKINIT (replaced_reply_key set)') 235 realm.pkinit(realm.user_princ) 236 realm.run(['./adata', realm.krbtgt_princ], 237 expected_msg='?128: [1, 2, 6, 7, 10]') 238 239# S4U2Self (should have no indicators since client did not authenticate) 240mark('S4U2Self (no auth indicators expected)') 241realm.kinit('service/1', None, ['-k', '-f', '-X', 'indicators=inds1']) 242realm.run([kvno, '-U', 'user', 'service/1']) 243out = realm.run(['./adata', '-p', realm.user_princ, 'service/1']) 244if '97:' in out: 245 fail('auth-indicator present in S4U2Self response') 246 247# Get another S4U2Self ticket with requested authdata. 248realm.run(['./s4u2self', 'user', 'service/1', '-', '-2', 'self_ad']) 249realm.run(['./adata', '-p', realm.user_princ, 'service/1', '-2', 'self_ad'], 250 expected_msg=' -2: self_ad') 251 252# S4U2Proxy (indicators should come from evidence ticket, not TGT) 253mark('S4U2Proxy (auth indicators from evidence ticket expected)') 254realm.kinit(realm.user_princ, None, ['-k', '-f', '-X', 'indicators=indcl', 255 '-S', 'service/1', '-c', usercache]) 256realm.run(['./s4u2proxy', usercache, 'service/2']) 257out = realm.run(['./adata', '-p', realm.user_princ, 'service/2']) 258if '+97: [indcl]' not in out or '[inds1]' in out: 259 fail('correct auth-indicator not seen for S4U2Proxy req') 260# Make sure a PAC with an S4U_DELEGATION_INFO(11) buffer is included. 261if '?128: [1, 6, 7, 10, 11, 16, 19]' not in out: 262 fail('PAC with delegation info not seen for S4U2Proxy req') 263 264# Get another S4U2Proxy ticket including request-authdata. 265realm.run(['./s4u2proxy', usercache, 'service/2', '-2', 'proxy_ad']) 266realm.run(['./adata', '-p', realm.user_princ, 'service/2', '-2', 'proxy_ad'], 267 expected_msg=' -2: proxy_ad') 268 269# Get an S4U2Proxy ticket using an evidence ticket obtained by S4U2Self, 270# with request authdata in both steps. 271realm.run(['./s4u2self', 'user2', 'service/1', usercache, '-2', 'self_ad']) 272realm.run(['./s4u2proxy', usercache, 'service/2', '-2', 'proxy_ad']) 273out = realm.run(['./adata', '-p', 'user2', 'service/2', '-2', 'proxy_ad']) 274if ' -2: self_ad' not in out or ' -2: proxy_ad' not in out: 275 fail('expected authdata not seen in S4U2Proxy ticket') 276 277# Test alteration of auth indicators by KDB module (AS and TGS). 278realm.kinit(realm.user_princ, None, ['-k', '-X', 'indicators=dummy dbincr1']) 279realm.run(['./adata', realm.krbtgt_princ], expected_msg='+97: [dbincr2]') 280realm.run(['./adata', 'service/1'], expected_msg='+97: [dbincr3]') 281realm.kinit(realm.user_princ, None, 282 ['-k', '-X', 'indicators=strong', '-S', 'rservice']) 283# Test enforcement of altered indicators during AS request. 284realm.kinit(realm.user_princ, None, 285 ['-k', '-X', 'indicators=strong dbincr1', '-S', 'rservice'], 286 expected_code=1) 287 288# Test that the PAC is suppressed in an AS request by a negative PAC 289# request. 290mark('AS-REQ PAC client supression') 291realm.kinit(realm.user_princ, None, ['-k', '--no-request-pac']) 292out = realm.run(['./adata', realm.krbtgt_princ]) 293if '128:' in out: 294 fail('PAC not suppressed by --no-request-pac') 295 296mark('S4U2Proxy with a foreign client') 297 298a_princs = {'krbtgt/A': {'keys': 'aes128-cts'}, 299 'krbtgt/B': {'keys': 'aes128-cts'}, 300 'impersonator': {'keys': 'aes128-cts'}, 301 'impersonator2': {'keys': 'aes128-cts'}, 302 'resource': {'keys': 'aes128-cts'}} 303a_kconf = {'realms': {'$realm': {'database_module': 'test'}}, 304 'dbmodules': {'test': {'db_library': 'test', 305 'delegation': {'impersonator' : 'resource'}, 306 'princs': a_princs, 307 'alias': {'service/rb.b': '@B'}}}} 308 309b_princs = {'krbtgt/B': {'keys': 'aes128-cts'}, 310 'krbtgt/A': {'keys': 'aes128-cts'}, 311 'user': {'keys': 'aes128-cts', 'flags': '+preauth'}, 312 'rb': {'keys': 'aes128-cts'}} 313b_kconf = {'realms': {'$realm': {'database_module': 'test'}}, 314 'dbmodules': {'test': {'db_library': 'test', 315 'princs': b_princs, 316 'rbcd': {'rb@B': 'impersonator2@A'}, 317 'alias': {'service/rb.b': 'rb', 318 'impersonator2@A': '@A'}}}} 319 320ra, rb = cross_realms(2, xtgts=(), 321 args=({'realm': 'A', 'kdc_conf': a_kconf}, 322 {'realm': 'B', 'kdc_conf': b_kconf}), 323 create_kdb=False) 324 325ra.start_kdc() 326rb.start_kdc() 327 328ra.extract_keytab('impersonator@A', ra.keytab) 329ra.extract_keytab('impersonator2@A', ra.keytab) 330rb.extract_keytab('user@B', rb.keytab) 331 332usercache = 'FILE:' + os.path.join(rb.testdir, 'usercache') 333rb.kinit(rb.user_princ, None, ['-k', '-f', '-c', usercache]) 334rb.run([kvno, '-C', 'impersonator@A', '-c', usercache]) 335 336ra.kinit('impersonator@A', None, ['-f', '-k', '-t', ra.keytab]) 337ra.run(['./s4u2proxy', usercache, 'resource@A']) 338 339mark('Cross realm S4U authdata tests') 340 341ra.kinit('impersonator2@A', None, ['-f', '-k', '-t', ra.keytab]) 342ra.run(['./s4u2self', rb.user_princ, 'impersonator2@A', usercache, '-2', 343 'cross_s4u_self_ad']) 344out = ra.run(['./adata', '-c', usercache, '-p', rb.user_princ, 345 'impersonator2@A', '-2', 'cross_s4u_self_ad']) 346if out.count(' -2: cross_s4u_self_ad') != 1: 347 fail('expected one cross_s4u_self_ad, got: %s' % count) 348 349ra.run(['./s4u2proxy', usercache, 'service/rb.b', '-2', 350 'cross_s4u_proxy_ad']) 351rb.extract_keytab('service/rb.b', ra.keytab) 352out = ra.run(['./adata', '-p', rb.user_princ, 'service/rb.b', '-2', 353 'cross_s4u_proxy_ad']) 354if out.count(' -2: cross_s4u_self_ad') != 1: 355 fail('expected one cross_s4u_self_ad, got: %s' % count) 356if out.count(' -2: cross_s4u_proxy_ad') != 1: 357 fail('expected one cross_s4u_proxy_ad, got: %s' % count) 358 359ra.stop() 360rb.stop() 361 362success('Authorization data tests') 363