Added logic to check if user is allowed to see requested data #89

This commit is contained in:
2023-02-11 12:54:14 +01:00
parent 84937dde0a
commit dd64435c65
15 changed files with 199 additions and 113 deletions

View File

@@ -52,17 +52,13 @@ class AuthServiceABC(ABC):
pass
@abstractmethod
async def add_auth_user_async(self, user_dto: AuthUserDTO):
def add_auth_user(self, user_dto: AuthUserDTO):
pass
@abstractmethod
async def add_auth_user_by_oauth_async(self, dto: OAuthDTO):
pass
@abstractmethod
async def add_auth_user_by_discord_async(self, user_dto: AuthUserDTO, dc_id: int) -> OAuthDTO:
pass
@abstractmethod
async def update_user_async(self, update_user_dto: UpdateAuthUserDTO):
pass
@@ -84,7 +80,7 @@ class AuthServiceABC(ABC):
pass
@abstractmethod
async def verify_api_key(self, api_key: str) -> bool:
def verify_api_key(self, api_key: str) -> bool:
pass
@abstractmethod
@@ -92,7 +88,7 @@ class AuthServiceABC(ABC):
pass
@abstractmethod
async def login_discord_async(self, oauth_dto: AuthUserDTO) -> TokenDTO:
async def login_discord_async(self, oauth_dto: AuthUserDTO, dc_id: int) -> TokenDTO:
pass
@abstractmethod

View File

@@ -6,8 +6,6 @@ from flask import request, jsonify, Response
from bot_api.abc.auth_service_abc import AuthServiceABC
from bot_api.api import Api
from bot_api.exception.service_error_code_enum import ServiceErrorCode
from bot_api.exception.service_exception import ServiceException
from bot_api.filter.auth_user_select_criteria import AuthUserSelectCriteria
from bot_api.json_processor import JSONProcessor
from bot_api.logging.api_logger import ApiLogger
@@ -73,7 +71,7 @@ class AuthController:
@Route.post(f"{BasePath}/register")
async def register(self):
dto: AuthUserDTO = JSONProcessor.process(AuthUserDTO, request.get_json(force=True, silent=True))
await self._auth_service.add_auth_user_async(dto)
await self._auth_service.add_auth_user(dto)
return "", 200
@Route.post(f"{BasePath}/register-by-id/<id>")

View File

@@ -77,23 +77,6 @@ class AuthDiscordController:
login_url, state = oauth.authorization_url(self._auth_settings.auth_url)
return jsonify({"loginUrl": login_url})
@Route.get(f"{BasePath}/create-user")
async def discord_create_user(self) -> Response:
response = self._get_user_from_discord_response()
result = await self._auth_service.add_auth_user_by_discord_async(
AuthUserDTO(
0,
response["username"],
response["discriminator"],
response["email"],
str(uuid.uuid4()),
None,
AuthRoleEnum.normal,
),
response["id"],
)
return jsonify(result.to_dict())
@Route.get(f"{BasePath}/login")
async def discord_login(self) -> Response:
response = self._get_user_from_discord_response()
@@ -107,5 +90,5 @@ class AuthDiscordController:
AuthRoleEnum.normal,
)
result = await self._auth_service.login_discord_async(dto)
result = await self._auth_service.login_discord_async(dto, response["id"])
return jsonify(result.to_dict())

View File

@@ -1,6 +1,6 @@
import functools
from functools import wraps
from typing import Optional, Callable
from typing import Optional, Callable, Union
from cpl_core.dependency_injection import ServiceProviderABC
from cpl_core.environment import ApplicationEnvironmentABC
@@ -13,6 +13,7 @@ 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
from bot_data.model.auth_user import AuthUser
class Route:
@@ -29,6 +30,27 @@ class Route:
cls._auth = auth
cls._env = env.environment_name
@classmethod
def get_user(cls) -> Optional[Union[str, AuthUser]]:
token = None
api_key = None
authorization = request.headers.get("Authorization").split()
match authorization[0]:
case "Bearer":
token = authorization[1]
case "API-Key":
api_key = authorization[1]
if api_key is not None:
return "system"
if token is None:
return None
jwt = cls._auth.decode_token(token)
user = cls._auth_users.get_auth_user_by_email(jwt["email"])
return user
@classmethod
def authorize(cls, f: Callable = None, role: AuthRoleEnum = None, skip_in_dev=False, by_api_key=False):
if f is None:
@@ -39,10 +61,25 @@ class Route:
if skip_in_dev and cls._env == "development":
return await f(*args, **kwargs)
if "Authorization" not in request.headers and by_api_key and "API-Key" in request.headers:
token = None
api_key = None
if "Authorization" in request.headers:
if " " not in request.headers.get("Authorization"):
ex = ServiceException(ServiceErrorCode.Unauthorized, f"Token not set")
error = ErrorDTO(ex.error_code, ex.message)
return jsonify(error.to_dict()), 401
authorization = request.headers.get("Authorization").split()
match authorization[0]:
case "Bearer":
token = authorization[1]
case "API-Key":
api_key = authorization[1]
if api_key is not None:
valid = False
try:
valid = cls._auth.verify_api_key(request.headers["API-Key"])
valid = cls._auth.verify_api_key(api_key)
except ServiceException as e:
error = ErrorDTO(e.error_code, e.message)
return jsonify(error.to_dict()), 403
@@ -56,11 +93,6 @@ class Route:
return await f(*args, **kwargs)
token = None
if "Authorization" in request.headers:
bearer = request.headers.get("Authorization")
token = bearer.split()[1]
if token is None:
ex = ServiceException(ServiceErrorCode.Unauthorized, f"Token not set")
error = ErrorDTO(ex.error_code, ex.message)

View File

@@ -223,18 +223,13 @@ class AuthService(AuthServiceABC):
user = self._auth_users.find_auth_user_by_email(email)
return AUT.to_dto(user) if user is not None else None
async def add_auth_user_async(self, user_dto: AuthUserDTO):
def add_auth_user(self, user_dto: AuthUserDTO):
db_user = self._auth_users.find_auth_user_by_email(user_dto.email)
if db_user is not None:
raise ServiceException(ServiceErrorCode.InvalidUser, "User already exists")
user = AUT.to_db(user_dto)
if (
self._auth_users.get_all_auth_users()
.where(lambda x: x.name != "internal" and x.email != "internal@localhost")
.count()
== 0
):
if self._auth_users.get_all_auth_users().count() == 0:
user.auth_role = AuthRoleEnum.admin
user.password_salt = uuid.uuid4()
@@ -277,51 +272,6 @@ class AuthService(AuthServiceABC):
self._db.save_changes()
async def add_auth_user_by_discord_async(self, user_dto: AuthUserDTO, dc_id: int) -> OAuthDTO:
db_auth_user = self._auth_users.find_auth_user_by_email(user_dto.email)
# user exists
if db_auth_user is not None and db_auth_user.users.count() > 0:
# raise ServiceException(ServiceErrorCode.InvalidUser, 'User already exists')
self._logger.debug(__name__, f"Discord user already exists")
return OAuthDTO(AUT.to_dto(db_auth_user), None)
# user exists but discord user id not set
elif db_auth_user is not None and db_auth_user.users.count() == 0:
self._logger.debug(__name__, f"Auth user exists but not linked with discord")
# users = self._users.get_users_by_discord_id(user_dto.user_id)
# add auth_user to user refs
db_auth_user.oauth_id = None
else:
# user does not exists
self._logger.debug(__name__, f"Auth user does not exist")
try:
user_dto.user_id = self._users.get_users_by_discord_id(user_dto.user_id).single().user_id
except Exception as e:
self._logger.error(__name__, f"User not found")
user_dto.user_id = None
await self.add_auth_user_async(user_dto)
db_auth_user = self._auth_users.get_auth_user_by_email(user_dto.email)
db_auth_user.oauth_id = uuid.uuid4()
for g in self._bot.guilds:
member = g.get_member(int(dc_id))
if member is None:
continue
server = self._servers.get_server_by_discord_id(g.id)
users = self._users.get_users_by_discord_id(dc_id)
for user in users:
if user.server.server_id != server.server_id:
continue
self._auth_users.add_auth_user_user_rel(AuthUserUsersRelation(db_auth_user, user))
self._auth_users.update_auth_user(db_auth_user)
self._db.save_changes()
return OAuthDTO(AUT.to_dto(db_auth_user), db_auth_user.oauth_id)
async def update_user_async(self, update_user_dto: UpdateAuthUserDTO):
if update_user_dto is None:
raise ServiceException(ServiceErrorCode.InvalidData, f"User is empty")
@@ -498,7 +448,7 @@ class AuthService(AuthServiceABC):
if not keys.contains(api_key):
raise ServiceException(ServiceErrorCode.InvalidData, "API-Key invalid")
except Exception as e:
self._logger.error(__name__, f"Token invalid", e)
self._logger.error(__name__, f"API-Key invalid", e)
return False
return True
@@ -523,16 +473,21 @@ class AuthService(AuthServiceABC):
self._db.save_changes()
return TokenDTO(token, refresh_token)
async def login_discord_async(self, user_dto: AuthUserDTO) -> TokenDTO:
async def login_discord_async(self, user_dto: AuthUserDTO, dc_id: int) -> TokenDTO:
if user_dto is None:
raise ServiceException(ServiceErrorCode.InvalidData, "User not set")
db_user = self._auth_users.find_auth_user_by_email(user_dto.email)
if db_user is None:
await self.add_auth_user_async(user_dto)
self.add_auth_user(user_dto)
# raise ServiceException(ServiceErrorCode.InvalidUser, f'User not found')
db_user = self._auth_users.get_auth_user_by_email(user_dto.email)
if db_user.users.count() == 0:
self._users.get_users_by_discord_id(dc_id).for_each(
lambda x: self._auth_users.add_auth_user_user_rel(AuthUserUsersRelation(db_user, x))
)
token = self.generate_token(db_user)
refresh_token = self._create_and_save_refresh_token(db_user)
if db_user.forgot_password_id is not None: