Exemple #1
0
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()
Exemple #2
0
def test_guard_uses_audit_correctly(audit_log, inquiry, is_allowed, expect_msg):
    # setup logger consumer
    log_capture_str = io.StringIO()
    h = logging.StreamHandler(log_capture_str)
    h.setFormatter(logging.Formatter(
        'msg: %(message)s | effect: %(effect)s | deciders: %(deciders)s | candidates: %(candidates)s | ' +
        'inquiry: %(inquiry)s'
    ))
    h.setLevel(logging.INFO)
    audit_log.setLevel(logging.INFO)
    audit_log.addHandler(h)
    # setup guard
    st = MemoryStorage()
    st.add(PolicyAllow(uid='a', subjects=['Max'], actions=['<.*>'], resources=['<.*>']))
    st.add(PolicyAllow(uid='b', subjects=['Max'], actions=['get'], resources=['<.*>']))
    st.add(PolicyAllow(uid='c', subjects=['Jim'], actions=['<.*>'], resources=['<.*>']))
    st.add(PolicyDeny(uid='d', subjects=['Jim'], actions=['<.*>'], resources=['<.*>']))
    st.add(PolicyAllow(uid='e'))
    g = Guard(st, RegexChecker())
    # Run tests
    assert is_allowed == g.is_allowed(inquiry)
    result = log_capture_str.getvalue().strip()
    # a little hack to get rid of <Object ID 4502567760> in inquiry output
    result = re.sub(r'<Object ID \d+>', '<Object ID some_ID>', result)
    assert expect_msg == result
Exemple #3
0
 def test_find_for_inquiry_with_regex_checker(self, st, policies, inquiry, expected_reference):
     mem_storage = MemoryStorage()  # it returns all stored policies so we consider Guard as a reference
     for p in policies:
         st.add(p)
         mem_storage.add(p)
     reference_answer = Guard(mem_storage, RegexChecker()).is_allowed(inquiry)
     assert expected_reference == reference_answer, 'Check reference answer'
     assert reference_answer == Guard(st, RegexChecker()).is_allowed(inquiry), \
         'SQL storage should give the same answers as reference'
Exemple #4
0
def test_guard_if_unexpected_exception_raised():
    # for testing unexpected exception
    class BadMemoryStorage(MemoryStorage):
        def find_for_inquiry(self, inquiry=None, checker=None):
            raise Exception('This is test class that raises errors')

    g = Guard(BadMemoryStorage(), RegexChecker())
    assert not g.is_allowed(
        Inquiry(subject='foo', action='bar', resource='baz'))
Exemple #5
0
def test_guard_logs_messages_at_info_level(audit_log):
    log_capture_str = io.StringIO()
    h = logging.StreamHandler(log_capture_str)
    h.setLevel(logging.INFO)
    audit_log.setLevel(logging.INFO)
    audit_log.addHandler(h)
    g = Guard(MemoryStorage(), RegexChecker())
    g.is_allowed(Inquiry())
    assert 'No potential' in log_capture_str.getvalue().strip()
Exemple #6
0
def test_guard_does_not_log_messages_at_more_than_info_level(audit_log):
    log_capture_str = io.StringIO()
    h = logging.StreamHandler(log_capture_str)
    h.setLevel(logging.WARN)
    audit_log.setLevel(logging.WARN)
    audit_log.addHandler(h)
    g = Guard(MemoryStorage(), RegexChecker())
    g.is_allowed(Inquiry())
    assert '' == log_capture_str.getvalue().strip()
Exemple #7
0
def test_guard_can_use_specific_policies_message_class(audit_log):
    # setup logger consumer
    log_capture_str = io.StringIO()
    h = logging.StreamHandler(log_capture_str)
    h.setFormatter(logging.Formatter('decs: %(deciders)s, candidates: %(candidates)s'))
    h.setLevel(logging.INFO)
    audit_log.setLevel(logging.INFO)
    audit_log.addHandler(h)
    # setup guard
    st = MemoryStorage()
    st.add(PolicyAllow('122'))
    st.add(PolicyAllow('123', actions=['<.*>'], resources=['<.*>'], subjects=['<.*>']))
    st.add(PolicyDeny('124', actions=['<.*>'], resources=['<.*>'], subjects=['<.*>']))
    st.add(PolicyDeny('125', actions=['<.*>'], resources=['<.*>'], subjects=['<.*>']))
    g = Guard(st, RegexChecker(), audit_policies_cls=PoliciesCountMsg)
    # Run tests
    g.is_allowed(Inquiry(action='get', subject='Kim', resource='TV'))
    assert 'decs: count = 1, candidates: count = 3' == log_capture_str.getvalue().strip()
Exemple #8
0
def test_guard_logs_inquiry_decision(logger, inquiry, result, expect_message):
    # set up logging
    log_capture_str = io.StringIO()
    h = logging.StreamHandler(log_capture_str)
    h.setLevel(logging.INFO)
    logger.setLevel(logging.INFO)
    logger.addHandler(h)
    # set up Guard
    storage = MemoryStorage()
    storage.add(
        Policy(
            uid='1',
            effect=ALLOW_ACCESS,
            subjects=['Max'],
            actions=['watch'],
            resources=['TV'],
        ))
    g = Guard(storage, RegexChecker())
    assert result == g.is_allowed(inquiry)
    log_res = log_capture_str.getvalue().strip()
    # a little hack to get rid of <Object ID 4502567760> in inquiry output
    log_res = re.sub(r'<Object ID \d+>', '<Object ID some_ID>', log_res)
    assert expect_message == log_res
Exemple #9
0
def test_not_allowed_when_similar_policies_have_at_least_one_deny_access():
    st = MemoryStorage()
    policies = (
        Policy(
            uid='1',
            effect=ALLOW_ACCESS,
            subjects=['foo'],
            actions=['bar'],
            resources=['baz'],
        ),
        Policy(
            uid='2',
            effect=DENY_ACCESS,
            subjects=['foo'],
            actions=['bar'],
            resources=['baz'],
        ),
    )
    for p in policies:
        st.add(p)
    g = Guard(st, RegexChecker())
    assert not g.is_allowed(
        Inquiry(subject='foo', action='bar', resource='baz'))
Exemple #10
0
def test_policy_inquiry_checker_examples(desc, policy, inquiry, checker,
                                         should_be_allowed):
    storage = MemoryStorage()
    storage.add(policy)
    g = Guard(storage, checker)
    assert should_be_allowed == g.is_allowed(inquiry)
Exemple #11
0
def test_is_allowed(desc, inquiry, should_be_allowed):
    g = Guard(st, RegexChecker())
    assert should_be_allowed == g.is_allowed(inquiry)
Exemple #12
0
    def test_up(self, storage):
        migration = Migration1x1x0To1x1x1(storage)
        # prepare docs that might have been saved by users in v 1.1.0
        docs = [
            ("""
                { "_id" : 10, "uid" : 10, "description" : null, "subjects" : [ ], "effect" : "allow", 
                "resources" : [ ], "actions" : [ ], "rules" : { "secret" : 
                "{\\"type\\": \\"vakt.rules.string.StringEqualRule\\", \\"contents\\": {\\"val\\": \\"i-am-a-foo\\"}}", 
                "name":"{\\"type\\": \\"vakt.rules.string.StringEqualRule\\", \\"contents\\":{\\"val\\": \\"Max\\"}}" }}
                """, """
                { "_id" : 10, "actions" : [ ], "description" : null, "effect" : "allow", "resources" : [ ], 
                "rules" : { "name" : {"py/object": "vakt.rules.string.StringEqualRule", "val": "Max" },
                "secret" : {"py/object": "vakt.rules.string.StringEqualRule", "val": "i-am-a-foo"} }, 
                "subjects" : [ ], "uid" : 10 }
                """),
            ("""
                { "_id" : 20, "uid" : 20, "description" : "foo bar", "subjects" : [ "<.*>" ], "effect" : "allow",
                "resources" : [ "<.*>" ], "actions" : [ "<.*>" ], "rules" : { "secret" :
                "{\\"type\\": \\"vakt.rules.string.StringEqualRule\\", \\"contents\\": {\\"val\\": \\"John\\"}}" } }
                """, """
                { "_id" : 20, "actions" : [ "<.*>" ], "description" : "foo bar", "effect" : "allow",
                "resources" : [ "<.*>" ], "rules" : { "secret" :
                { "py/object": "vakt.rules.string.StringEqualRule", "val": "John"} }, "subjects" : [ "<.*>" ],
                "uid" : 20 }
                """),
            ("""
                { "_id" : 30, "uid" : 30, "description" : "foo bar", "subjects" : [ "<.*>" ], "effect" : "allow",
                "resources" : [ "<.*>" ], "actions" : [ "<.*>" ], "rules" : {  } }
                """, """
                { "_id" : 30, "actions" : [ "<.*>" ], "description" : "foo bar", "effect" : "allow",
                "resources" : [ "<.*>" ], "rules" : {  }, "subjects" : [ "<.*>" ], "uid" : 30 }
                """),
            ("""
                { "_id" : 40, "uid" : 40, "description" : null, "subjects" : [ "<.*>" ], "effect" : "allow", 
                "resources" : [ "<.*>" ], "actions" : [ "<.*>" ], "rules" : 
                { "num" : 
                "{\\"type\\": \\"storage.test_mongo_migration.Simple\\", \\"contents\\": {\\"val\\": \\"123\\"}}", 
                "a" : "{\\"type\\": \\"vakt.rules.string.StringEqualRule\\", \\"contents\\": {\\"val\\": \\"foo\\"}}" }}
                """, """
                { "_id" : 40, "actions" : [ "<.*>" ], "description" : null, "effect" : "allow",  "resources" : ["<.*>"],
                "rules" : { "a" : {"py/object": "vakt.rules.string.StringEqualRule", "val": "foo"},
                "num" : { "py/object": "storage.test_mongo_migration.Simple", "val": "123"} }, "subjects" : ["<.*>"],
                "uid" : 40 }
                """),
            ("""
                { "_id" : 50, "uid" : 50, "description" : null, "subjects" : [ ], "effect" : "allow", "resources" : [ ], 
                "actions" : [ ], "rules" : { "num" : 
                "{\\"type\\": \\"storage.test_mongo_migration.Simple\\", \\"contents\\": {\\"val\\": \\"46\\"}}" } }
                """, """
                { "_id" : 50, "actions" : [ ], "description" : null, "effect" : "allow", "resources" : [ ],
                "rules" : { "num" : { "py/object": "storage.test_mongo_migration.Simple", "val": "46"} },
                "subjects" : [ ], "uid" : 50 }
                """),
        ]
        for (doc, _) in docs:
            d = b_json.loads(doc)
            migration.storage.collection.insert_one(d)

        migration.up()

        # test no new docs were added and no docs deleted
        assert len(docs) == len(list(migration.storage.collection.find({})))
        # test Policy.from_json() is called without errors for each doc (implicitly)
        assert len(docs) == len(list(migration.storage.get_all(1000, 0)))
        # test string contents of each doc
        for (doc, result_doc) in docs:
            new_doc = migration.storage.collection.find_one(
                {'uid': json.loads(doc)['uid']})
            expected = result_doc.replace("\n", '').replace(' ', '')
            actual = json.dumps(new_doc,
                                sort_keys=True).replace("\n",
                                                        '').replace(' ', '')
            assert expected == actual
        # test full guard allowance run
        if version_info() < (1, 2, 0):  # pragma: no cover
            g = Guard(migration.storage, RegexChecker())
            inq = Inquiry(action='foo',
                          resource='bar',
                          subject='Max',
                          context={
                              'val': 'foo',
                              'num': '123'
                          })
            assert g.is_allowed(inq)
Exemple #13
0
            print()
    print()


def single_inquiry_benchmark():
    global guard
    if guard.is_allowed(inq):
        return True
    return False


overall_policies_created = 0
similar_regexp_policies_created = 0
store = MemoryStorage()
checker = RegexChecker(CACHE_SIZE) if CACHE_SIZE else RegexChecker()
guard = Guard(store, checker)
inq = Inquiry(action='get',
              subject='xo',
              resource='library:books:1234',
              context={'ip': '127.0.0.1'})

if __name__ == '__main__':
    line_length = 80
    print('=' * line_length)
    print('Populating MemoryStorage with Policies')
    print_generation(populate_storage, int(POLICIES_NUMBER / 100 * 1),
                     line_length)
    print('START BENCHMARK!')
    start = timeit.default_timer()
    allowed = single_inquiry_benchmark()
    stop = timeit.default_timer()
Exemple #14
0
def test_is_allowed_for_inquiry_match_rules(desc, policy, inquiry, result):
    storage = MemoryStorage()
    storage.add(policy)
    g = Guard(storage, RulesChecker())
    assert result == g.is_allowed(inquiry), 'Failed for case: ' + desc
Exemple #15
0
def test_is_allowed(desc, inquiry, should_be_allowed, checker):
    g = Guard(st, checker)
    assert should_be_allowed == g.is_allowed(inquiry)
Exemple #16
0
def test_is_allowed_for_none_policies():
    g = Guard(MemoryStorage(), RegexChecker())
    assert not g.is_allowed(
        Inquiry(subject='foo', action='bar', resource='baz'))
Exemple #17
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)