Esempio n. 1
0
 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')
Esempio n. 2
0
    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,
        )
Esempio n. 3
0
    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
Esempio n. 4
0
    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
Esempio n. 5
0
    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)
Esempio n. 6
0
    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)
Esempio n. 7
0
 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))
Esempio n. 9
0
 def _base_verifier(self, type: MacaroonType) -> pymacaroons.Verifier:
     v = pymacaroons.Verifier()
     v.satisfy_exact("gen = 1")
     v.satisfy_exact(f"type = {type}")
     return v