def test_operations_checker(self): tests = [ ('all allowed', checkers.allow_caveat( ['op1', 'op2', 'op4', 'op3']), ['op1', 'op3', 'op2'], None), ('none denied', checkers.deny_caveat(['op1', 'op2']), ['op3', 'op4'], None), ('one not allowed', checkers.allow_caveat(['op1', 'op2']), ['op1', 'op3'], 'caveat "allow op1 op2" not satisfied: op3 not allowed'), ('one not denied', checkers.deny_caveat(['op1', 'op2']), ['op4', 'op5', 'op2'], 'caveat "deny op1 op2" not satisfied: op2 not allowed'), ('no operations, allow caveat', checkers.allow_caveat(['op1']), [], 'caveat "allow op1" not satisfied: op1 not allowed'), ('no operations, deny caveat', checkers.deny_caveat(['op1']), [], None), ('no operations, empty allow caveat', checkers.Caveat( condition=checkers.COND_ALLOW), [], 'caveat "allow" not satisfied: no operations allowed'), ] checker = checkers.Checker() for test in tests: print(test[0]) ctx = checkers.context_with_operations(checkers.AuthContext(), test[2]) err = checker.check_first_party_caveat(ctx, test[1].condition) if test[3] is None: self.assertIsNone(err) continue self.assertEqual(err, test[3])
def test_operations_checker(self): tests = [ ('all allowed', checkers.allow_caveat(['op1', 'op2', 'op4', 'op3' ]), ['op1', 'op3', 'op2'], None), ('none denied', checkers.deny_caveat(['op1', 'op2']), ['op3', 'op4'], None), ('one not allowed', checkers.allow_caveat(['op1', 'op2']), ['op1', 'op3'], 'caveat "allow op1 op2" not satisfied: op3 not allowed'), ('one not denied', checkers.deny_caveat(['op1', 'op2']), ['op4', 'op5', 'op2'], 'caveat "deny op1 op2" not satisfied: op2 not allowed'), ('no operations, allow caveat', checkers.allow_caveat(['op1']), [], 'caveat "allow op1" not satisfied: op1 not allowed'), ('no operations, deny caveat', checkers.deny_caveat(['op1']), [], None), ('no operations, empty allow caveat', checkers.Caveat(condition=checkers.COND_ALLOW), [], 'caveat "allow" not satisfied: no operations allowed'), ] checker = checkers.Checker() for test in tests: print(test[0]) ctx = checkers.context_with_operations(checkers.AuthContext(), test[2]) err = checker.check_first_party_caveat(ctx, test[1].condition) if test[3] is None: self.assertIsNone(err) continue self.assertEqual(err, test[3])
def test_operation_error_caveat(self): tests = [('empty allow', checkers.allow_caveat(None), 'error no operations allowed'), ('allow: invalid operation name', checkers.allow_caveat(['op1', 'operation number 2']), 'error invalid operation name "operation number 2"'), ('deny: invalid operation name', checkers.deny_caveat(['op1', 'operation number 2']), 'error invalid operation name "operation number 2"')] for test in tests: print(test[0]) self.assertEqual(test[1].condition, test[2])
def test_operation_error_caveat(self): tests = [ ('empty allow', checkers.allow_caveat(None), 'error no operations allowed'), ('allow: invalid operation name', checkers.allow_caveat(['op1', 'operation number 2']), 'error invalid operation name "operation number 2"'), ('deny: invalid operation name', checkers.deny_caveat(['op1', 'operation number 2']), 'error invalid operation name "operation number 2"') ] for test in tests: print(test[0]) self.assertEqual(test[1].condition, test[2])
def test_operation_allow_caveat(self): locator = _DischargerLocator() ids = _IdService('ids', locator, self) auth = _OpAuthorizer({ macaroonbakery.Op(entity='e1', action='read'): {'bob'}, macaroonbakery.Op(entity='e1', action='write'): {'bob'}, macaroonbakery.Op(entity='e2', action='read'): {'bob'}, }) ts = _Service('myservice', auth, ids, locator) client = _Client(locator) ctx = test_context.with_value(_DISCHARGE_USER_KEY, 'bob') m = client.capability(ctx, ts, [ macaroonbakery.Op(entity='e1', action='read'), macaroonbakery.Op(entity='e1', action='write'), macaroonbakery.Op(entity='e2', action='read') ]) # Sanity check that we can do a write. ts.do(test_context, [[m.macaroon]], [macaroonbakery.Op(entity='e1', action='write')]) m.add_caveat(checkers.allow_caveat(['read']), None, None) # A read operation should work. ts.do(test_context, [[m.macaroon]], [ macaroonbakery.Op(entity='e1', action='read'), macaroonbakery.Op(entity='e2', action='read') ]) # A write operation should fail # even though the original macaroon allowed it. with self.assertRaises(_DischargeRequiredError): ts.do(test_context, [[m.macaroon]], [macaroonbakery.Op(entity='e1', action='write')])
def test_operation_allow_caveat(self): locator = _DischargerLocator() ids = _IdService('ids', locator, self) auth = _OpAuthorizer({ bakery.Op(entity='e1', action='read'): {'bob'}, bakery.Op(entity='e1', action='write'): {'bob'}, bakery.Op(entity='e2', action='read'): {'bob'}, }) ts = _Service('myservice', auth, ids, locator) client = _Client(locator) ctx = test_context.with_value(_DISCHARGE_USER_KEY, 'bob') m = client.capability(ctx, ts, [ bakery.Op(entity='e1', action='read'), bakery.Op(entity='e1', action='write'), bakery.Op(entity='e2', action='read'), ]) # Sanity check that we can do a write. ts.do(test_context, [[m.macaroon]], [bakery.Op(entity='e1', action='write')]) m.add_caveat(checkers.allow_caveat(['read']), None, None) # A read operation should work. ts.do(test_context, [[m.macaroon]], [ bakery.Op(entity='e1', action='read'), bakery.Op(entity='e2', action='read'), ]) # A write operation should fail # even though the original macaroon allowed it. with self.assertRaises(_DischargeRequiredError): ts.do(test_context, [[m.macaroon]], [ bakery.Op(entity='e1', action='write'), ])
def test_first_party_caveat_squashing(self): locator = _DischargerLocator() ids = _IdService('ids', locator, self) auth = _OpAuthorizer({ bakery.Op(entity='e1', action='read'): {'alice'}, bakery.Op(entity='e2', action='read'): {'alice'}, }) ts = _Service('myservice', auth, ids, locator) tests = [ ('duplicates removed', [ checkers.Caveat(condition='true 1', namespace='testns'), checkers.Caveat(condition='true 2', namespace='testns'), checkers.Caveat(condition='true 1', namespace='testns'), checkers.Caveat(condition='true 1', namespace='testns'), checkers.Caveat(condition='true 3', namespace='testns'), ], [ checkers.Caveat(condition='true 1', namespace='testns'), checkers.Caveat(condition='true 2', namespace='testns'), checkers.Caveat(condition='true 3', namespace='testns'), ]), ('earliest time before', [ checkers.time_before_caveat(epoch + timedelta(days=1)), checkers.Caveat(condition='true 1', namespace='testns'), checkers.time_before_caveat( epoch + timedelta(days=0, hours=1)), checkers.time_before_caveat(epoch + timedelta( days=0, hours=0, minutes=5)), ], [ checkers.time_before_caveat(epoch + timedelta( days=0, hours=0, minutes=5)), checkers.Caveat(condition='true 1', namespace='testns'), ]), ('operations and declared caveats removed', [ checkers.deny_caveat(['foo']), checkers.allow_caveat(['read', 'write']), checkers.declared_caveat('username', 'bob'), checkers.Caveat(condition='true 1', namespace='testns'), ], [ checkers.Caveat(condition='true 1', namespace='testns'), ]) ] for test in tests: print(test[0]) # Make a first macaroon with all the required first party caveats. ctx = test_context.with_value(_DISCHARGE_USER_KEY, 'alice') m1 = _Client(locator).capability( ctx, ts, [bakery.Op(entity='e1', action='read')]) m1.add_caveats(test[1], None, None) # Make a second macaroon that's not used to check that it's # caveats are not added. m2 = _Client(locator).capability( ctx, ts, [bakery.Op(entity='e1', action='read')]) m2.add_caveat(checkers.Caveat( condition='true notused', namespace='testns'), None, None) client = _Client(locator) client.add_macaroon(ts, 'authz1', [m1.macaroon]) client.add_macaroon(ts, 'authz2', [m2.macaroon]) m3 = client.capability( test_context, ts, [bakery.Op(entity='e1', action='read')]) self.assertEqual( _macaroon_conditions(m3.macaroon.caveats, False), _resolve_caveats(m3.namespace, test[2]))
def test_first_party_caveat_squashing(self): locator = _DischargerLocator() ids = _IdService('ids', locator, self) auth = _OpAuthorizer({ macaroonbakery.Op(entity='e1', action='read'): {'alice'}, macaroonbakery.Op(entity='e2', action='read'): {'alice'}, }) ts = _Service('myservice', auth, ids, locator) tests = [('duplicates removed', [ checkers.Caveat(condition='true 1', namespace='testns'), checkers.Caveat(condition='true 2', namespace='testns'), checkers.Caveat(condition='true 1', namespace='testns'), checkers.Caveat(condition='true 1', namespace='testns'), checkers.Caveat(condition='true 3', namespace='testns'), ], [ checkers.Caveat(condition='true 1', namespace='testns'), checkers.Caveat(condition='true 2', namespace='testns'), checkers.Caveat(condition='true 3', namespace='testns'), ]), ('earliest time before', [ checkers.time_before_caveat(epoch + timedelta(days=1)), checkers.Caveat(condition='true 1', namespace='testns'), checkers.time_before_caveat(epoch + timedelta(days=0, hours=1)), checkers.time_before_caveat( epoch + timedelta(days=0, hours=0, minutes=5)), ], [ checkers.time_before_caveat( epoch + timedelta(days=0, hours=0, minutes=5)), checkers.Caveat(condition='true 1', namespace='testns'), ]), ('operations and declared caveats removed', [ checkers.deny_caveat(['foo']), checkers.allow_caveat(['read', 'write']), checkers.declared_caveat('username', 'bob'), checkers.Caveat(condition='true 1', namespace='testns'), ], [ checkers.Caveat(condition='true 1', namespace='testns'), ])] for test in tests: print(test[0]) # Make a first macaroon with all the required first party caveats. ctx = test_context.with_value(_DISCHARGE_USER_KEY, 'alice') m1 = _Client(locator).capability( ctx, ts, [macaroonbakery.Op(entity='e1', action='read')]) m1.add_caveats(test[1], None, None) # Make a second macaroon that's not used to check that it's # caveats are not added. m2 = _Client(locator).capability( ctx, ts, [macaroonbakery.Op(entity='e1', action='read')]) m2.add_caveat( checkers.Caveat(condition='true notused', namespace='testns'), None, None) client = _Client(locator) client.add_macaroon(ts, 'authz1', [m1.macaroon]) client.add_macaroon(ts, 'authz2', [m2.macaroon]) m3 = client.capability( test_context, ts, [macaroonbakery.Op(entity='e1', action='read')]) self.assertEqual(_macaroon_conditions(m3.macaroon.caveats, False), _resolve_caveats(m3.namespace, test[2]))