示例#1
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}
示例#2
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"]
示例#3
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
示例#4
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']
示例#5
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')
示例#6
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)
示例#7
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)
示例#8
0
def verify_jwt(
    jwt: JWT,
    token: str,
    required_claims: ClaimsRequired = {},
    max_lifetime: Optional[int] = None,
    max_timeskew: int = 0,
    enforce_lifetime: bool = True,
) -> dict:
    """Authenticate API request using JWK"""
    logger = _logger.getChild("verify_jwt")
    try:
        payload = jwt.unpack(token)
    except BadSyntax:
        raise BadRequest("Invalid token syntax")
    except BadSignature:
        raise Unauthorized("Invalid token signature")
    except IssuerNotFound as exc:
        raise Unauthorized("Issuer not found: " + str(exc))
    except NoSuitableSigningKeys as exc:
        logger.warning("Unknown token issuer",
                       extra={
                           "jwt": token,
                           "error": str(exc)
                       })
        raise Unauthorized("Unknown token issuer")
    logger.debug("Verified token payload: %s",
                 payload,
                 extra={"jwt_payload": payload})
    now = int(time.time())
    if max_lifetime is not None and max_lifetime < 0:
        raise ValueError("Negative max_lifetime")
    if max_timeskew is not None and max_timeskew < 0:
        raise ValueError("Negative max_timeskew")
    if "nbf" in payload:
        nbf = int(payload["nbf"]) - max_timeskew
        if now < nbf:
            raise Unauthorized("Token not yet valid (t < nbf)")
    if "exp" in payload:
        exp = int(payload["exp"])
        delta = exp - now
        if max_lifetime is not None and delta > max_lifetime:
            if enforce_lifetime:
                logger.warning(
                    "Token expire exceeded, truncated (max %d, got %d)",
                    max_lifetime,
                    delta,
                )
                exp = now + max_lifetime
            else:
                logger.warning(
                    "Token expire exceeded, not enforced (max %d, got %d)",
                    max_lifetime,
                    delta,
                )
        if now >= exp:
            raise Unauthorized("Token expired (t >= exp)")
    ensure_claims(payload, required_claims)
    return dict(payload)
示例#9
0
def test_jwt_pack_encrypt():
    alice = JWT(key_jar=ALICE_KEY_JAR, iss=ALICE)
    payload = {"sub": "sub", "aud": BOB}
    _jwt = alice.pack(payload=payload, encrypt=True, recv=BOB)

    bob = JWT(key_jar=BOB_KEY_JAR, iss=BOB)
    info = bob.unpack(_jwt)

    assert set(info.keys()) == {"iat", "iss", "sub", "aud"}
示例#10
0
def test_jwt_pack_and_unpack_with_lifetime():
    alice = JWT(key_jar=ALICE_KEY_JAR, iss=ALICE, lifetime=600)
    payload = {'sub': 'sub'}
    _jwt = alice.pack(payload=payload)

    bob = JWT(key_jar=BOB_KEY_JAR, iss=BOB)
    info = bob.unpack(_jwt)

    assert set(info.keys()) == {'iat', 'iss', 'sub', 'exp'}
def test_jwt_pack_unpack_sym():
    _sym_key = SYMKey(key='hemligt ord', use='sig')
    alice = JWT(own_keys=[_sym_key], iss=ALICE, sign_alg="HS256")
    payload = {'sub': 'sub2'}
    _jwt = alice.pack(payload=payload)

    bob = JWT(own_keys=None, iss=BOB, rec_keys={ALICE: [_sym_key]})
    info = bob.unpack(_jwt)
    assert info
def test_jwt_pack_encrypt():
    alice = JWT(own_keys=ALICE_KEYS, iss=ALICE, rec_keys={BOB: BOB_PUB_KEYS})
    payload = {'sub': 'sub', 'aud': BOB}
    _jwt = alice.pack(payload=payload, encrypt=True, recv=BOB)

    bob = JWT(own_keys=BOB_KEYS, iss=BOB, rec_keys={ALICE: ALICE_PUB_KEYS})
    info = bob.unpack(_jwt)

    assert set(info.keys()) == {'iat', 'iss', 'sub', 'kid', 'aud'}
def test_jwt_pack_and_unpack_with_lifetime():
    alice = JWT(own_keys=ALICE_KEYS, iss=ALICE, lifetime=600)
    payload = {'sub': 'sub'}
    _jwt = alice.pack(payload=payload)

    bob = JWT(own_keys=BOB_KEYS, iss=BOB, rec_keys={ALICE: ALICE_PUB_KEYS})
    info = bob.unpack(_jwt)

    assert set(info.keys()) == {'iat', 'iss', 'sub', 'kid', 'exp', 'aud'}
示例#14
0
def test_jwt_pack_encrypt():
    alice = JWT(key_jar=ALICE_KEY_JAR, iss=ALICE)
    payload = {'sub': 'sub', 'aud': BOB}
    _jwt = alice.pack(payload=payload, encrypt=True, recv=BOB)

    bob = JWT(key_jar=BOB_KEY_JAR, iss=BOB)
    info = bob.unpack(_jwt)

    assert set(info.keys()) == {'iat', 'iss', 'sub', 'aud'}
示例#15
0
def test_jwt_pack_and_unpack():
    alice = JWT(key_jar=ALICE_KEY_JAR, iss=ALICE, sign_alg='RS256')
    payload = {'sub': 'sub'}
    _jwt = alice.pack(payload=payload)

    bob = JWT(key_jar=BOB_KEY_JAR, iss=BOB, allowed_sign_algs=["RS256"])
    info = bob.unpack(_jwt)

    assert set(info.keys()) == {'iat', 'iss', 'sub'}
示例#16
0
def test_jwt_pack_and_unpack_with_alg():
    alice = JWT(key_jar=ALICE_KEY_JAR, iss=ALICE, sign_alg="RS384")
    payload = {"sub": "sub"}
    _jwt = alice.pack(payload=payload)

    bob = JWT(BOB_KEY_JAR, sign_alg="RS384")
    info = bob.unpack(_jwt)

    assert set(info.keys()) == {"iat", "iss", "sub"}
示例#17
0
def test_jwt_pack_and_unpack_with_alg():
    alice = JWT(key_jar=ALICE_KEY_JAR, iss=ALICE, sign_alg='RS384')
    payload = {'sub': 'sub'}
    _jwt = alice.pack(payload=payload)

    bob = JWT(BOB_KEY_JAR, sign_alg='RS384')
    info = bob.unpack(_jwt)

    assert set(info.keys()) == {'iat', 'iss', 'sub'}
示例#18
0
def test_jwt_pack_and_unpack_with_lifetime():
    alice = JWT(key_jar=ALICE_KEY_JAR, iss=ALICE, lifetime=600)
    payload = {"sub": "sub"}
    _jwt = alice.pack(payload=payload)

    bob = JWT(key_jar=BOB_KEY_JAR, iss=BOB)
    info = bob.unpack(_jwt)

    assert set(info.keys()) == {"iat", "iss", "sub", "exp"}
示例#19
0
def test_jwt_pack_and_unpack_unknown_issuer():
    alice = JWT(key_jar=ALICE_KEY_JAR, iss=ALICE, sign_alg="RS256")
    payload = {"sub": "sub"}
    _jwt = alice.pack(payload=payload)

    kj = KeyJar()
    bob = JWT(key_jar=kj, iss=BOB, allowed_sign_algs=["RS256"])
    with pytest.raises(IssuerNotFound):
        info = bob.unpack(_jwt)
示例#20
0
def test_jwt_pack_and_unpack():
    alice = JWT(key_jar=ALICE_KEY_JAR, iss=ALICE, sign_alg="RS256")
    payload = {"sub": "sub"}
    _jwt = alice.pack(payload=payload)

    bob = JWT(key_jar=BOB_KEY_JAR, iss=BOB, allowed_sign_algs=["RS256"])
    info = bob.unpack(_jwt)

    assert set(info.keys()) == {"iat", "iss", "sub"}
示例#21
0
def test_jwt_pack_and_unpack_unknown_key():
    alice = JWT(key_jar=ALICE_KEY_JAR, iss=ALICE, sign_alg="RS256")
    payload = {"sub": "sub"}
    _jwt = alice.pack(payload=payload)

    kj = KeyJar()
    kj.add_kb(ALICE, KeyBundle())
    bob = JWT(key_jar=kj, iss=BOB, allowed_sign_algs=["RS256"])
    with pytest.raises(NoSuitableSigningKeys):
        info = bob.unpack(_jwt)
示例#22
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)
示例#23
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"}
示例#24
0
def test_msg_cls():
    _kj = KeyJar()
    _kj.add_symmetric(ALICE, "hemligt ordsprak", usage=["sig"])

    alice = JWT(key_jar=_kj, iss=ALICE, sign_alg="HS256")
    payload = {"sub": "sub2"}
    _jwt = alice.pack(payload=payload)

    bob = JWT(key_jar=_kj, iss=BOB, sign_alg="HS256")
    bob.msg_cls = DummyMsg
    info = bob.unpack(_jwt)
    assert isinstance(info, DummyMsg)
示例#25
0
def test_jwt_pack_unpack_sym():
    _kj = KeyJar()
    _kj.add_symmetric(ALICE, 'hemligt ordsprak', usage=['sig'])
    alice = JWT(key_jar=_kj, iss=ALICE, sign_alg="HS256")
    payload = {'sub': 'sub2'}
    _jwt = alice.pack(payload=payload)

    _kj = KeyJar()
    _kj.add_symmetric(ALICE, 'hemligt ordsprak', usage=['sig'])
    bob = JWT(key_jar=_kj, iss=BOB, sign_alg="HS256")
    info = bob.unpack(_jwt)
    assert info
示例#26
0
def test_with_jti():
    _kj = KeyJar()
    _kj.add_symmetric(ALICE, "hemligt ordsprak", usage=["sig"])

    alice = JWT(key_jar=_kj, iss=ALICE, sign_alg="HS256")
    alice.with_jti = True
    payload = {"sub": "sub2"}
    _jwt = alice.pack(payload=payload)

    bob = JWT(key_jar=_kj, iss=BOB, sign_alg="HS256")
    info = bob.unpack(_jwt)
    assert "jti" in info
示例#27
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}
示例#28
0
 def test_no_default_claims(self):
     session_info = {
         "authn_req": AREQN,
         "sub": "sub",
         "authn_event": {
             "authn_info": "loa2",
             "authn_time": time.time(),
             "uid": "diana"
         },
     }
     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 "nickname" not in res
示例#29
0
    def test_parse(self):
        session_id = self._create_session(AUTH_REQ)
        # apply consent
        grant = self.endpoint_context.authz(session_id=session_id,
                                            request=AUTH_REQ)
        # grant = self.session_manager[session_id]
        code = self._mint_token("authorization_code", grant, session_id)
        access_token = self._mint_token("access_token",
                                        grant,
                                        session_id,
                                        code,
                                        resources=[AUTH_REQ["client_id"]])

        _verifier = JWT(self.endpoint_context.keyjar)
        _info = _verifier.unpack(access_token.value)

        assert _info["token_class"] == "access_token"
        # assert _info["eduperson_scoped_affiliation"] == ["*****@*****.**"]
        assert set(_info["aud"]) == {"client_1"}
示例#30
0
    def test_enable_claims_per_client(self, enable_claims_per_client):
        # Set up configuration
        self.endpoint_context.cdb["client_1"]["access_token_claims"] = {
            "address": None
        }
        self.endpoint_context.session_manager.token_handler.handler[
            "access_token"].kwargs[
                "enable_claims_per_client"] = enable_claims_per_client

        session_id = self._create_session(AUTH_REQ)
        # apply consent
        grant = self.endpoint_context.authz(session_id=session_id,
                                            request=AUTH_REQ)
        #
        code = self._mint_token("authorization_code", grant, session_id)
        access_token = self._mint_token("access_token", grant, session_id,
                                        code)

        _jwt = JWT(key_jar=KEYJAR, iss="client_1")
        res = _jwt.unpack(access_token.value)
        assert enable_claims_per_client is ("address" in res)