def test_add_third_party_caveat(self): locator = bakery.ThirdPartyStore() bs = common.new_bakery('bs-loc', locator) lbv = six.int2byte(bakery.LATEST_VERSION) tests = [ ('no existing id', b'', [], lbv + six.int2byte(0)), ('several existing ids', b'', [ lbv + six.int2byte(0), lbv + six.int2byte(1), lbv + six.int2byte(2) ], lbv + six.int2byte(3)), ('with base id', lbv + six.int2byte(0), [lbv + six.int2byte(0)], lbv + six.int2byte(0) + six.int2byte(0)), ('with base id and existing id', lbv + six.int2byte(0), [ lbv + six.int2byte(0) + six.int2byte(0) ], lbv + six.int2byte(0) + six.int2byte(1)) ] for test in tests: print('test ', test[0]) m = bakery.Macaroon( root_key=b'root key', id=b'id', location='location', version=bakery.LATEST_VERSION) for id in test[2]: m.macaroon.add_third_party_caveat(key=None, key_id=id, location='') m._caveat_id_prefix = test[1] m.add_caveat(checkers.Caveat(location='bs-loc', condition='something'), bs.oven.key, locator) self.assertEqual(m.macaroon.caveats[len(test[2])].caveat_id, test[3])
def test_marshal_json_latest_version(self): locator = bakery.ThirdPartyStore() bs = common.new_bakery('bs-loc', locator) ns = checkers.Namespace({ 'testns': 'x', 'otherns': 'y', }) m = bakery.Macaroon( root_key=b'root key', id=b'id', location='location', version=bakery.LATEST_VERSION, namespace=ns) m.add_caveat(checkers.Caveat(location='bs-loc', condition='something'), bs.oven.key, locator) data = m.serialize_json() m1 = bakery.Macaroon.deserialize_json(data) # Just check the signature and version - we're not interested in fully # checking the macaroon marshaling here. self.assertEqual(m1.macaroon.signature, m.macaroon.signature) self.assertEqual(m1.macaroon.version, m.macaroon.version) self.assertEqual(len(m1.macaroon.caveats), 1) self.assertEqual(m1.namespace, m.namespace) self.assertEqual(m1._caveat_data, m._caveat_data) # test with the encoder, decoder data = json.dumps(m, cls=bakery.MacaroonJSONEncoder) m1 = json.loads(data, cls=bakery.MacaroonJSONDecoder) self.assertEqual(m1.macaroon.signature, m.macaroon.signature) self.assertEqual(m1.macaroon.version, m.macaroon.version) self.assertEqual(len(m1.macaroon.caveats), 1) self.assertEqual(m1.namespace, m.namespace) self.assertEqual(m1._caveat_data, m._caveat_data)
def test_add_first_party_caveat(self): m = bakery.Macaroon('rootkey', 'some id', 'here', bakery.LATEST_VERSION) m.add_caveat(checkers.Caveat('test_condition')) caveats = m.first_party_caveats() self.assertEquals(len(caveats), 1) self.assertEquals(caveats[0].caveat_id, b'test_condition')
def _test_json_with_version(self, version): locator = bakery.ThirdPartyStore() bs = common.new_bakery('bs-loc', locator) ns = checkers.Namespace({ 'testns': 'x', }) m = bakery.Macaroon( root_key=b'root key', id=b'id', location='location', version=version, namespace=ns) m.add_caveat(checkers.Caveat(location='bs-loc', condition='something'), bs.oven.key, locator) # Sanity check that no external caveat data has been added. self.assertEqual(len(m._caveat_data), 0) data = json.dumps(m, cls=bakery.MacaroonJSONEncoder) m1 = json.loads(data, cls=bakery.MacaroonJSONDecoder) # Just check the signature and version - we're not interested in fully # checking the macaroon marshaling here. self.assertEqual(m1.macaroon.signature, m.macaroon.signature) self.assertEqual(m1.macaroon.version, bakery.macaroon_version(version)) self.assertEqual(len(m1.macaroon.caveats), 1) # Namespace information has been thrown away. self.assertEqual(m1.namespace, bakery.legacy_namespace()) self.assertEqual(len(m1._caveat_data), 0)
def get_discharge(cav, payload): self.assertEqual(payload, None) m = bakery.Macaroon( root_key='root key {}'.format( cav.caveat_id.decode('utf-8')).encode('utf-8'), id=cav.caveat_id, location='', version=bakery.LATEST_VERSION) add_caveats(m) return m
def test_new_macaroon(self): m = bakery.Macaroon( b'rootkey', b'some id', 'here', bakery.LATEST_VERSION) self.assertIsNotNone(m) self.assertEquals(m._macaroon.identifier, b'some id') self.assertEquals(m._macaroon.location, 'here') self.assertEquals(m.version, bakery.LATEST_VERSION)
def discharge(url, request): wrong_macaroon = bakery.Macaroon(root_key=b'some key', id=b'xxx', location='some other location', version=bakery.VERSION_0) return { 'status_code': 200, 'content': { 'Macaroon': wrong_macaroon.to_dict() } }
def new_macaroon(self, caveats, namespace, ops): root_key, id = self._root_key_store.root_key() m_id = {'id': base64.urlsafe_b64encode(id).decode('utf-8'), 'ops': ops} data = json.dumps(m_id) m = bakery.Macaroon(root_key=root_key, id=data, location='', version=bakery.LATEST_VERSION, namespace=namespace) m.add_caveats(caveats, self._key, self._locator) return m
def test_discharge_all_no_discharges(self): root_key = b'root key' m = bakery.Macaroon( root_key=root_key, id=b'id0', location='loc0', version=bakery.LATEST_VERSION, namespace=common.test_checker().namespace()) ms = bakery.discharge_all(m, no_discharge(self)) self.assertEqual(len(ms), 1) self.assertEqual(ms[0], m.macaroon) v = Verifier() v.satisfy_general(always_ok) v.verify(m.macaroon, root_key, None)
def test_handle_error_cookie_path(self): macaroon = bakery.Macaroon(root_key=b'some key', id=b'xxx', location='some location', version=bakery.VERSION_0) info = { 'Macaroon': macaroon.to_dict(), 'MacaroonPath': '.', 'CookieNameSuffix': 'test' } error = httpbakery.Error(code=407, message='error', version=bakery.LATEST_VERSION, info=httpbakery.ErrorInfo.from_dict(info)) client = httpbakery.Client() client.handle_error(error, 'http://example.com/some/path') [cookie] = client.cookies self.assertEqual(cookie.path, "/some/")
def test_json_deserialize_from_go(self): ns = checkers.Namespace() ns.register("someuri", "x") m = bakery.Macaroon( root_key=b'rootkey', id=b'some id', location='here', version=bakery.LATEST_VERSION, namespace=ns) m.add_caveat(checkers.Caveat(condition='something', namespace='someuri')) data = '{"m":{"c":[{"i":"x:something"}],"l":"here","i":"some id",' \ '"s64":"c8edRIupArSrY-WZfa62pgZFD8VjDgqho9U2PlADe-E"},"v":3,' \ '"ns":"someuri:x"}' m_go = bakery.Macaroon.deserialize_json(data) self.assertEqual(m.macaroon.signature_bytes, m_go.macaroon.signature_bytes) self.assertEqual(m.macaroon.version, m_go.macaroon.version) self.assertEqual(len(m_go.macaroon.caveats), 1) self.assertEqual(m.namespace, m_go.namespace)
def test_discharge_all_many_discharges(self): root_key = b'root key' m0 = bakery.Macaroon( root_key=root_key, id=b'id0', location='loc0', version=bakery.LATEST_VERSION) class State(object): total_required = 40 id = 1 def add_caveats(m): for i in range(0, 1): if State.total_required == 0: break cid = 'id{}'.format(State.id) m.macaroon.add_third_party_caveat( location='somewhere', key='root key {}'.format(cid).encode('utf-8'), key_id=cid.encode('utf-8')) State.id += 1 State.total_required -= 1 add_caveats(m0) def get_discharge(cav, payload): self.assertEqual(payload, None) m = bakery.Macaroon( root_key='root key {}'.format( cav.caveat_id.decode('utf-8')).encode('utf-8'), id=cav.caveat_id, location='', version=bakery.LATEST_VERSION) add_caveats(m) return m ms = bakery.discharge_all(m0, get_discharge) self.assertEqual(len(ms), 41) v = Verifier() v.satisfy_general(always_ok) v.verify(ms[0], root_key, ms[1:])
def test_clone(self): locator = bakery.ThirdPartyStore() bs = common.new_bakery("bs-loc", locator) ns = checkers.Namespace({ "testns": "x", }) m = bakery.Macaroon( root_key=b'root key', id=b'id', location='location', version=bakery.LATEST_VERSION, namespace=ns) m.add_caveat(checkers.Caveat(location='bs-loc', condition='something'), bs.oven.key, locator) m1 = m.copy() self.assertEqual(len(m.macaroon.caveats), 1) self.assertEqual(len(m1.macaroon.caveats), 1) self.assertEqual(m._caveat_data, m1._caveat_data) m.add_caveat(checkers.Caveat(location='bs-loc', condition='something'), bs.oven.key, locator) self.assertEqual(len(m.macaroon.caveats), 2) self.assertEqual(len(m1.macaroon.caveats), 1) self.assertNotEqual(m._caveat_data, m1._caveat_data)
def test_discharge_all_many_discharges_with_real_third_party_caveats(self): # This is the same flow as TestDischargeAllManyDischarges except that # we're using actual third party caveats as added by # Macaroon.add_caveat and we use a larger number of caveats # so that caveat ids will need to get larger. locator = bakery.ThirdPartyStore() bakeries = {} total_discharges_required = 40 class M: bakery_id = 0 still_required = total_discharges_required def add_bakery(): M.bakery_id += 1 loc = 'loc{}'.format(M.bakery_id) bakeries[loc] = common.new_bakery(loc, locator) return loc ts = common.new_bakery('ts-loc', locator) def checker(_, ci): caveats = [] if ci.condition != 'something': self.fail('unexpected condition') for i in range(0, 2): if M.still_required <= 0: break caveats.append(checkers.Caveat(location=add_bakery(), condition='something')) M.still_required -= 1 return caveats root_key = b'root key' m0 = bakery.Macaroon( root_key=root_key, id=b'id0', location='ts-loc', version=bakery.LATEST_VERSION) m0.add_caveat(checkers. Caveat(location=add_bakery(), condition='something'), ts.oven.key, locator) # We've added a caveat (the first) so one less caveat is required. M.still_required -= 1 class ThirdPartyCaveatCheckerF(bakery.ThirdPartyCaveatChecker): def check_third_party_caveat(self, ctx, info): return checker(ctx, info) def get_discharge(cav, payload): return bakery.discharge( common.test_context, cav.caveat_id, payload, bakeries[cav.location].oven.key, ThirdPartyCaveatCheckerF(), locator) ms = bakery.discharge_all(m0, get_discharge) self.assertEqual(len(ms), total_discharges_required + 1) v = Verifier() v.satisfy_general(always_ok) v.verify(ms[0], root_key, ms[1:])