summaryrefslogtreecommitdiffstats
path: root/src/tests/t_localauth.py
blob: 1d498edf8a9aeb4ed5974d64d0760447b3c972e8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#!/usr/bin/python
from k5test import *

# Unfortunately, we can't reliably test the k5login module.  We can control
# the directory where k5login files are read, but we can't suppress the UID
# validity check, which might fail in some filesystems for a .k5login file
# we create.
conf = {'plugins': {'localauth': { 'disable': 'k5login'}}}
realm = K5Realm(create_kdb=False, krb5_conf=conf)

def test_an2ln(env, aname, result, msg):
    out = realm.run(['./t_localauth', aname], env=env)
    if out != result + '\n':
        fail(msg)

def test_an2ln_err(env, aname, err, msg):
    out = realm.run(['./t_localauth', aname], env=env, expected_code=1)
    if err not in out:
        fail(msg)

def test_userok(env, aname, lname, ok, msg):
    out = realm.run(['./t_localauth', aname, lname], env=env)
    if ((ok and out != 'yes\n') or
        (not ok and out != 'no\n')):
        fail(msg)

# The default an2ln method works only in the default realm, and works
# for a single-component principal or a two-component principal where
# the second component is the default realm.
test_an2ln(None, 'user@KRBTEST.COM', 'user', 'default rule 1')
test_an2ln(None, 'user/KRBTEST.COM@KRBTEST.COM', 'user', 'default rule 2')
test_an2ln_err(None, 'user/KRBTEST.COM/x@KRBTEST.COM', 'No translation',
               'default rule (3)')
test_an2ln_err(None, 'user/X@KRBTEST.COM', 'No translation',
               'default rule comp mismatch')
test_an2ln_err(None, 'user@X', 'No translation', 'default rule realm mismatch')

# auth_to_local_names matches ignore the realm but are case-sensitive.
conf_names1 = {'realms': {'$realm': {'auth_to_local_names': {'user': 'abcd'}}}}
names1 = realm.special_env('names1', False, conf_names1)
test_an2ln(names1, 'user@KRBTEST.COM', 'abcd', 'auth_to_local_names match')
test_an2ln(names1, 'user@X', 'abcd', 'auth_to_local_names out-of-realm match')
test_an2ln(names1, 'x@KRBTEST.COM', 'x', 'auth_to_local_names mismatch')
test_an2ln(names1, 'User@KRBTEST.COM', 'User', 'auth_to_local_names case')

# auth_to_local_names values must be in the default realm's section.
conf_names2 = {'realms': {'X': {'auth_to_local_names': {'user': 'abcd'}}}}
names2 = realm.special_env('names2', False, conf_names2)
test_an2ln_err(names2, 'user@X', 'No translation',
               'auth_to_local_names section mismatch')

# Return a realm environment containing an auth_to_local value (or list).
def a2l_realm(name, values):
    conf = {'realms': {'$realm': {'auth_to_local': values}}}
    return realm.special_env(name, False, conf)

# Test explicit use of default method.
auth1 = a2l_realm('auth1', 'DEFAULT')
test_an2ln(auth1, 'user@KRBTEST.COM', 'user', 'default rule')

# Test some invalid auth_to_local values.
auth2 = a2l_realm('auth2', 'RULE')
test_an2ln_err(auth2, 'user@X', 'Improper format', 'null rule')
auth3 = a2l_realm('auth3', 'UNRECOGNIZED:stuff')
test_an2ln_err(auth3, 'user@X', 'Improper format', 'null rule')

# An empty rule has the default selection string (unparsed principal
# without realm) and no match or substitutions.
rule1 = a2l_realm('rule1', 'RULE:')
test_an2ln(rule1, 'user@KRBTEST.COM', 'user', 'empty rule')
test_an2ln(rule1, 'user@X', 'user', 'empty rule (foreign realm)')
test_an2ln(rule1, 'a/b/c@X', 'a/b/c', 'empty rule (multi-component)')

# Test explicit selection string.  Also test that the default method
# is suppressed when auth_to_local values are present.
rule2 = a2l_realm('rule2', 'RULE:[2:$$0.$$2.$$1]')
test_an2ln(rule2, 'aaron/burr@REALM', 'REALM.burr.aaron', 'selection string')
test_an2ln_err(rule2, 'user@KRBTEST.COM', 'No translation', 'suppress default')

# Test match string.
rule3 = a2l_realm('rule3', 'RULE:(.*tail)')
test_an2ln(rule3, 'withtail@X', 'withtail', 'rule match 1')
test_an2ln(rule3, 'x/withtail@X', 'x/withtail', 'rule match 2')
test_an2ln_err(rule3, 'tails@X', 'No translation', 'rule anchor mismatch')

# Test substitutions.
rule4 = a2l_realm('rule4', 'RULE:s/birds/bees/')
test_an2ln(rule4, 'thebirdsbirdsbirds@X', 'thebeesbirdsbirds', 'subst 1')
rule5 = a2l_realm('rule4', 'RULE:s/birds/bees/g  s/bees/birds/')
test_an2ln(rule4, 'the/birdsbirdsbirds@x', 'the/birdsbeesbees', 'subst 2')

# Test a bunch of auth_to_local values and rule features in combination.
combo = a2l_realm('combo', ['RULE:[1:$$1-$$0](fred.*)s/-/ /g',
                            'DEFAULT',
                            'RULE:[3:$$1](z.*z)'])
test_an2ln(combo, 'fred@X', 'fred X', 'combo 1')
test_an2ln(combo, 'fred-too@X', 'fred too X', 'combo 2')
test_an2ln(combo, 'fred@KRBTEST.COM', 'fred KRBTEST.COM', 'combo 3')
test_an2ln(combo, 'user@KRBTEST.COM', 'user', 'combo 4')
test_an2ln(combo, 'zazz/b/c@X', 'zazz', 'combo 5')
test_an2ln_err(combo, 'a/b@KRBTEST.COM', 'No translation', 'combo 6')

# Test the an2ln userok method with the combo environment.
test_userok(combo, 'fred@X', 'fred X', True, 'combo userok 1')
test_userok(combo, 'user@KRBTEST.COM', 'user', True, 'combo userok 2')
test_userok(combo, 'user@KRBTEST.COM', 'X', False, 'combo userok 3')
test_userok(combo, 'a/b@KRBTEST.COM', 'a/b', False, 'combo userok 4')

# Register the two test modules and set up some auth_to_local and
# auth_to_local_names entries.
modpath = os.path.join(buildtop, 'plugins', 'localauth', 'test',
                       'localauth_test.so')
conf = {'plugins': {'localauth': { 'module': [
                'test1:' + modpath,
                'test2:' + modpath]}},
        'realms': {'$realm': {'auth_to_local': [
                'RULE:(test/rulefirst)s/.*/rule/',
                'TYPEA',
                'DEFAULT',
                'TYPEB:resid']},
                   'auth_to_local_names': {'test/a/b': 'name'}}}
mod = realm.special_env('mod', False, conf)

# test1's untyped an2ln method should come before the names method, mapping
# test/a/b@X to its realm name (superceding auth_to_local_names).
test_an2ln(mod, 'test/a/b@X', 'X', 'mod untyped an2ln')

# Match the auth_to_local values in order.  test2's TYPEA should map
# test/notrule to its second component, and its TYPEB should map
# anything which gets there to the residual string.
test_an2ln(mod, 'test/rulefirst@X', 'rule', 'mod auth_to_local 1')
test_an2ln(mod, 'test/notrule', 'notrule', 'mod auth_to_local 2')
test_an2ln(mod, 'user@KRBTEST.COM', 'user', 'mod auth_to_local 3')
test_an2ln(mod, 'xyz@X', 'resid', 'mod auth_to_local 4')

# test2's userok module should succeed when the number of components
# is equal to the length of the local name, should pass if the first
# component is 'pass', and should reject otherwise.
test_userok(mod, 'a/b/c/d@X', 'four', True, 'mod userok 1')
test_userok(mod, 'x/y/z@X', 'four', False, 'mod userok 2')
test_userok(mod, 'pass@KRBTEST.COM', 'pass', True, 'mod userok 3')
test_userok(mod, 'user@KRBTEST.COM', 'user', False, 'mod userok 4')

success('krb5_kuserok and krb5_aname_to_localname tests')