forked from sh-edraft.de/sh_discord_bot
		
	Secured password handling #70
This commit is contained in:
		| @@ -56,7 +56,7 @@ class AuthController: | ||||
|         return jsonify(result.to_dict()) | ||||
|  | ||||
|     @Route.get(f'{BasePath}/users/get/<email>') | ||||
|     @Route.authorize(role=AuthRoleEnum.admin) | ||||
|     @Route.authorize | ||||
|     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()) | ||||
|   | ||||
| @@ -63,8 +63,8 @@ class AuthService(AuthServiceABC): | ||||
|         return mail | ||||
|  | ||||
|     @staticmethod | ||||
|     def _hash_sha256(password: str) -> str: | ||||
|         return hashlib.sha256(password.encode('utf-8')).hexdigest() | ||||
|     def _hash_sha256(password: str, salt: str) -> str: | ||||
|         return hashlib.sha256(f'{password}{salt}'.encode('utf-8')).hexdigest() | ||||
|  | ||||
|     @staticmethod | ||||
|     def _is_email_valid(email: str) -> bool: | ||||
| @@ -188,8 +188,9 @@ class AuthService(AuthServiceABC): | ||||
|         if db_user is not None: | ||||
|             raise ServiceException(ServiceErrorCode.InvalidUser, 'User already exists') | ||||
|  | ||||
|         user_dto.password = self._hash_sha256(user_dto.password) | ||||
|         user = AUT.to_db(user_dto) | ||||
|         user.password_salt = uuid.uuid4() | ||||
|         user.password = self._hash_sha256(user_dto.password, user.password_salt) | ||||
|         if not self._is_email_valid(user.email): | ||||
|             raise ServiceException(ServiceErrorCode.InvalidData, 'Invalid E-Mail address') | ||||
|  | ||||
| @@ -244,17 +245,18 @@ class AuthService(AuthServiceABC): | ||||
|         # hash passwords in DTOs | ||||
|         if update_user_dto.auth_user.password is not None and update_user_dto.auth_user.password != '': | ||||
|             is_existing_password_set = True | ||||
|             update_user_dto.auth_user.password = self._hash_sha256(update_user_dto.auth_user.password) | ||||
|             update_user_dto.auth_user.password = self._hash_sha256(update_user_dto.auth_user.password, user.password_salt) | ||||
|  | ||||
|         if update_user_dto.auth_user.password != user.password: | ||||
|             raise ServiceException(ServiceErrorCode.InvalidUser, 'Wrong password') | ||||
|  | ||||
|         if update_user_dto.new_auth_user.password is not None and update_user_dto.new_auth_user.password != '': | ||||
|             is_new_password_set = True | ||||
|             update_user_dto.new_auth_user.password = self._hash_sha256(update_user_dto.new_auth_user.password) | ||||
|             update_user_dto.new_auth_user.password = self._hash_sha256(update_user_dto.new_auth_user.password, user.password_salt) | ||||
|  | ||||
|         # update password | ||||
|         if is_existing_password_set and is_new_password_set and update_user_dto.auth_user.password != update_user_dto.new_auth_user.password: | ||||
|             user.password_salt = uuid.uuid4() | ||||
|             user.password = update_user_dto.new_auth_user.password | ||||
|  | ||||
|         self._auth_users.update_auth_user(user) | ||||
| @@ -301,7 +303,8 @@ class AuthService(AuthServiceABC): | ||||
|  | ||||
|         # update password | ||||
|         if update_user_dto.change_password and update_user_dto.auth_user.password != update_user_dto.new_auth_user.password: | ||||
|             user.password = self._hash_sha256(update_user_dto.new_auth_user.password) | ||||
|             user.password_salt = uuid.uuid4() | ||||
|             user.password = self._hash_sha256(update_user_dto.new_auth_user.password, user.password_salt) | ||||
|  | ||||
|         # update role | ||||
|         if user.auth_role == update_user_dto.auth_user.auth_role and user.auth_role != update_user_dto.new_auth_user.auth_role: | ||||
| @@ -350,7 +353,7 @@ class AuthService(AuthServiceABC): | ||||
|         if db_user is None: | ||||
|             raise ServiceException(ServiceErrorCode.InvalidUser, f'User not found') | ||||
|  | ||||
|         user_dto.password = self._hash_sha256(user_dto.password) | ||||
|         user_dto.password = self._hash_sha256(user_dto.password, db_user.password_salt) | ||||
|         if db_user.password != user_dto.password: | ||||
|             raise ServiceException(ServiceErrorCode.InvalidUser, 'Wrong password') | ||||
|  | ||||
| @@ -432,5 +435,5 @@ class AuthService(AuthServiceABC): | ||||
|         if user.password is None or rp_dto.password == '': | ||||
|             raise ServiceException(ServiceErrorCode.InvalidData, f'Password not set') | ||||
|  | ||||
|         user.password = self._hash_sha256(rp_dto.password) | ||||
|         user.password = self._hash_sha256(rp_dto.password, user.password_salt) | ||||
|         self._db.save_changes() | ||||
|   | ||||
| @@ -18,6 +18,7 @@ class AuthUserTransformer(TransformerABC): | ||||
|             None, | ||||
|             None, | ||||
|             None, | ||||
|             None, | ||||
|             datetime.now(tz=timezone.utc), | ||||
|             AuthRoleEnum.normal if dto.auth_role is None else AuthRoleEnum(dto.auth_role), | ||||
|             dto.user_id, | ||||
| @@ -31,7 +32,7 @@ class AuthUserTransformer(TransformerABC): | ||||
|             db.first_name, | ||||
|             db.last_name, | ||||
|             db.email, | ||||
|             db.password, | ||||
|             '', | ||||
|             db.confirmation_id, | ||||
|             db.auth_role, | ||||
|             db.user_id | ||||
|   | ||||
| @@ -23,12 +23,13 @@ class ApiMigration(MigrationABC): | ||||
|               `LastName` VARCHAR(255), | ||||
|               `EMail` VARCHAR(255), | ||||
|               `Password` VARCHAR(255), | ||||
|               `PasswordSalt` VARCHAR(255), | ||||
|               `RefreshToken` VARCHAR(255), | ||||
|               `ConfirmationId` VARCHAR(255) DEFAULT NULL, | ||||
|               `ForgotPasswordId` VARCHAR(255) DEFAULT NULL, | ||||
|               `RefreshTokenExpiryTime` DATETIME(6) NOT NULL, | ||||
|               `AuthRole` INT NOT NULL DEFAULT '0', | ||||
|               `UserId` BIGINT NOT NULL DEFAULT '0', | ||||
|               `UserId` BIGINT DEFAULT NULL, | ||||
|               `CreatedOn` DATETIME(6) NOT NULL, | ||||
|               `LastModifiedOn` DATETIME(6) NOT NULL, | ||||
|               PRIMARY KEY(`Id`), | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| import uuid | ||||
| from datetime import datetime | ||||
| from typing import Optional | ||||
| from cpl_core.database import TableABC | ||||
| @@ -14,6 +15,7 @@ class AuthUser(TableABC): | ||||
|             last_name: str, | ||||
|             email: str, | ||||
|             password: str, | ||||
|             password_salt: Optional[str], | ||||
|             refresh_token: Optional[str], | ||||
|             confirmation_id: Optional[str], | ||||
|             forgot_password_id: Optional[str], | ||||
| @@ -29,6 +31,7 @@ class AuthUser(TableABC): | ||||
|         self._last_name = last_name | ||||
|         self._email = email | ||||
|         self._password = password | ||||
|         self._password_salt = uuid.uuid4() if password_salt is None else password_salt | ||||
|         self._refresh_token = refresh_token | ||||
|         self._confirmation_id = confirmation_id | ||||
|         self._forgot_password_id = forgot_password_id | ||||
| @@ -77,6 +80,14 @@ class AuthUser(TableABC): | ||||
|     def password(self, value: str): | ||||
|         self._password = value | ||||
|  | ||||
|     @property | ||||
|     def password_salt(self) -> str: | ||||
|         return self._password_salt | ||||
|  | ||||
|     @password_salt.setter | ||||
|     def password_salt(self, value: str): | ||||
|         self._password_salt = value | ||||
|  | ||||
|     @property | ||||
|     def refresh_token(self) -> Optional[str]: | ||||
|         return self._refresh_token | ||||
| @@ -168,6 +179,7 @@ class AuthUser(TableABC): | ||||
|                 `LastName`, | ||||
|                 `EMail`, | ||||
|                 `Password`, | ||||
|                 `PasswordSalt`, | ||||
|                 `RefreshToken`, | ||||
|                 `ConfirmationId`, | ||||
|                 `ForgotPasswordId`, | ||||
| @@ -182,12 +194,13 @@ class AuthUser(TableABC): | ||||
|                     '{self._last_name}', | ||||
|                     '{self._email}', | ||||
|                     '{self._password}',  | ||||
|                     '{self._refresh_token}', | ||||
|                     '{self._password_salt}',  | ||||
|                     '{"NULL" if self._refresh_token is None else self._refresh_token}', | ||||
|                     '{"NULL" if self._confirmation_id is None else self._confirmation_id}', | ||||
|                     '{"NULL" if self._forgot_password_id is None else self._forgot_password_id}', | ||||
|                     '{self._refresh_token_expire_time}', | ||||
|                     {self._auth_role_id.value}, | ||||
|                     {"NULL" if self._user_id is None else self._user_id} | ||||
|                     {"NULL" if self._user_id is None else self._user_id}, | ||||
|                     '{self._created_at}',  | ||||
|                     '{self._modified_at}' | ||||
|                 ) | ||||
| @@ -201,6 +214,7 @@ class AuthUser(TableABC): | ||||
|             `LastName` = '{self._last_name}',  | ||||
|             `EMail` = '{self._email}',  | ||||
|             `Password` = '{self._password}',  | ||||
|             `PasswordSalt` = '{self._password_salt}',  | ||||
|             `RefreshToken` = '{self._refresh_token}',  | ||||
|             `ConfirmationId` = '{"NULL" if self._confirmation_id is None else self._confirmation_id}',  | ||||
|             `ForgotPasswordId` = '{"NULL" if self._forgot_password_id is None else self._forgot_password_id}', | ||||
|   | ||||
| @@ -36,8 +36,9 @@ class AuthUserRepositoryService(AuthUserRepositoryABC): | ||||
|             self._get_value_from_result(result[6]), | ||||
|             self._get_value_from_result(result[7]), | ||||
|             self._get_value_from_result(result[8]), | ||||
|             AuthRoleEnum(self._get_value_from_result(result[9])), | ||||
|             self._get_value_from_result(result[10]), | ||||
|             self._get_value_from_result(result[9]), | ||||
|             AuthRoleEnum(self._get_value_from_result(result[10])), | ||||
|             self._get_value_from_result(result[11]), | ||||
|             id=self._get_value_from_result(result[0]) | ||||
|         ) | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user