diff options
Diffstat (limited to 'macaroonbakery/tests/test_macaroon.py')
-rw-r--r-- | macaroonbakery/tests/test_macaroon.py | 230 |
1 files changed, 184 insertions, 46 deletions
diff --git a/macaroonbakery/tests/test_macaroon.py b/macaroonbakery/tests/test_macaroon.py index afc7d52..7e77e2b 100644 --- a/macaroonbakery/tests/test_macaroon.py +++ b/macaroonbakery/tests/test_macaroon.py @@ -1,64 +1,202 @@ # Copyright 2017 Canonical Ltd. # Licensed under the LGPLv3, see LICENCE file for details. - +import json from unittest import TestCase import six +import pymacaroons +from pymacaroons import serializers -import nacl.utils - -from macaroonbakery import bakery, macaroon, checkers, codec +import macaroonbakery +import macaroonbakery.checkers as checkers +from macaroonbakery.tests import common class TestMacaroon(TestCase): def test_new_macaroon(self): - m = macaroon.Macaroon(b'rootkey', - b'some id', - 'here', - bakery.LATEST_BAKERY_VERSION) + m = macaroonbakery.Macaroon( + b'rootkey', + b'some id', + 'here', + macaroonbakery.LATEST_BAKERY_VERSION) self.assertIsNotNone(m) - self.assertEquals(m._macaroon.identifier, 'some id') + self.assertEquals(m._macaroon.identifier, b'some id') self.assertEquals(m._macaroon.location, 'here') - self.assertEquals(m.version, macaroon.macaroon_version( - bakery.LATEST_BAKERY_VERSION)) + self.assertEquals(m.version, macaroonbakery.LATEST_BAKERY_VERSION) def test_add_first_party_caveat(self): - m = macaroon.Macaroon('rootkey', - 'some id', - 'here', - bakery.LATEST_BAKERY_VERSION) - m = m.add_caveat(checkers.Caveat('test_condition')) + m = macaroonbakery.Macaroon('rootkey', 'some id', 'here', + macaroonbakery.LATEST_BAKERY_VERSION) + m.add_caveat(checkers.Caveat('test_condition')) caveats = m.first_party_caveats() self.assertEquals(len(caveats), 1) - self.assertEquals(caveats[0].caveat_id, 'test_condition') + self.assertEquals(caveats[0].caveat_id, b'test_condition') def test_add_third_party_caveat(self): - m = macaroon.Macaroon('rootkey', - 'some id', - 'here', - bakery.LATEST_BAKERY_VERSION) - loc = macaroon.ThirdPartyLocator() - fp_key = nacl.public.PrivateKey.generate() - tp_key = nacl.public.PrivateKey.generate() - - loc.add_info('test_location', - bakery.ThirdPartyInfo( - bakery.BAKERY_V1, - tp_key.public_key)) - m = m.add_caveat(checkers.Caveat(condition='test_condition', - location='test_location'), - fp_key, loc) - - tp_cav = m.third_party_caveats() - self.assertEquals(len(tp_cav), 1) - self.assertEquals(tp_cav[0].location, 'test_location') - cav = codec.decode_caveat(tp_key, six.b(tp_cav[0].caveat_id)) - self.assertEquals(cav, macaroon.ThirdPartyCaveatInfo( - condition='test_condition', - first_party_public_key=fp_key.public_key, - third_party_key_pair=tp_key, - root_key='random', - caveat=six.b(tp_cav[0].caveat_id), - version=bakery.BAKERY_V1, - ns=macaroon.legacy_namespace() - )) + locator = macaroonbakery.ThirdPartyStore() + bs = common.new_bakery('bs-loc', locator) + + lbv = six.int2byte(macaroonbakery.LATEST_BAKERY_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 = macaroonbakery.Macaroon( + root_key=b'root key', id=b'id', + location='location', + version=macaroonbakery.LATEST_BAKERY_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 = macaroonbakery.ThirdPartyStore() + bs = common.new_bakery('bs-loc', locator) + ns = checkers.Namespace({ + 'testns': 'x', + 'otherns': 'y', + }) + m = macaroonbakery.Macaroon( + root_key=b'root key', id=b'id', + location='location', + version=macaroonbakery.LATEST_BAKERY_VERSION, + namespace=ns) + m.add_caveat(checkers.Caveat(location='bs-loc', condition='something'), + bs.oven.key, locator) + data = m.serialize_json() + m1 = macaroonbakery.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=macaroonbakery.MacaroonJSONEncoder) + m1 = json.loads(data, cls=macaroonbakery.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_json_version1(self): + self._test_json_with_version(macaroonbakery.BAKERY_V1) + + def test_json_version2(self): + self._test_json_with_version(macaroonbakery.BAKERY_V2) + + def _test_json_with_version(self, version): + locator = macaroonbakery.ThirdPartyStore() + bs = common.new_bakery('bs-loc', locator) + + ns = checkers.Namespace({ + 'testns': 'x', + }) + + m = macaroonbakery.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=macaroonbakery.MacaroonJSONEncoder) + m1 = json.loads(data, cls=macaroonbakery.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, + macaroonbakery.macaroon_version(version)) + self.assertEqual(len(m1.macaroon.caveats), 1) + + # Namespace information has been thrown away. + self.assertEqual(m1.namespace, macaroonbakery.legacy_namespace()) + + self.assertEqual(len(m1._caveat_data), 0) + + def test_json_unknown_version(self): + m = pymacaroons.Macaroon(version=pymacaroons.MACAROON_V2) + with self.assertRaises(ValueError) as exc: + json.loads(json.dumps({ + 'm': m.serialize(serializer=serializers.JsonSerializer()), + 'v': macaroonbakery.LATEST_BAKERY_VERSION + 1 + }), cls=macaroonbakery.MacaroonJSONDecoder) + self.assertEqual('unknow bakery version 4', exc.exception.args[0]) + + def test_json_inconsistent_version(self): + m = pymacaroons.Macaroon(version=pymacaroons.MACAROON_V1) + with self.assertRaises(ValueError) as exc: + json.loads(json.dumps({ + 'm': json.loads(m.serialize( + serializer=serializers.JsonSerializer())), + 'v': macaroonbakery.LATEST_BAKERY_VERSION + }), cls=macaroonbakery.MacaroonJSONDecoder) + self.assertEqual('underlying macaroon has inconsistent version; ' + 'got 1 want 2', exc.exception.args[0]) + + def test_clone(self): + locator = macaroonbakery.ThirdPartyStore() + bs = common.new_bakery("bs-loc", locator) + ns = checkers.Namespace({ + "testns": "x", + }) + m = macaroonbakery.Macaroon( + root_key=b'root key', id=b'id', + location='location', + version=macaroonbakery.LATEST_BAKERY_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_json_deserialize_from_go(self): + ns = checkers.Namespace() + ns.register("someuri", "x") + m = macaroonbakery.Macaroon( + root_key=b'rootkey', id=b'some id', location='here', + version=macaroonbakery.LATEST_BAKERY_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 = macaroonbakery.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) |