forked from sh-edraft.de/sh_discord_bot
Added role check to authorization #72
This commit is contained in:
parent
1857473ccc
commit
dfcc516389
@ -11,10 +11,12 @@ from flask import Flask
|
||||
from bot_api.abc.auth_service_abc import AuthServiceABC
|
||||
from bot_api.api import Api
|
||||
from bot_api.api_thread import ApiThread
|
||||
from bot_api.controller.discord.server_controller import ServerController
|
||||
from bot_api.controller.gui_controller import GuiController
|
||||
from bot_api.controller.auth_controller import AuthController
|
||||
from bot_api.event.bot_api_on_ready_event import BotApiOnReadyEvent
|
||||
from bot_api.service.auth_service import AuthService
|
||||
from bot_api.service.discord_service import DiscordService
|
||||
from bot_core.abc.module_abc import ModuleABC
|
||||
from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum
|
||||
|
||||
@ -41,6 +43,8 @@ class ApiModule(ModuleABC):
|
||||
services.add_transient(AuthServiceABC, AuthService)
|
||||
services.add_transient(AuthController)
|
||||
services.add_transient(GuiController)
|
||||
services.add_transient(DiscordService)
|
||||
services.add_transient(ServerController)
|
||||
|
||||
# cpl-discord
|
||||
self._dc.add_event(DiscordEventTypesEnum.on_ready.value, BotApiOnReadyEvent)
|
||||
|
@ -15,6 +15,7 @@ from bot_api.model.auth_user_dto import AuthUserDTO
|
||||
from bot_api.model.token_dto import TokenDTO
|
||||
from bot_api.model.update_auth_user_dto import UpdateAuthUserDTO
|
||||
from bot_api.route.route import Route
|
||||
from bot_data.model.auth_role_enum import AuthRoleEnum
|
||||
|
||||
|
||||
class AuthController:
|
||||
@ -41,13 +42,13 @@ class AuthController:
|
||||
self._auth_service = auth_service
|
||||
|
||||
@Route.get(f'{BasePath}/users')
|
||||
@Route.authorize
|
||||
@Route.authorize(role=AuthRoleEnum.admin)
|
||||
async def get_all_users(self) -> Response:
|
||||
result = await self._auth_service.get_all_auth_users_async()
|
||||
return jsonify(result.select(lambda x: x.to_dict()))
|
||||
|
||||
@Route.post(f'{BasePath}/users/get/filtered')
|
||||
@Route.authorize
|
||||
@Route.authorize(role=AuthRoleEnum.admin)
|
||||
async def get_filtered_users(self) -> Response:
|
||||
dto: AuthUserSelectCriteria = JSONProcessor.process(AuthUserSelectCriteria, request.get_json(force=True, silent=True))
|
||||
result = await self._auth_service.get_filtered_auth_users_async(dto)
|
||||
@ -55,13 +56,13 @@ class AuthController:
|
||||
return jsonify(result.to_dict())
|
||||
|
||||
@Route.get(f'{BasePath}/users/get/<email>')
|
||||
@Route.authorize
|
||||
@Route.authorize(role=AuthRoleEnum.admin)
|
||||
async def get_user_from_email(self, email: str) -> Response:
|
||||
result = await self._auth_service.get_auth_user_by_email_async(email)
|
||||
return jsonify(result.to_dict())
|
||||
|
||||
@Route.get(f'{BasePath}/users/find/<email>')
|
||||
@Route.authorize
|
||||
@Route.authorize(role=AuthRoleEnum.admin)
|
||||
async def find_user_from_email(self, email: str) -> Response:
|
||||
result = await self._auth_service.find_auth_user_by_email_async(email)
|
||||
return jsonify(result.to_dict())
|
||||
@ -109,7 +110,7 @@ class AuthController:
|
||||
return '', 200
|
||||
|
||||
@Route.post(f'{BasePath}/update-user-as-admin')
|
||||
@Route.authorize
|
||||
@Route.authorize(role=AuthRoleEnum.admin)
|
||||
async def update_user_as_admin(self):
|
||||
dto: UpdateAuthUserDTO = JSONProcessor.process(UpdateAuthUserDTO, request.get_json(force=True, silent=True))
|
||||
await self._auth_service.update_user_as_admin_async(dto)
|
||||
@ -129,14 +130,14 @@ class AuthController:
|
||||
return '', 200
|
||||
|
||||
@Route.post(f'{BasePath}/delete-user')
|
||||
@Route.authorize
|
||||
@Route.authorize(role=AuthRoleEnum.admin)
|
||||
async def delete_user(self):
|
||||
dto: AuthUserDTO = JSONProcessor.process(AuthUserDTO, request.get_json(force=True, silent=True))
|
||||
await self._auth_service.delete_auth_user_async(dto)
|
||||
return '', 200
|
||||
|
||||
@Route.post(f'{BasePath}/delete-user-by-mail/<email>')
|
||||
@Route.authorize
|
||||
@Route.authorize(role=AuthRoleEnum.admin)
|
||||
async def delete_user_by_mail(self, email: str):
|
||||
await self._auth_service.delete_auth_user_by_email_async(email)
|
||||
return '', 200
|
||||
|
@ -8,6 +8,7 @@ from bot_api.api import Api
|
||||
from bot_api.logging.api_logger import ApiLogger
|
||||
from bot_api.route.route import Route
|
||||
from bot_api.service.discord_service import DiscordService
|
||||
from bot_data.model.auth_role_enum import AuthRoleEnum
|
||||
|
||||
|
||||
class ServerController:
|
||||
@ -34,6 +35,6 @@ class ServerController:
|
||||
self._discord_service = discord_service
|
||||
|
||||
@Route.get(f'{BasePath}/servers')
|
||||
@Route.authorize
|
||||
@Route.authorize(role=AuthRoleEnum.admin)
|
||||
async def get_all_servers(self) -> Response:
|
||||
return jsonify(self._discord_service.get_all_servers().select(lambda x: x.to_dict()))
|
||||
|
@ -21,3 +21,4 @@ class ServiceErrorCode(Enum):
|
||||
MailError = 10
|
||||
|
||||
Unauthorized = 11
|
||||
Forbidden = 12
|
||||
|
@ -1,5 +1,6 @@
|
||||
import functools
|
||||
from functools import wraps
|
||||
from typing import Optional
|
||||
from typing import Optional, Callable
|
||||
|
||||
from flask import request, jsonify
|
||||
from flask_cors import cross_origin
|
||||
@ -9,6 +10,7 @@ from bot_api.exception.service_error_code_enum import ServiceErrorCode
|
||||
from bot_api.exception.service_exception import ServiceException
|
||||
from bot_api.model.error_dto import ErrorDTO
|
||||
from bot_data.abc.auth_user_repository_abc import AuthUserRepositoryABC
|
||||
from bot_data.model.auth_role_enum import AuthRoleEnum
|
||||
|
||||
|
||||
class Route:
|
||||
@ -23,7 +25,10 @@ class Route:
|
||||
cls._auth = auth
|
||||
|
||||
@classmethod
|
||||
def authorize(cls, f):
|
||||
def authorize(cls, f: Callable = None, role: AuthRoleEnum = None):
|
||||
if f is None:
|
||||
return functools.partial(cls.authorize, role=role)
|
||||
|
||||
@wraps(f)
|
||||
async def decorator(*args, **kwargs):
|
||||
token = None
|
||||
@ -46,6 +51,23 @@ class Route:
|
||||
error = ErrorDTO(ex.error_code, ex.message)
|
||||
return jsonify(error.to_dict()), 401
|
||||
|
||||
token = cls._auth.decode_token(token)
|
||||
if token is None or 'email' not in token:
|
||||
ex = ServiceException(ServiceErrorCode.Unauthorized, f'Token invalid')
|
||||
error = ErrorDTO(ex.error_code, ex.message)
|
||||
return jsonify(error.to_dict()), 401
|
||||
|
||||
user = cls._auth_users.get_auth_user_by_email(token['email'])
|
||||
if user is None:
|
||||
ex = ServiceException(ServiceErrorCode.Unauthorized, f'Token invalid')
|
||||
error = ErrorDTO(ex.error_code, ex.message)
|
||||
return jsonify(error.to_dict()), 401
|
||||
|
||||
if role is not None and user.auth_role.value < role.value:
|
||||
ex = ServiceException(ServiceErrorCode.Unauthorized, f'Role {role} required')
|
||||
error = ErrorDTO(ex.error_code, ex.message)
|
||||
return jsonify(error.to_dict()), 403
|
||||
|
||||
return await f(*args, **kwargs)
|
||||
|
||||
return decorator
|
||||
|
@ -27,6 +27,8 @@ from bot_api.transformer.auth_user_transformer import AuthUserTransformer as AUT
|
||||
from bot_data.abc.auth_user_repository_abc import AuthUserRepositoryABC
|
||||
from bot_data.model.auth_user import AuthUser
|
||||
|
||||
_email_regex = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'
|
||||
|
||||
|
||||
class AuthService(AuthServiceABC):
|
||||
|
||||
@ -65,7 +67,7 @@ class AuthService(AuthServiceABC):
|
||||
|
||||
@staticmethod
|
||||
def _is_email_valid(email: str) -> bool:
|
||||
if re.match(re.compile(r'^[a-z0-9]+[\._]?[a-z0-9]+[@]\w+[.]\w{2,3}$'), email) is not None:
|
||||
if re.fullmatch(_email_regex, email) is not None:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
@ -19,7 +19,7 @@ class AuthUserTransformer(TransformerABC):
|
||||
None,
|
||||
None,
|
||||
datetime.now(tz=timezone.utc),
|
||||
AuthRoleEnum.normal if dto.auth_role is None else dto.auth_role,
|
||||
AuthRoleEnum.normal if dto.auth_role is None else AuthRoleEnum(dto.auth_role),
|
||||
id=0 if dto.id is None else dto.id
|
||||
)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user