def test_get(st): st.add(Policy('1')) st.add(Policy(2, description='some text')) assert isinstance(st.get('1'), Policy) assert '1' == st.get('1').uid assert 2 == st.get(2).uid assert 'some text' == st.get(2).description
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
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
def test_find_for_inquiry_with_regex_or_none_checker_specified_return_all_existing_policies(self, st, checker): st.add(Policy('1', subjects=['max', 'bob'])) st.add(Policy('2', subjects=['sam', 'foo'])) st.add(Policy('3', subjects=['bar'])) inquiry = Inquiry(subject='Jim', action='delete', resource='server') found = st.find_for_inquiry(inquiry, checker) found = list(found) assert 3 == len(found)
def test_get(self, st): st.add(Policy('1')) st.add(Policy(2, description='some text')) assert isinstance(st.get('1'), Policy) assert '1' == st.get('1').uid # SQL storage stores all uid as string assert '2' == st.get('2').uid assert 'some text' == st.get('2').description
def test_find_for_inquiry(st): st.add(Policy('1', subjects=['max', 'bob'])) st.add(Policy('2', subjects=['sam', 'nina'])) inquiry = Inquiry(subject='sam', action='get', resource='books') found = st.find_for_inquiry(inquiry) assert 2 == len(found) assert ['max', 'bob'] == found[0].subjects or ['max', 'bob' ] == found[1].subjects
def test_custom_pickle_serializer_works(self, st): st.sr = PickleSerializer(3, fix_imports=False) st.add(Policy('1')) st.add(Policy(2, description='some text')) assert isinstance(st.get('1'), Policy) assert '1' == st.get('1').uid assert 2 == st.get(2).uid assert 'some text' == st.get(2).description
def test_get_all_returns_generator(self, st): st.add(Policy('1')) st.add(Policy('2')) found = st.get_all(500, 0) assert isinstance(found, types.GeneratorType) pols = [] for p in found: pols.append(p.uid) assert 2 == len(pols)
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'])) 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
def test_find_for_inquiry_returns_generator(self, st): st.add(Policy('1', subjects=['max', 'bob'], actions=['get'], resources=['comics'])) st.add(Policy('2', subjects=['max', 'bob'], actions=['get'], resources=['comics'])) inquiry = Inquiry(subject='max', action='get', resource='comics') found = st.find_for_inquiry(inquiry) assert isinstance(found, types.GeneratorType) l = [] for p in found: l.append(p.uid) assert 2 == len(l)
def test_policies_description_msg(): p1 = Policy(123, description='foo', actions=['books:<foo.bar>'], resources=['bb'], subjects=['<qwerty>'], context={}) p2 = Policy('asdf', description='bar', actions=['books:<foo.bar>'], resources=['aa'], subjects=['<qwerty>'], context={}) m = PoliciesDescriptionMsg([p1, p2]) assert "['foo', 'bar']" == str(m) m = PoliciesDescriptionMsg([p2]) assert "['bar']" == str(m) m = PoliciesDescriptionMsg() assert '[]' == str(m)
def test_policies_count_msg(): p1 = Policy(123, description='foo', actions=['books:<foo.bar>'], resources=['bb'], subjects=['<qwerty>'], context={}) p2 = Policy('asdf', description='bar', actions=['books:<foo.bar>'], resources=['aa'], subjects=['<qwerty>'], context={}) m = PoliciesCountMsg([p1, p2]) assert 'count = 2' == str(m) m = PoliciesCountMsg([p2]) assert 'count = 1' == str(m) m = PoliciesCountMsg() assert 'count = 0' == str(m)
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)
def test_json_roundtrip_of_a_policy_with_context(): p = Policy('123', context={ 'ip': CIDR('192.168.1.0/24'), 'sub': Equal('test-me') }) s = p.to_json() p1 = Policy.from_json(s) assert '123' == 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('test-me') # 'context' wins over deprecated rules p = Policy('456', context={ 'ip': CIDR('192.168.1.0/24'), 'sub': Equal('foo-bar') }, rules={ 'ip': CIDR('127.0.0.1'), 'sub': Equal('baz') }) s = p.to_json() p1 = Policy.from_json(s) assert '456' == 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('foo-bar') assert p1.context['ip'].satisfied('192.168.1.0') assert not hasattr(p1, 'rules') # 'rules' are allowed, but they become a 'context' class field with pytest.deprecated_call(): 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')
def test_find_for_inquiry_returns_existing_policies( self, st, checker, expect_number): st.add(Policy('1', subjects=['<[mM]ax', '<.*>'])) st.add(Policy('2', subjects=['sam<.*>', 'foo'])) st.add(Policy('3', subjects=[{'stars': Eq(90)}, Eq('Max')])) st.add( Policy('4', subjects=['Jim'], actions=['delete'], resources=['server'])) st.add(Policy('5', subjects=[Eq('Jim'), Eq('Nina')])) inquiry = Inquiry(subject='Jim', action='delete', resource='server') found = st.find_for_inquiry(inquiry, checker) assert expect_number == len(list(found))
def test_find_for_inquiry_with_rules_checker(self, st): assertions = unittest.TestCase('__init__') st.add(Policy(1, subjects=[{'name': Equal('Max')}], actions=[{'foo': Equal('bar')}])) st.add(Policy(2, subjects=[{'name': Equal('Max')}], actions=[{'foo': Equal('bar2')}])) st.add(Policy(3, subjects=['sam', 'nina'])) st.add(Policy(4, actions=[r'<\d+>'], effect=ALLOW_ACCESS, resources=[r'<\w{1,3}>'], subjects=[r'<\w{2}-\d+>'])) st.add(Policy(5, subjects=[{'name': Equal('Jim')}], actions=[{'foo': Equal('bar3')}])) inquiry = Inquiry(subject={'name': 'max'}, action='get', resource='books') found = st.find_for_inquiry(inquiry, RulesChecker()) found = list(found) assert 3 == len(found) found_uids = list(map(operator.attrgetter('uid'), found)) found_uids.sort() assertions.assertListEqual(['1', '2', '5'], found_uids)
def test_get_all(self, st, limit, offset, result): for i in range(20): desc = ''.join(random.choice('abcde') for _ in range(30)) st.add(Policy(str(i), description=desc)) policies = list(st.get_all(limit=limit, offset=offset)) ll = len(policies) assert result == ll
def populate_storage(): global store, overall_policies_created, similar_regexp_policies_created static_subjects = gen_regexp() for x in range(POLICIES_NUMBER): if USE_REGEXP_POLICIES: if similar_regexp_policies_created < SAME_REGEX_POLICIES_NUMBER: subjects = static_subjects similar_regexp_policies_created += 1 else: subjects = gen_regexp() else: subjects = (rand_string(), rand_string()) policy = Policy( uid=gen_id(), effect=ALLOW_ACCESS if rand_true() else DENY_ACCESS, subjects=subjects, resources=('library:books:<.+>', 'office:magazines:<.+>'), actions=['<read|get>'], rules={ 'ip': CIDRRule('127.0.0.1'), }, ) store.add(policy) overall_policies_created += 1 yield
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)
def test_to_policy(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) _p = p_model.to_policy() assert p.uid == _p.uid assert p.type == _p.type assert p.description == _p.description assert len(p.subjects) == len(_p.subjects) assert all(p.subjects[x] == _p.subjects[x] for x in range(len(p.subjects))) assert len(p.resources) == len(_p.resources) assert all(p.resources[x] == _p.resources[x] for x in range(len(p.resources))) assert len(p.actions) == len(_p.actions) assert all(p.actions[x] == _p.actions[x] for x in range(len(p.actions))) assert 'secret' in _p.context assert isinstance(_p.context['secret'], Equal) assert _p.context['secret'].val == 'i-am-a-teacher'
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)
def test_guard_does_not_fail_if_storage_returns_none(logger): class BadStorage(MemoryStorage): def find_for_inquiry(self, inquiry, checker=None): return None # set up logging log_capture_str = io.StringIO() h = logging.StreamHandler(log_capture_str) h.setLevel(logging.ERROR) logger.setLevel(logging.ERROR) logger.addHandler(h) # set up Guard storage = BadStorage() storage.add( Policy( uid='1', effect=ALLOW_ACCESS, subjects=['Max'], actions=['watch'], resources=['TV'], )) g = Guard(storage, RegexChecker()) assert not g.is_allowed( Inquiry(subject='Max', action='watch', resource='TV')) assert 'Storage returned None, but is supposed to return at least an empty list' == \ log_capture_str.getvalue().strip()
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
def test_delete(st): policy = Policy('1') st.add(policy) assert '1' == st.get('1').uid st.delete('1') assert None is st.get('1') st.delete('1000000')
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
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
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
def test_get_all_with_incorrect_args(self, st): for i in range(10): st.add(Policy(str(i), description='foo')) with pytest.raises(ValueError) as e: list(st.get_all(-1, 9)) assert "Limit can't be negative" == str(e.value) with pytest.raises(ValueError) as e: list(st.get_all(0, -3)) assert "Offset can't be negative" == str(e.value)
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 "'rules': {}" in str(p)
def test_add_with_bson_object_id(self, st): id = str(ObjectId()) p = Policy( uid=id, description='foo', ) st.add(p) back = st.get(id) assert id == back.uid