def test_decode_caveat_v3_from_go(self): tp_key = bakery.PrivateKey( nacl.public.PrivateKey(base64.b64decode( 'TSpvLpQkRj+T3JXnsW2n43n5zP/0X4zn0RvDiWC3IJ0='))) fp_key = bakery.PrivateKey(nacl.public.PrivateKey( base64.b64decode( 'KXpsoJ9ujZYi/O2Cca6kaWh65MSawzy79LWkrjOfzcs='))) root_key = base64.b64decode(b'oqOXI3/Mz/pKjCuFOt2eYxb7ndLq66GY') # This caveat has been generated from the go code # to check the compatibilty encrypted_cav = bakery.b64decode( 'A_D-xlUf2MdGMgtu7OKRQnCP1OQJk6PKeFWRK26WIBA6DNwKGNLeFSkD2M-8A' 'EYvmgVH95GWu7T7caKxKhhOQFcEKgnXKJvYXxz1zin4cZc4Q6C7gVqA-J4_j3' '1LX4VKxymqG62UGPo78wOv0_fKjr3OI6PPJOYOQgBMclemlRF2', ) cav = bakery.decode_caveat(tp_key, encrypted_cav) self.assertEquals(cav, bakery.ThirdPartyCaveatInfo( condition='third party condition', first_party_public_key=fp_key.public_key, third_party_key_pair=tp_key, root_key=root_key, caveat=encrypted_cav, version=bakery.VERSION_3, id=None, namespace=bakery.legacy_namespace() ))
def test_decode_caveat_v2_from_go(self): tp_key = bakery.PrivateKey(nacl.public.PrivateKey( base64.b64decode( 'TSpvLpQkRj+T3JXnsW2n43n5zP/0X4zn0RvDiWC3IJ0='))) fp_key = bakery.PrivateKey( nacl.public.PrivateKey(base64.b64decode( 'KXpsoJ9ujZYi/O2Cca6kaWh65MSawzy79LWkrjOfzcs='))) root_key = base64.b64decode('wh0HSM65wWHOIxoGjgJJOFvQKn2jJFhC') # This caveat has been generated from the go code # to check the compatibilty encrypted_cav = bakery.b64decode( 'AvD-xlUf2MdGMgtu7OKRQnCP1OQJk6PKeFWRK26WIBA6DNwKGIHq9xGcHS9IZ' 'Lh0cL6D9qpeKI0mXmCPfnwRQDuVYC8y5gVWd-oCGZaj5TGtk3byp2Vnw6ojmt' 'sULDhY59YA_J_Y0ATkERO5T9ajoRWBxU2OXBoX6bImXA', ) cav = bakery.decode_caveat(tp_key, encrypted_cav) self.assertEqual(cav, bakery.ThirdPartyCaveatInfo( condition='third party condition', first_party_public_key=fp_key.public_key, third_party_key_pair=tp_key, root_key=root_key, caveat=encrypted_cav, version=bakery.VERSION_2, id=None, namespace=bakery.legacy_namespace() ))
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 _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 test_decode_caveat_v1_from_go(self): tp_key = macaroonbakery.PrivateKey( nacl.public.PrivateKey( base64.b64decode( 'TSpvLpQkRj+T3JXnsW2n43n5zP/0X4zn0RvDiWC3IJ0='))) fp_key = macaroonbakery.PrivateKey( nacl.public.PrivateKey( base64.b64decode( 'KXpsoJ9ujZYi/O2Cca6kaWh65MSawzy79LWkrjOfzcs='))) root_key = base64.b64decode('vDxEmWZEkgiNEFlJ+8ruXe3qDSLf1H+o') # This caveat has been generated from the go code # to check the compatibilty encrypted_cav = six.b( 'eyJUaGlyZFBhcnR5UHVibGljS2V5IjoiOFA3R1ZZc3BlWlN4c' '3hFdmJsSVFFSTFqdTBTSWl0WlIrRFdhWE40cmxocz0iLCJGaX' 'JzdFBhcnR5UHVibGljS2V5IjoiSDlqSFJqSUxidXppa1VKd2o' '5VGtDWk9qeW5oVmtTdHVsaUFRT2d6Y0NoZz0iLCJOb25jZSI6' 'Ii9lWTRTTWR6TGFxbDlsRFc3bHUyZTZuSzJnVG9veVl0IiwiS' 'WQiOiJra0ZuOGJEaEt4RUxtUjd0NkJxTU0vdHhMMFVqaEZjR1' 'BORldUUExGdjVla1dWUjA4Uk1sbGJhc3c4VGdFbkhzM0laeVo' '0V2lEOHhRUWdjU3ljOHY4eUt4dEhxejVEczJOYmh1ZDJhUFdt' 'UTVMcVlNWitmZ2FNaTAxdE9DIn0=') cav = macaroonbakery.decode_caveat(tp_key, encrypted_cav) self.assertEquals( cav, macaroonbakery.ThirdPartyCaveatInfo( condition='caveat condition', first_party_public_key=fp_key.public_key, third_party_key_pair=tp_key, root_key=root_key, caveat=encrypted_cav, version=macaroonbakery.BAKERY_V1, namespace=macaroonbakery.legacy_namespace()))
def test_decode_caveat_v2_from_go(self): tp_key = macaroonbakery.PrivateKey( nacl.public.PrivateKey( base64.b64decode( 'TSpvLpQkRj+T3JXnsW2n43n5zP/0X4zn0RvDiWC3IJ0='))) fp_key = macaroonbakery.PrivateKey( nacl.public.PrivateKey( base64.b64decode( 'KXpsoJ9ujZYi/O2Cca6kaWh65MSawzy79LWkrjOfzcs='))) root_key = base64.b64decode('wh0HSM65wWHOIxoGjgJJOFvQKn2jJFhC') # This caveat has been generated from the go code # to check the compatibilty encrypted_cav = base64.urlsafe_b64decode( utils.add_base64_padding( six. b('AvD-xlUf2MdGMgtu7OKRQnCP1OQJk6PKeFWRK26WIBA6DNwKGIHq9xGcHS9IZ' 'Lh0cL6D9qpeKI0mXmCPfnwRQDuVYC8y5gVWd-oCGZaj5TGtk3byp2Vnw6ojmt' 'sULDhY59YA_J_Y0ATkERO5T9ajoRWBxU2OXBoX6bImXA'))) cav = macaroonbakery.decode_caveat(tp_key, encrypted_cav) self.assertEqual( cav, macaroonbakery.ThirdPartyCaveatInfo( condition='third party condition', first_party_public_key=fp_key.public_key, third_party_key_pair=tp_key, root_key=root_key, caveat=encrypted_cav, version=macaroonbakery.BAKERY_V2, namespace=macaroonbakery.legacy_namespace()))
def test_decode_caveat_v3_from_go(self): tp_key = macaroonbakery.PrivateKey( nacl.public.PrivateKey( base64.b64decode( 'TSpvLpQkRj+T3JXnsW2n43n5zP/0X4zn0RvDiWC3IJ0='))) fp_key = macaroonbakery.PrivateKey( nacl.public.PrivateKey( base64.b64decode( 'KXpsoJ9ujZYi/O2Cca6kaWh65MSawzy79LWkrjOfzcs='))) root_key = base64.b64decode(b'oqOXI3/Mz/pKjCuFOt2eYxb7ndLq66GY') # This caveat has been generated from the go code # to check the compatibilty encrypted_cav = base64.urlsafe_b64decode( utils.add_base64_padding( six. b('A_D-xlUf2MdGMgtu7OKRQnCP1OQJk6PKeFWRK26WIBA6DNwKGNLeFSkD2M-8A' 'EYvmgVH95GWu7T7caKxKhhOQFcEKgnXKJvYXxz1zin4cZc4Q6C7gVqA-J4_j3' '1LX4VKxymqG62UGPo78wOv0_fKjr3OI6PPJOYOQgBMclemlRF2'))) cav = macaroonbakery.decode_caveat(tp_key, encrypted_cav) self.assertEquals( cav, macaroonbakery.ThirdPartyCaveatInfo( condition='third party condition', first_party_public_key=fp_key.public_key, third_party_key_pair=tp_key, root_key=root_key, caveat=encrypted_cav, version=macaroonbakery.BAKERY_V3, namespace=macaroonbakery.legacy_namespace()))
def test_decode_caveat_v1_from_go(self): tp_key = bakery.PrivateKey( nacl.public.PrivateKey(base64.b64decode( 'TSpvLpQkRj+T3JXnsW2n43n5zP/0X4zn0RvDiWC3IJ0='))) fp_key = bakery.PrivateKey( nacl.public.PrivateKey(base64.b64decode( 'KXpsoJ9ujZYi/O2Cca6kaWh65MSawzy79LWkrjOfzcs='))) root_key = base64.b64decode('vDxEmWZEkgiNEFlJ+8ruXe3qDSLf1H+o') # This caveat has been generated from the go code # to check the compatibilty encrypted_cav = six.b( 'eyJUaGlyZFBhcnR5UHVibGljS2V5IjoiOFA3R1ZZc3BlWlN4c' '3hFdmJsSVFFSTFqdTBTSWl0WlIrRFdhWE40cmxocz0iLCJGaX' 'JzdFBhcnR5UHVibGljS2V5IjoiSDlqSFJqSUxidXppa1VKd2o' '5VGtDWk9qeW5oVmtTdHVsaUFRT2d6Y0NoZz0iLCJOb25jZSI6' 'Ii9lWTRTTWR6TGFxbDlsRFc3bHUyZTZuSzJnVG9veVl0IiwiS' 'WQiOiJra0ZuOGJEaEt4RUxtUjd0NkJxTU0vdHhMMFVqaEZjR1' 'BORldUUExGdjVla1dWUjA4Uk1sbGJhc3c4VGdFbkhzM0laeVo' '0V2lEOHhRUWdjU3ljOHY4eUt4dEhxejVEczJOYmh1ZDJhUFdt' 'UTVMcVlNWitmZ2FNaTAxdE9DIn0=') cav = bakery.decode_caveat(tp_key, encrypted_cav) self.assertEquals(cav, bakery.ThirdPartyCaveatInfo( condition='caveat condition', first_party_public_key=fp_key.public_key, third_party_key_pair=tp_key, root_key=root_key, caveat=encrypted_cav, version=bakery.VERSION_1, id=None, namespace=bakery.legacy_namespace() ))
def test_v2_round_trip(self): tp_info = bakery.ThirdPartyInfo(version=bakery.VERSION_2, public_key=self.tp_key.public_key) cid = bakery.encode_caveat('is-authenticated-user', b'a random string', tp_info, self.fp_key, None) res = bakery.decode_caveat(self.tp_key, cid) self.assertEquals( res, bakery.ThirdPartyCaveatInfo( first_party_public_key=self.fp_key.public_key, root_key=b'a random string', condition='is-authenticated-user', caveat=cid, third_party_key_pair=self.tp_key, version=bakery.VERSION_2, id=None, namespace=bakery.legacy_namespace()))
def from_dict(cls, json_dict): '''Return a macaroon obtained from the given dictionary as deserialized from JSON. @param json_dict The deserialized JSON object. ''' json_macaroon = json_dict.get('m') if json_macaroon is None: # Try the v1 format if we don't have a macaroon field. m = pymacaroons.Macaroon.deserialize( json.dumps(json_dict), json_serializer.JsonSerializer()) macaroon = Macaroon(root_key=None, id=None, namespace=bakery.legacy_namespace(), version=_bakery_version(m.version)) macaroon._macaroon = m return macaroon version = json_dict.get('v', None) if version is None: raise ValueError('no version specified') if (version < bakery.VERSION_3 or version > bakery.LATEST_VERSION): raise ValueError('unknown bakery version {}'.format(version)) m = pymacaroons.Macaroon.deserialize(json.dumps(json_macaroon), json_serializer.JsonSerializer()) if m.version != macaroon_version(version): raise ValueError('underlying macaroon has inconsistent version; ' 'got {} want {}'.format( m.version, macaroon_version(version))) namespace = checkers.deserialize_namespace(json_dict.get('ns')) cdata = json_dict.get('cdata', {}) caveat_data = {} for id64 in cdata: id = utils.b64decode(id64) data = utils.b64decode(cdata[id64]) caveat_data[id] = data macaroon = Macaroon(root_key=None, id=None, namespace=namespace, version=version) macaroon._caveat_data = caveat_data macaroon._macaroon = m return macaroon
def from_dict(cls, json_dict): '''Return a macaroon obtained from the given dictionary as deserialized from JSON. @param json_dict The deserialized JSON object. ''' json_macaroon = json_dict.get('m') if json_macaroon is None: # Try the v1 format if we don't have a macaroon field. m = pymacaroons.Macaroon.deserialize( json.dumps(json_dict), json_serializer.JsonSerializer()) macaroon = Macaroon(root_key=None, id=None, namespace=bakery.legacy_namespace(), version=_bakery_version(m.version)) macaroon._macaroon = m return macaroon version = json_dict.get('v', None) if version is None: raise ValueError('no version specified') if (version < bakery.VERSION_3 or version > bakery.LATEST_VERSION): raise ValueError('unknown bakery version {}'.format(version)) m = pymacaroons.Macaroon.deserialize(json.dumps(json_macaroon), json_serializer.JsonSerializer()) if m.version != macaroon_version(version): raise ValueError( 'underlying macaroon has inconsistent version; ' 'got {} want {}'.format(m.version, macaroon_version(version))) namespace = checkers.deserialize_namespace(json_dict.get('ns')) cdata = json_dict.get('cdata', {}) caveat_data = {} for id64 in cdata: id = utils.b64decode(id64) data = utils.b64decode(cdata[id64]) caveat_data[id] = data macaroon = Macaroon(root_key=None, id=None, namespace=namespace, version=version) macaroon._caveat_data = caveat_data macaroon._macaroon = m return macaroon
def test_v2_round_trip(self): tp_info = bakery.ThirdPartyInfo( version=bakery.VERSION_2, public_key=self.tp_key.public_key) cid = bakery.encode_caveat( 'is-authenticated-user', b'a random string', tp_info, self.fp_key, None) res = bakery.decode_caveat(self.tp_key, cid) self.assertEquals(res, bakery.ThirdPartyCaveatInfo( first_party_public_key=self.fp_key.public_key, root_key=b'a random string', condition='is-authenticated-user', caveat=cid, third_party_key_pair=self.tp_key, version=bakery.VERSION_2, id=None, namespace=bakery.legacy_namespace() ))
def deserialize_json(cls, serialized_json): serialized = json.loads(serialized_json) json_macaroon = serialized.get('m') if json_macaroon is None: # Try the v1 format if we don't have a macaroon filed m = pymacaroons.Macaroon.deserialize( serialized_json, json_serializer.JsonSerializer()) macaroon = Macaroon(root_key=None, id=None, namespace=macaroonbakery.legacy_namespace(), version=_bakery_version(m.version)) macaroon._macaroon = m return macaroon version = serialized.get('v', None) if version is None: raise ValueError('no version specified') if (version < macaroonbakery.BAKERY_V3 or version > macaroonbakery.LATEST_BAKERY_VERSION): raise ValueError('unknow bakery version {}'.format(version)) m = pymacaroons.Macaroon.deserialize(json.dumps(json_macaroon), json_serializer.JsonSerializer()) if m.version != macaroon_version(version): raise ValueError('underlying macaroon has inconsistent version; ' 'got {} want {}'.format( m.version, macaroon_version(version))) namespace = checkers.deserialize_namespace(serialized.get('ns')) cdata = serialized.get('cdata', {}) caveat_data = {} for id64 in cdata: id = utils.raw_b64decode(id64) data = utils.raw_b64decode(cdata[id64]) caveat_data[id] = data macaroon = Macaroon(root_key=None, id=None, namespace=namespace, version=version) macaroon._caveat_data = caveat_data macaroon._macaroon = m return macaroon
def _decode_secret_part_v2_v3(version, data): if len(data) < 1: raise bakery.VerificationError('secret part too short') got_version = six.byte2int(data[:1]) data = data[1:] if version != got_version: raise bakery.VerificationError( 'unexpected secret part version, got {} want {}'.format( got_version, version)) root_key_length, read = decode_uvarint(data) data = data[read:] root_key = data[:root_key_length] data = data[root_key_length:] if version >= bakery.VERSION_3: namespace_length, read = decode_uvarint(data) data = data[read:] ns_data = data[:namespace_length] data = data[namespace_length:] ns = checkers.deserialize_namespace(ns_data) else: ns = bakery.legacy_namespace() return root_key, data, ns
def _decode_secret_part_v2_v3(version, data): if len(data) < 1: raise macaroonbakery.VerificationError('secret part too short') got_version = six.byte2int(data[:1]) data = data[1:] if version != got_version: raise macaroonbakery.VerificationError( 'unexpected secret part version, got {} want {}'.format( got_version, version)) root_key_length, read = decode_uvarint(data) data = data[read:] root_key = data[:root_key_length] data = data[root_key_length:] if version >= macaroonbakery.BAKERY_V3: namespace_length, read = decode_uvarint(data) data = data[read:] ns_data = data[:namespace_length] data = data[namespace_length:] ns = checkers.deserialize_namespace(ns_data) else: ns = macaroonbakery.legacy_namespace() return root_key, data, ns
def _decode_caveat_v1(key, caveat): '''Decode a base64 encoded JSON id. @param key the nacl private key to decode. @param caveat a base64 encoded JSON string. ''' data = base64.b64decode(caveat).decode('utf-8') wrapper = json.loads(data) tp_public_key = nacl.public.PublicKey( base64.b64decode(wrapper['ThirdPartyPublicKey'])) if key.public_key.key != tp_public_key: raise Exception('public key mismatch') # TODO if wrapper.get('FirstPartyPublicKey', None) is None: raise Exception('target service public key not specified') # The encrypted string is base64 encoded in the JSON representation. secret = base64.b64decode(wrapper.get('Id')) nonce = base64.b64decode(wrapper.get('Nonce')) fp_public_key = nacl.public.PublicKey(base64.b64decode( wrapper.get('FirstPartyPublicKey'))) box = nacl.public.Box(key.key, fp_public_key) c = box.decrypt(secret, nonce) record = json.loads(c.decode('utf-8')) fp_key = nacl.public.PublicKey( base64.b64decode(wrapper.get('FirstPartyPublicKey'))) return bakery.ThirdPartyCaveatInfo( condition=record.get('Condition'), first_party_public_key=bakery.PublicKey(fp_key), third_party_key_pair=key, root_key=base64.b64decode(record.get('RootKey')), caveat=caveat, id=None, version=bakery.VERSION_1, namespace=bakery.legacy_namespace() )
def _decode_caveat_v1(key, caveat): '''Decode a base64 encoded JSON id. @param key the nacl private key to decode. @param caveat a base64 encoded JSON string. ''' data = base64.b64decode(caveat).decode('utf-8') wrapper = json.loads(data) tp_public_key = nacl.public.PublicKey( base64.b64decode(wrapper['ThirdPartyPublicKey'])) if key.public_key.key != tp_public_key: raise Exception('public key mismatch') # TODO if wrapper.get('FirstPartyPublicKey', None) is None: raise Exception('target service public key not specified') # The encrypted string is base64 encoded in the JSON representation. secret = base64.b64decode(wrapper.get('Id')) nonce = base64.b64decode(wrapper.get('Nonce')) fp_public_key = nacl.public.PublicKey( base64.b64decode(wrapper.get('FirstPartyPublicKey'))) box = nacl.public.Box(key.key, fp_public_key) c = box.decrypt(secret, nonce) record = json.loads(c.decode('utf-8')) fp_key = nacl.public.PublicKey( base64.b64decode(wrapper.get('FirstPartyPublicKey'))) return bakery.ThirdPartyCaveatInfo( condition=record.get('Condition'), first_party_public_key=bakery.PublicKey(fp_key), third_party_key_pair=key, root_key=base64.b64decode(record.get('RootKey')), caveat=caveat, id=None, version=bakery.VERSION_1, namespace=bakery.legacy_namespace())