def test_parse_open_id_request(self): userinfo_claims = Claims(name={"essential": True}, nickname=None, email={"essential": True}, email_verified={"essential": True}, picture=None) id_token_claims = Claims(auth_time={ "essential": True, "acr": { "values": ["urn:mace:incommon:iap:silver"] } }) claims_req = ClaimsRequest(userinfo=userinfo_claims, id_token=id_token_claims) oidreq = OpenIDRequest(response_type=["code", "id_token"], client_id=CLIENT_ID, redirect_uri="https://client.example.com/cb", scope="openid profile", state="n-0S6_WzA2Mj", nonce="af0ifjsldkj", max_age=86400, claims=claims_req) request = self.srv.parse_open_id_request(data=oidreq.to_json(), sformat="json") assert isinstance(request, OpenIDRequest) assert _eq(request.keys(), [ 'nonce', 'claims', 'state', 'redirect_uri', 'response_type', 'client_id', 'scope', 'max_age' ]) assert request["nonce"] == "af0ifjsldkj" assert "email" in request["claims"]["userinfo"]
def test_claims_ser_json(): claims = Claims(name={"essential": True}, nickname=None, email={"essential": True}, email_verified={"essential": True}, picture=None) claims = claims_deser(claims_ser(claims, "json"), sformat="json") assert _eq(claims.keys(), ['name', 'nickname', 'email', 'email_verified', 'picture'])
def test_get_approved_attributes(self, frontend): claims_req = ClaimsRequest(id_token=Claims(email=None), userinfo=Claims(userinfo_claim=None)) req = AuthorizationRequest(scope="openid profile", claims=claims_req) provider_supported_claims = ["email", "name", "given_name", "family_name", "userinfo_claim", "extra_claim"] result = frontend._get_approved_attributes(provider_supported_claims, req) assert Counter(result) == Counter(["email", "name", "given_name", "family_name", "userinfo_claim"])
def test_openid_request_with_request_1(self): claims = { "name": { "essential": True }, "nickname": None, "email": { "essential": True }, "verified": { "essential": True }, "picture": None } areq = self.client.construct_AuthorizationRequest( request_args={ "scope": "openid", "response_type": ["code"], "claims": ClaimsRequest(userinfo=Claims(**claims), id_token=Claims(auth_time=None, acr={"values": ["2"]})), "max_age": 86400, }, request_param="request") print areq.to_dict() assert areq assert "request" in areq
def test_with_multiple_requested_sub(self): self.authn_request_args['claims'] = ClaimsRequest( userinfo=Claims(sub={'value': 'nomatch1'}), id_token=Claims(sub={'value': 'nomatch2'})) auth_req = AuthorizationRequest().from_dict(self.authn_request_args) with pytest.raises(AuthorizationError) as exc: self.provider.authorize(auth_req, TEST_USER_ID) assert 'different' in str(exc.value)
def test_claims_ser_json(): claims = Claims( name={"essential": True}, nickname=None, email={"essential": True}, email_verified={"essential": True}, picture=None, ) claims = claims_deser(claims_ser(claims, "json"), sformat="json") assert _eq(claims.keys(), ["name", "nickname", "email", "email_verified", "picture"])
def test_claims_deser(): pre = Claims(name={"essential": True}, nickname=None, email={"essential": True}, email_verified={"essential": True}, picture=None) claims = claims_deser(pre.to_json(), format="json") assert _eq(claims.keys(), ['name', 'nickname', 'email', 'email_verified', 'picture']) claims = claims_deser(pre.to_dict(), format="dict") assert _eq(claims.keys(), ['name', 'nickname', 'email', 'email_verified', 'picture'])
def _collect_user_info(self, session, userinfo_claims=None): """ Collect information about a user. This can happen in two cases, either when constructing an IdToken or when returning user info through the UserInfo endpoint :param session: Session information :param userinfo_claims: user info claims :return: User info """ if userinfo_claims is None: uic = {} for scope in session["scope"]: try: claims = dict([(name, None) for name in SCOPE2CLAIMS[scope]]) uic.update(claims) except KeyError: pass if "oidreq" in session: oidreq = OpenIDRequest().deserialize(session["oidreq"], "json") logger.debug("OIDREQ: %s" % oidreq.to_dict()) try: _claims = oidreq["claims"]["userinfo"] except KeyError: pass else: for key, val in uic.items(): if key not in _claims: _claims[key] = val uic = _claims if uic: userinfo_claims = Claims(**uic) else: userinfo_claims = None elif uic: userinfo_claims = Claims(**uic) else: userinfo_claims = None logger.debug("userinfo_claim: %s" % userinfo_claims.to_dict()) logger.debug("Session info: %s" % session) info = self.userinfo(session["local_sub"], userinfo_claims) info["sub"] = session["sub"] logger.debug("user_info_response: %s" % (info,)) return info
def authorize(user): if user.orcid is None: proofing_state = current_app.proofing_statedb.get_state_by_eppn(user.eppn, raise_on_missing=False) if not proofing_state: current_app.logger.debug( 'No proofing state found for user {!s}. Initializing new proofing state.'.format(user) ) proofing_state = OrcidProofingState( id=None, modified_ts=None, eppn=user.eppn, state=get_unique_hash(), nonce=get_unique_hash() ) current_app.proofing_statedb.save(proofing_state) claims_request = ClaimsRequest(userinfo=Claims(id=None)) oidc_args = { 'client_id': current_app.oidc_client.client_id, 'response_type': 'code', 'scope': 'openid', 'claims': claims_request.to_json(), 'redirect_uri': url_for('orcid.authorization_response', _external=True), 'state': proofing_state.state, 'nonce': proofing_state.nonce, } authorization_url = '{}?{}'.format(current_app.oidc_client.authorization_endpoint, urlencode(oidc_args)) current_app.logger.debug('Authorization url: {!s}'.format(authorization_url)) current_app.stats.count(name='authn_request') return redirect(authorization_url) # Orcid already connected to user redirect_url = current_app.config.orcid_verify_redirect_url return redirect_with_msg(redirect_url, OrcidMsg.already_connected)
def freja_proofing(user, nin): proofing_state = current_app.proofing_statedb.get_state_by_eppn( user.eppn, raise_on_missing=False) if not proofing_state: current_app.logger.debug( 'No proofing state found for user {!s}. Initializing new proofing flow.' .format(user)) proofing_state = helpers.create_proofing_state(user, nin) # Initiate authn request try: redirect_url = url_for('oidc_proofing.authorization_response', _external=True) claims_request = ClaimsRequest(userinfo=Claims(results=None)) success = helpers.do_authn_request(proofing_state, claims_request, redirect_url) if not success: current_app.stats.count(name='freja.authn_request_op_error') return error_response(message=CommonMsg.temp_problem) except requests.exceptions.ConnectionError as e: current_app.logger.error( 'No connection to authorization endpoint: {!s}'.format(e)) return error_response(message=OIDCMsg.no_conn) # If authentication request went well save user state current_app.stats.count(name='freja.authn_request_success') current_app.proofing_statedb.save(proofing_state) current_app.logger.debug( 'Proofing state {!s} for user {!s} saved'.format( proofing_state.state, user)) # Add the nin used to initiate the proofing state to the user # NOOP if the user already have the nin add_nin_to_user(user, proofing_state) return get_freja_state()
def test_include_userinfo_claims_request_with_response_type_id_token(self): self.authn_request_args['claims'] = ClaimsRequest(userinfo=Claims( nickname=None)).to_json() self.provider.clients[TEST_CLIENT_ID]['response_types'] = ['id_token'] self.authn_request_args['response_type'] = 'id_token' with pytest.raises(InvalidAuthenticationRequest): self.provider.parse_authentication_request( urlencode(self.authn_request_args))
def authn_req(self): state = "my_state" nonce = "nonce" redirect_uri = "https://client.example.com" claims_req = ClaimsRequest(id_token=Claims(email=None)) req = AuthorizationRequest(client_id=CLIENT_ID, state=state, scope="openid", response_type="id_token", redirect_uri=redirect_uri, nonce=nonce, claims=claims_req) return req
def test_full_flow(self, satosa_config_dict, oidc_frontend_config, saml_backend_config, idp_conf): subject_id = "testuser1" # proxy config satosa_config_dict["FRONTEND_MODULES"] = [oidc_frontend_config] satosa_config_dict["BACKEND_MODULES"] = [saml_backend_config] satosa_config_dict["INTERNAL_ATTRIBUTES"]["attributes"] = {attr_name: {"openid": [attr_name], "saml": [attr_name]} for attr_name in USERS[subject_id]} _, backend_metadata = create_entity_descriptors(SATOSAConfig(satosa_config_dict)) # application test_client = Client(make_app(SATOSAConfig(satosa_config_dict)), Response) # get frontend OP config info provider_config = json.loads(test_client.get("/.well-known/openid-configuration").data.decode("utf-8")) # create auth req claims_request = ClaimsRequest(id_token=Claims(**{k: None for k in USERS[subject_id]})) req_args = {"scope": "openid", "response_type": "id_token", "client_id": CLIENT_ID, "redirect_uri": REDIRECT_URI, "nonce": "nonce", "claims": claims_request.to_json()} auth_req = urlparse(provider_config["authorization_endpoint"]).path + "?" + urlencode(req_args) # make auth req to proxy proxied_auth_req = test_client.get(auth_req) assert proxied_auth_req.status == "303 See Other" # config test IdP backend_metadata_str = str(backend_metadata[saml_backend_config["name"]][0]) idp_conf["metadata"]["inline"].append(backend_metadata_str) fakeidp = FakeIdP(USERS, config=IdPConfig().load(idp_conf)) # create auth resp req_params = dict(parse_qsl(urlparse(proxied_auth_req.data.decode("utf-8")).query)) url, authn_resp = fakeidp.handle_auth_req( req_params["SAMLRequest"], req_params["RelayState"], BINDING_HTTP_REDIRECT, subject_id, response_binding=BINDING_HTTP_REDIRECT) # make auth resp to proxy authn_resp_req = urlparse(url).path + "?" + urlencode(authn_resp) authn_resp = test_client.get(authn_resp_req) assert authn_resp.status == "303 See Other" # verify auth resp from proxy resp_dict = dict(parse_qsl(urlparse(authn_resp.data.decode("utf-8")).fragment)) signing_key = RSAKey(key=rsa_load(oidc_frontend_config["config"]["signing_key_path"]), use="sig", alg="RS256") id_token_claims = JWS().verify_compact(resp_dict["id_token"], keys=[signing_key]) assert all( (name, values) in id_token_claims.items() for name, values in OIDC_USERS[subject_id].items() )
def make_openid_request(arq, keys=None, userinfo_claims=None, idtoken_claims=None, algorithm=None, **kwargs): """ Construct the specification of what I want returned. The request will be signed :param arq: The Authorization request :param keys: Keys to use for signing/encrypting :param userinfo_claims: UserInfo claims :param idtoken_claims: IdToken claims :param algorithm: Which signing/encrypting algorithm to use :return: JWT encoded OpenID request """ oir_args = {} for prop in OpenIDRequest.c_param.keys(): try: oir_args[prop] = arq[prop] except KeyError: pass for attr in ["scope", "response_type"]: if attr in oir_args: oir_args[attr] = " ".join(oir_args[attr]) c_args = {} if userinfo_claims is not None: # UserInfoClaims c_args["userinfo"] = Claims(**userinfo_claims) if idtoken_claims is not None: #IdTokenClaims c_args["id_token"] = Claims(**idtoken_claims) if c_args: oir_args["claims"] = ClaimsRequest(**c_args) oir = OpenIDRequest(**oir_args) return oir.to_jwt(key=keys, algorithm=algorithm)
def test_claims_request_not_allowed_for_client(self): client_id = 'client1' provider = Mock() provider.clients = {client_id: {'allowed_claims': []}} auth_req = AuthorizationRequest( claims=ClaimsRequest(id_token=Claims(domain=None)), client_id=client_id) with pytest.raises(InvalidAuthenticationRequest): claims_request_is_valid_for_client(provider, auth_req)
def test_valid_claims_request_for_client(self): client_id = 'client1' provider = Mock() provider.clients = {client_id: {'allowed_claims': ['domain']}} auth_req = AuthorizationRequest( claims=ClaimsRequest(id_token=Claims(domain=None)), client_id=client_id) # should not raise an exception claims_request_is_valid_for_client(provider, auth_req)
def test_authorize_includes_requested_id_token_claims_even_if_token_request_can_be_made( self): self.authn_request_args['response_type'] = ['id_token', 'token'] self.authn_request_args['claims'] = ClaimsRequest(id_token=Claims( email=None)) auth_req = AuthorizationRequest().from_dict(self.authn_request_args) resp = self.provider.authorize(auth_req, TEST_USER_ID) id_token = assert_id_token_base_claims(resp['id_token'], self.provider.signing_key, self.provider, auth_req) assert id_token['email'] == self.provider.userinfo[TEST_USER_ID][ 'email']
def build_userinfo_claims(claims, sformat="signed", locale="us-en"): """ config example:: "userinfo":{ "name": {"essential": true}, "nickname": null, "email": {"essential": true}, "email_verified": {"essential": true}, "picture": null } """ return Claims(format=sformat, **claims)
def test_handle_userinfo_with_custom_sub(self, monkeypatch): sub = 'test_sub1' monkeypatch.setitem(self.provider.userinfo._db[TEST_USER_ID], 'sub', sub) claims_request = ClaimsRequest(userinfo=Claims(email=None)) access_token = self.create_access_token({ 'scope': 'openid profile', 'claims': claims_request }) response = self.provider.handle_userinfo_request( urlencode({'access_token': access_token})) assert response['sub'] == sub
def test_handle_userinfo(self): claims_request = ClaimsRequest(userinfo=Claims(email=None)) access_token = self.create_access_token({ 'scope': 'openid profile', 'claims': claims_request }) response = self.provider.handle_userinfo_request( urlencode({'access_token': access_token})) response_sub = response['sub'] del response['sub'] assert response.to_dict() == self.provider.userinfo[TEST_USER_ID] assert self.provider.authz_state.get_user_id_for_subject_identifier( response_sub) == TEST_USER_ID
def test_code_exchange_request_with_claims_requested_in_id_token(self): claims_req = {'claims': ClaimsRequest(id_token=Claims(email=None))} self.authorization_code_exchange_request_args[ 'code'] = self.create_authz_code(extra_auth_req_params=claims_req) response = self.provider._do_code_exchange( self.authorization_code_exchange_request_args, None) assert response[ 'access_token'] in self.provider.authz_state.access_tokens id_token = assert_id_token_base_claims(response['id_token'], self.provider.signing_key, self.provider, self.authn_request_args) assert id_token['email'] == self.provider.userinfo[TEST_USER_ID][ 'email']
def test_authorize_include_user_claims_from_scope_in_id_token_if_no_userinfo_req_can_be_made( self): self.authn_request_args['response_type'] = 'id_token' self.authn_request_args['scope'] = 'openid profile' self.authn_request_args['claims'] = ClaimsRequest(id_token=Claims( email={'essential': True})) auth_req = AuthorizationRequest().from_dict(self.authn_request_args) resp = self.provider.authorize(auth_req, TEST_USER_ID) id_token = IdToken().from_jwt(resp['id_token'], key=[self.provider.signing_key]) # verify all claims are part of the ID Token assert all( id_token[claim] == value for claim, value in self.provider.userinfo[TEST_USER_ID].items())
def get_state(**kwargs): eppn = mock_auth.authenticate(kwargs) current_app.logger.debug( 'Getting state for user with eppn {}.'.format(eppn)) proofing_state = current_app.proofing_statedb.get_state_by_eppn( eppn, raise_on_missing=False) if not proofing_state: current_app.logger.debug( 'No proofing state found, initializing new proofing flow.'.format( eppn)) state = get_unique_hash() nonce = get_unique_hash() token = get_unique_hash() proofing_state = OidcProofingState({ 'eduPersonPrincipalName': eppn, 'state': state, 'nonce': nonce, 'token': token }) claims_request = ClaimsRequest( userinfo=Claims(identity=None, vetting_time=None, metadata=None)) # Initiate proofing response = do_authentication_request(state, nonce, token, claims_request) if response.status_code != 200: payload = {'error': response.reason, 'message': response.content} raise ApiException(status_code=response.status_code, payload=payload) # If authentication request went well save user state current_app.proofing_statedb.save(proofing_state) current_app.logger.debug('Proofing state {} for user {} saved'.format( proofing_state.state, eppn)) # Return nonce and nonce as qr code current_app.logger.debug('Returning nonce for user {}'.format(eppn)) buf = BytesIO() qr_code = '1' + json.dumps({ 'nonce': proofing_state.nonce, 'token': proofing_state.token }) qrcode.make(qr_code).save(buf) qr_b64 = base64.b64encode(buf.getvalue()).decode() ret = { 'qr_code': qr_code, 'qr_img': '<img src="data:image/png;base64, {}"/>'.format(qr_b64), } return ret
def seleg_proofing(user, nin): proofing_state = current_app.proofing_statedb.get_state_by_eppn( user.eppn, raise_on_missing=False) if not proofing_state: current_app.logger.debug( 'No proofing state found for user {!s}. Initializing new proofing flow.' .format(user)) proofing_state = helpers.create_proofing_state(user, nin) # Initiate authn request try: redirect_url = url_for('oidc_proofing.authorization_response', _external=True) claims_request = ClaimsRequest(userinfo=Claims( identity=None, vetting_time=None, metadata=None)) success = helpers.do_authn_request(proofing_state, claims_request, redirect_url) if not success: current_app.stats.count(name='seleg.authn_request_op_error') return { '_status': 'error', 'message': 'Temporary technical problems' } except requests.exceptions.ConnectionError as e: current_app.logger.error( 'No connection to authorization endpoint: {!s}'.format(e)) return { '_status': 'error', 'message': 'No connection to authorization endpoint' } # If authentication request went well save user state current_app.stats.count(name='seleg.authn_request_success') current_app.proofing_statedb.save(proofing_state) current_app.logger.debug( 'Proofing state {!s} for user {!s} saved'.format( proofing_state.state, user)) # Add the nin used to initiate the proofing state to the user # NOOP if the user already have the nin add_nin_to_user(user, proofing_state) return get_seleg_state()
def login_shi(): session["state"] = rndstr() session["nonce"] = rndstr() claims_request = ClaimsRequest( userinfo=Claims( uiucedu_uin={"essential": True} ) ) args = { "client_id": client.client_id, "response_type": "code", "scope": Config.SCOPES, "claims": claims_request, "nonce": session["nonce"], "redirect_uri": client.registration_response["redirect_uris"][0], "state": session["state"] } auth_req = client.construct_AuthorizationRequest(request_args=args) login_url = auth_req.request(client.authorization_endpoint) return Redirect(login_url)
def claims_endpoint(self, request, http_authz, *args): _log_info = logger.info ucreq = self.srvmethod.parse_user_claims_request(request) _log_info("request: %s" % ucreq) try: resp = self.client_authn(self, ucreq, http_authz) except Exception as err: _log_info("Failed to verify client due to: %s" % err) resp = False if "claims_names" in ucreq: args = dict([(n, { "optional": True }) for n in ucreq["claims_names"]]) uic = Claims(**args) else: uic = None _log_info("User info claims: %s" % uic) #oicsrv, userdb, subject, client_id="", user_info_claims=None info = self.userinfo(ucreq["sub"], user_info_claims=uic, client_id=ucreq["client_id"]) _log_info("User info: %s" % info) # Convert to message format info = OpenIDSchema(**info) if self.do_aggregation(info, ucreq["sub"]): cresp = self._aggregation(info) else: cresp = self._distributed(info) _log_info("response: %s" % cresp.to_dict()) return Response(cresp.to_json(), content="application/json")
def login(): session['state'] = rndstr() session['nonce'] = rndstr() # setup claim request claims_request = ClaimsRequest( userinfo = Claims(uiucedu_uin={"essential": True}) ) args = { "client_id": client.client_id, "response_type": "code", "scope": app.config["SCOPES"], "nonce": session["nonce"], "redirect_uri": app.config["REDIRECT_URIS"][0], "state": session["state"], "claims": claims_request } auth_req = client.construct_AuthorizationRequest(request_args=args) login_url = auth_req.request(client.authorization_endpoint) return Redirect(login_url)
def get_authorization_url(client, state): args = { 'client_id': client.client_id, 'response_type': 'code', 'scope': 'openid', 'state': state, 'redirect_uri': client.registration_response['redirect_uris'][0], 'claims': ClaimsRequest(userinfo=Claims( given_name={'essential': True}, family_name={'essential': True}, email={'essential': True}, )), } auth_req = client.construct_AuthorizationRequest(request_args=args) return auth_req.request(client.provider_info['authorization_endpoint'])
def get_authorization_url(client, state): args = { "client_id": client.client_id, "response_type": "code", "scope": "openid", "state": state, "redirect_uri": client.registration_response["redirect_uris"][0], "claims": ClaimsRequest(userinfo=Claims( given_name={"essential": True}, family_name={"essential": True}, email={"essential": True}, )), } auth_req = client.construct_AuthorizationRequest(request_args=args) return auth_req.request(client.provider_info["authorization_endpoint"])
def begin(self, scope="", response_type="", use_nonce=False, path="", **kwargs): """ Begin the OIDC flow :param scope: Defines which user info claims is wanted :param response_type: Controls the parameters returned in the response from the Authorization Endpoint :param use_nonce: If not implicit flow nonce is optional. This defines if it should be used anyway. :param path: The path part of the redirect URL :return: A 2-tuple, session identifier and URL to which the user should be redirected """ _log_info = logger.info if self.debug: _log_info("- begin -") _page = self.config["authz_page"] if not path.endswith("/"): if _page.startswith("/"): self.redirect_uris = [path + _page] else: self.redirect_uris = ["%s/%s" % (path, _page)] else: if _page.startswith("/"): self.redirect_uris = [path + _page[1:]] else: self.redirect_uris = ["%s/%s" % (path, _page)] # Put myself in the dictionary of sessions, keyed on session-id if not self.seed: self.seed = rndstr() if not scope: scope = self.config["scope"] if not response_type: response_type = self.config["response_type"] sid = stateID(path, self.seed) self.grant[sid] = Grant(seed=self.seed) self._backup(sid) self.sdb["seed:%s" % self.seed] = sid args = { "client_id": self.client_id, "state": sid, "response_type": response_type, "scope": scope, } # nonce is REQUIRED in implicit flow, # OPTIONAL on code flow. if "token" in response_type or use_nonce: self.nonce = rndstr(12) args["nonce"] = self.nonce if "max_age" in self.config: args["max_age"] = self.config["max_age"] _claims = None if "user_info" in self.config: _claims = ClaimsRequest(userinfo=Claims( **self.config["user_info"])) if "id_token" in self.config: if _claims: _claims["id_token"] = Claims(**self.config["id_token"]) else: _claims = ClaimsRequest(id_token=Claims( **self.config["id_token"])) if _claims: args["claims"] = _claims if "request_method" in self.config: areq = self.construct_AuthorizationRequest(request_args=args, extra_args=None, request_param="request") if self.config["request_method"] == "file": id_request = areq["request"] del areq["request"] _filedir = self.config["temp_dir"] _webpath = self.config["temp_path"] _name = rndstr(10) filename = os.path.join(_filedir, _name) while os.path.exists(filename): _name = rndstr(10) filename = os.path.join(_filedir, _name) fid = open(filename, mode="w") fid.write(id_request) fid.close() _webname = "%s%s%s" % (path, _webpath, _name) areq["request_uri"] = _webname self.request_uri = _webname self._backup(sid) else: if "userinfo_claims" in args: # can only be carried in an IDRequest raise PyoidcError("Need a request method") areq = self.construct_AuthorizationRequest(AuthorizationRequest, request_args=args) location = areq.request(self.authorization_endpoint) if self.debug: _log_info("Redirecting to: %s" % location) return sid, location
class ClaimsServer(Provider): def __init__(self, name, sdb, cdb, userinfo, client_authn, urlmap=None, ca_certs="", keyjar=None, hostname="", dist_claims_mode=None): Provider.__init__(self, name, sdb, cdb, None, userinfo, None, client_authn, "", urlmap, ca_certs, keyjar, hostname) if keyjar is None: keyjar = KeyJar(ca_certs) for cid, _dic in cdb.items(): try: keyjar.add_symmetric(cid, _dic["client_secret"], ["sig", "ver"]) except KeyError: pass self.srvmethod = OICCServer(keyjar=keyjar) self.dist_claims_mode = dist_claims_mode self.info_store = {} self.claims_userinfo_endpoint = "" def _aggregation(self, info): jwt_key = self.keyjar.get_signing_key() cresp = UserClaimsResponse(jwt=info.to_jwt(key=jwt_key, algorithm="RS256"), claims_names=info.keys()) logger.info("RESPONSE: %s" % (cresp.to_dict(), )) return cresp #noinspection PyUnusedLocal def _distributed(self, info): # store the user info so it can be accessed later access_token = rndstr() self.info_store[access_token] = info return UserClaimsResponse(endpoint=self.claims_userinfo_endpoint, access_token=access_token, claims_names=info.keys()) #noinspection PyUnusedLocal def do_aggregation(self, info, uid): return self.dist_claims_mode.aggregate(uid, info) #noinspection PyUnusedLocal def claims_endpoint(self, request, http_authz, *args): _log_info = logger.info ucreq = self.srvmethod.parse_user_claims_request(request) _log_info("request: %s" % ucreq) try: resp = self.client_authn(self, ucreq, http_authz) except Exception, err: _log_info("Failed to verify client due to: %s" % err) resp = False if "claims_names" in ucreq: args = dict([(n, { "optional": True }) for n in ucreq["claims_names"]]) uic = Claims(**args) else: uic = None _log_info("User info claims: %s" % uic) #oicsrv, userdb, subject, client_id="", user_info_claims=None info = self.userinfo(ucreq["sub"], user_info_claims=uic, client_id=ucreq["client_id"]) _log_info("User info: %s" % info) # Convert to message format info = OpenIDSchema(**info) if self.do_aggregation(info, ucreq["sub"]): cresp = self._aggregation(info) else: cresp = self._distributed(info) _log_info("response: %s" % cresp.to_dict()) return Response(cresp.to_json(), content="application/json")
def get(self): self.create_client() # When we have a code, request id token if self.get_argument('code', False): response = self.request.query response = self.client.parse_response( AuthorizationResponse, info=response, sformat="urlencoded") # The query is checked against the state in the cookie code = response['code'] if 'code' in response else None state = response['state'] if 'state' in response else None cookie = self.get_secure_cookie(self.contest.name + "_auth") if code and cookie and json.loads(cookie)[0] == state: args = { "code": code, "token_endpoint": self.op_info["token_endpoint"], "redirect_uri": self.redirect_uri, } # Request an access token to the authentication server resp = yield self.get_access_token( state=state, request_args=args, authn_method="client_secret_basic" ) else: self.redirect_login_error() self.clear_cookie(self.contest.name + "_auth") # The token is checked against the nonce in the cookie id_token = resp["id_token"] if id_token["nonce"] != json.loads(cookie)[1]: self.redirect_login_error() first_name = ( id_token["given_name"] if "given_name" in id_token else "") last_name = ( id_token["family_name"] if "family_name" in id_token else "") email = ( id_token["email"] if "email" in id_token else "") username = id_token["sub"] # Check if the user already exists user = self.sql_session.query(User)\ .filter(User.username == username).first() # Create the user if it doesn't exist yet if user is None: user = User( first_name, last_name, username, email=email, password=build_password(generate_random_password())) self.sql_session.add(user) self.sql_session.commit() if not [p for p in user.participations if p.contest_id == self.contest.id]: participation = Participation( contest=self.contest, user=user) self.sql_session.add(participation) self.sql_session.commit() self.try_user_login(user) # Request a code else: state = rndstr() nonce = rndstr() self.set_secure_cookie( self.contest.name + "_auth", json.dumps([state, nonce]), expires_days=None) claims_request = ClaimsRequest( id_token=Claims( sub={"essential": True} ), userinfo=Claims( given_name={"essential": True}, family_name={"essential": True}, preferred_username={"essential": True}, ) ) args = { "client_id": self.client.client_id, "response_type": "code", "scope": ["openid", "offline_access"], "nonce": nonce, "redirect_uri": self.redirect_uri, "state": state, "claims": claims_request, } next_page = self.get_argument('next', None) if next_page: args["next"] = next_page auth_req = (self.client.construct_AuthorizationRequest (request_args=args)) login_url = auth_req.request( self.op_info["authorization_endpoint"]) self.redirect(login_url)