attempting to respect permissions w/ burnettk

This commit is contained in:
jasquat 2022-10-12 17:19:05 -04:00
parent 10c443a2d8
commit d07fbbeff9
6 changed files with 82 additions and 4 deletions

View File

@ -17,7 +17,9 @@ from flask_mail import Mail # type: ignore
import spiffworkflow_backend.load_database_models # noqa: F401
from spiffworkflow_backend.config import setup_config
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.user import verify_token
from spiffworkflow_backend.routes.user_blueprint import user_blueprint
from spiffworkflow_backend.services.background_processing_service import (
BackgroundProcessingService,
@ -113,6 +115,9 @@ def create_app() -> flask.app.Flask:
configure_sentry(app)
app.before_request(verify_token)
app.before_request(check_for_permission)
return app # type: ignore

View File

@ -6,8 +6,8 @@ info:
name: MIT
servers:
- url: http://localhost:5000/v1.0
security:
- jwt: ["secret"]
security: []
# - jwt: ["secret"]
# - oAuth2AuthCode:
# - read_email
# - uid
@ -378,7 +378,6 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/OkTrue"
# process model update
put:
operationId: spiffworkflow_backend.routes.process_api_blueprint.process_model_update
summary: Modifies an existing process mosel with the given parameters.
@ -827,7 +826,6 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/File"
# process_model_file_update
put:
operationId: spiffworkflow_backend.routes.process_api_blueprint.process_model_file_update
summary: save the contents to the given file

View File

@ -31,7 +31,13 @@ class Permission(enum.Enum):
read = "read"
update = "update"
delete = "delete"
# maybe read to GET process_model/process-instances instead?
list = "list"
# maybe use create instead on
# POST http://localhost:7000/v1.0/process-models/category_number_one/call-activity/process-instances/*
# POST http://localhost:7000/v1.0/process-models/category_number_one/call-activity/process-instances/332/run
instantiate = "instantiate" # this is something you do to a process model

View File

@ -4,10 +4,14 @@ import os
import random
import string
import uuid
from functools import wraps
from typing import Any
from typing import Callable
from typing import cast
from typing import Dict
from typing import Optional
from typing import TypedDict
from typing import TypeVar
from typing import Union
import connexion # type: ignore
@ -53,6 +57,7 @@ from spiffworkflow_backend.models.secret_model import SecretModel
from spiffworkflow_backend.models.secret_model import SecretModelSchema
from spiffworkflow_backend.models.spiff_logging import SpiffLoggingModel
from spiffworkflow_backend.models.user import UserModel
from spiffworkflow_backend.services.authorization_service import AuthorizationService
from spiffworkflow_backend.services.error_handling_service import ErrorHandlingService
from spiffworkflow_backend.services.file_system_service import FileSystemService
from spiffworkflow_backend.services.git_service import GitService
@ -87,6 +92,51 @@ class ReactJsonSchemaSelectOption(TypedDict):
process_api_blueprint = Blueprint("process_api", __name__)
authorization_exclusion_list = ['status']
def check_for_permission() -> None:
"""Check_for_permission."""
if request.method == 'OPTIONS':
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__ 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]:
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:

View File

@ -10,6 +10,7 @@ import jwt
from flask import current_app
from flask import g
from flask import redirect
from flask import request
from flask_bpmn.api.api_error import ApiError
from werkzeug.wrappers.response import Response
@ -26,6 +27,7 @@ from spiffworkflow_backend.services.user_service import UserService
"""
# authorization_exclusion_list = ['status']
def verify_token(token: Optional[str] = None) -> Dict[str, Optional[Union[str, int]]]:
"""Verify the token for the user (if provided).
@ -41,6 +43,17 @@ def verify_token(token: Optional[str] = None) -> Dict[str, Optional[Union[str, i
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 request.method == 'OPTIONS':
return None
api_view_function = current_app.view_functions[request.endpoint]
if api_view_function and api_view_function.__name__.startswith('login'):
return None
if not token and 'Authorization' in request.headers:
token = request.headers['Authorization'].removeprefix('Bearer ')
if token:
user_model = None
decoded_token = get_decoded_token(token)

View File

@ -21,6 +21,9 @@ from spiffworkflow_backend.models.user_group_assignment import UserGroupAssignme
from spiffworkflow_backend.services.user_service import UserService
class PermissionsFileNotSetError(Exception):
pass
class AuthorizationService:
"""Determine whether a user has permission to perform their request."""
@ -77,6 +80,9 @@ class AuthorizationService:
cls, raise_if_missing_user: bool = False
) -> None:
"""Import_permissions_from_yaml_file."""
if current_app.config["SPIFFWORKFLOW_BACKEND_PERMISSIONS_FILE_NAME"] is None:
raise(PermissionsFileNotSetError("SPIFFWORKFLOW_BACKEND_PERMISSIONS_FILE_NAME needs to be set in order to import permissions"))
permission_configs = None
with open(current_app.config["PERMISSIONS_FILE_FULLPATH"]) as file:
permission_configs = yaml.safe_load(file)