Example #1
0
    def verify(self, **kwargs):
        """Authorization Request parameters that are OPTIONAL in the OAuth 2.0
        specification MAY be included in the OpenID Request Object without also
        passing them as OAuth 2.0 Authorization Request parameters, with one
        exception: The scope parameter MUST always be present in OAuth 2.0
        Authorization Request parameters.
        All parameter values that are present both in the OAuth 2.0
        Authorization Request and in the OpenID Request Object MUST exactly
        match."""
        super(AuthorizationRequest, self).verify(**kwargs)

        args = {}
        for arg in ["key", "keyjar", "opponent_id", "sender"]:
            try:
                args[arg] = kwargs[arg]
            except KeyError:
                pass

        if "opponent_id" not in kwargs:
            args["opponent_id"] = self["client_id"]

        if "request" in self:
            if isinstance(self["request"], six.string_types):
                # Try to decode the JWT, checks the signature
                oidr = OpenIDRequest().from_jwt(str(self["request"]), **args)

                # verify that nothing is change in the original message
                for key, val in oidr.items():
                    if key in self:
                        assert self[key] == val

                # replace the JWT with the parsed and verified instance
                self["request"] = oidr

        if "id_token_hint" in self:
            if isinstance(self["id_token_hint"], six.string_types):
                idt = IdToken().from_jwt(str(self["id_token_hint"]), **args)
                self["id_token_hint"] = idt

        if "response_type" not in self:
            raise MissingRequiredAttribute("response_type missing", self)

        _rt = self["response_type"]
        if "token" in _rt or "id_token" in _rt:
            if "nonce" not in self:
                raise MissingRequiredAttribute("Nonce missing", self)

        if "openid" not in self.get("scope", []):
            raise MissingRequiredValue("openid not in scope", self)

        if "offline_access" in self.get("scope", []):
            if "prompt" not in self or "consent" not in self["prompt"]:
                raise MissingRequiredValue("consent in prompt", self)

        if "prompt" in self:
            if "none" in self["prompt"] and len(self["prompt"]) > 1:
                raise InvalidRequest("prompt none combined with other value",
                                     self)

        return True
Example #2
0
    def verify(self, **kwargs):
        super(IdToken, self).verify(**kwargs)

        if "aud" in self:
            if "client_id" in kwargs:
                # check that I'm among the recipients
                if kwargs["client_id"] not in self["aud"]:
                    raise NotForMe(
                        "{} not in aud:{}".format(kwargs["client_id"],
                                                  self["aud"]), self)

            # Then azp has to be present and be one of the aud values
            if len(self["aud"]) > 1:
                try:
                    assert "azp" in self
                except AssertionError:
                    raise VerificationError("azp missing", self)
                else:
                    try:
                        assert self["azp"] in self["aud"]
                    except AssertionError:
                        raise VerificationError(
                            "Mismatch between azp and aud claims", self)

        if "azp" in self:
            if "client_id" in kwargs:
                if kwargs["client_id"] != self["azp"]:
                    raise NotForMe(
                        "{} != azp:{}".format(kwargs["client_id"],
                                              self["azp"]), self)

        _now = time_util.utc_time_sans_frac()

        try:
            _skew = kwargs['skew']
        except KeyError:
            _skew = 0

        try:
            _exp = self['exp']
        except KeyError:
            raise MissingRequiredAttribute('exp')
        else:
            if (_now - _skew) > _exp:
                raise EXPError('Invalid expiration time')

        try:
            _storage_time = kwargs['nonce_storage_time']
        except KeyError:
            _storage_time = NONCE_STORAGE_TIME

        try:
            _iat = self['iat']
        except KeyError:
            raise MissingRequiredAttribute('iat')
        else:
            if (_iat + _storage_time) < (_now - _skew):
                raise IATError('Issued too long ago')

        return True
Example #3
0
def verify_id_token(instance, check_hash=False, **kwargs):
    # Try to decode the JWT, checks the signature
    args = {}
    for arg in TOKEN_VERIFY_ARGS:
        try:
            args[arg] = kwargs[arg]
        except KeyError:
            pass

    _jws = str(instance["id_token"])

    # It can be encrypted, so try to decrypt first
    _jwe = JWE_factory(_jws)
    if _jwe is not None:
        try:
            _jws = _jwe.decrypt(keys=kwargs["keyjar"].get_decrypt_key())
        except JWEException as err:
            raise VerificationError("Could not decrypt id_token", err)
    _packer = JWT()
    _body = _packer.unpack(_jws).payload()

    if "keyjar" in kwargs:
        try:
            if _body["iss"] not in kwargs["keyjar"]:
                raise ValueError("Unknown issuer")
        except KeyError:
            raise MissingRequiredAttribute("iss")

    if _jwe is not None:
        # Use the original encrypted token to set correct headers
        idt = IdToken().from_jwt(str(instance["id_token"]), **args)
    else:
        idt = IdToken().from_jwt(_jws, **args)
    if not idt.verify(**kwargs):
        raise VerificationError("Could not verify id_token", idt)

    if check_hash:
        _alg = idt.jws_header["alg"]
        if _alg != "none":
            hfunc = "HS" + _alg[-3:]
        else:
            # This is allowed only for `code` and it needs to be checked by a Client
            hfunc = None

        if "access_token" in instance and hfunc is not None:
            if "at_hash" not in idt:
                raise MissingRequiredAttribute("Missing at_hash property", idt)
            if idt["at_hash"] != jws.left_hash(instance["access_token"],
                                               hfunc):
                raise AtHashError("Failed to verify access_token hash", idt)

        if "code" in instance and hfunc is not None:
            if "c_hash" not in idt:
                raise MissingRequiredAttribute("Missing c_hash property", idt)
            if idt["c_hash"] != jws.left_hash(instance["code"], hfunc):
                raise CHashError("Failed to verify code hash", idt)

    return idt
Example #4
0
def verify_id_token(instance, check_hash=False, **kwargs):
    # Try to decode the JWT, checks the signature
    args = {}
    for arg in ["key", "keyjar", "algs", "sender"]:
        try:
            args[arg] = kwargs[arg]
        except KeyError:
            pass

    _jws = str(instance["id_token"])

    # It can be encrypted, so try to decrypt first
    _jwe = JWE_factory(_jws)
    if _jwe is not None:
        try:
            _jws = _jwe.decrypt(keys=kwargs['keyjar'].get_decrypt_key())
        except JWEException as err:
            raise VerificationError("Could not decrypt id_token", err)
    _packer = JWT()
    _body = _packer.unpack(_jws).payload()

    if 'keyjar' in kwargs:
        try:
            if _body['iss'] not in kwargs['keyjar']:
                raise ValueError('Unknown issuer')
        except KeyError:
            raise MissingRequiredAttribute('iss')

    if _jwe is not None:
        # Use the original encrypted token to set correct headers
        idt = IdToken().from_jwt(str(instance['id_token']), **args)
    else:
        idt = IdToken().from_jwt(_jws, **args)
    if not idt.verify(**kwargs):
        raise VerificationError("Could not verify id_token", idt)

    if check_hash:
        _alg = idt.jws_header["alg"]
        # What if _alg == 'none'

        hfunc = "HS" + _alg[-3:]

        if "access_token" in instance:
            if "at_hash" not in idt:
                raise MissingRequiredAttribute("Missing at_hash property", idt)
            if idt["at_hash"] != jws.left_hash(instance["access_token"],
                                               hfunc):
                raise AtHashError("Failed to verify access_token hash", idt)

        if "code" in instance:
            if "c_hash" not in idt:
                raise MissingRequiredAttribute("Missing c_hash property", idt)
            if idt["c_hash"] != jws.left_hash(instance["code"], hfunc):
                raise CHashError("Failed to verify code hash", idt)

    return idt
Example #5
0
    def verify(self, **kwargs):
        super(AuthorizationResponse, self).verify(**kwargs)

        if "aud" in self:
            if "client_id" in kwargs:
                # check that it's for me
                if kwargs["client_id"] not in self["aud"]:
                    return False

        if "id_token" in self:
            # Try to decode the JWT, checks the signature
            args = {}
            for arg in ["key", "keyjar", "algs", "sender"]:
                try:
                    args[arg] = kwargs[arg]
                except KeyError:
                    pass
            idt = IdToken().from_jwt(str(self["id_token"]), **args)
            if not idt.verify(**kwargs):
                raise VerificationError("Could not verify id_token", idt)

            _alg = idt.jws_header["alg"]
            # What if _alg == 'none'

            hfunc = "HS" + _alg[-3:]

            if "access_token" in self:
                try:
                    assert "at_hash" in idt
                except AssertionError:
                    raise MissingRequiredAttribute("Missing at_hash property",
                                                   idt)
                try:
                    assert idt["at_hash"] == jws.left_hash(
                        self["access_token"], hfunc)
                except AssertionError:
                    raise AtHashError("Failed to verify access_token hash",
                                      idt)

            if "code" in self:
                try:
                    assert "c_hash" in idt
                except AssertionError:
                    raise MissingRequiredAttribute("Missing c_hash property",
                                                   idt)
                try:
                    assert idt["c_hash"] == jws.left_hash(self["code"], hfunc)
                except AssertionError:
                    raise CHashError("Failed to verify code hash", idt)

            self["id_token"] = idt
        return True
Example #6
0
    def federated_client_registration_request(self, **kwargs):
        """
        Constructs a client registration request to be used by a client in a 
        federation.
        
        :param kwargs: A set of claims that should be part of the registration.
        :return: A :py:class:`ClientMetadataStatement` 
        """
        req = ClientMetadataStatement()

        try:
            req['redirect_uris'] = kwargs['redirect_uris']
        except KeyError:
            try:
                req["redirect_uris"] = self.redirect_uris
            except AttributeError:
                raise MissingRequiredAttribute("redirect_uris", kwargs)
        else:
            del kwargs['redirect_uris']

        req.update(kwargs)

        if self.federation:
            return self.federation_entity.update_request(
                req, federation=self.federation)
        elif self.provider_federations:
            return self.federation_entity.update_request(
                req, loes=self.provider_federations)
Example #7
0
    def verify(self, **kwargs):
        super(ProviderConfigurationResponse, self).verify(**kwargs)

        if "scopes_supported" in self:
            assert "openid" in self["scopes_supported"]
            for scope in self["scopes_supported"]:
                check_char_set(scope, SCOPE_CHARSET)

        parts = urlparse(self["issuer"])
        if parts.scheme != "https":
            raise SchemeError("Not HTTPS")

        assert not parts.query and not parts.fragment

        if any("code" in rt for rt in self["response_types_supported"]
               ) and "token_endpoint" not in self:
            raise MissingRequiredAttribute("token_endpoint")

        return True
Example #8
0
    def verify(self, **kwargs):
        super().verify(**kwargs)

        if "scopes_supported" in self:
            if "openid" not in self["scopes_supported"]:
                raise AssertionError()
            for scope in self["scopes_supported"]:
                check_char_set(scope, SCOPE_CHARSET)

        parts = urlparse(self["issuer"])
        if parts.scheme != "https":
            raise SchemeError("Not HTTPS")

        if parts.query or parts.fragment:
            raise AssertionError()

        if (any("code" in rt for rt in self["response_types_supported"])
                and "token_endpoint" not in self):
            raise MissingRequiredAttribute("token_endpoint")

        return True
Example #9
0
    def verify(self, **kwargs):
        super(IdToken, self).verify(**kwargs)

        try:
            if kwargs["iss"] != self["iss"]:
                raise IssuerMismatch("{} != {}".format(kwargs["iss"],
                                                       self["iss"]))
        except KeyError:
            pass

        if "aud" in self:
            if "client_id" in kwargs:
                # check that I'm among the recipients
                if kwargs["client_id"] not in self["aud"]:
                    raise NotForMe(
                        "{} not in aud:{}".format(kwargs["client_id"],
                                                  self["aud"]),
                        self,
                    )

            # Then azp has to be present and be one of the aud values
            if len(self["aud"]) > 1:
                if "azp" not in self:
                    raise VerificationError("azp missing", self)
                if self["azp"] not in self["aud"]:
                    raise VerificationError(
                        "Mismatch between azp and aud claims", self)

        if "azp" in self:
            if "client_id" in kwargs:
                if kwargs["client_id"] != self["azp"]:
                    raise NotForMe(
                        "{} != azp:{}".format(kwargs["client_id"],
                                              self["azp"]), self)

        _now = time_util.utc_time_sans_frac()

        try:
            _skew = kwargs["skew"]
        except KeyError:
            _skew = 0

        try:
            _exp = self["exp"]
        except KeyError:
            raise MissingRequiredAttribute("exp")
        else:
            if (_now - _skew) > _exp:
                raise EXPError("Invalid expiration time")

        try:
            _storage_time = kwargs["nonce_storage_time"]
        except KeyError:
            _storage_time = NONCE_STORAGE_TIME

        try:
            _iat = self["iat"]
        except KeyError:
            raise MissingRequiredAttribute("iat")
        else:
            if (_iat + _storage_time) < (_now - _skew):
                raise IATError("Issued too long ago")
            if _now < (_iat - _skew):
                raise IATError("Issued in the future")

        if _exp < _iat:
            raise EXPError("Invalid expiration time")

        return True