def _packetize(self, key, data): # The 2 covers the space and the newline packet_size = self.PACKET_PREFIX_LENGTH + 2 + len(key) + len(data) # Ignore the first two chars, 0x packet_size_hex = hex(packet_size)[2:] if packet_size > 65535: raise MacaroonSerializationException( 'Packet too long for serialization. ' 'Max length is 0xFFFF (65535). ' 'Packet length: 0x{hex_length} ({length}) ' 'Key: {key}'.format( key=key, hex_length=packet_size_hex, length=packet_size ) ) header = packet_size_hex.zfill(4).encode('ascii') packet_content = key + b' ' + convert_to_bytes(data) + b'\n' packet = struct.pack( convert_to_bytes("4s%ds" % len(packet_content)), header, packet_content ) return packet
def _serialize_v2(self, macaroon): from pymacaroons.macaroon import MACAROON_V2 # https://github.com/rescrv/libmacaroons/blob/master/doc/format.txt data = bytearray() data.append(MACAROON_V2) if macaroon.location is not None: self._append_packet(data, self._LOCATION, convert_to_bytes( macaroon.location)) self._append_packet(data, self._IDENTIFIER, macaroon.identifier_bytes) self._append_packet(data, self._EOS) for c in macaroon.caveats: if c.location is not None: self._append_packet(data, self._LOCATION, convert_to_bytes(c.location)) self._append_packet(data, self._IDENTIFIER, c.caveat_id_bytes) if c.verification_key_id is not None: self._append_packet(data, self._VID, convert_to_bytes( c.verification_key_id)) self._append_packet(data, self._EOS) self._append_packet(data, self._EOS) self._append_packet(data, self._SIGNATURE, binascii.unhexlify( macaroon.signature_bytes)) return bytes(data)
def add_first_party_caveat(self, macaroon, predicate, **kwargs): predicate = convert_to_bytes(predicate) caveat = Caveat(caveat_id=convert_to_bytes(predicate)) macaroon.caveats.append(caveat) encode_key = binascii.unhexlify(macaroon.signature_bytes) macaroon.signature = sign_first_party_caveat(encode_key, predicate) return macaroon
def verify(self, macaroon, key): key = generate_derived_key(convert_to_bytes(key)) return self.verify_discharge( macaroon, macaroon, key, )
def add_third_party_caveat(self, macaroon, location, key, key_id, **kwargs): derived_key = truncate_or_pad( generate_derived_key(convert_to_bytes(key)) ) old_key = truncate_or_pad(binascii.unhexlify(macaroon.signature_bytes)) box = SecretBox(key=old_key) verification_key_id = box.encrypt( derived_key, nonce=kwargs.get('nonce') ) caveat = Caveat( caveat_id=key_id, location=location, verification_key_id=verification_key_id ) macaroon.caveats.append(caveat) encode_key = binascii.unhexlify(macaroon.signature_bytes) macaroon.signature = sign_third_party_caveat( encode_key, caveat._verification_key_id, caveat._caveat_id ) return macaroon
def __init__(self, location=None, identifier=None, key=None, caveats=None, signature=None): self.caveats = caveats or [] self.location = location or '' self.identifier = identifier or '' self.signature = signature or '' self.first_party_caveat_delegate = FirstPartyCaveatDelegate() self.third_party_caveat_delegate = ThirdPartyCaveatDelegate() if key: self.signature = create_initial_signature( convert_to_bytes(key), convert_to_bytes(identifier) )
def _read_json_binary_field(deserialized, field): ''' Read the value of a JSON field that may be string or base64-encoded. ''' val = deserialized.get(field) if val is not None: return utils.convert_to_bytes(val) val = deserialized.get(field + '64') if val is None: return None return utils.raw_urlsafe_b64decode(val)
def deserialize(self, serialized): from pymacaroons.macaroon import Macaroon from pymacaroons.caveat import Caveat from pymacaroons.exceptions import MacaroonDeserializationException macaroon = Macaroon() decoded = urlsafe_b64decode(convert_to_bytes( serialized + "=" * (-len(serialized) % 4) )) index = 0 while index < len(decoded): packet_length = int( struct.unpack( b"4s", decoded[index:index + self.PACKET_PREFIX_LENGTH] )[0], 16 ) packet = decoded[ index + self.PACKET_PREFIX_LENGTH:index + packet_length ] key, value = self._depacketize(packet) if key == b'location': macaroon.location = value elif key == b'identifier': macaroon.identifier = value elif key == b'cid': macaroon.caveats.append(Caveat(caveat_id=value)) elif key == b'vid': macaroon.caveats[-1].verification_key_id = value elif key == b'cl': macaroon.caveats[-1].location = value elif key == b'signature': macaroon.signature = binascii.hexlify(value) else: raise MacaroonDeserializationException( 'Key {key} not valid key for this format. ' 'Value: {value}'.format( key=key, value=value ) ) index = index + packet_length return macaroon
def __init__(self, location=None, identifier=None, key=None, caveats=None, signature=None, version=MACAROON_V1): if version > MACAROON_V2: version = MACAROON_V2 self._version = version self.caveats = caveats or [] self.location = location or '' self.identifier = identifier or '' self.signature = signature or '' self.first_party_caveat_delegate = FirstPartyCaveatDelegate() self.third_party_caveat_delegate = ThirdPartyCaveatDelegate() if key: self.signature = create_initial_signature( convert_to_bytes(key), self.identifier_bytes )
def caveat_id(self, value): self._caveat_id = convert_to_bytes(value)
def decrypt(self, signature, field_data): key = truncate_or_pad(signature) box = SecretBox(key=key) encoded = convert_to_bytes(field_data[len(self.signifier):]) decrypted = box.decrypt(standard_b64decode(encoded)) return convert_to_string(decrypted)
def encrypt(self, signature, field_data): encrypt_key = truncate_or_pad(signature) box = SecretBox(key=encrypt_key) encrypted = box.encrypt(convert_to_bytes(field_data), nonce=self.nonce) return self._signifier + standard_b64encode(encrypted)
def signifier(self, string_or_bytes): self._signifier = convert_to_bytes(string_or_bytes)
def signifier(self): return convert_to_bytes(self._signifier)
def location(self, string_or_bytes): self._location = convert_to_bytes(string_or_bytes)
def identifier(self, string_or_bytes): self._identifier = convert_to_bytes(string_or_bytes)
def location(self, value): self._location = convert_to_bytes(value)
def _signatures_match(self, macaroon_signature, computed_signature): return constant_time_compare( convert_to_bytes(macaroon_signature), convert_to_bytes(computed_signature) )
def verification_key_id(self, value): self._verification_key_id = convert_to_bytes(value)
from mock import * from nose.tools import * from hypothesis import assume, given, strategy from hypothesis.specifiers import one_of, sampled_from from six import text_type, binary_type from pymacaroons import Macaroon, Verifier from pymacaroons.utils import convert_to_bytes ascii_text_strategy = strategy( [sampled_from(map(chr, range(0, 128)))] ).map(lambda c: ''.join(c)) ascii_bin_strategy = strategy(ascii_text_strategy).map( lambda s: convert_to_bytes(s) ) class TestMacaroon(object): def setup(self): pass @given( key_id=one_of((ascii_text_strategy, ascii_bin_strategy)), loc=one_of((ascii_text_strategy, ascii_bin_strategy)), key=one_of((ascii_text_strategy, ascii_bin_strategy)) ) def test_serializing_deserializing_macaroon(self, key_id, loc, key): assume(key_id and loc and key)
def signature(self, string_or_bytes): self._signature = convert_to_bytes(string_or_bytes)