def test_macaroon_to_dict(self): m = pymacaroons.Macaroon( key=b'rootkey', identifier=b'some id', location='here', version=2) as_dict = bakery.macaroon_to_dict(m) data = json.dumps(as_dict) m1 = pymacaroons.Macaroon.deserialize(data, json_serializer.JsonSerializer()) self.assertEqual(m1.signature, m.signature) pymacaroons.Verifier().verify(m1, b'rootkey')
def verify_oidc_session_token(self, session: bytes, state: str) -> "OidcSessionData": """Verifies and extract an OIDC session token. This verifies that a given session token was issued by this homeserver and extract the nonce and client_redirect_url caveats. Args: session: The session token to verify state: The state the OIDC provider gave back Returns: The data extracted from the session cookie Raises: ValueError if an expected caveat is missing from the macaroon. """ macaroon = pymacaroons.Macaroon.deserialize(session) v = pymacaroons.Verifier() v.satisfy_exact("gen = 1") v.satisfy_exact("type = session") v.satisfy_exact("state = %s" % (state, )) v.satisfy_general(lambda c: c.startswith("nonce = ")) v.satisfy_general(lambda c: c.startswith("idp_id = ")) v.satisfy_general(lambda c: c.startswith("client_redirect_url = ")) # Sometimes there's a UI auth session ID, it seems to be OK to attempt # to always satisfy this. v.satisfy_general(lambda c: c.startswith("ui_auth_session_id = ")) v.satisfy_general(self._verify_expiry) v.verify(macaroon, self._macaroon_secret_key) # Extract the session data from the token. nonce = self._get_value_from_macaroon(macaroon, "nonce") idp_id = self._get_value_from_macaroon(macaroon, "idp_id") client_redirect_url = self._get_value_from_macaroon( macaroon, "client_redirect_url") try: ui_auth_session_id = self._get_value_from_macaroon( macaroon, "ui_auth_session_id") # type: Optional[str] except ValueError: ui_auth_session_id = None return OidcSessionData( nonce=nonce, idp_id=idp_id, client_redirect_url=client_redirect_url, ui_auth_session_id=ui_auth_session_id, )
def check( self, key: Union[str, bytes], project: str, ) -> None: """ Raises pypitoken.ValidationError if the token is invalid. Parameters besides ``key`` will be used to provide the current context this token is used for, allowing to accept or reject the caveat restrictions. If a parameter is not passed, but a caveat using it is encountered, the caveat will not be met, the token will be found invalid, and this method will raise with an appropriate exception. Parameters ---------- key : str Key of the macaroon, stored in PyPI database project : Optional[str], optional Normalized name of the project the bearer is attempting to upload to. Raises ------ `pypitoken.ValidationError` Any error in validating the token will be raised as a ValidationError. The original exception (if any) will be attached as the exception cause (``raise from``). """ verifier = pymacaroons.Verifier() context = Context(project=project) errors: List[Exception] = [] verifier.satisfy_general( functools.partial(self._check_caveat, context=context, errors=errors)) try: verifier.verify(self._macaroon, key) # https://github.com/ecordell/pymacaroons/issues/51 except Exception as exc: if errors: # (we know it's actually a single item, there cannot be multiple items # in this list) (exc, ) = errors raise exceptions.ValidationError( f"Error while validating token: {exc}") from exc
def _verify_oidc_session_token( self, session: bytes, state: str ) -> Tuple[str, str, Optional[str]]: """Verifies and extract an OIDC session token. This verifies that a given session token was issued by this homeserver and extract the nonce and client_redirect_url caveats. Args: session: The session token to verify state: The state the OIDC provider gave back Returns: The nonce, client_redirect_url, and ui_auth_session_id for this session """ macaroon = pymacaroons.Macaroon.deserialize(session) v = pymacaroons.Verifier() v.satisfy_exact("gen = 1") v.satisfy_exact("type = session") v.satisfy_exact("state = %s" % (state,)) v.satisfy_general(lambda c: c.startswith("nonce = ")) v.satisfy_general(lambda c: c.startswith("client_redirect_url = ")) # Sometimes there's a UI auth session ID, it seems to be OK to attempt # to always satisfy this. v.satisfy_general(lambda c: c.startswith("ui_auth_session_id = ")) v.satisfy_general(self._verify_expiry) v.verify(macaroon, self._macaroon_secret_key) # Extract the `nonce`, `client_redirect_url`, and maybe the # `ui_auth_session_id` from the token. nonce = self._get_value_from_macaroon(macaroon, "nonce") client_redirect_url = self._get_value_from_macaroon( macaroon, "client_redirect_url" ) try: ui_auth_session_id = self._get_value_from_macaroon( macaroon, "ui_auth_session_id" ) # type: Optional[str] except ValueError: ui_auth_session_id = None return nonce, client_redirect_url, ui_auth_session_id
def test_macaroon_caveats(self): token = self.macaroon_generator.generate_access_token("a_user") macaroon = pymacaroons.Macaroon.deserialize(token) def verify_gen(caveat): return caveat == "gen = 1" def verify_user(caveat): return caveat == "user_id = a_user" def verify_type(caveat): return caveat == "type = access" def verify_nonce(caveat): return caveat.startswith("nonce =") v = pymacaroons.Verifier() v.satisfy_general(verify_gen) v.satisfy_general(verify_user) v.satisfy_general(verify_type) v.satisfy_general(verify_nonce) v.verify(macaroon, self.hs.config.macaroon_secret_key)
def validate_macaroon(self, macaroon, type_string, verify_expiry, user_id): """ validate that a Macaroon is understood by and was signed by this server. Args: macaroon(pymacaroons.Macaroon): The macaroon to validate type_string(str): The kind of token required (e.g. "access", "delete_pusher") verify_expiry(bool): Whether to verify whether the macaroon has expired. user_id (str): The user_id required """ v = pymacaroons.Verifier() # the verifier runs a test for every caveat on the macaroon, to check # that it is met for the current request. Each caveat must match at # least one of the predicates specified by satisfy_exact or # specify_general. v.satisfy_exact("gen = 1") v.satisfy_exact("type = " + type_string) v.satisfy_exact("user_id = %s" % user_id) v.satisfy_exact("guest = true") # verify_expiry should really always be True, but there exist access # tokens in the wild which expire when they should not, so we can't # enforce expiry yet (so we have to allow any caveat starting with # 'time < ' in access tokens). # # On the other hand, short-term login tokens (as used by CAS login, for # example) have an expiry time which we do want to enforce. if verify_expiry: v.satisfy_general(self._verify_expiry) else: v.satisfy_general(lambda c: c.startswith("time < ")) # access_tokens include a nonce for uniqueness: any value is acceptable v.satisfy_general(lambda c: c.startswith("nonce = ")) v.verify(macaroon, self.hs.config.macaroon_secret_key)
def __init__(self, macaroon, context, principals, permission): self.macaroon = macaroon self.context = context self.principals = principals self.permission = permission self.verifier = pymacaroons.Verifier()
#!/usr/bin/env python2 from __future__ import print_function import sys import pymacaroons if len(sys.argv) == 1: sys.stderr.write("usage: %s macaroon [key]\n" % (sys.argv[0],)) sys.exit(1) macaroon_string = sys.argv[1] key = sys.argv[2] if len(sys.argv) > 2 else None macaroon = pymacaroons.Macaroon.deserialize(macaroon_string) print(macaroon.inspect()) print("") verifier = pymacaroons.Verifier() verifier.satisfy_general(lambda c: True) try: verifier.verify(macaroon, key) print("Signature is correct") except Exception as e: print(str(e))
def _base_verifier(self, type: MacaroonType) -> pymacaroons.Verifier: v = pymacaroons.Verifier() v.satisfy_exact("gen = 1") v.satisfy_exact(f"type = {type}") return v