def test_add_return_value(self): cache_storage = MemoryStorage() back_storage = MemoryStorage() ec = EnfoldCache(back_storage, cache=cache_storage) backend_return = back_storage.add(Policy(1)) ec_return = ec.add(Policy(2)) assert backend_return == ec_return
def test_retrieve_all(self, storage): p1 = Policy(1) p2 = Policy(2) p3 = Policy(3) p4 = Policy(4) p5 = Policy(5) cache_storage = storage back_storage = Mock(spec=MongoStorage, **{'retrieve_all.return_value': []}) ec = EnfoldCache(back_storage, cache=cache_storage, populate=False) assert [] == ec.retrieve_all() back_storage.retrieve_all.assert_called_with() assert [] == ec.retrieve_all(batch=10) back_storage.retrieve_all.assert_called_with(batch=10) assert [] == ec.retrieve_all(10) back_storage.retrieve_all.assert_called_with(10) # test we return from the backend back_storage.retrieve_all = Mock(return_value=[p1, p2, p3]) assert [p1, p2, p3] == list(ec.retrieve_all()) back_storage.retrieve_all = Mock(return_value=[]) assert [] == list(ec.retrieve_all()) # test we return from the cache (cache is dirty) cache_storage.add(p4) cache_storage.add(p5) back_storage.retrieve_all = Mock(return_value=[p1, p2, p3]) assert [p4, p5] == list(ec.retrieve_all(1)) assert [p4, p5] == list(ec.retrieve_all(batch=1)) assert [p4, p5] == list(ec.retrieve_all())
def test_init_without_populate(self): cache = MemoryStorage() policies = [Policy(1), Policy(2), Policy(3)] back = Mock(spec=MongoStorage, **{'retrieve_all.return_value': [policies]}) c = EnfoldCache(back, cache=cache, populate=False) assert not back.retrieve_all.called assert [] == c.cache.get_all(1000, 0)
def test_general_flow(self, log_mock): cache_storage = MemoryStorage() back_storage = MemoryStorage() inq = Inquiry(action='get') chk1 = RulesChecker() p1 = Policy(1, description='initial') p2 = Policy(2, description='initial') p3 = Policy(3, description='added later') # initialize backend storage back_storage.add(p1) back_storage.add(p2) # create enfold-cache but do not populate it ec = EnfoldCache(back_storage, cache=cache_storage, populate=False) # make sure policies are returned from the backend assert [p1, p2] == list(ec.find_for_inquiry(inquiry=inq, checker=chk1)) # make sure we logged warning about cache miss log_mock.warning.assert_called_with( '%s cache miss for find_for_inquiry. Trying it from backend storage', 'EnfoldCache') log_mock.reset_mock() # populate cache with backend policies so that we do not make cache hit misses ec.populate() # make sure policies are returned assert [p1, p2] == list(ec.find_for_inquiry(inquiry=inq, checker=chk1)) # make sure we do not have cache misses assert 0 == log_mock.warning.call_count log_mock.reset_mock() # let's add a new policy via enfold-cache ec.add(p3) # make sure policies are returned assert [p1, p2, p3] == list(ec.find_for_inquiry(inquiry=inq, checker=chk1)) # make sure we do not have cache misses assert 0 == log_mock.warning.call_count log_mock.reset_mock() # make sure we have those policies in the backend-storage assert [p1, p2, p3] == list( back_storage.find_for_inquiry(inquiry=inq, checker=chk1)) # make sure we have those policies in the cache-storage assert [p1, p2, p3] == list( cache_storage.find_for_inquiry(inquiry=inq, checker=chk1)) # ----------------------- # ----------------------- # ----------------------- # let's re-create enfold cache. This time with initial population cache_storage2 = MemoryStorage() ec2 = EnfoldCache(back_storage, cache=cache_storage2, populate=True) # make sure we have all policies in the cache-storage assert [p1, p2, p3] == list( cache_storage2.find_for_inquiry(inquiry=inq, checker=chk1)) # make sure policies are returned by find_for_inquiry assert [p1, p2, p3] == list(ec2.find_for_inquiry(inquiry=inq, checker=chk1)) # make sure we do not have cache misses assert 0 == log_mock.warning.call_count log_mock.reset_mock()
def test_init_with_populate_for_dirty_cache_storage(self): cache = MemoryStorage() cache.add(Policy(1)) policies = [Policy(1), Policy(2), Policy(3)] back = Mock(spec=MongoStorage, **{'retrieve_all.side_effect': [policies]}) with pytest.raises(Exception) as excinfo: EnfoldCache(back, cache=cache, populate=True) assert 'Conflicting UID = 1' == str(excinfo.value) assert back.retrieve_all.called
def test_update_return_value(self): cache_storage = MemoryStorage() back_storage = MemoryStorage() ec = EnfoldCache(back_storage, cache=cache_storage) p1 = Policy(1, description='foo') ec.add(p1) p1.description = 'foo upd' backend_return = back_storage.update(p1) ec_return = ec.update(p1) assert backend_return == ec_return
def gen_policy(): if ARGS.checker == 'rules': return Policy( uid=gen_id(), effect=ALLOW_ACCESS if rand_true() else DENY_ACCESS, subjects=[ { 'name': logic.Or(operator.Eq('Nicky'), operator.Eq('Nick')), 'stars': logic.And( operator.Greater(random.randint(-1000, -1)), operator.Less(random.randint(1000, 3000)), operator.Eq(900) ), 'status': operator.Eq('registered') }, ], resources=( { 'method': list.AnyIn('get', 'post', 'delete'), 'path': list.NotIn('org/custom', 'vacations/pending', 'должность/повысить'), 'id': operator.Eq(rand_string()) }, { 'method': operator.Eq('violate'), } ), actions=( {'before': operator.Eq('foo')}, {'after': list.In(rand_string(), rand_string(), rand_string())}, ), context={ 'ip': net.CIDR('127.0.0.1'), }, ) else: global similar_regexp_policies_created static_subjects = gen_regexp() if ARGS.regexp: if similar_regexp_policies_created < ARGS.same: subjects = static_subjects similar_regexp_policies_created += 1 else: subjects = gen_regexp() else: subjects = (rand_string(), rand_string()) return Policy( uid=gen_id(), effect=ALLOW_ACCESS if rand_true() else DENY_ACCESS, subjects=subjects, resources=('library:books:<.+>', 'office:magazines:<.+>'), actions=['<' + rand_string() + '|' + rand_string() + '>'], context={ 'ip': net.CIDR('127.0.0.1'), }, )
def test_init_with_populate_and_populate_is_true_by_default(self): cache = MemoryStorage() policies = [Policy(1), Policy(2), Policy(3)] back = Mock(spec=MongoStorage, **{ 'retrieve_all.side_effect': [policies], 'get_all.side_effect': [] }) ec = EnfoldCache(back, cache=cache) assert back.retrieve_all.called assert policies == ec.cache.get_all(10000, 0)
def test_delete_ok(self): cache_storage = MemoryStorage() back_storage = MemoryStorage() ec = EnfoldCache(back_storage, cache=cache_storage) p1 = Policy(1, description='foo') p2 = Policy(2, description='bar') ec.add(p1) ec.add(p2) ec.delete(1) ec.delete(2) assert [] == cache_storage.get_all(100, 0) assert [] == back_storage.get_all(100, 0)
def test_add(self, factory): st, mem, observer = factory() p1 = Policy(1) p2 = Policy(2) p3 = Policy(3) st.add(p1) st.add(p2) assert 2 == observer.count assert 2 == len(list(mem.retrieve_all())) assert 2 == len(list(st.retrieve_all())) st.add(p3) assert 3 == observer.count
def test_find_for_inquiry_return_value(self, storage): cache_storage = storage back_storage = MemoryStorage() ec = EnfoldCache(back_storage, cache=cache_storage) inq = Inquiry(action='get') p1 = Policy(1) p2 = Policy(2) ec.add(p1) ec.add(p2) backend_return = back_storage.find_for_inquiry(inq) ec_return = ec.find_for_inquiry(inq) assert list(backend_return) == list(ec_return)
def test_update(self, factory): st, mem, observer = factory() p1 = Policy('a') st.add(p1) p1.uid = 'b' st.update(p1) assert 'b' == list(mem.retrieve_all())[0].uid assert 'b' == list(st.retrieve_all())[0].uid assert 2 == observer.count p1.uid = 'c' st.update(p1) assert 3 == observer.count
def test_get_all_return_value(self, storage): cache_storage = storage back_storage = MemoryStorage() ec = EnfoldCache(back_storage, cache=cache_storage) p1 = Policy(1) p2 = Policy(2) p3 = Policy(3) ec.add(p1) ec.add(p2) ec.add(p3) backend_return = back_storage.get_all(100, 0) ec_return = back_storage.get_all(100, 0) assert backend_return == ec_return
def test_retrieve_all_return_value(self, storage): cache_storage = storage back_storage = MemoryStorage() ec = EnfoldCache(back_storage, cache=cache_storage) p1 = Policy(1) p2 = Policy(2) p3 = Policy(3) ec.add(p1) ec.add(p2) ec.add(p3) backend_return = back_storage.retrieve_all() ec_return = back_storage.retrieve_all() assert list(backend_return) == list(ec_return)
def test_add_ok(self): cache_storage = MemoryStorage() back_storage = MemoryStorage() ec = EnfoldCache(back_storage, cache=cache_storage) p1 = Policy(1) p2 = Policy(2) p3 = Policy(3) ec.add(p1) assert [p1] == cache_storage.get_all(100, 0) assert [p1] == back_storage.get_all(100, 0) ec.add(p2) ec.add(p3) assert [p1, p2, p3] == cache_storage.get_all(100, 0) assert [p1, p2, p3] == back_storage.get_all(100, 0)
def test_delete_fail(self): cache_storage = MemoryStorage() back_storage = MemoryStorage() ec = EnfoldCache(back_storage, cache=cache_storage) p1 = Policy(1, description='foo') p2 = Policy(2, description='bar') ec.add(p1) ec.add(p2) back_storage.delete = Mock(side_effect=Exception('error!')) with pytest.raises(Exception) as excinfo: ec.delete(2) assert 'error!' == str(excinfo.value) assert [p1, p2] == back_storage.get_all(1000, 0) assert [p1, p2] == cache_storage.get_all(1000, 0)
def test_find_for_inquiry(self, factory): st, mem, observer = factory() inq = Inquiry(action='get', subject='foo', resource='bar') p1 = Policy('a') p2 = Policy('b') st.add(p1) st.add(p2) mem_found = list(mem.find_for_inquiry(inq)) assert [p1, p2] == mem_found or [p2, p1] == mem_found st_found = list(st.find_for_inquiry(inq)) assert [p1, p2] == st_found or [p2, p1] == st_found assert 2 == observer.count st.find_for_inquiry(inq) st.find_for_inquiry(inq) assert 2 == observer.count
def add_policy(self, ied, action, protocol, address=None, access=ALLOW_ACCESS): if type(ied) is not list: ied = [ied] if type(action) is not list: action = [action] if type(protocol) is not list: protocol = [protocol] if address: self._storage.add(Policy( str(uuid4()), subjects=ied, actions=action, context=address, resources=protocol, effect=access)) else: self._storage.add(Policy( str(uuid4()), subjects=ied, actions=action, resources=protocol, effect=access))
def forwards_func(apps, schema_editor): # add AuthzAction AuthzAction = apps.get_model('noclook', 'AuthzAction') list_aa, created = AuthzAction.objects.get_or_create(name="list") # get storage and guard storage, guard = sriutils.get_vakt_storage_and_guard() Context = apps.get_model('noclook', 'Context') DjPolicy = apps.get_model('djangovakt', 'Policy') # iterate over all the existent contexts to add # a list policy for each of them all_contexts = Context.objects.all() for context in all_contexts: # check if the policy exist first qs = DjPolicy.objects.filter(doc__actions__0__val=list_aa.name) qs = qs.filter(doc__context__module__elem__in=(context.name,)) if not qs.exists(): policy = Policy( uuid.uuid4(), actions=[vakt_rules.Eq(list_aa.name)], resources=[vakt_rules.Any()], subjects=[srirules.HasAuthAction(list_aa, context)], context={ 'module': srirules.ContainsElement(context.name) }, effect=ALLOW_ACCESS, description='Automatically created policy' ) storage.add(policy)
def test_find_for_inquiry_for_populated_cache(self, log_mock): cache_storage = MemoryStorage() back_storage = MemoryStorage() inq = Inquiry(action='get') chk1 = RulesChecker() p1 = Policy(1, description='foo') p2 = Policy(2, description='bar') cache_storage.add(p1) cache_storage.add(p2) ec = EnfoldCache(back_storage, cache=cache_storage, populate=True) # Make first request assert [p1, p2] == list(ec.find_for_inquiry(inquiry=inq, checker=chk1)) assert 0 == log_mock.warning.call_count log_mock.reset_mock() # Make second request assert [p1, p2] == list(ec.find_for_inquiry(inquiry=inq, checker=chk1)) assert 0 == log_mock.warning.call_count
def test_get_for_non_populated_cache(self, log_mock): cache_storage = MemoryStorage() back_storage = MemoryStorage() p1 = Policy(1, description='foo') p2 = Policy(2, description='bar') back_storage.add(p1) back_storage.add(p2) ec = EnfoldCache(back_storage, cache=cache_storage, populate=False) assert p1 == ec.get(1) log_mock.warning.assert_called_with( '%s cache miss for get Policy with UID=%s. Trying to get it from backend storage', 'EnfoldCache', 1) log_mock.reset_mock() assert p2 == ec.get(2) assert 1 == log_mock.warning.call_count log_mock.reset_mock() # test we won't return any inexistent policies assert ec.get(3) is None
def test_get_return_value(self): cache_storage = MemoryStorage() back_storage = MemoryStorage() ec = EnfoldCache(back_storage, cache=cache_storage) p1 = Policy(1) ec.add(p1) backend_return = back_storage.get(1) ec_return = ec.get(1) assert backend_return == ec_return
def test_get_all(self, factory): st, mem, observer = factory() p1 = Policy('a') st.add(p1) assert 'a' == list(mem.get_all(5, 0))[0].uid assert 'a' == list(st.get_all(5, 0))[0].uid assert 1 == observer.count st.get_all(9, 0) st.get_all(888, 0) assert 1 == observer.count
def test_get(self, factory): st, mem, observer = factory() p1 = Policy('a') st.add(p1) assert 'a' == st.get('a').uid assert 'a' == mem.get('a').uid assert 1 == observer.count assert None is st.get('b') assert None is mem.get('b') assert 1 == observer.count
def test_cache_is_invalidated_on_policy_change(self): def assert_after_modification(): assert 0 == cache.info().hits assert 0 == cache.info().misses assert 0 == cache.info().currsize assert not guard.is_allowed(inq1) assert not guard.is_allowed(inq1) assert guard.is_allowed(inq2) assert guard.is_allowed(inq2) assert guard.is_allowed(inq2) assert 3 == cache.info().hits assert 2 == cache.info().misses assert 2 == cache.info().currsize inq1 = Inquiry(action='get', resource='book', subject='Max') inq2 = Inquiry(action='get', resource='book', subject='Jim') guard, storage, cache = create_cached_guard(MemoryStorage(), RulesChecker(), maxsize=256) p1 = Policy(1, actions=[Eq('get')], resources=[Eq('book')], subjects=[Eq('Max')], effect=ALLOW_ACCESS) p2 = Policy(2, actions=[Eq('get')], resources=[Eq('magazine')], subjects=[Eq('Max')], effect=ALLOW_ACCESS) storage.add(p1) assert guard.is_allowed(inq1) assert guard.is_allowed(inq1) assert 1 == cache.info().hits assert 1 == cache.info().misses assert 1 == cache.info().currsize # start modifications p1.subjects = [Eq('Jim')] storage.update(p1) assert_after_modification() storage.add(p2) assert_after_modification() storage.delete(p2) assert_after_modification()
def test_add_fail(self): cache_storage = MemoryStorage() back_storage = MemoryStorage() ec = EnfoldCache(back_storage, cache=cache_storage) p1 = Policy(1) p2 = Policy(2) p3 = Policy(3) ec.add(p1) back_storage.add = Mock(side_effect=PolicyExistsError('2')) with pytest.raises(PolicyExistsError) as excinfo: ec.add(p2) assert 'Conflicting UID = 2' == str(excinfo.value) assert [p1] == back_storage.get_all(1000, 0) # test general exception back_storage.add = Mock(side_effect=Exception('foo')) with pytest.raises(Exception) as excinfo: ec.add(p3) assert 'foo' == str(excinfo.value) assert [p1] == back_storage.get_all(1000, 0) assert [p1] == cache_storage.get_all(1000, 0)
def test_find_for_inquiry_for_non_populated_cache(self, log_mock): cache_storage = MemoryStorage() back_storage = MemoryStorage() inq = Inquiry(action='get') chk1 = RulesChecker() p1 = Policy(1, description='foo') p2 = Policy(2, description='bar') back_storage.add(p1) back_storage.add(p2) ec = EnfoldCache(back_storage, cache=cache_storage, populate=False) # Make first request assert [p1, p2] == list(ec.find_for_inquiry(inquiry=inq, checker=chk1)) log_mock.warning.assert_called_with( '%s cache miss for find_for_inquiry. Trying it from backend storage', 'EnfoldCache') log_mock.reset_mock() # Make second request assert [p1, p2] == list(ec.find_for_inquiry(inquiry=inq, checker=chk1)) assert 1 == log_mock.warning.call_count log_mock.reset_mock()
def forwards_func(apps, schema_editor): # get storage and guard storage, guard = sriutils.get_vakt_storage_and_guard() # create policies using storage instead Context = apps.get_model('noclook', 'Context') AuthzAction = apps.get_model('noclook', 'AuthzAction') # iterate over all existent contexts and authzactions # and create policies for each of them all_contexts = Context.objects.all() rw_authzactions = AuthzAction.objects.filter(name__in=( sriutils.READ_AA_NAME, sriutils.WRITE_AA_NAME, )) # add read and write policies for context in all_contexts: for authzaction in rw_authzactions: policy = Policy( uuid.uuid4(), actions=[vakt_rules.Eq(authzaction.name)], resources=[srirules.BelongsContext(context)], subjects=[srirules.HasAuthAction(authzaction, context)], context={'module': srirules.ContainsElement(context.name)}, effect=ALLOW_ACCESS, description='Automatically created policy') storage.add(policy) # add admin policies admin_aa = AuthzAction.objects.get(name=sriutils.ADMIN_AA_NAME) for context in all_contexts: policy = Policy( uuid.uuid4(), actions=[vakt_rules.Eq(admin_aa.name)], resources=[vakt_rules.Any()], subjects=[srirules.HasAuthAction(admin_aa, context)], context={'module': srirules.ContainsElement(context.name)}, effect=ALLOW_ACCESS, description='Automatically created policy') storage.add(policy)
def test_delete(self, factory): st, mem, observer = factory() p1 = Policy('a') st.add(p1) st.delete('a') assert [] == list(mem.retrieve_all()) assert [] == list(st.retrieve_all()) assert 2 == observer.count st.delete('a') assert [] == list(mem.retrieve_all()) assert [] == list(st.retrieve_all()) assert 3 == observer.count
def test_retrieve_all(self, factory): st, mem, observer = factory() p1 = Policy('a') st.add(p1) assert 'a' == list(mem.retrieve_all())[0].uid assert 'a' == list(st.retrieve_all())[0].uid assert 1 == observer.count assert 'a' == list(mem.retrieve_all(batch=2))[0].uid assert 'a' == list(st.retrieve_all(batch=2))[0].uid assert 1 == observer.count assert 'a' == list(mem.retrieve_all(5))[0].uid assert 'a' == list(st.retrieve_all(5))[0].uid assert 1 == observer.count