コード例 #1
0
 def test_find_for_inquiry_with_fuzzy_string_checker(self, st):
     st.add(
         Policy('1',
                subjects=['max', 'bob'],
                actions=['get'],
                resources=['books', 'comics', 'magazines']))
     st.add(
         Policy('2',
                subjects=['maxim'],
                actions=['get'],
                resources=['books', 'foos']))
     st.add(
         Policy('3',
                subjects=['Max'],
                actions=['get'],
                resources=['books', 'comics']))
     st.add(Policy('4', subjects=['sam', 'nina']))
     st.add(Policy('5', subjects=[Eq('sam'), Eq('nina')]))
     inquiry = Inquiry(subject='max', action='et', resource='oo')
     found = st.find_for_inquiry(inquiry, StringFuzzyChecker())
     found = list(found)
     assert 2 == len(found)
     ids = [found[0].uid, found[1].uid]
     assert '1' in ids
     assert '2' in ids
     inquiry = Inquiry(subject='Max', action='get', resource='comics')
     found = st.find_for_inquiry(inquiry, StringFuzzyChecker())
     found = list(found)
     assert 1 == len(found)
     assert '3' == found[0].uid
コード例 #2
0
ファイル: test_redis.py プロジェクト: vinhphamduc/vakt
 def test_add(self, st):
     id = str(uuid.uuid4())
     p = Policy(
         uid=id,
         description='foo bar баз',
         subjects=('Edward Rooney', 'Florence Sparrow'),
         actions=['好'],
         resources=['<.*>'],
         context={
             'secret': Equal('i-am-a-teacher'),
             'rating': And(Eq(80), Greater(80))
         },
     )
     st.add(p)
     back = st.get(id)
     assert id == back.uid
     assert 'foo bar баз' == back.description
     assert isinstance(back.context['secret'], Equal)
     assert isinstance(back.context['rating'], And)
     assert '好' == back.actions[0]
     st.add(
         Policy('2',
                actions=[Eq('get'), Eq('put')],
                subjects=[Any()],
                resources=[{
                    'books': Eq('Harry')
                }]))
     assert '2' == st.get('2').uid
     assert 2 == len(st.get('2').actions)
     assert 1 == len(st.get('2').subjects)
     assert isinstance(st.get('2').subjects[0], Any)
     assert 1 == len(st.get('2').resources)
     assert isinstance(st.get('2').resources[0]['books'], Eq)
     assert 'Harry' == st.get('2').resources[0]['books'].val
コード例 #3
0
ファイル: test_sql.py プロジェクト: RYefccd/vakt
 def test_find_for_inquiry_with_exact_string_checker(self, st):
     st.add(Policy('1', subjects=['max', 'bob'], actions=['get'], resources=['books', 'comics', 'magazines']))
     st.add(Policy('2', subjects=['maxim'], actions=['get'], resources=['books', 'comics', 'magazines']))
     st.add(Policy('3', subjects=['sam', 'nina']))
     st.add(Policy('4', subjects=[Eq('sam'), Eq('nina')]))
     inquiry = Inquiry(subject='max', action='get', resource='books')
     found = st.find_for_inquiry(inquiry, StringExactChecker())
     found = list(found)
     assert 1 == len(found)
     assert '1' == found[0].uid
コード例 #4
0
ファイル: test_sql.py プロジェクト: RYefccd/vakt
 def test_find_for_inquiry_returns_existing_policies(self, st, checker, expect_number):
     st.add(Policy('1', subjects=['<[mM]ax>', '<.*>'], actions=['delete'], resources=['server']))
     st.add(Policy('2', subjects=['Ji<[mM]+>'], actions=['delete'], resources=[r'server<\s*>']))
     st.add(Policy('3', subjects=['sam<.*>', 'foo']))
     st.add(Policy('5', subjects=['Jim'], actions=['delete'], resources=['server']))
     st.add(Policy('4', subjects=[{'stars': Eq(90)}, Eq('Max')]))
     st.add(Policy('6', subjects=[Eq('Jim'), Eq('Nina')]))
     inquiry = Inquiry(subject='Jim', action='delete', resource='server')
     found = st.find_for_inquiry(inquiry, checker)
     found = list(found)
     assert expect_number == len(found)
コード例 #5
0
ファイル: test_memory.py プロジェクト: neerajshukla1911/vakt
def test_find_for_inquiry(st):
    st.add(Policy('1', subjects=['max', 'bob']))
    st.add(Policy('2', subjects=['sam', 'nina']))
    st.add(Policy('3', subjects=[Eq('max'), Eq('bob')]))
    inquiry = Inquiry(subject='sam', action='get', resource='books')
    found = st.find_for_inquiry(inquiry)
    found = list(found)
    assert 3 == len(found)
    assert ['max', 'bob'] == found[0].subjects or \
           ['max', 'bob'] == found[1].subjects or \
           ['max', 'bob'] == found[2].subjects
コード例 #6
0
def test_pretty_print():
    p = Policy('1', description='readme', subjects=['user'])
    assert "<class 'vakt.policy.Policy'>" in str(p)
    assert "'uid': '1'" in str(p)
    assert "'description': 'readme'" in str(p)
    assert "'subjects': ['user']" in str(p)
    assert "'effect': 'deny'" in str(p)
    assert "'resources': ()" in str(p)
    assert "'actions': ()" in str(p)
    assert "'context': {}" in str(p)
    p = Policy('2', actions=[Eq('get'), Eq('post')])
    assert "vakt.rules.operator.Eq" in str(p.actions)
コード例 #7
0
ファイル: test_model.py プロジェクト: vinhphamduc/vakt
 def test_update(self):
     id = str(uuid.uuid4())
     p = Policy(
         uid=id,
         description='foo bar баз',
         subjects=('Edward Rooney', 'Florence Sparrow'),
         actions=['<.*>'],
         resources=['<.*>'],
         context={
             'secret': Equal('i-am-a-teacher'),
         },
     )
     p_model = PolicyModel.from_policy(p)
     new_p = Policy(2, actions=[], subjects=[Eq('max'), Eq('bob')])
     p_model.update(new_p)
     policy__model_assert(p_model, new_p)
コード例 #8
0
def test_PolicyAllow_and_PolicyDeny(klass, is_allowed, effect):
    p = klass(1,
              actions=['<foo.bar>'],
              resources=['asdf'],
              subjects=['<qwerty>'],
              description='test')
    assert is_allowed == p.allow_access()
    assert 1 == p.uid
    assert 'test' == p.description
    assert TYPE_STRING_BASED == p.type
    assert ['<foo.bar>'] == p.actions
    assert ['asdf'] == p.resources
    assert ['<qwerty>'] == p.subjects
    assert {} == p.context
    assert '{"actions": ["<foo.bar>"], "context": {}, "description": "test", "effect": "%s", ' % effect + \
           '"resources": ["asdf"], "subjects": ["<qwerty>"], "type": 1, "uid": 1}' == p.to_json(sort=True)
    assert ['<foo.bar>'] == Policy.from_json(p.to_json()).actions
    p.effect = DENY_ACCESS
    assert DENY_ACCESS == p.effect
    p2 = klass(2, context={'a': Eq(100)})
    assert isinstance(p2.context.get('a'), Eq)
    assert 100 == p2.context.get('a').val
    # check positional arguments
    p3 = Policy(1,
                actions=['<foo.bar>'],
                resources=['asdf'],
                subjects=['<qwerty>'],
                description='test',
                effect=ALLOW_ACCESS if is_allowed else DENY_ACCESS)
    p4 = klass(1, ['<qwerty>'], ['asdf'], ['<foo.bar>'], {}, 'test')
    assert p3.to_json(sort=True) == p4.to_json(sort=True)
コード例 #9
0
ファイル: test_sql.py プロジェクト: RYefccd/vakt
 def test_regex_checker_find_for_inquiry_policies_count_return_by_storage(self, st, dialect, expect_number):
     if st.dialect != dialect:
         pytest.skip('skipping for %s dialect' % dialect)
     st.add(Policy('1', subjects=['<[mM]ax>', '<.*>'], actions=['delete'], resources=['server']))
     st.add(Policy('2', subjects=['Ji<[mM]+>'], actions=['delete'], resources=[r'server<\s*>']))
     st.add(Policy('3', subjects=['sam<.*>', 'foo']))
     st.add(Policy('5', subjects=['Jim'], actions=['delete'], resources=['server']))
     st.add(Policy('6', subjects=['Ji<[mM]+>'], actions=[r'<[a-zA-Z]{6}>'], resources=['serve<(r|rs)>']))
     st.add(Policy('7', subjects=['Ji<[mM]+>'], actions=[r'<[a-zA-Z]{6}>'], resources=['serve<(u|rs)>']))
     st.add(Policy('8', subjects=['Ji<[mM]+>'], actions=[r'<[a-zA-Z]{6}>'], resources=['serve<(u|rs)>', 'server']))
     st.add(Policy('40', subjects=[{'stars': Eq(90)}, Eq('Max')]))
     st.add(Policy('60', subjects=[Eq('Jim'), Eq('Nina')]))
     inquiry = Inquiry(subject='Jim', action='delete', resource='server')
     found = st.find_for_inquiry(inquiry, RegexChecker())
     found = list(found)
     assert expect_number == len(found)
コード例 #10
0
ファイル: test_memory.py プロジェクト: neerajshukla1911/vakt
def test_update(st):
    policy = Policy('1')
    st.add(policy)
    assert '1' == st.get('1').uid
    assert None is st.get('1').description
    policy.description = 'foo'
    st.update(policy)
    assert '1' == st.get('1').uid
    assert 'foo' == st.get('1').description
    p = Policy(2, actions=[Any()], subjects=[Eq('max'), Eq('bob')])
    st.add(p)
    assert 2 == st.get(2).uid
    p.actions = [Eq('get')]
    st.update(p)
    assert 1 == len(st.get(2).actions)
    assert 'get' == st.get(2).actions[0].val
コード例 #11
0
def test_policy_type_on_attribute_change():
    p = Policy(1,
               actions=['<foo.bar>'],
               resources=['asdf'],
               subjects=['<qwerty>'])
    assert TYPE_STRING_BASED == p.type
    p.effect = ALLOW_ACCESS
    assert TYPE_STRING_BASED == p.type
    with pytest.raises(PolicyCreationError):
        p.actions = [{'ip': CIDR('0.0.0.0')}]
    assert TYPE_STRING_BASED == p.type
    with pytest.raises(PolicyCreationError):
        p.subjects = [{'ip': CIDR('0.0.0.0')}]
    with pytest.raises(PolicyCreationError):
        p.actions = [Any()]
    assert TYPE_STRING_BASED == p.type
    p.actions = ['<.*>']
    assert TYPE_STRING_BASED == p.type
    p.subjects = ['<.*>']
    assert TYPE_STRING_BASED == p.type
    p.type = TYPE_RULE_BASED  # explicit assign doesn't help
    assert TYPE_STRING_BASED == p.type
    # testing the from the opposite direction
    p = Policy(2,
               actions=[Any()],
               resources=[{
                   'book': Eq('UX Manual')
               }],
               subjects=[Eq('Sally'), Eq('Bob')])
    assert TYPE_RULE_BASED == p.type
    p.effect = ALLOW_ACCESS
    assert TYPE_RULE_BASED == p.type
    with pytest.raises(PolicyCreationError):
        p.actions = ['<foo.bar>']
    assert TYPE_RULE_BASED == p.type
    with pytest.raises(PolicyCreationError):
        p.subjects = ['<foo.bar>', 'baz']
    with pytest.raises(PolicyCreationError):
        p.actions = ['baz<.*>']
    assert TYPE_RULE_BASED == p.type
    p.actions = [Any()]
    assert TYPE_RULE_BASED == p.type
    p.subjects = [Any()]
    assert TYPE_RULE_BASED == p.type
    p.type = TYPE_STRING_BASED  # explicit assign doesn't help
    assert TYPE_RULE_BASED == p.type
コード例 #12
0
ファイル: test_memory.py プロジェクト: neerajshukla1911/vakt
def test_add(st):
    st.add(Policy('1', description='foo'))
    assert '1' == st.get('1').uid
    assert 'foo' == st.get('1').description
    st.add(
        Policy('2',
               actions=[Eq('get'), Eq('put')],
               subjects=[Any()],
               resources=[{
                   'books': Eq('Harry')
               }]))
    assert '2' == st.get('2').uid
    assert 2 == len(st.get('2').actions)
    assert 1 == len(st.get('2').subjects)
    assert isinstance(st.get('2').subjects[0], Any)
    assert 1 == len(st.get('2').resources)
    assert isinstance(st.get('2').resources[0]['books'], Eq)
    assert 'Harry' == st.get('2').resources[0]['books'].val
コード例 #13
0
ファイル: test_redis.py プロジェクト: vinhphamduc/vakt
 def test_update(self, st):
     id = str(uuid.uuid4())
     policy = Policy(id)
     st.add(policy)
     assert id == st.get(id).uid
     assert None is st.get(id).description
     assert () == st.get(id).actions or [] == st.get(id).actions
     policy.description = 'foo'
     policy.actions = ['a', 'b', 'c']
     st.update(policy)
     assert id == st.get(id).uid
     assert 'foo' == st.get(id).description
     assert ['a', 'b', 'c'] == st.get(id).actions
     p = Policy(2, actions=[Any()], subjects=[Eq('max'), Eq('bob')])
     st.add(p)
     assert 2 == st.get(2).uid
     p.actions = [Eq('get')]
     st.update(p)
     assert 1 == len(st.get(2).actions)
     assert 'get' == st.get(2).actions[0].val
コード例 #14
0
 def test_update(self, st):
     # SQL storage stores all uids as string
     id = str(uuid.uuid4())
     policy = Policy(id)
     st.add(policy)
     assert id == st.get(id).uid
     assert None is st.get(id).description
     assert [] == st.get(id).actions
     policy.description = 'foo'
     policy.actions = ['a', 'b', 'c']
     st.update(policy)
     assert id == st.get(id).uid
     assert 'foo' == st.get(id).description
     assert ['a', 'b', 'c'] == st.get(id).actions
     p = Policy('2', actions=[Any()], subjects=[Eq('max'), Eq('bob')])
     st.add(p)
     assert '2' == st.get('2').uid
     p.actions = [Eq('get')]
     st.update(p)
     assert 1 == len(st.get('2').actions)
     assert 'get' == st.get('2').actions[0].val
コード例 #15
0
ファイル: test_mongo.py プロジェクト: vinhphamduc/vakt
 def test_find_for_inquiry_with_regex_checker_for_mongodb_prior_to_4_2(
         self, st):
     # mock db server version for this test
     st.db_server_version = (3, 4, 0)
     st.add(Policy('1', subjects=['<[mM]ax>', '<.*>']))
     st.add(Policy('2', subjects=['sam<.*>', 'foo']))
     st.add(
         Policy('3',
                subjects=['Jim'],
                actions=['delete'],
                resources=['server']))
     st.add(
         Policy('3.1',
                subjects=['Jim'],
                actions=[r'del<\w+>'],
                resources=['server']))
     st.add(Policy('4', subjects=[{'stars': Eq(90)}, Eq('Max')]))
     st.add(Policy('5', subjects=[Eq('Jim'), Eq('Nina')]))
     inquiry = Inquiry(subject='Jim', action='delete', resource='server')
     found = st.find_for_inquiry(inquiry, RegexChecker())
     found = list(found)
     # should return all string-based polices, but not only matched ones
     assert 4 == len(found)
     assert ['1', '2', '3', '3.1'] == sorted(map(attrgetter('uid'), found))
コード例 #16
0
def test_or_rule_uses_short_circuit_but_and_rule_does_not():
    x = []

    def get_inc(x):
        def inc():
            x.append(1)
            return True

        return inc

    f = get_inc(x)
    rules = [Eq(f), Truthy()]
    # test Or
    r = Or(*rules)
    assert r.satisfied(f, None)
    assert r.satisfied(f, None)
    assert 0 == len(x)
    # test And
    r = And(*rules)
    assert r.satisfied(f, None)
    assert 1 == len(x)
    assert r.satisfied(f, None)
    assert 2 == len(x)
コード例 #17
0
     Policy(
         uid=1,
         effect=ALLOW_ACCESS,
         subjects=['foo'],
     ),
     Inquiry(subject='foo'),
     RegexChecker(),
     False,
 ),
 (
     'RulesChecker: Should not match since actions and resources are not specified',
     Policy(
         uid=1,
         effect=ALLOW_ACCESS,
         subjects=[{
             'name': Eq('Sally')
         }],
     ),
     Inquiry(subject={'name': 'Sally'}),
     RulesChecker(),
     False,
 ),
 (
     'RulesChecker: Should not match since resources are not specified',
     Policy(
         uid=1,
         effect=ALLOW_ACCESS,
         subjects=[{
             'name': Eq('Sally')
         }],
         actions=[{
コード例 #18
0
    ),
    Policy(uid='4'),
    Policy(
        uid='5',
        description='Allows Nina to update any resources that have only digits',
        effect=ALLOW_ACCESS,
        subjects=['Nina'],
        actions=['update'],
        resources=[r'<[\d]+>'],
    ),
    Policy(
        uid='6',
        description=
        'Allows Nina to update any resources that have only digits. Defined by rules',
        effect=ALLOW_ACCESS,
        subjects=[Eq('Nina')],
        actions=[Eq('update'), Eq('read')],
        resources=[{
            'id': RegexMatch(r'\d+'),
            'magazine': RegexMatch(r'[\d\w]+')
        }],
    ),
]
for p in policies:
    st.add(p)


@pytest.mark.parametrize('desc, inquiry, should_be_allowed, checker', [
    (
        'Empty inquiry carries no information, so nothing is allowed, even empty Policy #4',
        Inquiry(),
コード例 #19
0
def test_and_or_rules_bad_args():
    expected_msg = "Arguments should be of Rule class or it's derivatives"
    with pytest.raises(TypeError) as excinfo:
        And(Inquiry())
    assert expected_msg in str(excinfo.value)
    with pytest.raises(TypeError) as excinfo:
        Or(Inquiry(), 123)
    assert expected_msg in str(excinfo.value)


@pytest.mark.parametrize('rules, what, inquiry, result', [
    ([], 1, None, False),
    ([Greater(-1)], 1, None, True),
    ([Greater(55)], 1, None, False),
    ([Greater(-1), Less(10)], 1, None, True),
    ([Greater(-1), Less(10), Eq(700)], 1, None, False),
    ([Eq('read'), In('read', 'write'),
      ActionEqual()], 'read', Inquiry(action='read'), True),
    ([Eq('read'), In('write'), ActionEqual()
      ], 'read', Inquiry(action='read'), False),
])
def test_and_rule(rules, what, inquiry, result):
    r = And(*rules)
    assert result == r.satisfied(what, inquiry)
    # test after (de)serialization
    assert result == Rule.from_json(And(*rules).to_json()).satisfied(
        what, inquiry)


@pytest.mark.parametrize('rules, what, inquiry, result', [
    ([], 1, None, False),
コード例 #20
0
ファイル: test_policy.py プロジェクト: neerajshukla1911/vakt
        p = Policy('789', rules={'ip': CIDR('127.0.0.1'), 'sub': Equal('baz')})
        s = p.to_json()
        p1 = Policy.from_json(s)
        assert '789' == p1.uid
        assert 2 == len(p1.context)
        assert 'ip' in p1.context
        assert 'sub' in p1.context
        assert isinstance(p1.context['ip'], CIDR)
        assert isinstance(p1.context['sub'], Equal)
        assert p1.context['sub'].satisfied('baz')
        assert p1.context['ip'].satisfied('127.0.0.1')
        assert not hasattr(p1, 'rules')


@pytest.mark.parametrize('policy', [
    Policy(1, subjects=[{'name': Eq('Max'), 'rate': Greater(90)}], actions=[Eq('get'), Eq('post')], resources=[Any()]),
    Policy(2, subjects=[{'login': Eq('sally')}], actions=[Eq('get'), Eq('post')], context={'ip': Eq('127.0.0.1')}),
    Policy(3, subjects=[{'rating': AnyIn(1, 2)}], actions=[And(Eq('get'), Eq('post'))]),
    Policy(4, subjects=[{'rating': AnyIn(1, 2)}], actions=[And(Eq('get'), Eq('post'))]),
    Policy(5, actions=[Eq('get')]),
])
def test_json_roundtrip_of_a_rules_based_policy(policy):
    pj = policy.to_json()
    p2 = Policy.from_json(pj)
    assert policy.to_json() == p2.to_json()


@pytest.mark.parametrize('data, exception, msg', [
    ('{}', PolicyCreationError, "'uid'"),
    ('{"uid":}', ValueError, ''),
    ('', ValueError, ''),
コード例 #21
0
from vakt.checker import StringFuzzyChecker
from vakt.policy import Policy
from vakt.rules.operator import Eq


@pytest.mark.parametrize('policy, field, what, result', [
    (Policy('1', actions=['get']), 'actions', 'get', True),
    (Policy('1', actions=['get']), 'actions', 'g', True),
    (Policy('1', actions=['get']), 'actions', 'et', True),
    (Policy('1', actions=['get']), 'actions', 't', True),
    (Policy('1', actions=['get', 'list']), 'actions', 'list', True),
    (Policy('1', actions=['get', 'list']), 'non_existing_field', 'get', False),
    (Policy('1', actions=['<get>']), 'actions', 'get', True),
    (Policy('1', actions=['<get>']), 'actions', 'e', True),
    (Policy('1', actions=['<get>']), 'actions', '<get>', False),
    (Policy('1', actions=['<get>']), 'actions', '<t>', False),
    (Policy('1', actions=['<get']), 'actions', 'get', True),
    (Policy('1', actions=['<get']), 'actions', 'ge', True),
    (Policy('1', resources=['books:1', 'books:2'
                            ]), 'resources', 'books', True),
    (Policy('1', resources=['books:1', 'books:2']), 'resources', ':', True),
    (Policy('1', resources=['books:1', 'books:2']), 'resources', '3', False),
    (Policy('1', actions=[Eq('create')]), 'actions', 'create', False),
    (Policy('1', actions=[{
        'foo': Eq('create')
    }]), 'actions', 'create', False),
])
def test_fits(policy, field, what, result):
    c = StringFuzzyChecker()
    assert result == c.fits(policy, field, what)
コード例 #22
0
def test_is_allowed(desc, inquiry, should_be_allowed, checker):
    # Create all required test policies
    st = MemoryStorage()
    policies = [
        Policy(
            uid='1',
            description="""
            Max, Nina, Ben, Henry are allowed to create, delete, get the resources
            only if the client IP matches and the inquiry states that any of them is the resource owner
            """,
            effect=ALLOW_ACCESS,
            subjects=('Max', 'Nina', '<Ben|Henry>'),
            resources=('myrn:example.com:resource:123',
                       'myrn:example.com:resource:345',
                       'myrn:something:foo:<.+>'),
            actions=('<create|delete>', 'get'),
            context={
                'ip': CIDR('127.0.0.1/32'),
                'owner': SubjectEqual(),
            },
        ),
        Policy(
            uid='2',
            description='Allows Max to update any resource',
            effect=ALLOW_ACCESS,
            subjects=['Max'],
            actions=['update'],
            resources=['<.*>'],
        ),
        Policy(
            uid='3',
            description='Max is not allowed to print any resource',
            effect=DENY_ACCESS,
            subjects=['Max'],
            actions=['print'],
            resources=['<.*>'],
        ),
        Policy(uid='4'),
        Policy(
            uid='5',
            description=
            'Allows Nina to update any resources that have only digits',
            effect=ALLOW_ACCESS,
            subjects=['Nina'],
            actions=['update'],
            resources=[r'<[\d]+>'],
        ),
        Policy(
            uid='6',
            description=
            'Allows Nina to update any resources that have only digits. Defined by rules',
            effect=ALLOW_ACCESS,
            subjects=[Eq('Nina')],
            actions=[Eq('update'), Eq('read')],
            resources=[{
                'id': RegexMatch(r'\d+'),
                'magazine': RegexMatch(r'[\d\w]+')
            }],
        ),
    ]
    for p in policies:
        st.add(p)
    g = Guard(st, checker)
    assert should_be_allowed == g.is_allowed(inquiry)
コード例 #23
0
        p1 = Policy.from_json(s)
        assert '789' == p1.uid
        assert 2 == len(p1.context)
        assert 'ip' in p1.context
        assert 'sub' in p1.context
        assert isinstance(p1.context['ip'], CIDR)
        assert isinstance(p1.context['sub'], Equal)
        assert p1.context['sub'].satisfied('baz')
        assert p1.context['ip'].satisfied('127.0.0.1')
        assert not hasattr(p1, 'rules')


@pytest.mark.parametrize('policy', [
    Policy(1,
           subjects=[{
               'name': Eq('Max'),
               'rate': Greater(90)
           }],
           actions=[Eq('get'), Eq('post')],
           resources=[Any()]),
    Policy(2,
           subjects=[{
               'login': Eq('sally')
           }],
           actions=[Eq('get'), Eq('post')],
           context={'ip': Eq('127.0.0.1')}),
    Policy(3,
           subjects=[{
               'rating': AnyIn(1, 2)
           }],
           actions=[And(Eq('get'), Eq('post'))]),