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 assert_macaroon(m, discharge, version): assert_equal(m.location, 'my location') assert_equal(m.version, version) assert_equal(m.identifier_bytes, b'my identifier') v = Verifier(discharge_macaroons=[discharge]) v.satisfy_exact('fp caveat') verified = v.verify( m, "my secret key", ) assert_true(verified)
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_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 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 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_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 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_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_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_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 photo_album(): macaroonCookie = request.cookies.get('macaroonCookie') if macaroonCookie is not None and macaroonCookie != "": m = Macaroon.deserialize(macaroonCookie) v = Verifier() v.satisfy_exact('view_pictures = True') try: verified = v.verify(m, keys[m.identifier]) except MacaroonInvalidSignatureException: verified = False images = [True, True, True] resp = make_response( render_template("home.html", showimages=verified, images=images, macaroon=m.inspect().replace("\n", "<br/>"))) return resp else: return redirect(url_for("login"))
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 macaroon_ops(self, macaroons): ''' This method makes the oven satisfy the MacaroonOpStore protocol required by the Checker class. For macaroons minted with previous bakery versions, it always returns a single LoginOp operation. :param macaroons: :return: ''' if len(macaroons) == 0: raise ValueError('no macaroons provided') storage_id, ops = _decode_macaroon_id(macaroons[0].identifier_bytes) root_key = self.root_keystore_for_ops(ops).get(storage_id) if root_key is None: raise bakery.VerificationError( 'macaroon key not found in storage') v = Verifier() conditions = [] def validator(condition): # Verify the macaroon's signature only. Don't check any of the # caveats yet but save them so that we can return them. conditions.append(condition) return True v.satisfy_general(validator) try: v.verify(macaroons[0], root_key, macaroons[1:]) except (MacaroonUnmetCaveatException, MacaroonInvalidSignatureException) as exc: raise bakery.VerificationError( 'verification failed: {}'.format(exc.args[0])) if (self.ops_store is not None and len(ops) == 1 and ops[0].entity.startswith('multi-')): # It's a multi-op entity, so retrieve the actual operations # it's associated with. ops = self.ops_store.get_ops(ops[0].entity) return ops, conditions
def satisfy_expiry(v: pymacaroons.Verifier, get_time_ms: Callable[[], int]) -> None: """Make a macaroon verifier which accepts 'time' caveats Builds a caveat verifier which will accept unexpired 'time' caveats, and adds it to the given macaroon verifier. Args: v: the macaroon verifier get_time_ms: a callable which will return the timestamp after which the caveat should be considered expired. Normally the current time. """ def verify_expiry_caveat(caveat: str) -> bool: time_msec = get_time_ms() prefix = "time < " if not caveat.startswith(prefix): return False expiry = int(caveat[len(prefix):]) return time_msec < expiry v.satisfy_general(verify_expiry_caveat)
def _verify_macaroon(mac): v = Verifier() #verify the role is valid v.satisfy_general(_role_verification) #verify username is valid, only checks to make sure it only contains ascii, could be improved. v.satisfy_general(_user_verification) f = open("/var/EMR/secret_key", "r") if f.mode == 'r': secret_key = f.read() return v.verify(mac, secret_key) return None
def match(self, macaroons): mismatch = Contains("root").match(macaroons) if mismatch is not None: return mismatch root_macaroon = Macaroon.deserialize(macaroons["root"]) if "discharge" in macaroons: discharge_macaroons = [ Macaroon.deserialize(macaroons["discharge"])] else: discharge_macaroons = [] try: Verifier().verify(root_macaroon, self.key, discharge_macaroons) except Exception as e: return Mismatch("Macaroons do not verify: %s" % e)
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 macaroon_ops(self, macaroons): ''' This method makes the oven satisfy the MacaroonOpStore protocol required by the Checker class. For macaroons minted with previous bakery versions, it always returns a single LoginOp operation. :param macaroons: :return: ''' if len(macaroons) == 0: raise ValueError('no macaroons provided') storage_id, ops = _decode_macaroon_id(macaroons[0].identifier_bytes) root_key = self.root_keystore_for_ops(ops).get(storage_id) if root_key is None: raise VerificationError( 'macaroon key not found in storage') v = Verifier() conditions = [] def validator(condition): # Verify the macaroon's signature only. Don't check any of the # caveats yet but save them so that we can return them. conditions.append(condition) return True v.satisfy_general(validator) try: v.verify(macaroons[0], root_key, macaroons[1:]) except Exception as exc: # Unfortunately pymacaroons doesn't control # the set of exceptions that can be raised here. # Possible candidates are: # pymacaroons.exceptions.MacaroonUnmetCaveatException # pymacaroons.exceptions.MacaroonInvalidSignatureException # ValueError # nacl.exceptions.CryptoError # # There may be others too, so just catch everything. raise six.raise_from( VerificationError('verification failed: {}'.format(str(exc))), exc, ) if (self.ops_store is not None and len(ops) == 1 and ops[0].entity.startswith('multi-')): # It's a multi-op entity, so retrieve the actual operations # it's associated with. ops = self.ops_store.get_ops(ops[0].entity) return ops, conditions
def access_picture_with_macaroon(picture_id, macaroon): m = Macaroon.deserialize(macaroon) v = Verifier() v.satisfy_exact('view_pictures = True') v.satisfy_exact('picture_id = ' + str(picture_id)) try: verified = v.verify(m, keys[m.identifier]) except MacaroonInvalidSignatureException: verified = False images = [False, False, False] images[picture_id] = True resp = make_response( render_template("home.html", showimages=verified, images=images, macaroon=m.inspect().replace("\n", "<br/>"))) return resp
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 gallery_token(token, image_name): if token: #Decode token n = Macaroon.deserialize(token) v = Verifier() form = forms.VerifyEmail() #On valid for submission if form.validate_on_submit(): #Verify Macaroon is valid v.satisfy_exact('email = {}'.format(form.email.data)) v.satisfy_exact('image_name = {}'.format(image_name)) v.satisfy_general(check_expiry) try: verified = v.verify(n, keys[n.identifier]) return send_from_directory(app.config['UPLOADED_IMAGES_DEST'], filename=image_name, as_attachment=False) except: flash("Unable to access") return render_template('validate_email.html', form=form, token=token, image_name=image_name) return render_template('validate_email.html', form=form, token=token, image_name=image_name) else: flash("Unable to access") return render_template('validate_email.html', form=form, token=token, image_name=image_name)
def macaroon_ops(self, macaroons): ''' This method makes the oven satisfy the MacaroonOpStore protocol required by the Checker class. For macaroons minted with previous bakery versions, it always returns a single LoginOp operation. :param macaroons: :return: ''' if len(macaroons) == 0: raise ValueError('no macaroons provided') storage_id, ops = _decode_macaroon_id(macaroons[0].identifier_bytes) root_key = self.root_keystore_for_ops(ops).get(storage_id) if root_key is None: raise bakery.VerificationError('macaroon key not found in storage') v = Verifier() conditions = [] def validator(condition): # Verify the macaroon's signature only. Don't check any of the # caveats yet but save them so that we can return them. conditions.append(condition) return True v.satisfy_general(validator) try: v.verify(macaroons[0], root_key, macaroons[1:]) except (MacaroonUnmetCaveatException, MacaroonInvalidSignatureException) as exc: raise bakery.VerificationError('verification failed: {}'.format( exc.args[0])) if (self.ops_store is not None and len(ops) == 1 and ops[0].entity.startswith('multi-')): # It's a multi-op entity, so retrieve the actual operations # it's associated with. ops = self.ops_store.get_ops(ops[0].entity) return ops, conditions
def verifyMacaroon(self, macaroon, context, require_context=True, errors=None, **kwargs): """See `IMacaroonIssuer`.""" if macaroon.location != config.vhost.mainsite.hostname: if errors is not None: errors.append("Macaroon has unknown location '%s'." % macaroon.location) return None if require_context and context is None: if errors is not None: errors.append( "Expected macaroon verification context but got None.") return None if context is not None: try: context = self.checkVerificationContext(context) except BadMacaroonContext as e: if errors is not None: errors.append(str(e)) return None seen = set() verified = MacaroonVerificationResult(self.identifier) def verify(caveat): try: caveat_name, caveat_value = caveat.split(" ", 1) except ValueError: if errors is not None: errors.append("Cannot parse caveat '%s'." % caveat) return False if caveat_name not in self.allow_multiple and caveat_name in seen: if errors is not None: errors.append("Multiple '%s' caveats are not allowed." % caveat_name) return False seen.add(caveat_name) if caveat_name == self._primary_caveat_name: checker = self.verifyPrimaryCaveat else: checker = self.checkers.get(caveat_name) if checker is None: if errors is not None: errors.append("Unhandled caveat name '%s'." % caveat_name) return False if not checker(caveat_value, context, **kwargs): if errors is not None: errors.append("Caveat check for '%s' failed." % caveat) return False return True try: verifier = Verifier() verifier.satisfy_general(verify) if verifier.verify(macaroon, self._root_secret): return verified else: return None # XXX cjwatson 2019-04-24: This can currently raise a number of # other exceptions in the presence of non-well-formed input data, # but most of them are too broad to reasonably catch so we let them # turn into OOPSes for now. Revisit this once # https://github.com/ecordell/pymacaroons/issues/51 is fixed. except MacaroonVerificationFailedException as e: if errors is not None and not errors: errors.append(str(e)) return None
def verify( macaroon: Macaroon, key: bytes, roles: List[str], caveats: List[str], used: int, req: Request, ) -> bool: assert macaroon v_obj = Verifier() v_obj.satisfy_exact(f"user = {macaroon.identifier}") for role in roles: v_obj.satisfy_exact(f"role = {role}") # satisfy specific actions in the API for caveat in caveats: v_obj.satisfy_exact(f"action = {caveat}") # satify same origin restrictions v_obj.satisfy_exact(f"origin = {req.headers['origin']}") # satisfy macaroon with time expiry v_obj.satisfy_general(lambda x: x.split(" = ")[0] == "expiry" and int( x.split(" = ")[1]) > time()) # satisfy macaroon with limited uses v_obj.satisfy_general(lambda x: x.split(" = ")[0] == "uses" and int( x.split(" = ")[1]) > used) # satisfy any with 'amount' caveat. Currently only included so macaroon user can tell amount v_obj.satisfy_general(lambda x: x.split(" = ")[0] == "amount") return bool(v_obj.verify(macaroon, key))