def _verify_redirect_uri(self, areq): # MUST NOT contain a fragment try: _redirect_uri = areq["redirect_uri"] part = urlparse.urlparse(_redirect_uri) if part.fragment: raise ValueError match = False for registered in self.cdb[areq["client_id"]]["redirect_uris"]: if _redirect_uri == registered: match=True break elif _redirect_uri.startswith(registered): match=True break if not match: raise AssertionError return None except Exception: logger.error("Faulty redirect_uri: %s" % areq["redirect_uri"]) logger.info("Registered redirect_uris: %s" % ( self.cdb[areq["client_id"]]["redirect_uris"],)) response = AuthorizationErrorResponse(error="invalid_request", error_description="Faulty redirect_uri") return Response(response.to_json(), content="application/json", status="400 Bad Request")
def _authz_error(self, error, descr=None): response = AuthorizationErrorResponse(error=error) if descr: response["error_description"] = descr return Response(response.to_json(), content="application/json", status="400 Bad Request")
def handle_backend_error(self, exception): """ See super class satosa.frontends.base.FrontendModule :type exception: satosa.exception.SATOSAError :rtype: oic.utils.http_util.Response """ auth_req = self._get_authn_request_from_state(exception.state) error_resp = AuthorizationErrorResponse(error="access_denied", error_description=exception.message) satosa_logging(logger, logging.DEBUG, exception.message, exception.state) return SeeOther(error_resp.request(auth_req["redirect_uri"], should_fragment_encode(auth_req)))
def handle_backend_error(self, exception): """ See super class satosa.frontends.base.FrontendModule :type exception: satosa.exception.SATOSAError :rtype: oic.utils.http_util.Response """ auth_req = self._get_authn_request_from_state(exception.state) error_resp = AuthorizationErrorResponse(error="access_denied", error_description=exception.message) satosa_logging(logger, logging.DEBUG, exception.message, exception.state) return SeeOther(error_resp.request(auth_req["redirect_uri"], should_fragment_encode(auth_req)))
def client_error_message(redirect_uri, error="access_denied", error_description="", state=""): """Construct an error response and send in fragment part of redirect_uri. :param redirect_uri: redirect_uri of the client :param error: OpenID Connect error code :param error_description: human readable description of the error """ error_resp = AuthorizationErrorResponse(error=error, error_description=error_description, state=state) location = error_resp.request(redirect_uri, True) raise cherrypy.HTTPRedirect(location)
def to_error_url(self): redirect_uri = self.request.get('redirect_uri') response_type = self.request.get('response_type') if redirect_uri and response_type and self.oauth_error: error_resp = AuthorizationErrorResponse( error=self.oauth_error, error_message=str(self), state=self.request.get('state')) return error_resp.request(redirect_uri, should_fragment_encode(self.request)) return None
def handle_backend_error(self, exception): """ See super class satosa.frontends.base.FrontendModule :type exception: satosa.exception.SATOSAError :rtype: oic.utils.http_util.Response """ auth_req = self._get_authn_request_from_state(exception.state) # If the client sent us a state parameter, we should reflect it back according to the spec if 'state' in auth_req: error_resp = AuthorizationErrorResponse(error="access_denied", error_description=exception.message, state=auth_req['state']) else: error_resp = AuthorizationErrorResponse(error="access_denied", error_description=exception.message) satosa_logging(logger, logging.DEBUG, exception.message, exception.state) return SeeOther(error_resp.request(auth_req["redirect_uri"], should_fragment_encode(auth_req)))
def handle_authn_response(self, context, internal_resp): auth_req = self._get_authn_request_from_state(context.state) affiliation_attribute = self.converter.from_internal( 'openid', internal_resp.attributes)['affiliation'] scope = auth_req['scope'] matching_affiliation = get_matching_affiliation( scope, affiliation_attribute) if matching_affiliation: return super().handle_authn_response( context, internal_resp, {'auth_time': internal_resp.auth_info.timestamp}) auth_error = AuthorizationErrorResponse(error='access_denied') del context.state[self.name] http_response = auth_error.request(auth_req['redirect_uri'], should_fragment_encode(auth_req)) return SeeOther(http_response)
def handle_authn_response(self, context, internal_resp): auth_req = self._get_authn_request_from_state(context.state) # User might not give us consent to release affiliation if 'affiliation' in internal_resp.attributes: affiliation_attribute = self.converter.from_internal('openid', internal_resp.attributes)['affiliation'] scope = auth_req['scope'] matching_affiliation = get_matching_affiliation(scope, affiliation_attribute) if matching_affiliation: return super().handle_authn_response(context, internal_resp, {'auth_time': internal_resp.auth_info.timestamp, 'requested_scopes': {'values': scope}}) # User's affiliation was not released or was not the one requested so return an error # If the client sent us a state parameter, we should reflect it back according to the spec if 'state' in auth_req: auth_error = AuthorizationErrorResponse(error='access_denied', state=auth_req['state']) else: auth_error = AuthorizationErrorResponse(error='access_denied') del context.state[self.name] http_response = auth_error.request(auth_req['redirect_uri'], should_fragment_encode(auth_req)) return SeeOther(http_response)
def handle_authn_response(self, context, internal_resp): auth_req = self._get_authn_request_from_state(context.state) resp_rp = auth_req.get('client_id') # User might not give us consent to release affiliation if 'affiliation' in internal_resp.attributes: affiliation_attribute = self.converter.from_internal('openid', internal_resp.attributes)['affiliation'] scope = auth_req['scope'] matching_affiliation = get_matching_affiliation(scope, affiliation_attribute) if matching_affiliation: transaction_log(context.state, self.config.get("response_exit_order", 1200), "inacademia_frontend", "response", "exit", "success", resp_rp , '', 'Responding successful validation to RP') return super().handle_authn_response(context, internal_resp, {'auth_time': parser.parse(internal_resp.auth_info.timestamp).timestamp(), 'requested_scopes': {'values': scope}}) # User's affiliation was not released or was not the one requested so return an error # If the client sent us a state parameter, we should reflect it back according to the spec transaction_log(context.state, self.config.get("response_exit_order", 1210), "inacademia_frontend", "response", "exit", "failed", resp_rp, '', ErrorDescription.REQUESTED_AFFILIATION_MISMATCH[LOG_MSG]) if 'state' in auth_req: auth_error = AuthorizationErrorResponse(error='access_denied', state=auth_req['state'], error_description=ErrorDescription.REQUESTED_AFFILIATION_MISMATCH[ ERROR_DESC]) else: auth_error = AuthorizationErrorResponse(error='access_denied', error_description=ErrorDescription.REQUESTED_AFFILIATION_MISMATCH[ ERROR_DESC]) del context.state[self.name] http_response = auth_error.request(auth_req['redirect_uri'], should_fragment_encode(auth_req)) return SeeOther(http_response)
def test_handle_backend_error(self, context, frontend): redirect_uri = "https://client.example.com" areq = AuthorizationRequest(client_id=CLIENT_ID, scope="openid", response_type="id_token", redirect_uri=redirect_uri) context.state[frontend.name] = {"oidc_request": areq.to_urlencoded()} # fake an error message = "test error" error = SATOSAAuthenticationError(context.state, message) resp = frontend.handle_backend_error(error) assert resp.message.startswith(redirect_uri) error_response = AuthorizationErrorResponse().deserialize(urlparse(resp.message).fragment) error_response["error"] = "access_denied" error_response["error_description"] == message
def test_handle_authn_response_returns_error_access_denied_for_wrong_affiliation( self, context, scope_value, affiliation): authn_req = AuthorizationRequest( scope='openid ' + scope_value, client_id='client1', redirect_uri='https://client.example.com', response_type='id_token') context.state[self.frontend.name] = { 'oidc_request': authn_req.to_urlencoded() } internal_response = InternalResponse() internal_response.attributes['affiliation'] = [affiliation] internal_response.user_id = 'user1' resp = self.frontend.handle_authn_response(context, internal_response) auth_resp = AuthorizationErrorResponse().from_urlencoded( urlparse(resp.message).fragment) assert auth_resp['error'] == 'access_denied'