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