summaryrefslogtreecommitdiff
path: root/macaroonbakery/tests/test_authorizer.py
blob: f90d2b5588ac19c47ed004d4f28a31dc892f8533 (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
# Copyright 2017 Canonical Ltd.
# Licensed under the LGPLv3, see LICENCE file for details.
from unittest import TestCase

import macaroonbakery as bakery
import macaroonbakery.checkers as checkers


class TestAuthorizer(TestCase):
    def test_authorize_func(self):
        def f(ctx, identity, op):
            self.assertEqual(identity.id(), 'bob')
            if op.entity == 'a':
                return False, None
            elif op.entity == 'b':
                return True, None
            elif op.entity == 'c':
                return True, [checkers.Caveat(location='somewhere',
                                              condition='c')]
            elif op.entity == 'd':
                return True, [checkers.Caveat(location='somewhere',
                                              condition='d')]
            else:
                self.fail('unexpected entity: ' + op.Entity)

        ops = [bakery.Op('a', 'x'), bakery.Op('b', 'x'),
               bakery.Op('c', 'x'), bakery.Op('d', 'x')]
        allowed, caveats = bakery.AuthorizerFunc(f).authorize(
            checkers.AuthContext(),
            bakery.SimpleIdentity('bob'),
            ops
        )
        self.assertEqual(allowed, [False, True, True, True])
        self.assertEqual(caveats, [
            checkers.Caveat(location='somewhere', condition='c'),
            checkers.Caveat(location='somewhere', condition='d')
        ])

    def test_acl_authorizer(self):
        ctx = checkers.AuthContext()
        tests = [
            ('no ops, no problem',
             bakery.ACLAuthorizer(allow_public=True, get_acl=lambda x, y: []),
             None,
             [],
             []),
            ('identity that does not implement ACLIdentity; '
             'user should be denied except for everyone group',
             bakery.ACLAuthorizer(
                 allow_public=True,
                 get_acl=lambda ctx, op: [bakery.EVERYONE] if op.entity == 'a' else ['alice'],
             ),
             SimplestIdentity('bob'),
             [bakery.Op(entity='a', action='a'),
              bakery.Op(entity='b', action='b')],
             [True, False]),
            ('identity that does not implement ACLIdentity with user == Id; '
             'user should be denied except for everyone group',
             bakery.ACLAuthorizer(
                 allow_public=True,
                 get_acl=lambda ctx, op: [bakery.EVERYONE] if op.entity == 'a' else ['bob'],
             ),
             SimplestIdentity('bob'),
             [bakery.Op(entity='a', action='a'),
              bakery.Op(entity='b', action='b')],
             [True, False]),
            ('permission denied for everyone without AllowPublic',
             bakery.ACLAuthorizer(
                 allow_public=False,
                 get_acl=lambda x, y: [bakery.EVERYONE],
             ),
             SimplestIdentity('bob'),
             [bakery.Op(entity='a', action='a')],
             [False]),
            ('permission granted to anyone with no identity with AllowPublic',
             bakery.ACLAuthorizer(
                 allow_public=True,
                 get_acl=lambda x, y: [bakery.EVERYONE],
             ),
             None,
             [bakery.Op(entity='a', action='a')],
             [True])
        ]
        for test in tests:
            allowed, caveats = test[1].authorize(ctx, test[2], test[3])
            self.assertEqual(len(caveats), 0)
            self.assertEqual(allowed, test[4])

    def test_context_wired_properly(self):
        ctx = checkers.AuthContext({'a': 'aval'})

        class Visited:
            in_f = False
            in_allow = False
            in_get_acl = False

        def f(ctx, identity, op):
            self.assertEqual(ctx.get('a'), 'aval')
            Visited.in_f = True
            return False, None

        bakery.AuthorizerFunc(f).authorize(
            ctx, bakery.SimpleIdentity('bob'), ['op1']
        )
        self.assertTrue(Visited.in_f)

        class TestIdentity(SimplestIdentity, bakery.ACLIdentity):
            def allow(other, ctx, acls):
                self.assertEqual(ctx.get('a'), 'aval')
                Visited.in_allow = True
                return False

        def get_acl(ctx, acl):
            self.assertEqual(ctx.get('a'), 'aval')
            Visited.in_get_acl = True
            return []

        bakery.ACLAuthorizer(
            allow_public=False,
            get_acl=get_acl,
        ).authorize(ctx, TestIdentity('bob'), ['op1'])
        self.assertTrue(Visited.in_get_acl)
        self.assertTrue(Visited.in_allow)


class SimplestIdentity(bakery.Identity):
    # SimplestIdentity implements Identity for a string. Unlike
    # SimpleIdentity, it does not implement ACLIdentity.
    def __init__(self, user):
        self._identity = user

    def domain(self):
        return ''

    def id(self):
        return self._identity