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 _pre_construct(self, response_args, request, **kwargs): _context = self.endpoint_context _access_code = request["code"].replace(' ', '+') _info = _context.sdb[_access_code] _authn_req = _info['authn_req'] try: _client_id = request['client_id'] except KeyError: _client_id = _authn_req['client_id'] if "openid" in _authn_req["scope"]: userinfo = userinfo_in_id_token_claims(_context, _info) try: _idtoken = sign_encrypt_id_token(_context, _info, str(_client_id), user_info=userinfo) except (JWEException, NoSuitableSigningKeys) as err: logger.warning(str(err)) return self.error_cls( error="invalid_request", error_description="Could not sign/encrypt id_token") _context.sdb.update_by_token(_access_code, id_token=_idtoken) response_args['id_token'] = _idtoken return response_args
def create_authn_response(endpoint_context, request, sid): # create the response aresp = AuthorizationResponse() try: aresp["state"] = request["state"] except KeyError: pass if "response_type" in request and request["response_type"] == ["none"]: fragment_enc = False else: _sinfo = endpoint_context.sdb[sid] try: aresp["scope"] = request["scope"] except KeyError: pass rtype = set(request["response_type"][:]) handled_response_type = [] if len(rtype) == 1 and "code" in rtype: fragment_enc = False else: fragment_enc = True if "code" in request["response_type"]: _code = aresp["code"] = endpoint_context.sdb[sid]["code"] handled_response_type.append("code") else: endpoint_context.sdb.update(sid, code=None) _code = None if "token" in rtype: _dic = endpoint_context.sdb.upgrade_to_token(issue_refresh=False, key=sid) logger.debug("_dic: %s" % sanitize(_dic)) for key, val in _dic.items(): if key in aresp.parameters() and val is not None: aresp[key] = val handled_response_type.append("token") try: _access_token = aresp["access_token"] except KeyError: _access_token = None if "id_token" in request["response_type"]: user_info = userinfo_in_id_token_claims(endpoint_context, _sinfo) if request["response_type"] == ["id_token"]: # scopes should be returned here info = collect_user_info(endpoint_context, _sinfo) if user_info is None: user_info = info else: user_info.update(info) # client_info = endpoint_context.cdb[str(request["client_id"])] hargs = {} if {'code', 'id_token', 'token'}.issubset(rtype): hargs = {"code": _code, "access_token": _access_token} elif {'code', 'id_token'}.issubset(rtype): hargs = {"code": _code} elif {'id_token', 'token'}.issubset(rtype): hargs = {"access_token": _access_token} # or 'code id_token' try: id_token = sign_encrypt_id_token(endpoint_context, _sinfo, str(request["client_id"]), user_info=user_info, sign=True, **hargs) except (JWEException, NoSuitableSigningKeys) as err: logger.warning(str(err)) return AuthorizationErrorResponse( error="invalid_request", error_description="Could not sign/encrypt id_token") aresp["id_token"] = id_token _sinfo["id_token"] = id_token handled_response_type.append("id_token") not_handled = rtype.difference(handled_response_type) if not_handled: raise UnSupported("unsupported_response_type", list(not_handled)) return {'response_args': aresp, 'fragment_enc': fragment_enc}
def _access_token(self, req, **kwargs): _context = self.endpoint_context _sdb = _context.sdb _log_debug = logger.debug if req["grant_type"] != "authorization_code": return self.error_cls(error='invalid_request', error_description='Unknown grant_type') try: _access_code = req["code"].replace(' ', '+') except KeyError: # Missing code parameter - absolutely fatal return self.error_cls(error='invalid_request', error_description='Missing code') # Session might not exist or _access_code malformed try: _info = _sdb[_access_code] except KeyError: return self.error_cls(error="invalid_request", error_description="Code is invalid") _authn_req = _info['authn_req'] # assert that the code is valid if _context.sdb.is_session_revoked(_access_code): return self.error_cls(error="invalid_request", error_description="Session is revoked") # If redirect_uri was in the initial authorization request # verify that the one given here is the correct one. if "redirect_uri" in _authn_req: if req["redirect_uri"] != _authn_req["redirect_uri"]: return self.error_cls(error="invalid_request", error_description="redirect_uri mismatch") _log_debug("All checks OK") issue_refresh = False if "issue_refresh" in kwargs: issue_refresh = kwargs["issue_refresh"] # offline_access the default if nothing is specified permissions = _info.get('permission', ['offline_access']) if 'offline_access' in _authn_req['scope'] and 'offline_access' in permissions: issue_refresh = True try: _info = _sdb.upgrade_to_token(_access_code, issue_refresh=issue_refresh) except AccessCodeUsed as err: logger.error("%s" % err) # Should revoke the token issued to this access code _sdb.revoke_all_tokens(_access_code) return self.error_cls(error="access_denied", error_description="Access Code already used") if "openid" in _authn_req["scope"]: userinfo = userinfo_in_id_token_claims(_context, _info) try: _client_id = req['client_id'] except KeyError: _client_id = _authn_req['client_id'] try: _idtoken = sign_encrypt_id_token(_context, _info, _client_id, sign=True, user_info=userinfo) except (JWEException, NoSuitableSigningKeys) as err: logger.warning(str(err)) return self.error_cls( error="invalid_request", error_description="Could not sign/encrypt id_token") _sdb.update_by_token(_access_code, id_token=_idtoken) _info = _sdb[_access_code] return by_schema(AccessTokenResponse, **_info)