1*7f2fe78bSCy Schubertfrom k5test import * 2*7f2fe78bSCy Schubertfrom datetime import datetime 3*7f2fe78bSCy Schubertimport re 4*7f2fe78bSCy Schubert 5*7f2fe78bSCy Schubertconf = {'realms': {'$realm': {'max_life': '20h', 'max_renewable_life': '20h'}}} 6*7f2fe78bSCy Schubertrealm = K5Realm(create_host=False, get_creds=False, kdc_conf=conf) 7*7f2fe78bSCy Schubert 8*7f2fe78bSCy Schubert# We will be scraping timestamps from klist to compute lifetimes, so 9*7f2fe78bSCy Schubert# use a time zone with no daylight savings time. 10*7f2fe78bSCy Schubertrealm.env['TZ'] = 'UTC' 11*7f2fe78bSCy Schubert 12*7f2fe78bSCy Schubertdef test(testname, life, rlife, exp_life, exp_rlife, env=None): 13*7f2fe78bSCy Schubert global realm 14*7f2fe78bSCy Schubert flags = ['-l', life] 15*7f2fe78bSCy Schubert if rlife is not None: 16*7f2fe78bSCy Schubert flags += ['-r', rlife] 17*7f2fe78bSCy Schubert realm.kinit(realm.user_princ, password('user'), flags=flags, env=env) 18*7f2fe78bSCy Schubert out = realm.run([klist, '-f']) 19*7f2fe78bSCy Schubert 20*7f2fe78bSCy Schubert if ('Default principal: %s\n' % realm.user_princ) not in out: 21*7f2fe78bSCy Schubert fail('%s: did not get tickets' % testname) 22*7f2fe78bSCy Schubert 23*7f2fe78bSCy Schubert # Extract flags and check the renewable flag against expectations. 24*7f2fe78bSCy Schubert flags = re.findall(r'Flags: ([a-zA-Z]*)', out)[0] 25*7f2fe78bSCy Schubert if exp_rlife is None and 'R' in flags: 26*7f2fe78bSCy Schubert fail('%s: ticket unexpectedly renewable' % testname) 27*7f2fe78bSCy Schubert if exp_rlife is not None and 'R' not in flags: 28*7f2fe78bSCy Schubert fail('%s: ticket unexpectedly non-renewable' % testname) 29*7f2fe78bSCy Schubert 30*7f2fe78bSCy Schubert # Extract the start time, end time, and renewable end time if present. 31*7f2fe78bSCy Schubert times = re.findall(r'\d\d/\d\d/\d\d \d\d:\d\d:\d\d', out) 32*7f2fe78bSCy Schubert times = [datetime.strptime(t, '%m/%d/%y %H:%M:%S') for t in times] 33*7f2fe78bSCy Schubert starttime = times[0] 34*7f2fe78bSCy Schubert endtime = times[1] 35*7f2fe78bSCy Schubert rtime = times[2] if len(times) >= 3 else None 36*7f2fe78bSCy Schubert 37*7f2fe78bSCy Schubert # Check the ticket lifetime against expectations. If the lifetime 38*7f2fe78bSCy Schubert # was determined by the request, there may be a small error 39*7f2fe78bSCy Schubert # because KDC requests contain an end time rather than a lifetime. 40*7f2fe78bSCy Schubert life = (endtime - starttime).seconds 41*7f2fe78bSCy Schubert if abs(life - exp_life) > 5: 42*7f2fe78bSCy Schubert fail('%s: expected life %d, got %d' % (testname, exp_life, life)) 43*7f2fe78bSCy Schubert 44*7f2fe78bSCy Schubert # Check the ticket renewable lifetime against expectations. 45*7f2fe78bSCy Schubert if exp_rlife is None and rtime is not None: 46*7f2fe78bSCy Schubert fail('%s: ticket has unexpected renew_till' % testname) 47*7f2fe78bSCy Schubert if exp_rlife is not None and rtime is None: 48*7f2fe78bSCy Schubert fail('%s: ticket is renewable but has no renew_till' % testname) 49*7f2fe78bSCy Schubert if rtime is not None: 50*7f2fe78bSCy Schubert rlife = (rtime - starttime).seconds 51*7f2fe78bSCy Schubert if abs(rlife - exp_rlife) > 5: 52*7f2fe78bSCy Schubert fail('%s: expected rlife %d, got %d' % 53*7f2fe78bSCy Schubert (testname, exp_rlife, rlife)) 54*7f2fe78bSCy Schubert 55*7f2fe78bSCy Schubert# Get renewable tickets. 56*7f2fe78bSCy Schuberttest('simple', '1h', '2h', 3600, 7200) 57*7f2fe78bSCy Schubert 58*7f2fe78bSCy Schubert# Renew twice, to test that renewed tickets are renewable. 59*7f2fe78bSCy Schubertmark('renew twice') 60*7f2fe78bSCy Schubertrealm.kinit(realm.user_princ, flags=['-R']) 61*7f2fe78bSCy Schubertrealm.kinit(realm.user_princ, flags=['-R']) 62*7f2fe78bSCy Schubertrealm.klist(realm.user_princ) 63*7f2fe78bSCy Schubert 64*7f2fe78bSCy Schubert# Make sure we can use a renewed ticket. 65*7f2fe78bSCy Schubertrealm.run([kvno, realm.user_princ]) 66*7f2fe78bSCy Schubert 67*7f2fe78bSCy Schubert# Make sure we can't renew non-renewable tickets. 68*7f2fe78bSCy Schubertmark('non-renewable') 69*7f2fe78bSCy Schuberttest('non-renewable', '1h', None, 3600, None) 70*7f2fe78bSCy Schubertrealm.kinit(realm.user_princ, flags=['-R'], expected_code=1, 71*7f2fe78bSCy Schubert expected_msg="KDC can't fulfill requested option") 72*7f2fe78bSCy Schubert 73*7f2fe78bSCy Schubert# Test that -allow_renewable on the client principal works. 74*7f2fe78bSCy Schubertmark('allow_renewable (client)') 75*7f2fe78bSCy Schubertrealm.run([kadminl, 'modprinc', '-allow_renewable', 'user']) 76*7f2fe78bSCy Schuberttest('disallowed client', '1h', '2h', 3600, None) 77*7f2fe78bSCy Schubertrealm.run([kadminl, 'modprinc', '+allow_renewable', 'user']) 78*7f2fe78bSCy Schubert 79*7f2fe78bSCy Schubert# Test that -allow_renewable on the server principal works. 80*7f2fe78bSCy Schubertmark('allow_renewable (server)') 81*7f2fe78bSCy Schubertrealm.run([kadminl, 'modprinc', '-allow_renewable', realm.krbtgt_princ]) 82*7f2fe78bSCy Schuberttest('disallowed server', '1h', '2h', 3600, None) 83*7f2fe78bSCy Schubertrealm.run([kadminl, 'modprinc', '+allow_renewable', realm.krbtgt_princ]) 84*7f2fe78bSCy Schubert 85*7f2fe78bSCy Schubert# Test that trivially renewable tickets are issued if renew_till <= 86*7f2fe78bSCy Schubert# till. (Our client code bumps up the requested renewable life to the 87*7f2fe78bSCy Schubert# requested life.) 88*7f2fe78bSCy Schubertmark('trivially renewable') 89*7f2fe78bSCy Schuberttest('short', '2h', '1h', 7200, 7200) 90*7f2fe78bSCy Schubert 91*7f2fe78bSCy Schubert# Test that renewable tickets are issued if till > max life by 92*7f2fe78bSCy Schubert# default, but not if we configure away the RENEWABLE-OK option. 93*7f2fe78bSCy Schubertmark('renewable-ok') 94*7f2fe78bSCy Schubertno_opts_conf = {'libdefaults': {'kdc_default_options': '0'}} 95*7f2fe78bSCy Schubertno_opts = realm.special_env('no_opts', False, krb5_conf=no_opts_conf) 96*7f2fe78bSCy Schubertrealm.run([kadminl, 'modprinc', '-maxlife', '10 hours', 'user']) 97*7f2fe78bSCy Schuberttest('long', '15h', None, 10 * 3600, 15 * 3600) 98*7f2fe78bSCy Schuberttest('long noopts', '15h', None, 10 * 3600, None, env=no_opts) 99*7f2fe78bSCy Schubertrealm.run([kadminl, 'modprinc', '-maxlife', '20 hours', 'user']) 100*7f2fe78bSCy Schubert 101*7f2fe78bSCy Schubert# Test maximum renewable life on the client principal. 102*7f2fe78bSCy Schubertmark('maxrenewlife (client)') 103*7f2fe78bSCy Schubertrealm.run([kadminl, 'modprinc', '-maxrenewlife', '5 hours', 'user']) 104*7f2fe78bSCy Schuberttest('maxrenewlife client 1', '4h', '5h', 4 * 3600, 5 * 3600) 105*7f2fe78bSCy Schuberttest('maxrenewlife client 2', '6h', '10h', 6 * 3600, 5 * 3600) 106*7f2fe78bSCy Schubert 107*7f2fe78bSCy Schubert# Test maximum renewable life on the server principal. 108*7f2fe78bSCy Schubertmark('maxrenewlife (server)') 109*7f2fe78bSCy Schubertrealm.run([kadminl, 'modprinc', '-maxrenewlife', '3 hours', 110*7f2fe78bSCy Schubert realm.krbtgt_princ]) 111*7f2fe78bSCy Schuberttest('maxrenewlife server 1', '2h', '3h', 2 * 3600, 3 * 3600) 112*7f2fe78bSCy Schuberttest('maxrenewlife server 2', '4h', '8h', 4 * 3600, 3 * 3600) 113*7f2fe78bSCy Schubert 114*7f2fe78bSCy Schubert# Test realm maximum life. 115*7f2fe78bSCy Schubertmark('realm maximum life') 116*7f2fe78bSCy Schubertrealm.run([kadminl, 'modprinc', '-maxrenewlife', '40 hours', 'user']) 117*7f2fe78bSCy Schubertrealm.run([kadminl, 'modprinc', '-maxrenewlife', '40 hours', 118*7f2fe78bSCy Schubert realm.krbtgt_princ]) 119*7f2fe78bSCy Schuberttest('maxrenewlife realm 1', '10h', '20h', 10 * 3600, 20 * 3600) 120*7f2fe78bSCy Schuberttest('maxrenewlife realm 2', '21h', '40h', 20 * 3600, 20 * 3600) 121*7f2fe78bSCy Schubert 122*7f2fe78bSCy Schubertsuccess('Renewing credentials') 123