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