def pick_key(keys, use, alg='', key_type='', kid=''):
    """

    :param keys: List of keys
    :param use: What the key is going to be used for
    :param alg: crypto algorithm
    :param key_type: Type of key
    :param kid: Ley ID
    :return: list of keys that match the pattern
    """
    res = []
    if not key_type:
        if use == 'sig':
            key_type = jws.alg2keytype(alg)
        else:
            key_type = jwe.alg2keytype(alg)
    for key in keys:
        if key.use != use:
            continue

        if key.kty == key_type:
            if key.alg == '' or alg == '' or key.alg == alg:
                if key.kid == '' or kid == '' or key.kid == kid:
                    res.append(key)
    return res
def get_jwt_keys(jwt, keys, use):
    try:
        if use == 'sig':
            _key_type = jws.alg2keytype(jwt.headers['alg'])
        else:
            _key_type = jwe.alg2keytype(jwt.headers['alg'])
    except KeyError:
        _key_type = ''

    try:
        _kid = jwt.headers['kid']
    except KeyError:
        _kid = ''  # Unknown

    # pick issuer keys
    if use == 'sig':
        payload = json.loads(as_unicode(jwt.part[1]))
        try:
            _keys = keys[payload['iss']]
        except KeyError:  # No issuer, not kosher
            raise MissingValue('iss')
        if not _kid:
            try:
                _kid = payload['kid']
            except KeyError:
                _kid = ''  # Unknown
    else:
        _keys = keys

    return pick_key(_keys, use, key_type=_key_type, kid=_kid)
示例#3
0
def store_signed_jwks(keyjar, sign_keyjar, path, alg, iss=''):
    _jwks = keyjar.export_jwks()
    _jws = JWS(_jwks, alg=alg)
    _jwt = _jws.sign_compact(
        sign_keyjar.get_signing_key(owner=iss, key_type=alg2keytype(alg)))
    fp = open(path, 'w')
    fp.write(_jwt)
    fp.close()
示例#4
0
    def get_signing_key(self, algorithm, cli_info):
        """
        Pick signing key based on signing algorithm to be used

        :param algorithm: Signing algorithm
        :param cli_info: A :py:class:`oiccli.client_info.ClientInfo` instance
        :return: A key
        """
        return cli_info.keyjar.get_signing_key(
            alg2keytype(algorithm), alg=algorithm)
示例#5
0
    def verify(self, areq, **kwargs):
        try:
            try:
                argv = {'sender': areq['client_id']}
            except KeyError:
                argv = {}
            bjwt = AuthnToken().from_jwt(areq["client_assertion"],
                                         keyjar=self.srv.keyjar,
                                         **argv)
        except (Invalid, MissingKey) as err:
            logger.info("%s" % sanitize(err))
            raise AuthnFailure("Could not verify client_assertion.")

        logger.debug("authntoken: %s" % sanitize(bjwt.to_dict()))
        areq['parsed_client_assertion'] = bjwt

        # logger.debug("known clients: %s" % sanitize(self.cli.cdb.keys()))
        try:
            cid = kwargs["client_id"]
        except KeyError:
            cid = bjwt["iss"]

        try:
            # There might not be a client_id in the request
            assert str(cid) in self.srv.cdb  # It's a client I know
        except KeyError:
            pass

        # aud can be a string or a list
        _aud = bjwt["aud"]
        logger.debug("audience: %s, baseurl: %s" % (_aud, self.srv.baseurl))

        # figure out authn method
        if alg2keytype(bjwt.jws_header['alg']) == 'oct':  # Symmetric key
            authn_method = 'client_secret_jwt'
        else:
            authn_method = 'private_key_jwt'

        try:
            if isinstance(_aud, six.string_types):
                assert str(_aud).startswith(self.srv.baseurl)
            else:
                for target in _aud:
                    if target.startswith(self.srv.baseurl):
                        return cid, authn_method
                raise NotForMe("Not for me!")
        except AssertionError:
            raise NotForMe("Not for me!")

        return cid, authn_method
示例#6
0
    def get_key_by_kid(self, kid, algorithm, cli_info):
        """
        Pick a key that matches a given key ID and signing algorithm.

        :param kid: Key ID
        :param algorithm: Signing algorithm
        :param cli_info: A :py:class:`oiccli.client_info.ClientInfo` instance
        :return: A matching key
        """
        _key = cli_info.keyjar.get_key_by_kid(kid)
        if _key:
            ktype = alg2keytype(algorithm)
            if _key.kty != ktype:
                raise NoMatchingKey("Wrong key type")
            else:
                return _key
        else:
            raise NoMatchingKey("No key with kid:%s" % kid)
示例#7
0
    def oic_post_construct(self, cli_info, req, **kwargs):
        if 'openid' in req['scope']:
            _response_type = req['response_type'][0]
            if 'id_token' in _response_type or 'code' in _response_type:
                if 'nonce' not in req:
                    _nonce = rndstr(32)
                    req['nonce'] = _nonce
                    cli_info.state_db.bind_nonce_to_state(_nonce, req['state'])

        try:
            _request_param = kwargs['request_param']
        except KeyError:
            return req
        else:
            del kwargs['request_param']

            alg = None
            for arg in ["request_object_signing_alg", "algorithm"]:
                try:  # Trumps everything
                    alg = kwargs[arg]
                except KeyError:
                    pass
                else:
                    break

            if not alg:
                try:
                    alg = cli_info.behaviour["request_object_signing_alg"]
                except KeyError:  # Use default
                    alg = "RS256"

            kwargs["request_object_signing_alg"] = alg

            if "keys" not in kwargs and alg and alg != "none":
                _kty = jws.alg2keytype(alg)
                try:
                    _kid = kwargs["sig_kid"]
                except KeyError:
                    _kid = cli_info.kid["sig"].get(_kty, None)

                kwargs["keys"] = cli_info.keyjar.get_signing_key(_kty,
                                                                 kid=_kid)

            _req = make_openid_request(req, **kwargs)

            # Should the request be encrypted
            _req = request_object_encryption(_req, cli_info, **kwargs)

            if _request_param == "request":
                req["request"] = _req
            else:
                try:
                    _webname = cli_info.registration_response['request_uris'][
                        0]
                    filename = cli_info.filename_from_webname(_webname)
                except KeyError:
                    filename, _webname = construct_request_uri(**kwargs)
                fid = open(filename, mode="w")
                fid.write(_req)
                fid.close()
                req["request_uri"] = _webname

        return req
示例#8
0
 def get_signing_key(self, algorithm, cli_info=None):
     return cli_info.keyjar.get_signing_key(
         alg2keytype(algorithm), "", alg=algorithm)
示例#9
0
    def construct(self, request, cli_info=None, http_args=None, **kwargs):
        """
        Constructs a client assertion and signs it with a key.
        The request is modified as a side effect.

        :param request: The request
        :param cli_info: A :py:class:`oiccli.client_info.ClientInfo` instance
        :param http_args: HTTP arguments
        :param kwargs: Extra arguments
        :return: Constructed HTTP arguments, in this case none
        """

        if 'client_assertion' in kwargs:
            request["client_assertion"] = kwargs['client_assertion']
            if 'client_assertion_type' in kwargs:
                request[
                    'client_assertion_type'] = kwargs['client_assertion_type']
            else:
                request["client_assertion_type"] = JWT_BEARER
        elif 'client_assertion' in request:
            if 'client_assertion_type' not in request:
                request["client_assertion_type"] = JWT_BEARER
        else:
            algorithm = None
            # audience for the signed JWT depends on which endpoint
            # we're talking to.
            if kwargs['authn_endpoint'] in ['token', 'refresh']:
                try:
                    algorithm = cli_info.registration_info[
                        'token_endpoint_auth_signing_alg']
                except (KeyError, AttributeError):
                    pass
                audience = cli_info.provider_info['token_endpoint']
            else:
                audience = cli_info.provider_info['issuer']

            if not algorithm:
                algorithm = self.choose_algorithm(**kwargs)

            ktype = alg2keytype(algorithm)
            try:
                if 'kid' in kwargs:
                    signing_key = [self.get_key_by_kid(kwargs["kid"], algorithm,
                                                       cli_info)]
                elif ktype in cli_info.kid["sig"]:
                    try:
                        signing_key = [self.get_key_by_kid(
                            cli_info.kid["sig"][ktype], algorithm, cli_info)]
                    except KeyError:
                        signing_key = self.get_signing_key(algorithm, cli_info)
                else:
                    signing_key = self.get_signing_key(algorithm, cli_info)
            except NoMatchingKey as err:
                logger.error("%s" % sanitize(err))
                raise

            try:
                _args = {'lifetime': kwargs['lifetime']}
            except KeyError:
                _args = {}

            # construct the signed JWT with the assertions and add
            # it as value to the 'client_assertion' claim of the request
            request["client_assertion"] = assertion_jwt(
                cli_info.client_id, signing_key, audience,
                algorithm, **_args)

            request["client_assertion_type"] = JWT_BEARER

        try:
            del request["client_secret"]
        except KeyError:
            pass

        # If client_id is not required to be present, remove it.
        if not request.c_param["client_id"][VREQUIRED]:
            try:
                del request["client_id"]
            except KeyError:
                pass

        return {}