def test_userinfo_endpoint(): server = provider_init _session_db = {} cons = Consumer(_session_db, CONSUMER_CONFIG, CLIENT_CONFIG, server_info=SERVER_INFO) cons.debug = True cons.client_secret = "drickyoughurt" cons.config["response_type"] = ["token"] cons.config["request_method"] = "parameter" cons.keyjar[""] = KC_RSA state, location = cons.begin("openid", "token", path="http://localhost:8087") resp = server.authorization_endpoint(request=location.split("?")[1]) line = resp.message path, query = line.split("#") # redirect atr = AuthorizationResponse().deserialize(query, "urlencoded") uir = UserInfoRequest(access_token=atr["access_token"], schema="openid") resp3 = server.userinfo_endpoint(request=uir.to_urlencoded()) ident = OpenIDSchema().deserialize(resp3.message, "json") print ident.keys() assert _eq(ident.keys(), ['nickname', 'sub', 'name', 'email'])
def test_userinfo_endpoint(self): self.cons.client_secret = "drickyoughurt" self.cons.config["response_type"] = ["token"] self.cons.config["request_method"] = "parameter" state, location = self.cons.begin("openid", "token", path="http://localhost:8087") resp = self.server.authorization_endpoint( request=location.split("?")[1]) line = resp.message path, query = line.split("#") # redirect atr = AuthorizationResponse().deserialize(query, "urlencoded") uir = UserInfoRequest(access_token=atr["access_token"], schema="openid") resp3 = self.server.userinfo_endpoint(request=uir.to_urlencoded()) ident = OpenIDSchema().deserialize(resp3.message, "json") print ident.keys() assert _eq(ident.keys(), ['nickname', 'sub', 'name', 'email'])
def test_userinfo_endpoint(): server = provider_init _session_db = {} cons = Consumer(_session_db, CONSUMER_CONFIG, CLIENT_CONFIG, server_info=SERVER_INFO) cons.debug = True cons.client_secret = "drickyoughurt" cons.config["response_type"] = ["token"] cons.config["request_method"] = "parameter" cons.keyjar[""] = KC_RSA location = cons.begin("openid", "token", path="http://localhost:8087") resp = server.authorization_endpoint(request=location.split("?")[1]) line = resp.message path, query = line.split("?") # redirect atr = AuthorizationResponse().deserialize(query, "urlencoded") uir = UserInfoRequest(access_token=atr["access_token"], schema="openid") resp3 = server.userinfo_endpoint(request=uir.to_urlencoded()) ident = OpenIDSchema().deserialize(resp3.message, "json") print ident.keys() assert _eq(ident.keys(), ['nickname', 'sub', 'name', 'email']) assert ident["sub"] == USERDB["username"]["sub"]
def verify(self, **kwargs): if "jwt" in self: # Try to decode the JWT, checks the signature try: item = OpenIDSchema().from_jwt(str(self["jwt"]), kwargs["key"]) except Exception, _err: raise Exception(_err.__class__.__name__) if not item.verify(**kwargs): return False
def claims_info_endpoint(self, request, authn): _log_info = logger.info _log_info("Claims_info_endpoint query: '%s'" % sanitize(request)) ucreq = self.srvmethod.parse_userinfo_claims_request(request) # Access_token is mandatory in UserInfoClaimsRequest uiresp = OpenIDSchema(**self.info_store[ucreq["access_token"]]) _log_info("returning: %s" % sanitize(uiresp.to_dict())) return Response(uiresp.to_json(), content="application/json")
def claims_info_endpoint(self, request, authn): _log_info = logger.info _log_info("Claims_info_endpoint query: '%s'" % sanitize(request)) ucreq = self.srvmethod.parse_userinfo_claims_request(request) # Bearer header or body access_token = bearer_auth(ucreq, authn) uiresp = OpenIDSchema(**self.info_store[access_token]) _log_info("returning: %s" % sanitize(uiresp.to_dict())) return Response(uiresp.to_json(), content="application/json")
def claims_info_endpoint(self, environ, start_response, *args): _log_info = logger.info query = get_or_post(environ) _log_info("Claims_info_endpoint query: '%s'" % query) _log_info("environ: %s" % environ) #ucreq = self.srvmethod.parse_userinfo_claims_request(query) #_log_info("request: %s" % ucreq) # Supposed to be "Bearer <access_token> access_token = self._bearer_auth(environ) uiresp = OpenIDSchema(**self.info_store[access_token]) resp = Response(uiresp.to_json(), content="application/json") return resp(environ, start_response)
def test_userinfo_endpoint_authn(self): self.cons.client_secret = "drickyoughurt" self.cons.config["response_type"] = ["token"] self.cons.config["request_method"] = "parameter" state, location = self.cons.begin("openid", "token", path="http://localhost:8087") resp = self.provider.authorization_endpoint(request=urlparse(location).query) # redirect atr = AuthorizationResponse().deserialize(urlparse(resp.message).fragment, "urlencoded") uir = UserInfoRequest(schema="openid") resp = self.provider.userinfo_endpoint(request=uir.to_urlencoded(), authn="Bearer " + atr["access_token"]) ident = OpenIDSchema().deserialize(resp.message, "json") assert _eq(ident.keys(), ["nickname", "sub", "name", "email"])
def test_configurable_userinfo_endpoint_method_is_used(self, method): state = 'state' nonce = 'nonce' sub = 'foobar' authn = OIDCAuthentication( self.app, provider_configuration_info={ 'issuer': ISSUER, 'token_endpoint': '/token' }, client_registration_info={'client_id': 'foo'}, userinfo_endpoint_method=method) authn.client.do_access_token_request = MagicMock( return_value=AccessTokenResponse( **{ 'id_token': IdToken(**{ 'sub': sub, 'nonce': nonce }), 'access_token': 'access_token' })) userinfo_request_mock = MagicMock(return_value=OpenIDSchema( **{'sub': sub})) authn.client.do_user_info_request = userinfo_request_mock with self.app.test_request_context('/redirect_uri?code=foo&state=' + state): flask.session['state'] = state flask.session['nonce'] = nonce flask.session['destination'] = '/' authn._handle_authentication_response() userinfo_request_mock.assert_called_with(method=method, state=state)
def handle_userinfo_request(self, request=None, http_headers=None): # type: (Optional[str], Optional[Mapping[str, str]]) -> oic.oic.message.OpenIDSchema """ Handles a userinfo request. :param request: urlencoded request (either query string or POST body) :param http_headers: http headers """ if http_headers is None: http_headers = {} userinfo_request = dict(parse_qsl(request)) bearer_token = extract_bearer_token_from_http_request( userinfo_request, http_headers.get('Authorization')) introspection = self.authz_state.introspect_access_token(bearer_token) if not introspection['active']: raise InvalidAccessToken('The access token has expired') scope = introspection['scope'] user_id = self.authz_state.get_user_id_for_subject_identifier( introspection['sub']) requested_claims = scope2claims(scope.split()) authentication_request = self.authz_state.get_authorization_request_for_access_token( bearer_token) requested_claims.update( self._get_requested_claims_in(authentication_request, 'userinfo')) user_claims = self.userinfo.get_claims_for(user_id, requested_claims) user_claims.setdefault('sub', introspection['sub']) response = OpenIDSchema(**user_claims) logger.debug('userinfo=%s from requested_claims=%s userinfo=%s', response, requested_claims, user_claims) return response
def test_full_flow(self, context, frontend_with_extra_scopes): redirect_uri = "https://client.example.com/redirect" response_type = "code id_token token" mock_callback = Mock() frontend_with_extra_scopes.auth_req_callback_func = mock_callback # discovery http_response = frontend_with_extra_scopes.provider_config(context) provider_config = ProviderConfigurationResponse().deserialize(http_response.message, "json") # client registration registration_request = RegistrationRequest(redirect_uris=[redirect_uri], response_types=[response_type]) context.request = registration_request.to_dict() http_response = frontend_with_extra_scopes.client_registration(context) registration_response = RegistrationResponse().deserialize(http_response.message, "json") # authentication request authn_req = AuthorizationRequest( redirect_uri=redirect_uri, client_id=registration_response["client_id"], response_type=response_type, scope="openid email eduperson", state="state", nonce="nonce", ) context.request = dict(parse_qsl(authn_req.to_urlencoded())) frontend_with_extra_scopes.handle_authn_request(context) assert mock_callback.call_count == 1 # fake authentication response from backend internal_response = self.setup_for_authn_response( context, frontend_with_extra_scopes, authn_req ) http_response = frontend_with_extra_scopes.handle_authn_response( context, internal_response ) authn_resp = AuthorizationResponse().deserialize(urlparse(http_response.message).fragment, "urlencoded") assert "code" in authn_resp assert "access_token" in authn_resp assert "id_token" in authn_resp # token request context.request = AccessTokenRequest(redirect_uri=authn_req["redirect_uri"], code=authn_resp["code"]).to_dict() credentials = "{}:{}".format(registration_response["client_id"], registration_response["client_secret"]) basic_auth = urlsafe_b64encode(credentials.encode("utf-8")).decode("utf-8") context.request_authorization = "Basic {}".format(basic_auth) http_response = frontend_with_extra_scopes.token_endpoint(context) parsed = AccessTokenResponse().deserialize(http_response.message, "json") assert "access_token" in parsed assert "id_token" in parsed # userinfo request context.request = {} context.request_authorization = "Bearer {}".format(parsed["access_token"]) http_response = frontend_with_extra_scopes.userinfo_endpoint(context) parsed = OpenIDSchema().deserialize(http_response.message, "json") assert "email" in parsed assert "eduperson_principal_name" in parsed assert "eduperson_scoped_affiliation" in parsed
def __call__(self, request): data = request.body self.provider.parse_user_info_request(data) _info = { 'sub': 'test-sub', 'name': 'Test User', 'nickname': 'Tester', 'email': '*****@*****.**', 'verified': True, } resp = OpenIDSchema(**_info) userinfo = resp.to_json() return (200, {'Content-Type': 'application/json'}, userinfo)
def test_userinfo_endpoint(): server = provider_init _session_db = {} cons = Consumer(_session_db, CONSUMER_CONFIG, CLIENT_CONFIG, server_info=SERVER_INFO) cons.debug = True cons.client_secret = "drickyoughurt" cons.config["response_type"] = ["token"] cons.config["request_method"] = "parameter" cons.keyjar[""] = KC_RSA environ = BASE_ENVIRON location = cons.begin(environ, start_response) environ = BASE_ENVIRON.copy() environ["QUERY_STRING"] = location.split("?")[1] resp = server.authorization_endpoint(environ, start_response) sid = resp[0][len("<form>"):-len("</form>")] environ2 = create_return_form_env("user", "password", sid) resp2 = server.authenticated(environ2, start_response) line = resp2[0] start = line.index("<title>") start += len("<title>Redirecting to ") stop = line.index("</title>") path, query = line[start:stop].split("?") # redirect atr = AuthorizationResponse().deserialize(query, "urlencoded") uir = UserInfoRequest(access_token=atr["access_token"], schema="openid") environ = BASE_ENVIRON.copy() environ["QUERY_STRING"] = uir.to_urlencoded() resp3 = server.userinfo_endpoint(environ, start_response) ident = OpenIDSchema().deserialize(resp3[0], "json") print ident.keys() assert _eq(ident.keys(), ['nickname', 'sub', 'name', 'email']) assert ident["sub"] == USERDB["user"]["sub"]
def test_userinfo_endpoint(self, context, frontend, authn_req): user_id = "user1" self.insert_client_in_client_db(frontend, authn_req["redirect_uri"]) self.insert_user_in_user_db(frontend, user_id) authn_req["scope"] = "openid email" token = self.create_access_token(frontend, user_id, authn_req) context.request = {} context.request_authorization = "Bearer {}".format(token) response = frontend.userinfo_endpoint(context) parsed = OpenIDSchema().deserialize(response.message, "json") assert parsed["email"] == "*****@*****.**"
def test_userinfo_endpoint_authn(self): self.cons.client_secret = "drickyoughurt" self.cons.config["response_type"] = ["token"] self.cons.config["request_method"] = "parameter" state, location = self.cons.begin("openid", "token", path="http://localhost:8087") resp = self.provider.authorization_endpoint( request=urlparse(location).query) # redirect atr = AuthorizationResponse().deserialize( urlparse(resp.message).fragment, "urlencoded") uir = UserInfoRequest(schema="openid") resp = self.provider.userinfo_endpoint(request=uir.to_urlencoded(), authn='Bearer ' + atr[ 'access_token']) ident = OpenIDSchema().deserialize(resp.message, "json") assert _eq(ident.keys(), ['nickname', 'sub', 'name', 'email'])
def test_userinfo_endpoint(self): self.cons.client_secret = "drickyoughurt" self.cons.config["response_type"] = ["token"] self.cons.config["request_method"] = "parameter" state, location = self.cons.begin("openid", "token", path="http://localhost:8087") resp = self.server.authorization_endpoint(request=location.split("?")[1]) line = resp.message path, query = line.split("#") # redirect atr = AuthorizationResponse().deserialize(query, "urlencoded") uir = UserInfoRequest(access_token=atr["access_token"], schema="openid") resp3 = self.server.userinfo_endpoint(request=uir.to_urlencoded()) ident = OpenIDSchema().deserialize(resp3.message, "json") print ident.keys() assert _eq(ident.keys(), ['nickname', 'sub', 'name', 'email'])
def user_info(oicsrv, userdb, sub, client_id="", user_info_claims=None): identity = userdb[sub] if user_info_claims: result = {} for key, restr in user_info_claims["claims"].items(): try: result[key] = identity[key] except KeyError: if restr == {"essential": True}: raise Exception("Missing property '%s'" % key) else: result = identity return OpenIDSchema(**result)
def userinfo_endpoint(self, data): self.parse_user_info_request(data) _info = { "sub": "melgar", "name": "Melody Gardot", "nickname": "Mel", "email": "*****@*****.**", "verified": True, } resp = OpenIDSchema(**_info) response = Response() if self.userinfo_signed_response_alg: alg = self.userinfo_signed_response_alg response.headers = {"content-type": "application/jwt"} key = self.keyjar.get_signing_key(alg2keytype(alg), "", alg=alg) response.text = resp.to_jwt(key, alg) else: response.headers = {"content-type": "application/json"} response.text = resp.to_json() return response
def userinfo_endpoint(self, data): _ = self.parse_user_info_request(data) _info = { "sub": "melgar", "name": "Melody Gardot", "nickname": "Mel", "email": "*****@*****.**", "verified": True, } resp = OpenIDSchema(**_info) response = Response() if self.userinfo_signed_response_alg: alg = self.userinfo_signed_response_alg response.headers = {"content-type": "application/jwt"} key = self.keyjar.get_signing_key(alg2keytype(alg), "", alg=alg) response.text = resp.to_jwt(key, alg) else: response.headers = {"content-type": "application/json"} response.text = resp.to_json() return response
def test_userinfo_endpoint_with_extra_scopes( self, context, frontend_with_extra_scopes, authn_req_with_extra_scopes ): user_id = USERS["testuser1"]["eduPersonTargetedID"][0] self.insert_client_in_client_db( frontend_with_extra_scopes, authn_req_with_extra_scopes["redirect_uri"] ) self.insert_user_in_user_db(frontend_with_extra_scopes, user_id) token = self.create_access_token( frontend_with_extra_scopes, user_id, authn_req_with_extra_scopes ) context.request = {} context.request_authorization = "Bearer {}".format(token) response = frontend_with_extra_scopes.userinfo_endpoint(context) parsed = OpenIDSchema().deserialize(response.message, "json") assert parsed["email"] == "*****@*****.**" # TODO assert parsed["eduperson_scoped_affiliation"] == ["*****@*****.**"] assert parsed["eduperson_principal_name"] == ["*****@*****.**"]
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")
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 make_userinfo_request(self, access_token): resp = self.app.test_client().get('/userinfo', headers={'Authorization': 'Bearer {}'.format(access_token)}) assert resp.status_code == 200 userinfo = OpenIDSchema().from_json(resp.data.decode('utf-8')) userinfo.verify() return userinfo
def trace_output(lines, index, end): cont = False seq = [] _cls = None _data = [] _sent = {} _recv = {} phase = "" while index < end: line = lines[index] if cont: if line == "}": _data.append(line) cont = False _args = json.loads("".join(_data)) if _cls == "JWKS": try: _inst = jwks_load("".join(_data)) except TypeError: pass elif _cls == "UserInfo": _int = Message(**_args) try: _inst = OpenIDSchema(**_int["claims"]) except KeyError: _inst = OpenIDSchema(**_args) else: try: _inst.jwe_header = _int["jwe header parameters"] except KeyError: pass try: _inst.jws_header = _int["jws header parameters"] except KeyError: pass else: try: _inst = oic_factory(_cls)(**_args) except KeyError: _inst = oauth2_factory(_cls)(**args) seq.append((_cls, _inst)) else: _data.append(line) index += 1 continue if line == DIV: break elif line == "Trace output" or line == "": pass else: for phase in ORDER: m = PATTERN[phase].match(line) if m: if phase == "head": seq.append(m.groups()[0]) elif phase == "sent": key, val = m.groups() _sent[key] = val elif phase == "recv": key, val = m.groups() _recv[key] = val elif phase == "quer": _recv["QUERY"] = m.groups()[0] phase = "recv" elif phase == "data": m = DATA.match(line) cont = True _cls = m.groups()[0] _data = ['{'] elif phase == "tag": seq.append(("info", m.groups()[0])) if phase in ["head", "data", "end"]: if _sent: seq.append(("sent", _sent)) _sent = {} if _recv: seq.append(("recv", _recv)) _recv = {} break if phase == "end": break index += 1 return index, seq
def test_claim_not_booleans(json_param): with pytest.raises(MessageException): OpenIDSchema().from_json(json_param)
def userinfo_endpoint(self, request="", **kwargs): """ :param request: The request in a string format """ try: _log_debug = kwargs["logger"].debug _log_info = kwargs["logger"].info except KeyError: _log_debug = logger.debug _log_info = logger.info _sdb = self.sdb if not request or "access_token" not in request: _token = kwargs["authn"] assert _token.startswith("Bearer ") _token = _token[len("Bearer "):] logger.debug("Bearer token: '%s'" % _token) else: uireq = self.server.parse_user_info_request(data=request) logger.debug("user_info_request: %s" % uireq) _token = uireq["access_token"] # should be an access token typ, key = _sdb.token.type_and_key(_token) _log_debug("access_token type: '%s'" % (typ,)) try: assert typ == "T" except AssertionError: raise FailedAuthentication("Wrong type of token") #_log_info("keys: %s" % self.sdb.keys()) if _sdb.is_revoked(key): return self._error(error="access_denied", descr="Token is revoked") session = _sdb[key] # Scope can translate to userinfo_claims info = OpenIDSchema(**self._collect_user_info(session)) # Should I return a JSON or a JWT ? _cinfo = self.cdb[session["client_id"]] if "userinfo_signed_response_alg" in _cinfo: algo = _cinfo["userinfo_signed_response_alg"] # Use my key for signing key = self.keyjar.get_signing_key(alg2keytype(algo), "") jinfo = info.to_jwt(key, algo) content_type = "application/jwt" if "userinfo_encrypted_response_alg" in _cinfo: # encrypt with clients public key jinfo = self.encrypt(jinfo, _cinfo, session["client_id"], "userinfo") elif "userinfo_encrypted_response_alg" in _cinfo: jinfo = self.encrypt(info.to_json(), _cinfo, session["client_id"], "userinfo") content_type = "application/jwt" else: jinfo = info.to_json() content_type = "application/json" return Response(jinfo, content=content_type)
def test_claim_not_booleans(json_param): with pytest.raises(ValueError): OpenIDSchema().from_json(json_param)
def test_claim_booleans(json_param): assert OpenIDSchema().from_json(json_param)
def test_openidschema_from_json(json_param): with pytest.raises(ValueError): OpenIDSchema().from_json(json_param)
def test_openidschema(): inp = '{"middle_name":null, "updated_at":"20170328081544", "sub":"abc"}' ois = OpenIDSchema().from_json(inp) assert ois.verify() is False
def test_openidschema_from_json(json_param): with pytest.raises(MessageException): OpenIDSchema().from_json(json_param)