created common method to check whether an api method should have auth w/ burnettk
This commit is contained in:
parent
c955335d0e
commit
94d50efb1f
|
@ -17,10 +17,10 @@ from flask_mail import Mail # type: ignore
|
||||||
import spiffworkflow_backend.load_database_models # noqa: F401
|
import spiffworkflow_backend.load_database_models # noqa: F401
|
||||||
from spiffworkflow_backend.config import setup_config
|
from spiffworkflow_backend.config import setup_config
|
||||||
from spiffworkflow_backend.routes.admin_blueprint.admin_blueprint import admin_blueprint
|
from spiffworkflow_backend.routes.admin_blueprint.admin_blueprint import admin_blueprint
|
||||||
from spiffworkflow_backend.routes.process_api_blueprint import check_for_permission
|
|
||||||
from spiffworkflow_backend.routes.process_api_blueprint import process_api_blueprint
|
from spiffworkflow_backend.routes.process_api_blueprint import process_api_blueprint
|
||||||
from spiffworkflow_backend.routes.user import verify_token
|
from spiffworkflow_backend.routes.user import verify_token
|
||||||
from spiffworkflow_backend.routes.user_blueprint import user_blueprint
|
from spiffworkflow_backend.routes.user_blueprint import user_blueprint
|
||||||
|
from spiffworkflow_backend.services.authorization_service import AuthorizationService
|
||||||
from spiffworkflow_backend.services.background_processing_service import (
|
from spiffworkflow_backend.services.background_processing_service import (
|
||||||
BackgroundProcessingService,
|
BackgroundProcessingService,
|
||||||
)
|
)
|
||||||
|
@ -116,7 +116,7 @@ def create_app() -> flask.app.Flask:
|
||||||
configure_sentry(app)
|
configure_sentry(app)
|
||||||
|
|
||||||
app.before_request(verify_token)
|
app.before_request(verify_token)
|
||||||
app.before_request(check_for_permission)
|
app.before_request(AuthorizationService.check_for_permission)
|
||||||
|
|
||||||
return app # type: ignore
|
return app # type: ignore
|
||||||
|
|
||||||
|
|
|
@ -87,77 +87,6 @@ class ReactJsonSchemaSelectOption(TypedDict):
|
||||||
|
|
||||||
|
|
||||||
process_api_blueprint = Blueprint("process_api", __name__)
|
process_api_blueprint = Blueprint("process_api", __name__)
|
||||||
authorization_exclusion_list = ["status"]
|
|
||||||
|
|
||||||
|
|
||||||
# TODO: we can add the before_request to the blueprint
|
|
||||||
# directly when we switch over from connexion routes
|
|
||||||
# to blueprint routes
|
|
||||||
# @process_api_blueprint.before_request
|
|
||||||
def check_for_permission() -> None:
|
|
||||||
"""Check_for_permission."""
|
|
||||||
# print("WE CALL1")
|
|
||||||
if request.method == "OPTIONS":
|
|
||||||
return None
|
|
||||||
|
|
||||||
# print("WE CALL")
|
|
||||||
# return None
|
|
||||||
|
|
||||||
if not request.endpoint:
|
|
||||||
raise ApiError(
|
|
||||||
error_code="request_endpoint_not_found",
|
|
||||||
message="Could not find the endpong from the rquest.",
|
|
||||||
status_code=500,
|
|
||||||
)
|
|
||||||
|
|
||||||
api_view_function = current_app.view_functions[request.endpoint]
|
|
||||||
if (
|
|
||||||
api_view_function
|
|
||||||
and api_view_function.__name__.startswith("login")
|
|
||||||
or api_view_function.__name__.startswith("logout")
|
|
||||||
):
|
|
||||||
return None
|
|
||||||
|
|
||||||
if not hasattr(g, "user"):
|
|
||||||
raise ApiError(
|
|
||||||
error_code="user_not_logged_in",
|
|
||||||
message="User is not logged in. Please log in",
|
|
||||||
status_code=401,
|
|
||||||
)
|
|
||||||
|
|
||||||
if (
|
|
||||||
api_view_function
|
|
||||||
and api_view_function.__name__ not in authorization_exclusion_list
|
|
||||||
):
|
|
||||||
permission_string = get_permission_from_request_method()
|
|
||||||
if permission_string:
|
|
||||||
has_permission = AuthorizationService.user_has_permission(
|
|
||||||
user=g.user,
|
|
||||||
permission=permission_string,
|
|
||||||
target_uri=request.path,
|
|
||||||
)
|
|
||||||
if has_permission:
|
|
||||||
return None
|
|
||||||
|
|
||||||
raise ApiError(
|
|
||||||
error_code="unauthorized",
|
|
||||||
message="User is not authorized to perform requested action.",
|
|
||||||
status_code=403,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def get_permission_from_request_method() -> Optional[str]:
|
|
||||||
"""Get_permission_from_request_method."""
|
|
||||||
request_method_mapper = {
|
|
||||||
"POST": "create",
|
|
||||||
"GET": "read",
|
|
||||||
"PUT": "update",
|
|
||||||
"DELETE": "delete",
|
|
||||||
}
|
|
||||||
if request.method in request_method_mapper:
|
|
||||||
return request_method_mapper[request.method]
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def status() -> flask.wrappers.Response:
|
def status() -> flask.wrappers.Response:
|
||||||
|
|
|
@ -45,18 +45,9 @@ def verify_token(
|
||||||
ApiError: If not on production and token is not valid, returns an 'invalid_token' 403 error.
|
ApiError: If not on production and token is not valid, returns an 'invalid_token' 403 error.
|
||||||
If on production and user is not authenticated, returns a 'no_user' 403 error.
|
If on production and user is not authenticated, returns a 'no_user' 403 error.
|
||||||
"""
|
"""
|
||||||
if request.method == "OPTIONS":
|
if AuthorizationService.should_disable_auth_for_request():
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if request.endpoint:
|
|
||||||
api_view_function = current_app.view_functions[request.endpoint]
|
|
||||||
if (
|
|
||||||
api_view_function
|
|
||||||
and api_view_function.__name__.startswith("login")
|
|
||||||
or api_view_function.__name__.startswith("logout")
|
|
||||||
):
|
|
||||||
return None
|
|
||||||
|
|
||||||
if not token and "Authorization" in request.headers:
|
if not token and "Authorization" in request.headers:
|
||||||
token = request.headers["Authorization"].removeprefix("Bearer ")
|
token = request.headers["Authorization"].removeprefix("Bearer ")
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ from typing import Union
|
||||||
|
|
||||||
import jwt
|
import jwt
|
||||||
import yaml
|
import yaml
|
||||||
from flask import current_app
|
from flask import current_app, g, request
|
||||||
from flask_bpmn.api.api_error import ApiError
|
from flask_bpmn.api.api_error import ApiError
|
||||||
from flask_bpmn.models.db import db
|
from flask_bpmn.models.db import db
|
||||||
from sqlalchemy import text
|
from sqlalchemy import text
|
||||||
|
@ -184,6 +184,84 @@ class AuthorizationService:
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return permission_assignment
|
return permission_assignment
|
||||||
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def should_disable_auth_for_request(cls) -> bool:
|
||||||
|
authorization_exclusion_list = ["status"]
|
||||||
|
if request.method == "OPTIONS":
|
||||||
|
return True
|
||||||
|
|
||||||
|
if not request.endpoint:
|
||||||
|
raise ApiError(
|
||||||
|
error_code="request_endpoint_not_found",
|
||||||
|
message="Could not find the endpong from the rquest.",
|
||||||
|
status_code=500,
|
||||||
|
)
|
||||||
|
|
||||||
|
api_view_function = current_app.view_functions[request.endpoint]
|
||||||
|
if (
|
||||||
|
api_view_function
|
||||||
|
and api_view_function.__name__.startswith("login")
|
||||||
|
or api_view_function.__name__.startswith("logout")
|
||||||
|
or api_view_function.__name__ in authorization_exclusion_list
|
||||||
|
):
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_permission_from_request_method(cls) -> Optional[str]:
|
||||||
|
"""Get_permission_from_request_method."""
|
||||||
|
request_method_mapper = {
|
||||||
|
"POST": "create",
|
||||||
|
"GET": "read",
|
||||||
|
"PUT": "update",
|
||||||
|
"DELETE": "delete",
|
||||||
|
}
|
||||||
|
if request.method in request_method_mapper:
|
||||||
|
return request_method_mapper[request.method]
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: we can add the before_request to the blueprint
|
||||||
|
# directly when we switch over from connexion routes
|
||||||
|
# to blueprint routes
|
||||||
|
# @process_api_blueprint.before_request
|
||||||
|
@classmethod
|
||||||
|
def check_for_permission(cls) -> None:
|
||||||
|
"""Check_for_permission."""
|
||||||
|
if cls.should_disable_auth_for_request():
|
||||||
|
return None
|
||||||
|
|
||||||
|
if not hasattr(g, "user"):
|
||||||
|
raise ApiError(
|
||||||
|
error_code="user_not_logged_in",
|
||||||
|
message="User is not logged in. Please log in",
|
||||||
|
status_code=401,
|
||||||
|
)
|
||||||
|
|
||||||
|
api_view_function = current_app.view_functions[request.endpoint]
|
||||||
|
if (
|
||||||
|
api_view_function
|
||||||
|
):
|
||||||
|
permission_string = cls.get_permission_from_request_method()
|
||||||
|
if permission_string:
|
||||||
|
has_permission = AuthorizationService.user_has_permission(
|
||||||
|
user=g.user,
|
||||||
|
permission=permission_string,
|
||||||
|
target_uri=request.path,
|
||||||
|
)
|
||||||
|
if has_permission:
|
||||||
|
return None
|
||||||
|
|
||||||
|
raise ApiError(
|
||||||
|
error_code="unauthorized",
|
||||||
|
message="User is not authorized to perform requested action.",
|
||||||
|
status_code=403,
|
||||||
|
)
|
||||||
|
|
||||||
# def refresh_token(self, token: str) -> str:
|
# def refresh_token(self, token: str) -> str:
|
||||||
# """Refresh_token."""
|
# """Refresh_token."""
|
||||||
# # if isinstance(token, str):
|
# # if isinstance(token, str):
|
||||||
|
|
Loading…
Reference in New Issue