def __call__(self, session_id: Optional[str] = "", token_class: Optional[str] = "", **payload) -> str: """ Return a token. :param session_id: Session id :param token_class: Token class :param payload: A dictionary with information that is part of the payload of the JWT. :return: Signed JSON Web Token """ if not token_class and self.token_class: token_class = self.token_class else: token_class = "authorization_code" payload.update({"sid": session_id, "token_class": token_class}) payload = self.load_custom_claims(payload) # payload.update(kwargs) _context = self.server_get("endpoint_context") signer = JWT( key_jar=_context.keyjar, iss=self.issuer, lifetime=self.lifetime, sign_alg=self.alg, ) return signer.pack(payload)
def test_jwt_unknown_key(self): _keyjar = build_keyjar(KEYDEFS) _jwt = JWT( _keyjar, iss=self.introspection_endpoint.server_get( "endpoint_context").issuer, lifetime=3600, ) _jwt.with_jti = True _payload = {"sub": "subject_id"} _token = _jwt.pack(_payload, aud="client_1") _context = self.introspection_endpoint.server_get("endpoint_context") _req = self.introspection_endpoint.parse_request({ "token": _token, "client_id": "client_1", "client_secret": _context.cdb["client_1"]["client_secret"], }) _req = self.introspection_endpoint.parse_request(_req) _resp = self.introspection_endpoint.process_request(_req) assert _resp["response_args"]["active"] is False
def create_trust_mark(entity_id, key_jar, trust_mark_id, subject='', lifetime=0, trust_mark='', reference=''): """ Create Trust Mark. :param entity_id: The issuers entity_id :param key_jar: A KeyJar that contains useful keys :param trust_mark_id: The Trust Mark identifier :param subject: The subject's id :param lifetime: For how long the trust mark should be valid (0=for ever) :param trust_mark: A URL pointing to a graphic trust mark :param reference: A URL pointing to reference material for this trust mark :return: A signed JWT containing the provided information """ _tm = TrustMark( id=trust_mark_id, ) if trust_mark: _tm["mark"] = trust_mark if reference: _tm["ref"] = reference if subject: _tm['sub'] = subject else: _tm['sub'] = entity_id # Create the Signed JWT representing the Trust Mark _jwt = JWT(key_jar=key_jar, iss=entity_id, lifetime=lifetime) return _jwt.pack(_tm)
def test_process_request_using_private_key_jwt(self): session_id = setup_session( self.endpoint.endpoint_context, AUTH_REQ, uid="user", acr=INTERNETPROTOCOLPASSWORD, ) _token_request = TOKEN_REQ_DICT.copy() del _token_request["client_id"] del _token_request["client_secret"] _context = self.endpoint.endpoint_context _jwt = JWT(CLIENT_KEYJAR, iss=AUTH_REQ["client_id"], sign_alg="RS256") _jwt.with_jti = True _assertion = _jwt.pack({"aud": [_context.endpoint["token"].full_path]}) _token_request.update({ "client_assertion": _assertion, "client_assertion_type": JWT_BEARER }) _token_request["code"] = self.endpoint.endpoint_context.sdb[ session_id]["code"] _context.sdb.update(session_id, user="******") _req = self.endpoint.parse_request(_token_request) _resp = self.endpoint.process_request(request=_req) # 2nd time used with pytest.raises(UnAuthorizedClient): self.endpoint.parse_request(_token_request)
def test_get_trust_mark_3rd_party(): _iss = "https://feide.no" _sub = "https://op.ntnu.no" config = {'keys': {'key_defs': KEYSPEC}} federation_entity = FederationEntity( _iss, trusted_roots=ANCHOR, config=config, authority_hints=['https://ntnu.no'], entity_type='openid_relying_party', httpd=Publisher(ROOT_DIR), opponent_entity_type='openid_relying_party') federation_entity.collector = DummyCollector(httpd=Publisher(ROOT_DIR), trusted_roots=ANCHOR, root_dir=ROOT_DIR) _tm = TrustMark( id="https://refeds.org/wp-content/uploads/2016/01/Sirtfi-1.0.pdf", sub=_sub, ) # Create the Signed JWT representing the Trust Mark _jwt0 = JWT(key_jar=federation_entity.keyjar, iss=_iss, lifetime=3600) _jws = _jwt0.pack(_tm) trust_anchor_id = list(ANCHOR.keys())[0] _tm = get_trust_mark(federation_entity, _jws, _sub, trust_anchor_id) assert isinstance(_tm, TrustMark)
def test_client_claims_scopes_and_request_claims_no_match(self): session_id = self._create_session(AREQRC) grant = self.session_manager[session_id] self.session_manager.token_handler["id_token"].kwargs[ "add_claims_by_scope"] = True _claims = self.endpoint_context.claims_interface.get_claims( session_id=session_id, scopes=AREQRC["scope"], claims_release_point="id_token") grant.claims = {"id_token": _claims} id_token = self._mint_id_token(grant, session_id) 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(id_token.value) # User information, from scopes -> claims assert "address" in res assert "email" in res # User info, requested by claims parameter assert "nickname" in res
def test_client_claims(self): session_id = self._create_session(AREQ) grant = self.session_manager[session_id] self.session_manager.token_handler["id_token"].kwargs[ "enable_claims_per_client"] = True self.endpoint_context.cdb["client_1"]["id_token_claims"] = { "address": None } _claims = self.endpoint_context.claims_interface.get_claims( session_id=session_id, scopes=AREQ["scope"], claims_release_point="id_token") grant.claims = {"id_token": _claims} id_token = self._mint_id_token(grant, session_id) 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(id_token.value) assert "address" in res assert "nickname" not in res
def test_client_claims_scopes_and_request_claims_one_match(self): _req = AREQS.copy() _req["claims"] = { "id_token": { "email": { "value": "*****@*****.**" } } } session_id = self._create_session(_req) grant = self.session_manager[session_id] self.session_manager.token_handler["id_token"].kwargs[ "add_claims_by_scope"] = True _claims = self.endpoint_context.claims_interface.get_claims( session_id=session_id, scopes=_req["scope"], claims_release_point="id_token") grant.claims = {"id_token": _claims} id_token = self._mint_id_token(grant, session_id) 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(id_token.value) # Email didn't match assert "email" not in res # Scope -> claims assert "address" in res
def test_pushed_auth_request(self): _msg = Message().from_urlencoded(AUTHN_REQUEST) _jwt = JWT(key_jar=self.rp_keyjar, iss="s6BhdRkqt3") _jws = _jwt.pack(_msg.to_dict()) authn_request = "request={}".format(_jws) http_info = { "headers": {"authorization": "Basic czZCaGRSa3F0Mzo3RmpmcDBaQnIxS3REUmJuZlZkbUl3"} } _req = self.pushed_authorization_endpoint.parse_request(authn_request, http_info=http_info) assert isinstance(_req, AuthorizationRequest) _req = remove_jwt_parameters(_req) assert set(_req.keys()) == { "state", "redirect_uri", "response_type", "scope", "code_challenge_method", "client_id", "code_challenge", "request", "__verified_request", }
def test_process_request_using_private_key_jwt(self): session_id = self._create_session(AUTH_REQ) grant = self.session_manager[session_id] code = self._mint_code(grant, AUTH_REQ["client_id"]) _token_request = TOKEN_REQ_DICT.copy() del _token_request["client_id"] del _token_request["client_secret"] _context = self.endpoint_context _jwt = JWT(CLIENT_KEYJAR, iss=AUTH_REQ["client_id"], sign_alg="RS256") _jwt.with_jti = True _assertion = _jwt.pack({"aud": [self.token_endpoint.full_path]}) _token_request.update({ "client_assertion": _assertion, "client_assertion_type": JWT_BEARER }) _token_request["code"] = code.value _req = self.token_endpoint.parse_request(_token_request) _resp = self.token_endpoint.process_request(request=_req) # 2nd time used with pytest.raises(UnAuthorizedClient): self.token_endpoint.parse_request(_token_request)
def test_parse_request_uri(self): _jwt = JWT(key_jar=self.rp_keyjar, iss="client_1", sign_alg="HS256") _jws = _jwt.pack( AUTH_REQ_DICT, aud=self.endpoint.server_get( "endpoint_context").provider_info["issuer"], ) request_uri = "https://client.example.com/req" # ----------------- with responses.RequestsMock() as rsps: rsps.add("GET", request_uri, body=_jws, status=200) _req = self.endpoint.parse_request({ "request_uri": request_uri, "redirect_uri": AUTH_REQ.get("redirect_uri"), "response_type": AUTH_REQ.get("response_type"), "client_id": AUTH_REQ.get("client_id"), "scope": AUTH_REQ.get("scope"), }) assert "__verified_request" in _req
def _parse_remote_response(self, response): """ Parse simple JWKS or signed JWKS from the HTTP response. :param response: HTTP response from the 'jwks_uri' or 'signed_jwks_uri' endpoint :return: response parsed as JSON or None """ # Check if the content type is the right one. try: if response.headers["Content-Type"] == 'application/json': logger.debug( "Loaded JWKS: %s from %s" % (response.text, self.source)) try: return json.loads(response.text) except ValueError: return None elif response.headers["Content-Type"] == 'application/jwt': logger.debug( "Signed JWKS: %s from %s" % (response.text, self.source)) _jwt = JWT(key_jar=self.federation_keys) _resp = _jwt.unpack(response.text) return _resp else: logger.error('Wrong content type: {}'.format( response.headers['Content-Type'])) raise ValueError('Content-type mismatch') except KeyError: pass
def test_pushed_auth_urlencoded(self): # since all endpoint used the same endpoint_context I can grab anyone _op_context = self.registration_endpoint.server_get("endpoint_context") # This is cheating. Getting the OP's provider info _fe = self.registration_service.client_get("service_context").federation_entity trust_chain = TrustChain() trust_chain.metadata = _op_context.provider_info trust_chain.anchor = "https://feide.no" trust_chain.verified_chain = [{'iss': "https://ntnu.no"}] self.discovery_service.update_service_context([trust_chain]) # and the OP's federation keys _op_context.federation_entity.context.keyjar.import_jwks( read_info(os.path.join(ROOT_DIR, 'op.ntnu.no'), 'op.ntnu.no', 'jwks'), issuer_id=_op_context.provider_info['issuer']) # Add RP's OIDC keys to the OP's keyjar. _op_context.keyjar.import_jwks( self.discovery_service.client_get("service_context").keyjar.export_jwks(issuer_id=""), RP_ENTITY_ID ) authn_request = AuthorizationRequest( response_type="code", state="af0ifjsldkj", client_id=RP_ENTITY_ID, redirect_uri="{}/callback".format(RP_ENTITY_ID), code_challenge="K2-ltc83acc4h0c9w6ESC_rEMTJ3bww-uCHaoeK1t8U", code_challenge_method="S256", scope=["ais", "openid"] ) # Create the private_key_jwt assertion _jwt = JWT(self.registration_service.client_get("service_context").keyjar, iss=RP_ENTITY_ID, sign_alg="RS256") _jwt.with_jti = True _assertion = _jwt.pack( { "aud": [_op_context.provider_info["pushed_authorization_request_endpoint"]] }) authn_request.update({"client_assertion": _assertion, "client_assertion_type": JWT_BEARER}) _req = self.pushed_authorization_endpoint.parse_request(authn_request) assert isinstance(_req, AuthorizationRequest) assert set(_req.keys()) == { "state", "redirect_uri", "response_type", "scope", "code_challenge_method", "client_id", "code_challenge", "client_assertion", "client_assertion_type", '__verified_client_assertion' } # Should have a registered client now assert set(_op_context.cdb.keys()) == {RP_ENTITY_ID}
def signed_jwks(self, issuer, sign_alg: Optional[str] = "RS256"): """ :return: Signed JWT containing a JWKS """ jwks = json.loads(self.jwks()) _jwt = JWT(self.federation_keys, iss=issuer, sign_alg=sign_alg) return _jwt.pack(jwks)
def do_jws(self, token, default_response): _jwt = JWT(key_jar=self.endpoint_context.keyjar) try: _jwt_info = _jwt.unpack(token) except Exception: return {"response_args": default_response} return _jwt_info
def get_payload(self, token): _context = self.server_get("endpoint_context") verifier = JWT(key_jar=_context.keyjar, allowed_sign_algs=[self.alg]) try: _payload = verifier.unpack(token) except JWSException: raise UnknownToken() return _payload
def test_do_request_uri(self): request = AuthorizationRequest( redirect_uri="https://rp.example.com/cb", request_uri="https://example.com/request", ) orig_request = AuthorizationRequest( client_id="client_id", redirect_uri="https://rp.example.com/cb", response_type=["id_token token"], state="state", nonce="nonce", scope="openid", ) _jwt = JWT(key_jar=self.rp_keyjar, iss="client_1", sign_alg="HS256") _jws = _jwt.pack( orig_request.to_dict(), aud=self.endpoint.server_get("endpoint_context").provider_info["issuer"], ) endpoint_context = self.endpoint.server_get("endpoint_context") endpoint_context.cdb["client_1"]["request_uris"] = [("https://example.com/request", {})] with responses.RequestsMock() as rsps: rsps.add( "GET", request["request_uri"], body=_jws, adding_headers={"Content-Type": "application/jose"}, status=200, ) self.endpoint._do_request_uri(request, "client_1", endpoint_context) request["request_uri"] = "https://example.com/request#1" with responses.RequestsMock() as rsps: rsps.add( "GET", request["request_uri"], body=_jws, adding_headers={"Content-Type": "application/jose"}, status=200, ) self.endpoint._do_request_uri(request, "client_1", endpoint_context) request["request_uri"] = "https://example.com/another" with pytest.raises(ValueError): self.endpoint._do_request_uri(request, "client_1", endpoint_context) endpoint_context.provider_info["request_uri_parameter_supported"] = False with pytest.raises(ServiceError): self.endpoint._do_request_uri(request, "client_1", endpoint_context)
def is_expired(self, token, when=0): """ Evaluate whether the token has expired or not :param token: The token :param when: The time against which to check the expiration 0 means now. :return: True/False """ verifier = JWT(key_jar=self.key_jar, allowed_sign_algs=[self.alg]) _payload = verifier.unpack(token) return is_expired(_payload["exp"], when)
def _create_jwt(self, uid, lifetime=0, with_jti=False): _jwt = JWT( self.introspection_endpoint.endpoint_context.keyjar, iss=self.introspection_endpoint.endpoint_context.issuer, lifetime=lifetime, ) if with_jti: _jwt.with_jti = with_jti _info = self.introspection_endpoint.endpoint_context.userinfo.db[uid] _payload = {"sub": _info["sub"]} return _jwt.pack(_payload, aud="client_1")
def create_trust_mark(self, id, sub): _now = utc_time_sans_frac() _add = {'iat': _now, 'id': id, 'sub': sub} lifetime = self.tm_lifetime.get(id) if lifetime: _add['exp'] = _now + lifetime content = self.trust_marks[id].copy() content.update(_add) self.issued.add(id, content) _ctx = self.server_get("context") packer = JWT(key_jar=_ctx.keyjar, iss=_ctx.entity_id) return packer.pack(payload=content)
def test_no_available_claims(self): session_id = self._create_session(AREQ) grant = self.session_manager[session_id] grant.claims = {"id_token": {"foobar": None}} id_token = self._mint_id_token(grant, session_id) 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(id_token.value) assert "foobar" not in res
def test_lifetime_default(self): session_id = self._create_session(AREQ) grant = self.session_manager[session_id] id_token = self._mint_id_token(grant, session_id) 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(id_token.value) assert res["exp"] - res["iat"] == LIFETIME
def verify_self_signed_signature(config): """ Verify signature. Will raise exception if signature verification fails. :param config: Signed JWT :return: Payload of the signed JWT """ payload = unverified_entity_statement(config) keyjar = KeyJar() keyjar.import_jwks(payload['jwks'], payload['iss']) _jwt = JWT(key_jar=keyjar) _val = _jwt.unpack(config) return _val
def test_sign_encrypt_id_token(self): session_id = self._create_session(AREQ) grant = self.session_manager[session_id] id_token = self._mint_id_token(grant, session_id) _jws = factory(id_token.value) assert _jws.jwt.headers["alg"] == "RS256" 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(id_token.value) assert isinstance(res, dict) assert res["aud"] == ["client_1"]
def test_parse_request(self): _jwt = JWT(key_jar=self.rp_keyjar, iss="client_1", sign_alg="HS256") _jws = _jwt.pack( AUTH_REQ_DICT, aud=self.endpoint.server_get("endpoint_context").provider_info["issuer"], ) # ----------------- _req = self.endpoint.parse_request( { "request": _jws, "redirect_uri": AUTH_REQ.get("redirect_uri"), "response_type": AUTH_REQ.get("response_type"), "client_id": AUTH_REQ.get("client_id"), "scope": AUTH_REQ.get("scope"), } ) assert "__verified_request" in _req
def __call__(self, sid: str, uinfo: Dict, sinfo: Dict, *args, aud: Optional[Any], client_id: Optional[str], **kwargs): """ Return a token. :param sid: Session id :param uinfo: User information :param sinfo: Session information :param aud: The default audience == client_id :return: """ payload = {"sid": sid, "ttype": self.type, "sub": sinfo["sub"]} if self.add_claims: self.do_add_claims(payload, uinfo, self.add_claims) if self.add_claims_by_scope: self.do_add_claims( payload, uinfo, scope2claims(sinfo["authn_req"]["scope"], map=self.scope_claims_map).keys(), ) # Add claims if is access token if self.type == 'T' and self.enable_claims_per_client: client = self.cdb.get(client_id, {}) client_claims = client.get("access_token_claims") if client_claims: self.do_add_claims(payload, uinfo, client_claims) payload.update(kwargs) signer = JWT( key_jar=self.key_jar, iss=self.issuer, lifetime=self.lifetime, sign_alg=self.alg, ) if aud is None: _aud = self.def_aud else: _aud = aud if isinstance(aud, list) else [aud] _aud.extend(self.def_aud) return signer.pack(payload, aud=_aud)
def __call__( self, sid: str, uinfo: Dict, sinfo: Dict, *args, aud: Optional[Any], **kwargs ): """ Return a token. :param sid: Session id :param uinfo: User information :param sinfo: Session information :param aud: The default audience == client_id :return: """ payload = {"sid": sid, "ttype": self.type, "sub": sinfo["sub"]} if "add_claims" in self.args: self.add_claims(payload, uinfo, self.args["add_claims"]) if "add_claims_by_scope": self.add_claims( payload, uinfo, scope2claims(sinfo["authn_req"]["scope"]).keys() ) payload.update(kwargs) signer = JWT( key_jar=self.key_jar, iss=self.issuer, lifetime=self.lifetime, sign_alg=self.alg, ) if aud is None: _aud = self.def_aud else: _aud = aud if isinstance(aud, list) else [aud] _aud.extend(self.def_aud) return signer.pack(payload, aud=_aud)
def info(self, token): """ Return type of Token (A=Access code, T=Token, R=Refresh token) and the session id. :param token: A token :return: tuple of token type and session id """ verifier = JWT(key_jar=self.key_jar, allowed_sign_algs=[self.alg]) _payload = verifier.unpack(token) if is_expired(_payload["exp"]): raise ToOld("Token has expired") # All the token metadata _res = { "sid": _payload["sid"], "type": _payload["ttype"], "exp": _payload["exp"], "handler": self, } return _res
def test_client_claims_with_default(self): session_id = self._create_session(AREQ) grant = self.session_manager[session_id] _claims = self.endpoint_context.claims_interface.get_claims( session_id=session_id, scopes=AREQ["scope"], claims_release_point="id_token") grant.claims = {"id_token": _claims} id_token = self._mint_id_token(grant, session_id) 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(id_token.value) # No user info claims should be there assert "address" not in res assert "nickname" not in res
def test_create_trust_mark_self_signed(): _entity_id = "https://example.com/op" _tm = TrustMark( id="https://openid.net/certification/op", sub=_entity_id, mark="http://openid.net/wordpress-content/uploads/2016/05/oid-l-certification-mark-l-cmyk" \ "-150dpi-90mm.jpg", ref="https://openid.net/wordpress-content/uploads/2015/09/RolandHedberg-pyoidc-0.7.7" "-Basic-26-Sept-2015.zip" ) _key_jar = build_keyjar(KEYSPEC, issuer_id=_entity_id) # Create the Signed JWT representing the Trust Mark _jwt0 = JWT(key_jar=_key_jar, iss=_entity_id, lifetime=3600) _jws = _jwt0.pack(_tm) # Unpack and verify the Trust Mark _jwt1 = JWT(key_jar=_key_jar, msg_cls=TrustMark, allowed_sign_algs=["RS256"]) res_tm = _jwt1.unpack(_jws) res_tm.verify(entity_id=_entity_id) assert isinstance(res_tm, TrustMark) assert res_tm["id"] == "https://openid.net/certification/op"