Example #1
0
 def test_client_claims_with_default(self):
     session_info = {
         "authn_req": AREQN,
         "sub": "sub",
         "authn_event": {
             "authn_info": "loa2",
             "authn_time": time.time(),
             "uid": "diana"
         },
     }
     self.endpoint_context.cdb["client_1"]['id_token_claims'] = {
         "address": None
     }
     self.endpoint_context.idtoken.kwargs['default_claims'] = {
         "nickname": {
             "essential": True
         }
     }
     self.endpoint_context.idtoken.enable_claims_per_client = True
     req = {"client_id": "client_1"}
     _token = self.endpoint_context.idtoken.make(req, session_info)
     assert _token
     client_keyjar = KeyJar()
     _jwks = self.endpoint_context.keyjar.export_jwks()
     client_keyjar.import_jwks(_jwks, self.endpoint_context.issuer)
     _jwt = JWT(key_jar=client_keyjar, iss="client_1")
     res = _jwt.unpack(_token)
     assert "address" in res
     assert "nickname" in res
    def test_unpack_aggregated_response_missing_keys(self):
        claims = {
            "address": {
                "street_address": "1234 Hollywood Blvd.",
                "locality": "Los Angeles",
                "region": "CA",
                "postal_code": "90210",
                "country": "US"
            },
            "phone_number": "+1 (555) 123-4567"
        }

        _keyjar = build_keyjar(KEYSPEC)

        srv = JWT(_keyjar, iss=ISS, sign_alg='ES256')
        _jwt = srv.pack(payload=claims)

        resp = OpenIDSchema(sub='diana', given_name='Diana',
                            family_name='krall',
                            _claim_names={
                                'address': 'src1',
                                'phone_number': 'src1'
                            },
                            _claim_sources={'src1': {'JWT': _jwt}})

        _resp = self.service.parse_response(resp.to_json(), state='abcde')
        assert _resp
Example #3
0
def test_sign_encrypt_id_token():
    client_info = RegistrationResponse(id_token_signed_response_alg='RS512',
                                       client_id='client_1')
    session_info = {
        'authn_req': AREQN,
        'sub': 'sub',
        'authn_event': {
            "authn_info": 'loa2',
            "authn_time": time.time()
        }
    }

    ENDPOINT_CONTEXT.jwx_def["signing_alg"] = {'id_token': 'RS384'}
    ENDPOINT_CONTEXT.cdb['client_1'] = client_info.to_dict()

    _token = sign_encrypt_id_token(ENDPOINT_CONTEXT,
                                   session_info,
                                   'client_1',
                                   sign=True)
    assert _token

    _jws = jws.factory(_token)

    assert _jws.jwt.headers['alg'] == 'RS512'

    client_keyjar = KeyJar()
    _jwks = KEYJAR.export_jwks()
    client_keyjar.import_jwks(_jwks, ENDPOINT_CONTEXT.issuer)

    _jwt = JWT(key_jar=client_keyjar, iss='client_1')
    res = _jwt.unpack(_token)
    assert isinstance(res, dict)
    assert res['aud'] == ['client_1']
    def test_construct(self, entity):
        token_service = entity.client_get("service", 'accesstoken')
        kb_rsa = KeyBundle(source='file://{}'.format(
            os.path.join(BASE_PATH, "data/keys/rsa.key")),
                           fileformat='der')

        for key in kb_rsa:
            key.add_kid()

        _context = token_service.client_get("service_context")
        _context.keyjar.add_kb('', kb_rsa)
        _context.provider_info = {
            'issuer': 'https://example.com/',
            'token_endpoint': "https://example.com/token"
        }
        _context.registration_response = {
            'token_endpoint_auth_signing_alg': 'RS256'
        }
        token_service.endpoint = "https://example.com/token"

        request = AccessTokenRequest()
        pkj = PrivateKeyJWT()
        http_args = pkj.construct(request,
                                  service=token_service,
                                  authn_endpoint='token_endpoint')
        assert http_args == {}
        cas = request["client_assertion"]

        _kj = KeyJar()
        _kj.add_kb(_context.client_id, kb_rsa)
        jso = JWT(key_jar=_kj).unpack(cas)
        assert _eq(jso.keys(), ["aud", "iss", "sub", "jti", "exp", "iat"])
        # assert _jwt.headers == {'alg': 'RS256'}
        assert jso['aud'] == [_context.provider_info['token_endpoint']]
Example #5
0
    def test_sign_encrypt_id_token(self):
        client_info = RegistrationResponse(
            id_token_signed_response_alg="RS512", client_id="client_1")
        session_info = {
            "authn_req": AREQN,
            "sub": "sub",
            "authn_event": {
                "authn_info": "loa2",
                "authn_time": time.time()
            },
        }

        self.endpoint_context.jwx_def["signing_alg"] = {"id_token": "RS384"}
        self.endpoint_context.cdb["client_1"] = client_info.to_dict()

        _token = self.endpoint_context.idtoken.sign_encrypt(session_info,
                                                            "client_1",
                                                            sign=True)
        assert _token

        _jws = jws.factory(_token)

        assert _jws.jwt.headers["alg"] == "RS512"

        client_keyjar = KeyJar()
        _jwks = self.endpoint_context.keyjar.export_jwks()
        client_keyjar.import_jwks(_jwks, self.endpoint_context.issuer)

        _jwt = JWT(key_jar=client_keyjar, iss="client_1")
        res = _jwt.unpack(_token)
        assert isinstance(res, dict)
        assert res["aud"] == ["client_1"]
Example #6
0
    def verify(self, request, **kwargs):
        _jwt = JWT(self.endpoint_context.keyjar)
        try:
            ca_jwt = _jwt.unpack(request["client_assertion"])
        except (Invalid, MissingKey, BadSignature) as err:
            logger.info("%s" % sanitize(err))
            raise AuthnFailure("Could not verify client_assertion.")

        try:
            logger.debug("authntoken: %s" % sanitize(ca_jwt.to_dict()))
        except AttributeError:
            logger.debug("authntoken: %s" % sanitize(ca_jwt))

        request[verified_claim_name("client_assertion")] = ca_jwt

        try:
            client_id = kwargs["client_id"]
        except KeyError:
            client_id = ca_jwt["iss"]

        # I should be among the audience
        # could be either my issuer id or the token endpoint
        if self.endpoint_context.issuer in ca_jwt["aud"]:
            pass
        elif self.endpoint_context.endpoint["token"].full_path in ca_jwt[
                "aud"]:
            pass
        else:
            raise NotForMe("Not for me!")

        return {"client_id": client_id, "jwt": ca_jwt}
Example #7
0
    def test_construct(self, services):
        _service = services['accesstoken']
        kb_rsa = KeyBundle(source='file://{}'.format(
            os.path.join(BASE_PATH, "data/keys/rsa.key")),
                           fileformat='der')

        for key in kb_rsa:
            key.add_kid()

        _service.service_context.keyjar.add_kb('', kb_rsa)
        _service.service_context.set(
            'provider_info', {
                'issuer': 'https://example.com/',
                'token_endpoint': "https://example.com/token"
            })
        services['accesstoken'].endpoint = "https://example.com/token"

        request = AccessTokenRequest()
        pkj = PrivateKeyJWT()
        http_args = pkj.construct(request,
                                  service=_service,
                                  algorithm="RS256",
                                  authn_endpoint='token_endpoint')
        assert http_args == {}
        cas = request["client_assertion"]

        _kj = KeyJar()
        _kj.add_kb(_service.service_context.get('client_id'), kb_rsa)
        jso = JWT(key_jar=_kj).unpack(cas)
        assert _eq(jso.keys(), ["aud", "iss", "sub", "jti", "exp", "iat"])
        # assert _jwt.headers == {'alg': 'RS256'}
        assert jso['aud'] == [
            _service.service_context.get('provider_info')['token_endpoint']
        ]
    def test_private_key_jwt_auth_endpoint(self):
        # Own dynamic keys
        client_keyjar = build_keyjar(KEYDEFS)
        # The servers keys
        client_keyjar.import_jwks(KEYJAR.export_jwks(private=True),
                                  CONF["issuer"])

        _jwks = client_keyjar.export_jwks()
        self.method.server_get("endpoint_context").keyjar.import_jwks(
            _jwks, client_id)

        _jwt = JWT(client_keyjar, iss=client_id, sign_alg="RS256")
        _jwt.with_jti = True
        _assertion = _jwt.pack({
            "aud":
            [self.method.server_get("endpoint", "authorization").full_path]
        })

        request = {
            "client_assertion": _assertion,
            "client_assertion_type": JWT_BEARER
        }

        assert self.method.is_usable(request=request)
        authn_info = self.method.verify(
            request=request,
            endpoint=self.method.server_get("endpoint", "authorization"),
        )

        assert authn_info["client_id"] == client_id
        assert "jwt" in authn_info
    def test_verify_client_jws_authn_method(self):
        client_keyjar = KeyJar()
        client_keyjar.import_jwks(KEYJAR.export_jwks(private=True),
                                  CONF["issuer"])
        # The only own key the client has a this point
        client_keyjar.add_symmetric("", client_secret, ["sig"])

        _jwt = JWT(client_keyjar, iss=client_id, sign_alg="HS256")
        # Audience is OP issuer ID
        aud = "{}token".format(CONF["issuer"])  # aud == Token endpoint
        _assertion = _jwt.pack({"aud": [aud]})

        request = {
            "client_assertion": _assertion,
            "client_assertion_type": JWT_BEARER
        }
        http_info = {"headers": {}}
        res = verify_client(
            self.endpoint_context,
            request,
            http_info=http_info,
            endpoint=self.server.server_get("endpoint", "token"),
        )
        assert res["method"] == "client_secret_jwt"
        assert res["client_id"] == "client_id"
def test_private_key_jwt_reusage_other_endpoint():
    # Own dynamic keys
    client_keyjar = build_keyjar(KEYDEFS)
    # The servers keys
    client_keyjar[conf["issuer"]] = KEYJAR.issuer_keys[""]

    _jwks = client_keyjar.export_jwks()
    endpoint_context.keyjar.import_jwks(_jwks, client_id)

    _jwt = JWT(client_keyjar, iss=client_id, sign_alg="RS256")
    _jwt.with_jti = True
    _assertion = _jwt.pack(
        {"aud": [endpoint_context.endpoint["token"].full_path]})

    request = {
        "client_assertion": _assertion,
        "client_assertion_type": JWT_BEARER
    }

    # This should be OK
    PrivateKeyJWT(endpoint_context).verify(request, endpoint="token")

    # This should NOT be OK
    with pytest.raises(NotForMe):
        PrivateKeyJWT(endpoint_context).verify(request,
                                               endpoint="authorization")

    # This should NOT be OK
    with pytest.raises(MultipleUsage):
        PrivateKeyJWT(endpoint_context).verify(request, endpoint="token")
def make_openid_request(arq,
                        keys,
                        issuer,
                        request_object_signing_alg,
                        recv,
                        with_jti=False,
                        lifetime=0):
    """
    Construct the JWT to be passed by value (the request parameter) or by
    reference (request_uri).
    The request will be signed

    :param arq: The Authorization request
    :param keys: Keys to use for signing/encrypting. A KeyJar instance
    :param issuer: Who is signing this JSON Web Token
    :param request_object_signing_alg: Which signing algorithm to use
    :param recv: The intended receiver of the request
    :param with_jti: Whether a JTI should be included in the JWT.
    :param lifetime: How long the JWT is expect to be live.
    :return: JWT encoded OpenID request
    """

    _jwt = JWT(key_jar=keys, iss=issuer, sign_alg=request_object_signing_alg)
    if with_jti:
        _jwt.with_jti = True
    if lifetime:
        _jwt.lifetime = lifetime
    return _jwt.pack(arq.to_dict(), owner=issuer, recv=recv)
Example #12
0
    def do_back_channel_logout(self, cinfo, sid):
        """

        :param cinfo: Client information
        :param sid: The session ID
        :return: Tuple with logout URI and signed logout token
        """

        _context = self.server_get("endpoint_context")

        try:
            back_channel_logout_uri = cinfo["backchannel_logout_uri"]
        except KeyError:
            return None

        # Create the logout token
        # always include sub and sid so I don't check for
        # backchannel_logout_session_required

        enc_msg = self._encrypt_sid(sid)

        payload = {"sid": enc_msg, "events": {BACK_CHANNEL_LOGOUT_EVENT: {}}}

        try:
            alg = cinfo["id_token_signed_response_alg"]
        except KeyError:
            alg = _context.provider_info["id_token_signing_alg_values_supported"][0]

        _jws = JWT(_context.keyjar, iss=_context.issuer, lifetime=86400, sign_alg=alg)
        _jws.with_jti = True
        _logout_token = _jws.pack(payload=payload, recv=cinfo["client_id"])

        return back_channel_logout_uri, _logout_token
Example #13
0
    def test_client_secret_jwt(self, client):
        _ci = client.client_info
        _ci.token_endpoint = "https://example.com/token"
        _ci.provider_info = {
            'issuer': 'https://example.com/',
            'token_endpoint': "https://example.com/token"
        }

        csj = ClientSecretJWT()
        request = AccessTokenRequest()

        csj.construct(request,
                      cli_info=client.client_info,
                      algorithm="HS256",
                      authn_endpoint='userinfo')
        assert request["client_assertion_type"] == JWT_BEARER
        assert "client_assertion" in request
        cas = request["client_assertion"]

        _skey = [SYMKey(k=b64e(as_bytes(_ci.client_secret)), use='sig')]
        jso = JWT(rec_keys={client.client_id: _skey}).unpack(cas)
        assert _eq(jso.keys(), ["aud", "iss", "sub", "jti", "exp", "iat"])

        _rj = JWS()
        info = _rj.verify_compact(
            cas, [SYMKey(k=b64e(as_bytes(_ci.client_secret)))])

        assert _eq(info.keys(), ["aud", "iss", "sub", "jti", "exp", "iat"])
        assert info['aud'] == [_ci.provider_info['issuer']]
Example #14
0
    def test_client_secret_jwt(self, services):
        _service_context = services['accesstoken'].service_context
        _service_context.token_endpoint = "https://example.com/token"
        _service_context.set(
            'provider_info', {
                'issuer': 'https://example.com/',
                'token_endpoint': "https://example.com/token"
            })

        csj = ClientSecretJWT()
        request = AccessTokenRequest()

        csj.construct(request,
                      service=services['accesstoken'],
                      algorithm="HS256",
                      authn_endpoint='userinfo')
        assert request["client_assertion_type"] == JWT_BEARER
        assert "client_assertion" in request
        cas = request["client_assertion"]

        _kj = KeyJar()
        _kj.add_symmetric(_service_context.get('client_id'),
                          _service_context.get('client_secret'),
                          usage=['sig'])
        jso = JWT(key_jar=_kj, sign_alg='HS256').unpack(cas)
        assert _eq(jso.keys(), ["aud", "iss", "sub", "jti", "exp", "iat"])

        _rj = JWS(alg='HS256')
        info = _rj.verify_compact(
            cas,
            _kj.get_signing_key(issuer_id=_service_context.get('client_id')))

        assert _eq(info.keys(), ["aud", "iss", "sub", "jti", "exp", "iat"])
        assert info['aud'] == [_service_context.get('provider_info')['issuer']]
Example #15
0
class Challenger(object):
    def __init__(self, kb: KeyBundle, issuer: str, lifetime: int) -> None:
        self.logger = logging.getLogger(__name__).getChild(
            self.__class__.__name__)
        self.issuer = issuer
        self.kj = KeyJar()
        self.kj.add_kb(self.issuer, kb)
        sign_alg = None
        enc_alg = None
        enc_enc = None
        kid = None
        for key in self.kj.get(key_use="enc", issuer_id=issuer):
            kid = key.kid
            if key.kty == "oct":
                sign_alg = "HS256"
                enc_alg = None
                enc_enc = None
                break
            elif key.kty == "EC":
                sign_alg = "ES256"
                enc_alg = "ECDH-ES"
                enc_enc = "A128GCM"
                break
            elif key.kty == "RSA":
                sign_alg = "RS256"
                enc_alg = "RSA1_5"
                enc_enc = "A128GCM"
                break
        if kid is None:
            raise Exception("No challenge key found")
        sign = sign_alg is not None
        encrypt = enc_alg is not None
        self.logger.info("Using challenge key kid=%s sign=%s encrypt=%s", kid,
                         sign, encrypt)
        self.jwt = JWT(
            key_jar=self.kj,
            iss=self.issuer,
            lifetime=lifetime,
            sign=sign,
            sign_alg=sign_alg,
            encrypt=encrypt,
            enc_alg=enc_alg,
            enc_enc=enc_enc,
        )

    def issue_bytes(self, payload: dict) -> bytes:
        """Issue token challenge"""
        return str(self.jwt.pack(payload=payload, recv=self.issuer)).encode()

    def verify_bytes(self, challenge: bytes) -> dict:
        """Verify challenge and return payload"""
        token = challenge.decode()
        payload = self.jwt.unpack(token)
        now = time.time()
        if "nbf" in payload and now < int(payload.get("nbf")):
            raise BadSignature("Token not yet valid (t < nbf)")
        if "exp" in payload and now >= int(payload.get("exp")):
            raise BadSignature("Token expired (t >= exp)")
        return dict(payload)
Example #16
0
class EncryptedJWTFactory(EncryptedTokenFactory):

    key_jar: KeyJar

    def __init__(self,
                 key_jar: KeyJar = None,
                 encrypt: bool = True,
                 sign: bool = True,
                 **kwargs):

        if encrypt is not True:
            raise RuntimeError('JWT encryption is mandatory.')

        self.key_jar = key_jar if key_jar is not None else KeyJar()
        self._jwt = JWT(key_jar=self.key_jar,
                        encrypt=encrypt,
                        sign=sign,
                        **kwargs)

    @property
    def issuer_id(self):
        return self._jwt.iss

    @classmethod
    def new_keys(cls, iss: str = 'Generic', **kwargs):
        """Creates a new key jar based on RSA keys.
        """
        uses = ['enc', 'sig'] if kwargs.get('sign', True) else ['enc']
        key_specs = [{"type": "RSA", "use": uses}]
        key_jar = build_keyjar(key_specs, issuer_id=iss)
        return cls(key_jar, iss=iss, **kwargs)

    def generate(self,
                 payload: dict,
                 subject: str = 'token',
                 recv: typing.Optional[str] = None) -> str:
        if recv is None:
            recv = self._jwt.iss
        token = self._jwt.pack(
            recv=recv,
            payload={
                "sub": subject,
                "data": payload
            },
            encrypt=True,
        )
        return token

    def decrypt(self, token: str) -> dict:
        info = self._jwt.unpack(token)
        if self._jwt.lifetime:
            now = utc_time_sans_frac()
            if 'iat' not in info or 'exp' not in info:
                raise MissingExpirationHeader()
            if now < info['iat']:
                raise NotYet()
            if now > info['exp']:
                raise Expired()
        return info.get('data')
Example #17
0
 def _do_jwt(self, info):
     args = {'allowed_sign_algs': self.service_context.get_sign_alg(self.service_name)}
     enc_algs = self.service_context.get_enc_alg_enc(self.service_name)
     args['allowed_enc_algs'] = enc_algs['alg']
     args['allowed_enc_encs'] = enc_algs['enc']
     _jwt = JWT(key_jar=self.service_context.keyjar, **args)
     _jwt.iss = self.service_context.get('client_id')
     return _jwt.unpack(info)
Example #18
0
    def do_response(self,
                    response_args=None,
                    request=None,
                    client_id="",
                    **kwargs):

        if "error" in kwargs and kwargs["error"]:
            return Endpoint.do_response(self, response_args, request, **kwargs)

        _context = self.endpoint_context
        if not client_id:
            raise MissingValue("client_id")

        # Should I return a JSON or a JWT ?
        _cinfo = _context.cdb[client_id]

        # default is not to sign or encrypt
        try:
            sign_alg = _cinfo["userinfo_signed_response_alg"]
            sign = True
        except KeyError:
            sign_alg = ""
            sign = False

        try:
            enc_enc = _cinfo["userinfo_encrypted_response_enc"]
            enc_alg = _cinfo["userinfo_encrypted_response_alg"]
            encrypt = True
        except KeyError:
            encrypt = False
            enc_alg = enc_enc = ""

        if encrypt or sign:
            _jwt = JWT(
                self.endpoint_context.keyjar,
                iss=self.endpoint_context.issuer,
                sign=sign,
                sign_alg=sign_alg,
                encrypt=encrypt,
                enc_enc=enc_enc,
                enc_alg=enc_alg,
            )

            resp = _jwt.pack(response_args, recv=client_id)
            content_type = "application/jwt"
        else:
            if isinstance(response_args, dict):
                resp = json.dumps(response_args)
            else:
                resp = response_args.to_json()
            content_type = "application/json"

        http_headers = [("Content-type", content_type)]
        http_headers.extend(OAUTH2_NOCACHE_HEADERS)

        return {"response": resp, "http_headers": http_headers}
Example #19
0
    def sign_encrypt(
        self,
        session_info,
        client_id,
        code=None,
        access_token=None,
        user_info=None,
        sign=True,
        encrypt=False,
        lifetime=None,
        extra_claims=None,
    ):
        """
        Signed and or encrypt a IDToken

        :param session_info: Session information
        :param client_id: Client ID
        :param code: Access grant
        :param access_token: Access Token
        :param user_info: User information
        :param sign: If the JWT should be signed
        :param encrypt: If the JWT should be encrypted
        :param extra_claims: Extra claims to be added to the ID Token
        :return: IDToken as a signed and/or encrypted JWT
        """

        _cntx = self.endpoint_context

        client_info = _cntx.cdb[client_id]
        alg_dict = get_sign_and_encrypt_algorithms(_cntx,
                                                   client_info,
                                                   "id_token",
                                                   sign=sign,
                                                   encrypt=encrypt)

        _authn_event = session_info["authn_event"]

        _idt_info = self.payload(
            session_info,
            acr=_authn_event["authn_info"],
            alg=alg_dict["sign_alg"],
            code=code,
            access_token=access_token,
            user_info=user_info,
            auth_time=_authn_event["authn_time"],
            lifetime=lifetime,
            extra_claims=extra_claims,
        )

        _jwt = JWT(_cntx.keyjar,
                   iss=_cntx.issuer,
                   lifetime=_idt_info["lifetime"],
                   **alg_dict)

        return _jwt.pack(_idt_info["payload"], recv=client_id)
Example #20
0
def create_entity_statement(iss,
                            sub,
                            key_jar,
                            metadata=None,
                            metadata_policy=None,
                            authority_hints=None,
                            lifetime=86400,
                            aud='',
                            include_jwks=True,
                            constraints=None,
                            **kwargs):
    """

    :param iss: The issuer of the signed JSON Web Token
    :param sub: The subject which the metadata describes
    :param key_jar: A KeyJar instance
    :param metadata: The entity's metadata organised as a dictionary with the
        entity type as key
    :param metadata_policy: Metadata policy
    :param authority_hints: A dictionary with immediate superiors in the
        trust chains as keys and lists of identifier of trust roots as values.
    :param lifetime: The life time of the signed JWT.
    :param aud: Possible audience for the JWT
    :param include_jwks: Add JWKS
    :param constraints: A dictionary with constraints.
    :return: A signed JSON Web Token
    """

    msg = {'sub': sub}
    if metadata:
        msg['metadata'] = metadata

    if metadata_policy:
        msg['metadata_policy'] = metadata_policy

    if authority_hints:
        msg['authority_hints'] = authority_hints

    if aud:
        msg['aud'] = aud

    if constraints:
        msg['constraints'] = constraints

    if kwargs:
        msg.update(kwargs)

    if include_jwks:
        # The public signing keys of the subject
        msg['jwks'] = key_jar.export_jwks(issuer_id=sub)

    packer = JWT(key_jar=key_jar, iss=iss, lifetime=lifetime)

    return packer.pack(payload=msg)
Example #21
0
def verify_signed_bundle(signed_bundle, ver_keys):
    """
    Verify the signature of a signed JWT.

    :param signed_bundle: A signed JWT where the body is a JWKS bundle
    :param ver_keys: Keys that can be used to verify signatures of the
        signed_bundle.
    :type ver_keys: A :py:class:`oidcmsg.key_jar.KeyJar` instance
    :return: The bundle or None
    """
    _jwt = JWT(ver_keys)
    return _jwt.unpack(signed_bundle)
Example #22
0
    def test_parse(self):
        session_id = setup_session(
            self.endpoint.endpoint_context, AUTH_REQ, uid="diana"
        )
        _dic = self.endpoint.endpoint_context.sdb.upgrade_to_token(key=session_id)

        _verifier = JWT(self.endpoint.endpoint_context.keyjar)
        _info = _verifier.unpack(_dic["access_token"])

        assert _info["ttype"] == "T"
        assert _info["phone_number"] == "+46907865000"
        assert set(_info["aud"]) == {"client_1", "https://example.org/appl"}
Example #23
0
    def verify(self, request, key_type, **kwargs):
        _context = self.server_get("endpoint_context")
        _jwt = JWT(_context.keyjar, msg_cls=JsonWebToken)
        try:
            ca_jwt = _jwt.unpack(request["client_assertion"])
        except (Invalid, MissingKey, BadSignature) as err:
            logger.info("%s" % sanitize(err))
            raise AuthnFailure("Could not verify client_assertion.")

        _sign_alg = ca_jwt.jws_header.get("alg")
        if _sign_alg and _sign_alg.startswith("HS"):
            if key_type == "private_key":
                raise AttributeError("Wrong key type")
            keys = _context.keyjar.get("sig", "oct", ca_jwt["iss"],
                                       ca_jwt.jws_header.get("kid"))
            _secret = _context.cdb[ca_jwt["iss"]].get("client_secret")
            if _secret and keys[0].key != as_bytes(_secret):
                raise AttributeError(
                    "Oct key used for signing not client_secret")
        else:
            if key_type == "client_secret":
                raise AttributeError("Wrong key type")

        authtoken = sanitize(ca_jwt.to_dict())
        logger.debug("authntoken: {}".format(authtoken))

        _endpoint = kwargs.get("endpoint")
        if _endpoint is None or not _endpoint:
            if _context.issuer in ca_jwt["aud"]:
                pass
            else:
                raise NotForMe("Not for me!")
        else:
            if set(ca_jwt["aud"]).intersection(
                    _endpoint.allowed_target_uris()):
                pass
            else:
                raise NotForMe("Not for me!")

        # If there is a jti use it to make sure one-time usage is true
        _jti = ca_jwt.get("jti")
        if _jti:
            _key = "{}:{}".format(ca_jwt["iss"], _jti)
            if _key in _context.jti_db:
                raise MultipleUsage("Have seen this token once before")
            else:
                _context.jti_db[_key] = utc_time_sans_frac()

        request[verified_claim_name("client_assertion")] = ca_jwt
        client_id = kwargs.get("client_id") or ca_jwt["iss"]

        return {"client_id": client_id, "jwt": ca_jwt}
    def test_jws_authn_method_wrong_key(self):
        client_keyjar = KeyJar()
        client_keyjar[CONF["issuer"]] = KEYJAR.issuer_keys[""]
        # Fake symmetric key
        client_keyjar.add_symmetric("", "client_secret:client_secret", ["sig"])

        _jwt = JWT(client_keyjar, iss=client_id, sign_alg="HS256")
        _assertion = _jwt.pack({"aud": [CONF["issuer"]]})

        request = {"client_assertion": _assertion, "client_assertion_type": JWT_BEARER}

        with pytest.raises(NoSuitableSigningKeys):
            self.method.verify(request=request, key_type='private_key')
Example #25
0
    def pack(self, req, receiver='', iss='', lifetime=0, sign=True,
             sign_alg='', encrypt=False, enc_enc="A128CBC-HS256",
             enc_alg="RSA1_5", aud=None):
        """

        :param req: Original metadata statement as a 
            :py:class:`MetadataStatement` instance
        :param receiver: The immediate receiver of the JWS
        :param iss:
        :param lifetime:
        :param sign:
        :param sign_alg:
        :param encrypt:
        :param enc_alg:
        :param enc_enc:
        :param aud: The audience, a list of receivers.
        :return: A dictionary with a signed JWT as value with the key 'sms'
        """
        if not iss:
            iss = self.iss
        if not lifetime:
            lifetime = self.lifetime

        keyjar = self.keyjar

        # Own copy
        _metadata = copy.deepcopy(req)
        if self.add_ons:
            _metadata.update(self.add_ons)

        args = {}
        if sign:
            if sign_alg:
                args['sign_alg'] = sign_alg
            else:
                args['sign_alg'] = self.alg
        if encrypt:
            args['enc_enc'] = enc_enc
            args['enc_alg'] = enc_alg

        _jwt = JWT(keyjar, iss=iss, msg_cls=_metadata.__class__,
                   lifetime=lifetime, **args)
        # _jwt.sign_alg = self.alg

        if iss in keyjar.issuer_keys:
            owner = iss
        else:
            owner = ''

        return _jwt.pack(payload=_metadata.to_dict(), owner=owner,
                         recv=receiver, aud=aud)
Example #26
0
    def sign_encrypt(
        self,
        session_id,
        client_id,
        code=None,
        access_token=None,
        sign=True,
        encrypt=False,
        lifetime=None,
        extra_claims=None,
    ) -> str:
        """
        Signed and or encrypt a IDToken

        :param lifetime: How long the ID Token should be valid
        :param session_id: Session information
        :param client_id: Client ID
        :param code: Access grant
        :param access_token: Access Token
        :param sign: If the JWT should be signed
        :param encrypt: If the JWT should be encrypted
        :param extra_claims: Extra claims to be added to the ID Token
        :return: IDToken as a signed and/or encrypted JWT
        """

        _context = self.server_get("endpoint_context")

        client_info = _context.cdb[client_id]
        alg_dict = get_sign_and_encrypt_algorithms(_context,
                                                   client_info,
                                                   "id_token",
                                                   sign=sign,
                                                   encrypt=encrypt)

        _payload = self.payload(
            session_id=session_id,
            alg=alg_dict["sign_alg"],
            code=code,
            access_token=access_token,
            extra_claims=extra_claims,
        )

        if lifetime is None:
            lifetime = self.lifetime

        _jwt = JWT(_context.keyjar,
                   iss=_context.issuer,
                   lifetime=lifetime,
                   **alg_dict)

        return _jwt.pack(_payload, recv=client_id)
Example #27
0
    def __init__(self,
                 key_jar: KeyJar = None,
                 encrypt: bool = True,
                 sign: bool = True,
                 **kwargs):

        if encrypt is not True:
            raise RuntimeError('JWT encryption is mandatory.')

        self.key_jar = key_jar if key_jar is not None else KeyJar()
        self._jwt = JWT(key_jar=self.key_jar,
                        encrypt=encrypt,
                        sign=sign,
                        **kwargs)
    def test_jws_authn_method_aud_userinfo_endpoint(self):
        client_keyjar = KeyJar()
        client_keyjar[CONF["issuer"]] = KEYJAR.issuer_keys[""]
        # The only own key the client has a this point
        client_keyjar.add_symmetric("", client_secret, ["sig"])

        _jwt = JWT(client_keyjar, iss=client_id, sign_alg="HS256")

        # audience is the OP - not specifically the user info endpoint
        _assertion = _jwt.pack({"aud": [CONF["issuer"]]})

        request = {"client_assertion": _assertion, "client_assertion_type": JWT_BEARER}

        assert self.method.verify(request=request, endpoint="userinfo", key_type='client_secret')
    def test_jws_authn_method_aud_iss(self):
        client_keyjar = KeyJar()
        client_keyjar[CONF["issuer"]] = KEYJAR.issuer_keys[""]
        # The only own key the client has a this point
        client_keyjar.add_symmetric("", client_secret, ["sig"])

        _jwt = JWT(client_keyjar, iss=client_id, sign_alg="HS256")
        # Audience is OP issuer ID
        aud = CONF["issuer"]
        _assertion = _jwt.pack({"aud": [aud]})

        request = {"client_assertion": _assertion, "client_assertion_type": JWT_BEARER}

        assert self.method.verify(request=request, key_type='client_secret')
Example #30
0
 def create_signed_bundle(self, sign_alg='RS256', iss_list=None):
     """
     Create a signed JWT containing a dictionary with Issuer IDs as keys
     and JWKSs as values. If iss_list is empty then all available issuers are
     included.
     
     :param sign_alg: Which algorithm to use when signing the JWT
     :param iss_list: A list of issuer IDs who's keys should be included in 
         the signed bundle.
     :return: A signed JWT
     """
     data = self.dict(iss_list)
     _jwt = JWT(self.sign_keys, iss=self.iss, sign_alg=sign_alg)
     return _jwt.pack({'bundle':data})