def test_serializing_max_length_packet(self): m = Macaroon(location='test', identifier='blah', key='secret', version=MACAROON_V1) m.add_first_party_caveat('x' * 65526) # exactly 0xFFFF assert_not_equal(m.serialize(), None)
def alice_server_access_service(): macaroon_cookie = request.cookies.get('macaroonCookie') discharge_cookie = request.cookies.get('macaroonDischargeCookie') if macaroon_cookie is not None and macaroon_cookie != "" and discharge_cookie is not None and discharge_cookie != "": m = Macaroon.deserialize(macaroon_cookie) dm = Macaroon.deserialize(discharge_cookie) # Should be done on the client pm = m.prepare_for_request(dm) v = Verifier() try: verified = v.verify(m, alice_server_keys[m.identifier], [pm]) except MacaroonInvalidSignatureException: verified = False if verified: resp = make_response( render_template("auth_demo.html", result="Successful Authentication")) else: resp = make_response( render_template("auth_demo.html", result="Auth failed")) return resp else: resp = make_response( render_template( "auth_demo.html", result="Couldn't get necessary macaroons from cookies")) return resp
def test_serializing_too_long_packet(self): m = Macaroon(location='test', identifier='blah', key='secret') m.add_first_party_caveat('x' * 65527) # one byte too long assert_raises( MacaroonSerializationException, m.serialize )
def test_serializing_too_long_packet(self): m = Macaroon(location='test', identifier='blah', key='secret', version=MACAROON_V1) m.add_first_party_caveat('x' * 65527) # one byte too long assert_raises(MacaroonSerializationException, m.serialize)
def test_serializing_max_length_packet(self): m = Macaroon(location='test', identifier='blah', key='secret') m.add_first_party_caveat('x' * 65526) # exactly 0xFFFF assert_not_equal( m.serialize(), None )
def after_login(resp): try: root = Macaroon.deserialize(flask.session.pop("macaroon_root")) except KeyError: return ( flask.render_template("templates/_error_login.html", ), 400, ) bound = root.prepare_for_request( Macaroon.deserialize(resp.extensions["macaroon"].discharge)) flask.session["authentication_token"] = binary_serialize_macaroons( [root, bound]).decode("utf-8") if not resp.nickname: return flask.redirect(flask.current_app.config["CANONICAL_LOGIN_URL"]) flask.session["openid"] = { "identity_url": resp.identity_url, "nickname": resp.nickname, "fullname": resp.fullname, "image": resp.image, "email": resp.email, } return flask.redirect(open_id.get_next_url())
def discharge_macaroon_raw(self): root_macaroon = Macaroon.deserialize(self.root_macaroon_raw) unbound_discharge_macaroon = Macaroon.deserialize( self.unbound_discharge_macaroon_raw) discharge_macaroon = root_macaroon.prepare_for_request( unbound_discharge_macaroon) return discharge_macaroon.serialize()
def test_upload_no_discharge(self): root_key = hashlib.sha256(self.factory.getUniqueString()).hexdigest() root_macaroon = Macaroon(key=root_key) snapbuild = self.makeUploadableSnapBuild( store_secrets={"root": root_macaroon.serialize()}) transaction.commit() self._addUnscannedUploadResponse() self._addSnapPushResponse() with dbuser(config.ISnapStoreUploadJobSource.dbuser): self.assertEqual( "http://sca.example/dev/api/snaps/1/builds/1/status", self.client.upload(snapbuild)) requests = [call.request for call in responses.calls] self.assertThat(requests, MatchesListwise([ RequestMatches( url=Equals("http://updown.example/unscanned-upload/"), method=Equals("POST"), form_data={ "binary": MatchesStructure.byEquality( name="binary", filename="test-snap.snap", value="dummy snap content", type="application/octet-stream", )}), RequestMatches( url=Equals("http://sca.example/dev/api/snap-push/"), method=Equals("POST"), headers=ContainsDict( {"Content-Type": Equals("application/json")}), auth=("Macaroon", MacaroonsVerify(root_key)), json_data={ "name": "test-snap", "updown_id": 1, "series": "rolling", }), ]))
def test_serializing_deserializing_macaroon(self, key_id, loc, key): assume(key_id and loc and key) macaroon = Macaroon(location=loc, identifier=key_id, key=key) deserialized = Macaroon.deserialize(macaroon.serialize()) assert_equal(macaroon.identifier, deserialized.identifier) assert_equal(macaroon.location, deserialized.location) assert_equal(macaroon.signature, deserialized.signature)
def test_verify_third_party_caveats_multi_level(self): # See https://github.com/ecordell/pymacaroons/issues/37 root = Macaroon(location="", identifier="root-id", key="root-key") root.add_third_party_caveat("bob", "bob-caveat-root-key", "bob-is-great") # Create a discharge macaroon that requires a secondary discharge. discharge1 = Macaroon(location="bob", identifier="bob-is-great", key="bob-caveat-root-key") discharge1.add_third_party_caveat("barbara", "barbara-caveat-root-key", "barbara-is-great") # Create the secondary discharge macaroon. discharge2 = Macaroon(location="barbara", identifier="barbara-is-great", key="barbara-caveat-root-key") # Prepare the discharge macaroons for request. discharge1 = root.prepare_for_request(discharge1) discharge2 = root.prepare_for_request(discharge2) verified = Verifier( discharge_macaroons=[discharge1, discharge2]).verify( root, "root-key") assert_true(verified)
def test_verify_unknown_issuer(self): macaroon = Macaroon(location=config.vhost.mainsite.hostname, identifier='unknown-issuer', key='test') self.assertEqual( faults.Unauthorized(), self.authserver.verifyMacaroon(macaroon.serialize(), 'LibraryFileAlias', 1))
def callback(request): new_macaroon = Macaroon( location="sso.example", key=self.discharge_key, identifier=self.discharge_caveat_id) new_macaroon.add_first_party_caveat("sso|expires|tomorrow") return ( 200, {}, json.dumps({"discharge_macaroon": new_macaroon.serialize()}))
def test_first_party_caveat(self): m = Macaroon( location='http://mybank/', identifier='we used our secret key', key='this is our super secret key; only we should know it') m.add_first_party_caveat('test = caveat') assert_equal( m.signature, '197bac7a044af33332865b9266e26d493bdd668a660e44d88ce1a998c23dbd67')
def bake(user: User, caveats: List[str]) -> str: m_obj = Macaroon(location=os.environ.get("ENDPOINT"), identifier=user.username, key=user.key) for caveat in caveats: m_obj.add_first_party_caveat(caveat) return m_obj.serialize()
def test_serializing_json(self): m = Macaroon( location='http://mybank/', identifier='we used our secret key', key='this is our super secret key; only we should know it') m.add_first_party_caveat('test = caveat') assert_equal( json.loads(m.serialize(serializer=JsonSerializer()))['signature'], "197bac7a044af33332865b9266e26d493bdd668a660e44d88ce1a998c23dbd67")
def get_authorization_header(root, discharge): """ Bind root and discharge macaroons and return the authorization header. """ bound = Macaroon.deserialize(root).prepare_for_request( Macaroon.deserialize(discharge)) return "Macaroon root={}, discharge={}".format(root, bound.serialize())
def issueMacaroon(self, context, **kwargs): """See `IMacaroonIssuer`.""" context = self.checkIssuingContext(context, **kwargs) macaroon = Macaroon(location=config.vhost.mainsite.hostname, identifier=self.identifier, key=self._root_secret) macaroon.add_first_party_caveat("%s %s" % (self._primary_caveat_name, context)) return macaroon
def test_serializing_json_v2(self): m = Macaroon( location='http://mybank/', identifier='we used our secret key', key='this is our super secret key; only we should know it', version=MACAROON_V2) m.add_first_party_caveat('test = caveat') assert_equal( json.loads(m.serialize(serializer=JsonSerializer()))['s64'], "GXusegRK8zMyhluSZuJtSTvdZopmDkTYjOGpmMI9vWc")
def get_authorization_header(root, discharge): """ Bind root and discharge macaroons and return the authorization header. """ bound = Macaroon.deserialize(root).prepare_for_request( Macaroon.deserialize(discharge) ) return "Macaroon root={}, discharge={}".format(root, bound.serialize())
def test_inspect(self): m = Macaroon( location='http://mybank/', identifier='we used our secret key', key='this is our super secret key; only we should know it' ) m.add_first_party_caveat('test = caveat') assert_equal(m.inspect(), 'location http://mybank/\nidentifier we used\ our secret key\ncid test = caveat\nsignature 197bac7a044af33332865b9266e26d49\ 3bdd668a660e44d88ce1a998c23dbd67')
def test_good_no_discharge(self): r = Request() root_key = hashlib.sha256("root").hexdigest() root_macaroon = Macaroon(key=root_key) MacaroonAuth(root_macaroon.serialize())(r) auth_value = r.headers["Authorization"] self.assertThat(auth_value, StartsWith("Macaroon ")) self.assertThat( parse_dict_header(auth_value[len("Macaroon "):]), MacaroonsVerify(root_key))
def login_device(macaroon, manufacturer, channel_id): m = Macaroon(location='localhost', identifier=manufacturer, key=keys[manufacturer]) m1 = Macaroon.deserialize(macaroon) channels = [] for caveat in m1.caveats: m.add_first_party_caveat(caveat.to_dict()['cid']) channels.append(caveat.to_dict()['cid']) return m1.signature == m.signature and channel_id in channels[2:]
def generate_macaroon(self, nonce): m = Macaroon( location='http://mybank/', identifier='we used our other secret key', key='this is a different super-secret key; \ never use the same secret twice' ) m.add_first_party_caveat('account = 3735928559') caveat_key = '4; guaranteed random by a fair toss of the dice' identifier = 'this was how we remind auth of key/pred' m.add_third_party_caveat( 'http://auth.mybank/', caveat_key, identifier, nonce=nonce, ) discharge = Macaroon( location='http://auth.mybank/', key=caveat_key, identifier=identifier ) discharge.add_first_party_caveat('time < 2015-01-01T00:00') protected = m.prepare_for_request(discharge) return protected.signature
def test_verify_third_party_caveats(self): m = Macaroon( location='http://mybank/', identifier='we used our other secret key', key='this is a different super-secret key; \ never use the same secret twice' ) m.add_first_party_caveat('account = 3735928559') caveat_key = '4; guaranteed random by a fair toss of the dice' identifier = 'this was how we remind auth of key/pred' m.add_third_party_caveat('http://auth.mybank/', caveat_key, identifier) discharge = Macaroon( location='http://auth.mybank/', key=caveat_key, identifier=identifier ) discharge.add_first_party_caveat('time < 2015-01-01T00:00') protected = m.prepare_for_request(discharge) v = Verifier() v.satisfy_exact('account = 3735928559') v.satisfy_exact('time < 2015-01-01T00:00') verified = v.verify( m, 'this is a different super-secret key; \ never use the same secret twice', discharge_macaroons=[protected] ) assert_true(verified)
def test_prepare_for_request(self, rand_nonce): # use a fixed nonce to ensure the same signature rand_nonce.return_value = truncate_or_pad( b'\0', size=crypto_box_NONCEBYTES ) m = Macaroon( location='http://mybank/', identifier='we used our other secret key', key='this is a different super-secret key; \ never use the same secret twice' ) m.add_first_party_caveat('account = 3735928559') caveat_key = '4; guaranteed random by a fair toss of the dice' identifier = 'this was how we remind auth of key/pred' m.add_third_party_caveat( 'http://auth.mybank/', caveat_key, identifier ) discharge = Macaroon( location='http://auth.mybank/', key=caveat_key, identifier=identifier ) discharge.add_first_party_caveat('time < 2015-01-01T00:00') protected = m.prepare_for_request(discharge) assert_equal( protected.signature, '2eb01d0dd2b4475330739140188648cf25dda0425ea9f661f1574ca0a9eac54e' )
def test_serializing_deserializing_macaroon(self, key_id, loc, key): assume(key_id and loc and key) macaroon = Macaroon( location=loc, identifier=key_id, key=key ) deserialized = Macaroon.deserialize(macaroon.serialize()) assert_equal(macaroon.identifier, deserialized.identifier) assert_equal(macaroon.location, deserialized.location) assert_equal(macaroon.signature, deserialized.signature)
def test_serializing_v2(self): m = Macaroon( location='http://mybank/', identifier='we used our secret key', key='this is our super secret key; only we should know it', version=MACAROON_V2 ) m.add_first_party_caveat('test = caveat') n = Macaroon.deserialize(m.serialize()) assert_equal(m.identifier_bytes, n.identifier_bytes) assert_equal(m.version, n.version)
def test_serializing_json(self): m = Macaroon( location='http://mybank/', identifier='we used our secret key', key='this is our super secret key; only we should know it' ) m.add_first_party_caveat('test = caveat') assert_equal( json.loads(m.serialize(serializer=JsonSerializer()))['signature'], "197bac7a044af33332865b9266e26d493bdd668a660e44d88ce1a998c23dbd67" )
def test_serializing(self): m = Macaroon( location='http://mybank/', identifier='we used our secret key', key='this is our super secret key; only we should know it') m.add_first_party_caveat('test = caveat') assert_equal( m.serialize(), 'MDAxY2xvY2F0aW9uIGh0dHA6Ly9teWJhbmsvCjAwMjZpZGVudGlmaWVyIHdlIHVzZ\ WQgb3VyIHNlY3JldCBrZXkKMDAxNmNpZCB0ZXN0ID0gY2F2ZWF0CjAwMmZzaWduYXR1cmUgGXusegR\ K8zMyhluSZuJtSTvdZopmDkTYjOGpmMI9vWcK')
def create_macaroons(self): (key_id, key) = create_key_id_pair(prefix='{loc}::{user}::'.format( loc=current_app.config['TARGET_SERVICE_LOCATION'], user=self.username)) macaroon = Macaroon( location=current_app.config['TARGET_SERVICE_LOCATION'], key=key, identifier=key_id) discharge = self._add_user_caveat(macaroon) protected = macaroon.prepare_for_request(discharge) return macaroon, protected
def test_verify_failing_first_party_general_caveats(self): m = Macaroon( location='http://mybank/', identifier='we used our secret key', key='this is our super secret key; only we should know it') m.add_first_party_caveat('general caveat') v = Verifier() v.satisfy_general(lambda _: False) with assert_raises(MacaroonInvalidSignatureException) as cm: v.verify(m, 'this is our super secret key; only we should know it')
def test_verify_first_party_exact_caveats(self): m = Macaroon( location='http://mybank/', identifier='we used our secret key', key='this is our super secret key; only we should know it') m.add_first_party_caveat('test = caveat') v = Verifier() v.satisfy_exact('test = caveat') verified = v.verify( m, 'this is our super secret key; only we should know it') assert_true(verified)
def _get_authorization_header(self, session): """ Bind root and discharge macaroons and return the authorization header. """ root = session["macaroon_root"] discharge = session["macaroon_discharge"] bound = (Macaroon.deserialize(root).prepare_for_request( Macaroon.deserialize(discharge)).serialize()) return {"Authorization": f"Macaroon root={root}, discharge={bound}"}
def test_encrypted_first_party_caveat(self): m = Macaroon( location='http://mybank/', identifier='we used our secret key', key='this is our super secret key; only we should know it') encryptor = SecretBoxEncryptor(nonce=ZERO_NONCE) m.first_party_caveat_delegate = EncryptedFirstPartyCaveatDelegate( field_encryptor=encryptor) m.add_first_party_caveat('test = caveat', encrypted=True) assert_equal( m.signature, 'a443bc61e8f45dca4f0c441d6cfde90b804cebb0b267aab60de1ec2ab8cc8522')
def test_serializing_json_v2(self): m = Macaroon( location='http://mybank/', identifier='we used our secret key', key='this is our super secret key; only we should know it', version=MACAROON_V2 ) m.add_first_party_caveat('test = caveat') assert_equal( json.loads(m.serialize(serializer=JsonSerializer()))['s64'], "GXusegRK8zMyhluSZuJtSTvdZopmDkTYjOGpmMI9vWc" )
def test_serializing_with_binary_v2(self): identifier = base64.b64decode('AK2o+q0Aq9+bONkXw7ky7HAuhCLO9hhaMMc==') m = Macaroon( location='http://mybank/', identifier=identifier, key='this is our super secret key; only we should know it', version=MACAROON_V2 ) m.add_first_party_caveat('test = caveat') n = Macaroon.deserialize(m.serialize()) assert_equal(m.identifier_bytes, n.identifier_bytes) assert_equal(m.version, n.version)
def test_serializing_deserializing_json(self): m = Macaroon( location='http://test/', identifier='first', key='secret_key_1' ) m.add_first_party_caveat('test = caveat') n = Macaroon.deserialize( m.serialize(serializer=JsonSerializer()), serializer=JsonSerializer() ) assert_equal(m.signature, n.signature)
def test_serializing_strips_padding(self): m = Macaroon( location='http://mybank/', identifier='we used our secret key', key='this is our super secret key; only we should know it') m.add_first_party_caveat('test = acaveat') assert_equal( m.serialize(), # In padded base64, this would end with '==' ('MDAxY2xvY2F0aW9uIGh0dHA6Ly9teWJhbmsvCjAwMjZpZGVudGlmaWVyIHdlIHVz' 'ZWQgb3VyIHNlY3JldCBrZXkKMDAxN2NpZCB0ZXN0ID0gYWNhdmVhdAowMDJmc2ln' 'bmF0dXJlIJRJ_V3WNJQnqlVq5eez7spnltwU_AXs8NIRY739sHooCg'))
def test_encrypted_first_party_caveat(self): m = Macaroon( location='http://mybank/', identifier='we used our secret key', key='this is our super secret key; only we should know it' ) encryptor = SecretBoxEncryptor(nonce=ZERO_NONCE) m.first_party_caveat_delegate = EncryptedFirstPartyCaveatDelegate(field_encryptor=encryptor) m.add_first_party_caveat('test = caveat', encrypted=True) assert_equal( m.signature, 'a443bc61e8f45dca4f0c441d6cfde90b804cebb0b267aab60de1ec2ab8cc8522' )
def test_serializing(self): m = Macaroon( location='http://mybank/', identifier='we used our secret key', key='this is our super secret key; only we should know it' ) m.add_first_party_caveat('test = caveat') assert_equal( m.serialize(), 'MDAxY2xvY2F0aW9uIGh0dHA6Ly9teWJhbmsvCjAwMjZpZGVudGlmaWVyIHdlIHVzZ\ WQgb3VyIHNlY3JldCBrZXkKMDAxNmNpZCB0ZXN0ID0gY2F2ZWF0CjAwMmZzaWduYXR1cmUgGXusegR\ K8zMyhluSZuJtSTvdZopmDkTYjOGpmMI9vWcK' )
def test_serializing_json_v2_with_binary(self): id = base64.b64decode('AK2o+q0Aq9+bONkXw7ky7HAuhCLO9hhaMMc==') m = Macaroon( location='http://mybank/', identifier=id, key='this is our super secret key; only we should know it', version=MACAROON_V2) assert_equal( json.loads(m.serialize(serializer=JsonSerializer()))['i64'], "AK2o-q0Aq9-bONkXw7ky7HAuhCLO9hhaMMc") n = Macaroon.deserialize(m.serialize(serializer=JsonSerializer()), serializer=JsonSerializer()) assert_equal(m.identifier_bytes, n.identifier_bytes)
def test_mutual_discharge(self): m1 = Macaroon(location="", identifier="root-id", key="root-key") m1.add_third_party_caveat("bob", "bob-caveat-root-key", "bob-is-great") m2 = Macaroon(location="bob", identifier="bob-is-great", key="bob-caveat-root-key") m2.add_third_party_caveat("charlie", "bob-caveat-root-key", "bob-is-great") m2 = m1.prepare_for_request(m2) Verifier(discharge_macaroons=[m2]).verify(m1, "root-key")
def verify(self, session, discharge): session_macaroon = Macaroon.from_binary(session) discharge_macaroon = Macaroon.from_binary(discharge) self.logger.debug('Root Macaroon:\n' + session_macaroon.inspect()) self.logger.debug('Discharge Macaroon:\n' + discharge_macaroon.inspect()) verifier = Verifier() verifier.satisfy_general(verify_time) verified = verifier.verify(session_macaroon, self.redis.get(session_macaroon.identifier), discharge_macaroons=[discharge_macaroon]) return verified
def _prepare_request(method, path, data=None, session=None): request = Request(method=method, url=f"{API_URL}{path}") if session: root = Macaroon.deserialize(session["macaroon_root"]) discharge = Macaroon.deserialize(session["macaroon_discharge"]) bound = root.prepare_for_request(discharge) token = binary_serialize_macaroons([root, bound]).decode("utf-8") request.headers["Authorization"] = f"Macaroon {token}" if data is not None: request.json = data return request.prepare()
def discharge_macaroon(self, macaroon, token): # Deserialize the macaroon with pymacaroons macaroon = Macaroon.deserialize(macaroon, JsonSerializer()) # Extract the caveat we are interested in caveat = self._extract_caveat_to_discharge(macaroon) data = {"id64": caveat, "token64": token, "token-kind": "macaroon"} response = self._request(method="POST", url=f"{CANDID_API_URL}discharge", data=data) return Macaroon.deserialize(json.dumps(response.json()["Macaroon"]), JsonSerializer())
def test_verify_first_party_exact_caveats(self): m = Macaroon( location='http://mybank/', identifier='we used our secret key', key='this is our super secret key; only we should know it' ) m.add_first_party_caveat('test = caveat') v = Verifier() v.satisfy_exact('test = caveat') verified = v.verify( m, 'this is our super secret key; only we should know it' ) assert_true(verified)
def test_serializing_strips_padding(self): m = Macaroon( location='http://mybank/', identifier='we used our secret key', key='this is our super secret key; only we should know it' ) m.add_first_party_caveat('test = acaveat') assert_equal( m.serialize(), # In padded base64, this would end with '==' ('MDAxY2xvY2F0aW9uIGh0dHA6Ly9teWJhbmsvCjAwMjZpZGVudGlmaWVyIHdlIHVz' 'ZWQgb3VyIHNlY3JldCBrZXkKMDAxN2NpZCB0ZXN0ID0gYWNhdmVhdAowMDJmc2ln' 'bmF0dXJlIJRJ_V3WNJQnqlVq5eez7spnltwU_AXs8NIRY739sHooCg') )
def test_verify_failing_first_party_general_caveats(self): m = Macaroon( location='http://mybank/', identifier='we used our secret key', key='this is our super secret key; only we should know it' ) m.add_first_party_caveat('general caveat') v = Verifier() v.satisfy_general(lambda _: False) with assert_raises(MacaroonInvalidSignatureException) as cm: v.verify( m, 'this is our super secret key; only we should know it' )
def test_serializing_json_v2_with_binary(self): id = base64.b64decode('AK2o+q0Aq9+bONkXw7ky7HAuhCLO9hhaMMc==') m = Macaroon( location='http://mybank/', identifier=id, key='this is our super secret key; only we should know it', version=MACAROON_V2 ) assert_equal( json.loads(m.serialize(serializer=JsonSerializer()))['i64'], "AK2o-q0Aq9-bONkXw7ky7HAuhCLO9hhaMMc" ) n = Macaroon.deserialize( m.serialize(serializer=JsonSerializer()), serializer=JsonSerializer() ) assert_equal(m.identifier_bytes, n.identifier_bytes)
def test_verify_encrypted_first_party_exact_caveats(self): m = Macaroon( location='http://mybank/', identifier='we used our secret key', key='this is our super secret key; only we should know it' ) m.first_party_caveat_delegate = EncryptedFirstPartyCaveatDelegate() m.add_first_party_caveat('test = caveat', encrypted=True) v = Verifier() v.first_party_caveat_verifier_delegate = EncryptedFirstPartyCaveatVerifierDelegate() v.satisfy_exact('test = caveat') verified = v.verify( m, 'this is our super secret key; only we should know it' ) assert_true(verified)
def test_from_go_macaroon_json_v2(self): # The following macaroon have been generated with # https://github.com/go-macaroon/macaroon # to test the deserialization. json_v1 = '{"caveats":[{"cid":"fp caveat"},{"cid":"tp caveat",' \ '"vid":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAp_MgxHrfLnfvNuYDo' \ 'zNKWTlRPPx6VemasWnPpJdAWE6FWmOuFX4sB4-a1oAURDp",' \ '"cl":"tp location"}],"location":"my location",' \ '"identifier":"my identifier",' \ '"signature":"483b3881c9990e5099cb6695da3164daa64da60417b' \ 'caf9e9dc4c0a9968f6636"}' json_v1_discharge = '{"caveats":[],"location":"tp location",' \ '"identifier":"tp caveat",' \ '"signature":"8506007f69ae3e6a654e0b9769f20dd9da5' \ 'd2af7860070d6776c15989fb7dea6"}' m = Macaroon.deserialize(json_v1, serializer=JsonSerializer()) discharge = Macaroon.deserialize(json_v1_discharge, serializer=JsonSerializer()) assert_macaroon(m, discharge, MACAROON_V1) binary_v1 = 'MDAxOWxvY2F0aW9uIG15IGxvY2F0aW9uCjAwMWRpZGVudGlmaWVyIG1' \ '5IGlkZW50aWZpZXIKMDAxMmNpZCBmcCBjYXZlYXQKMDAxMmNpZCB0cC' \ 'BjYXZlYXQKMDA1MXZpZCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACn' \ '8yDEet8ud+825gOjM0pZOVE8/HpV6Zqxac+kl0BYToVaY64VfiwHj5r' \ 'WgBREOkKMDAxM2NsIHRwIGxvY2F0aW9uCjAwMmZzaWduYXR1cmUgSDs' \ '4gcmZDlCZy2aV2jFk2qZNpgQXvK+encTAqZaPZjYK' binary_v1_discharge = 'MDAxOWxvY2F0aW9uIHRwIGxvY2F0aW9uCjAwMTlpZGVud' \ 'GlmaWVyIHRwIGNhdmVhdAowMDJmc2lnbmF0dXJlIIUGAH' \ '9prj5qZU4Ll2nyDdnaXSr3hgBw1ndsFZift96mCg' m = Macaroon.deserialize(binary_v1) discharge = Macaroon.deserialize(binary_v1_discharge) assert_macaroon(m, discharge, MACAROON_V1) json_v2 = '{"c":[{"i":"fp caveat"},{"i":"tp caveat",' \ '"v64":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAp_MgxHrfLnfvNuYDoz' \ 'NKWTlRPPx6VemasWnPpJdAWE6FWmOuFX4sB4-a1oAURDp",' \ '"l":"tp location"}],"l":"my location","i":"my identifier",' \ '"s64":"SDs4gcmZDlCZy2aV2jFk2qZNpgQXvK-encTAqZaPZjY"}' json_v2_discharge = '{"l":"tp location","i":"tp caveat","s64":"hQYAf2' \ 'muPmplTguXafIN2dpdKveGAHDWd2wVmJ-33qY"}' m = Macaroon.deserialize(json_v2, serializer=JsonSerializer()) discharge = Macaroon.deserialize(json_v2_discharge, serializer=JsonSerializer()) assert_macaroon(m, discharge, MACAROON_V2) binary_v2 = 'AgELbXkgbG9jYXRpb24CDW15IGlkZW50aWZpZXIAAglmcCBjYXZlYXQ' \ 'AAQt0cCBsb2NhdGlvbgIJdHAgY2F2ZWF0BEgAAAAAAAAAAAAAAAAAAA' \ 'AAAAAAAAAAAAACn8yDEet8ud+825gOjM0pZOVE8/HpV6Zqxac+kl0BY' \ 'ToVaY64VfiwHj5rWgBREOkAAAYgSDs4gcmZDlCZy2aV2jFk2qZNpgQX' \ 'vK+encTAqZaPZjY' binary_v2_discharge = 'AgELdHAgbG9jYXRpb24CCXRwIGNhdmVhdAAABiCFBgB/a' \ 'a4+amVOC5dp8g3Z2l0q94YAcNZ3bBWYn7fepg' m = Macaroon.deserialize(binary_v2) discharge = Macaroon.deserialize(binary_v2_discharge) assert_macaroon(m, discharge, MACAROON_V2)
def test_verify_first_party_general_caveats(self): m = Macaroon( location='http://mybank/', identifier='we used our secret key', key='this is our super secret key; only we should know it' ) m.add_first_party_caveat('general caveat') def general_caveat_validator(predicate): return predicate == 'general caveat' v = Verifier() v.satisfy_general(general_caveat_validator) verified = v.verify( m, 'this is our super secret key; only we should know it' ) assert_true(verified)
def macaroon_from_dict(json_macaroon): '''Return a pymacaroons.Macaroon object from the given JSON-deserialized dict. @param JSON-encoded macaroon as dict @return the deserialized macaroon object. ''' return Macaroon.deserialize(json.dumps(json_macaroon), json_serializer.JsonSerializer())
def get_store_authorization( email, permissions=None, channels=None, store_env=None, allowed_stores=None, snaps=None): """Return the serialised root and discharge macaroon. Get a permissions macaroon from SCA and discharge it in SSO. """ headers = DEFAULT_HEADERS.copy() # Request a SCA root macaroon with hard expiration in 180 days. sca_data = { 'permissions': permissions or ['package_access'], 'expires': ( datetime.date.today() + datetime.timedelta(days=180) ).strftime('%Y-%m-%d 00:00:00') } if channels: sca_data['channels'] = channels if allowed_stores: sca_data['store_ids'] = allowed_stores if snaps: sca_data['packages'] = [{'name': snap} for snap in snaps] response = requests.request( url='{}/dev/api/acl/'.format(CONSTANTS[store_env]['sca_base_url']), method='POST', json=sca_data, headers=headers) if response.status_code != 200: error = response.json()['title'] raise CliError("Error {}: {}".format(response.status_code, error)) root = response.json()['macaroon'] caveat, = [ c for c in Macaroon.deserialize(root).third_party_caveats() if c.location == CONSTANTS[store_env]['sso_location'] ] # Request a SSO discharge macaroon. sso_data = { 'email': email, 'password': getpass.getpass('Password for {}: '.format(email)), 'caveat_id': caveat.caveat_id, } response = requests.request( url='{}/api/v2/tokens/discharge'.format( CONSTANTS[store_env]['sso_base_url']), method='POST', json=sso_data, headers=headers) # OTP/2FA is optional. if (response.status_code == 401 and response.json().get('code') == 'TWOFACTOR_REQUIRED'): sys.stderr.write('Second-factor auth for {}: '.format(store_env)) sso_data.update({'otp': input()}) response = requests.request( url='{}/api/v2/tokens/discharge'.format( CONSTANTS[store_env]['sso_base_url']), method='POST', json=sso_data, headers=headers) discharge = response.json()['discharge_macaroon'] return root, discharge
def test_third_party_caveat(self): m = Macaroon( location='http://mybank/', identifier='we used our other secret key', key='this is a different super-secret key; \ never use the same secret twice' ) m.add_first_party_caveat('account = 3735928559') caveat_key = '4; guaranteed random by a fair toss of the dice' identifier = 'this was how we remind auth of key/pred' m.add_third_party_caveat( 'http://auth.mybank/', caveat_key, identifier, nonce=ZERO_NONCE) assert_equal( m.signature, 'd27db2fd1f22760e4c3dae8137e2d8fc1df6c0741c18aed4b97256bf78d1f55c' )
def test_deserializing_accepts_padding(self): m = Macaroon.deserialize( ('MDAxY2xvY2F0aW9uIGh0dHA6Ly9teWJhbmsvCjAwMjZpZGVudGlmaWVyIHdlIHVz' 'ZWQgb3VyIHNlY3JldCBrZXkKMDAxN2NpZCB0ZXN0ID0gYWNhdmVhdAowMDJmc2ln' 'bmF0dXJlIJRJ_V3WNJQnqlVq5eez7spnltwU_AXs8NIRY739sHooCg==') ) assert_equal( m.signature, '9449fd5dd6349427aa556ae5e7b3eeca6796dc14fc05ecf0d21163bdfdb07a28' )
def test_deserializing(self): m = Macaroon.deserialize( 'MDAxY2xvY2F0aW9uIGh0dHA6Ly9teWJhbmsvCjAwMjZpZGVudGlmaW\ VyIHdlIHVzZWQgb3VyIHNlY3JldCBrZXkKMDAxNmNpZCB0ZXN0ID0gY2F2ZWF0CjAwMmZzaWduYXR1\ cmUgGXusegRK8zMyhluSZuJtSTvdZopmDkTYjOGpmMI9vWcK' ) assert_equal( m.signature, '197bac7a044af33332865b9266e26d493bdd668a660e44d88ce1a998c23dbd67' )
def test_macaroon_paper_fig6_fails_with_binding_on_tampered_sig(self): ''' Runs a similar test as test_macaroon_paper_fig6 with the discharge macaroon binding being done on a tampered signature. ''' locator = bakery.ThirdPartyStore() bs = common.new_bakery('bs-loc', locator) ts = common.new_bakery('ts-loc', locator) # ts creates a macaroon. ts_macaroon = ts.oven.macaroon(bakery.LATEST_VERSION, common.ages, None, [bakery.LOGIN_OP]) # ts somehow sends the macaroon to fs which adds a third party caveat # to be discharged by as. ts_macaroon.add_caveat(checkers.Caveat(condition='user==bob', location='bs-loc'), ts.oven.key, ts.oven.locator) # client asks for a discharge macaroon for each third party caveat def get_discharge(cav, payload): self.assertEqual(cav.location, 'bs-loc') return bakery.discharge( common.test_context, cav.caveat_id_bytes, payload, bs.oven.key, common.ThirdPartyStrcmpChecker('user==bob'), bs.oven.locator, ) d = bakery.discharge_all(ts_macaroon, get_discharge) # client has all the discharge macaroons. For each discharge macaroon # bind it to our ts_macaroon and add it to our request. tampered_macaroon = Macaroon() for i, dm in enumerate(d[1:]): d[i + 1] = tampered_macaroon.prepare_for_request(dm) # client makes request to ts. with self.assertRaises(bakery.VerificationError) as exc: ts.checker.auth([d]).allow(common.test_context, bakery.LOGIN_OP) self.assertEqual('verification failed: Signatures do not match', exc.exception.args[0])
def test_login_handler_redirect(self): m = Macaroon() m.add_third_party_caveat("login.ubuntu.com", "key", "id") serialized_macaroon = m.serialize() responses.add( responses.Response( method="POST", url=self.api_url, json={"macaroon": serialized_macaroon}, status=200, ) ) response = self.client.get(self.endpoint_url) assert len(responses.calls) == 1 assert response.status_code == 302