From 5d9b69298280ef05f76c1ad73947997632a54135 Mon Sep 17 00:00:00 2001 From: "nik.n" Date: Tue, 2 Apr 2024 15:42:02 +0900 Subject: [PATCH 01/13] =?UTF-8?q?=E3=82=A2=E3=82=AB=E3=82=A6=E3=83=B3?= =?UTF-8?q?=E3=83=88=E3=83=AD=E3=83=83=E3=82=AF=E3=82=A2=E3=82=A6=E3=83=88?= =?UTF-8?q?=E5=AE=9F=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ecs/jskult-webapp/src/controller/login.py | 11 ++++++ ecs/jskult-webapp/src/model/db/user_master.py | 2 + .../repositories/user_master_repository.py | 39 +++++++++++++++++++ .../src/services/login_service.py | 6 +++ ecs/jskult-webapp/src/system_var/constants.py | 7 +++- 5 files changed, 64 insertions(+), 1 deletion(-) diff --git a/ecs/jskult-webapp/src/controller/login.py b/ecs/jskult-webapp/src/controller/login.py index 5c8d904e..c9555df7 100644 --- a/ecs/jskult-webapp/src/controller/login.py +++ b/ecs/jskult-webapp/src/controller/login.py @@ -66,10 +66,21 @@ def login( request: LoginModel = Depends(LoginModel.as_form), login_service: LoginService = Depends(get_service(LoginService)) ): + # ユーザーマスタ検索 + pre_login_user_record = login_service.logged_in_user(request.username) + # ログイン失敗回数が10回以上あれば、ログアウト画面にリダイレクトする + if pre_login_user_record is not None and pre_login_user_record.mntuser_login_failed_cnt >= constants.LOGIN_FAIL_LIMIT: + logger.info(f'ログイン失敗回数が10回以上: {request.username}') + # ユーザーが有効の場合、DBにアカウント無効にする + if pre_login_user_record.enabled_flg == 'Y': + login_service.on_retry_limit_exceeded(request.username) + raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=constants.LOGOUT_REASON_RETRY_LIMIT_EXCEEDED) + try: jwt_token = login_service.login(request.username, request.password) except NotAuthorizeException as e: logger.info(f'ログイン失敗:{e}') + login_service.incorrect_login_password_attempt(request.username) raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=constants.LOGOUT_REASON_LOGIN_ERROR) except JWTTokenVerifyException as e: logger.info(f'ログイン失敗:{e}') diff --git a/ecs/jskult-webapp/src/model/db/user_master.py b/ecs/jskult-webapp/src/model/db/user_master.py index 913b415e..8e5fb2ad 100644 --- a/ecs/jskult-webapp/src/model/db/user_master.py +++ b/ecs/jskult-webapp/src/model/db/user_master.py @@ -25,6 +25,8 @@ class UserMasterModel(BaseDBModel): updater: Optional[str] update_date: Optional[datetime] mntuser_flg: Optional[str] + mntuser_login_failed_cnt: Optional[int] + mntuser_last_login_failed_datetime: Optional[datetime] def is_enable_user(self): return self.enabled_flg == 'Y' diff --git a/ecs/jskult-webapp/src/repositories/user_master_repository.py b/ecs/jskult-webapp/src/repositories/user_master_repository.py index 7edde00a..3a4316d8 100644 --- a/ecs/jskult-webapp/src/repositories/user_master_repository.py +++ b/ecs/jskult-webapp/src/repositories/user_master_repository.py @@ -26,3 +26,42 @@ class UserMasterRepository(BaseRepository): except Exception as e: logger.exception(f"DB Error : Exception={e}") raise e + + def increase_login_retry_count(self, parameter: dict) -> UserMasterModel: + try: + query = """\ + UPDATE + src05.user_mst + SET + mntuser_login_failed_cnt = + CASE + WHEN DATE(mntuser_last_login_failed_datetime) = CURRENT_DATE() THEN mntuser_login_failed_cnt + 1 + ELSE 1 + END, + mntuser_last_login_failed_datetime = CURRENT_DATE() + WHERE + user_id = :user_id + AND + mntuser_flg = 1;\ + """ + self._database.execute(query, parameter) + except Exception as e: + logger.exception(f"DB Error : Exception={e}") + raise e + + def disable_mnt_user(self, parameter: dict) -> UserMasterModel: + try: + query = """\ + UPDATE + src05.user_mst + SET + enabled_flg = 'N' + WHERE + user_id = :user_id + AND + mntuser_flg = 1\ + """ + self._database.execute(query, parameter) + except Exception as e: + logger.exception(f"DB Error : Exception={e}") + raise e \ No newline at end of file diff --git a/ecs/jskult-webapp/src/services/login_service.py b/ecs/jskult-webapp/src/services/login_service.py index aa1f37fd..12fa05f4 100644 --- a/ecs/jskult-webapp/src/services/login_service.py +++ b/ecs/jskult-webapp/src/services/login_service.py @@ -49,6 +49,12 @@ class LoginService(BaseService): user_record: UserMasterModel = self.user_repository.fetch_one({'user_id': user_id}) return user_record + def incorrect_login_password_attempt(self, user_id: str): + self.user_repository.increase_login_retry_count({'user_id': user_id}) + + def on_retry_limit_exceeded(self, user_id: str): + self.user_repository.disable_mnt_user({'user_id': user_id}) + def __secret_hash(self, username: str): # see - https://aws.amazon.com/jp/premiumsupport/knowledge-center/cognito-unable-to-verify-secret-hash/ # noqa message = bytes(username + environment.COGNITO_CLIENT_ID, 'utf-8') diff --git a/ecs/jskult-webapp/src/system_var/constants.py b/ecs/jskult-webapp/src/system_var/constants.py index 3756facb..8758d585 100644 --- a/ecs/jskult-webapp/src/system_var/constants.py +++ b/ecs/jskult-webapp/src/system_var/constants.py @@ -63,6 +63,7 @@ LOGOUT_REASON_BACKUP_PROCESSING = 'dump_processing' LOGOUT_REASON_NOT_LOGIN = 'not_login' LOGOUT_REASON_DB_ERROR = 'db_error' LOGOUT_REASON_UNEXPECTED = 'unexpected' +LOGOUT_REASON_RETRY_LIMIT_EXCEEDED = 'retry_limit_exceeded' LOGOUT_REASON_MESSAGE_MAP = { LOGOUT_REASON_DO_LOGOUT: 'Logoutしました。', @@ -72,7 +73,8 @@ LOGOUT_REASON_MESSAGE_MAP = { LOGOUT_REASON_BACKUP_PROCESSING: 'バックアップ取得を開始しました。
日次バッチ更新が終了するまでマスターメンテは使用できません', LOGOUT_REASON_NOT_LOGIN: 'Loginしてからページにアクセスしてください。', LOGOUT_REASON_DB_ERROR: 'DB接続に失敗しました。
再度Loginするか、
管理者にお問い合わせください。', - LOGOUT_REASON_UNEXPECTED: '予期しないエラーが発生しました。
再度Loginするか、
管理者に問い合わせてください。' + LOGOUT_REASON_UNEXPECTED: '予期しないエラーが発生しました。
再度Loginするか、
管理者に問い合わせてください。', + LOGOUT_REASON_RETRY_LIMIT_EXCEEDED: 'ログイン失敗回数の上限を超えましたので
アカウントをロックしました。
管理者に連絡してください' } # 新規施設担当者登録CSV(マスターメンテ) @@ -207,3 +209,6 @@ DISPLAY_USER_STOP_DIV_SHORT = { '03': '特定項目停止', '04': '全DM停止' } + +# ログイン失敗回数上限(保守ユーザー) +LOGIN_FAIL_LIMIT = 10 \ No newline at end of file From 4270582d7abfdee89dc04aa1d01ddadc8a22b14e Mon Sep 17 00:00:00 2001 From: "nik.n" Date: Tue, 2 Apr 2024 17:50:50 +0900 Subject: [PATCH 02/13] =?UTF-8?q?=E5=91=BD=E5=90=8D=E6=8C=87=E6=91=98?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E3=83=BB=E6=9C=89=E5=8A=B9=E3=83=95=E3=83=A9?= =?UTF-8?q?=E3=82=B0=E5=88=A4=E5=AE=9A=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ecs/jskult-webapp/src/controller/login.py | 8 +++----- ecs/jskult-webapp/src/model/db/user_master.py | 5 ++++- .../src/repositories/user_master_repository.py | 4 ++-- ecs/jskult-webapp/src/services/login_service.py | 4 ++-- ecs/jskult-webapp/src/system_var/constants.py | 4 ++-- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/ecs/jskult-webapp/src/controller/login.py b/ecs/jskult-webapp/src/controller/login.py index c9555df7..6eee5b31 100644 --- a/ecs/jskult-webapp/src/controller/login.py +++ b/ecs/jskult-webapp/src/controller/login.py @@ -69,12 +69,10 @@ def login( # ユーザーマスタ検索 pre_login_user_record = login_service.logged_in_user(request.username) # ログイン失敗回数が10回以上あれば、ログアウト画面にリダイレクトする - if pre_login_user_record is not None and pre_login_user_record.mntuser_login_failed_cnt >= constants.LOGIN_FAIL_LIMIT: + if pre_login_user_record is not None and pre_login_user_record.is_login_failed_limit_exceeded(): logger.info(f'ログイン失敗回数が10回以上: {request.username}') - # ユーザーが有効の場合、DBにアカウント無効にする - if pre_login_user_record.enabled_flg == 'Y': - login_service.on_retry_limit_exceeded(request.username) - raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=constants.LOGOUT_REASON_RETRY_LIMIT_EXCEEDED) + login_service.on_login_fail_limit_exceeded(request.username) + raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=constants.LOGOUT_REASON_LOGIN_FAILED_LIMIT_EXCEEDED) try: jwt_token = login_service.login(request.username, request.password) diff --git a/ecs/jskult-webapp/src/model/db/user_master.py b/ecs/jskult-webapp/src/model/db/user_master.py index 8e5fb2ad..b8dee115 100644 --- a/ecs/jskult-webapp/src/model/db/user_master.py +++ b/ecs/jskult-webapp/src/model/db/user_master.py @@ -2,7 +2,7 @@ from datetime import datetime from typing import Optional from src.model.db.base_db_model import BaseDBModel - +from src.system_var import constants class UserMasterModel(BaseDBModel): user_id: Optional[str] @@ -36,3 +36,6 @@ class UserMasterModel(BaseDBModel): def is_groupware_user(self): return self.mntuser_flg == '0' or self.mntuser_flg is None + + def is_login_failed_limit_exceeded(self): + return self.mntuser_login_failed_cnt >= constants.LOGIN_FAIL_LIMIT diff --git a/ecs/jskult-webapp/src/repositories/user_master_repository.py b/ecs/jskult-webapp/src/repositories/user_master_repository.py index 3a4316d8..0516ec79 100644 --- a/ecs/jskult-webapp/src/repositories/user_master_repository.py +++ b/ecs/jskult-webapp/src/repositories/user_master_repository.py @@ -27,7 +27,7 @@ class UserMasterRepository(BaseRepository): logger.exception(f"DB Error : Exception={e}") raise e - def increase_login_retry_count(self, parameter: dict) -> UserMasterModel: + def increase_login_failed_count(self, parameter: dict) -> UserMasterModel: try: query = """\ UPDATE @@ -38,7 +38,7 @@ class UserMasterRepository(BaseRepository): WHEN DATE(mntuser_last_login_failed_datetime) = CURRENT_DATE() THEN mntuser_login_failed_cnt + 1 ELSE 1 END, - mntuser_last_login_failed_datetime = CURRENT_DATE() + mntuser_last_login_failed_datetime = CURRENT_TIMESTAMP() WHERE user_id = :user_id AND diff --git a/ecs/jskult-webapp/src/services/login_service.py b/ecs/jskult-webapp/src/services/login_service.py index 12fa05f4..ded8b7b7 100644 --- a/ecs/jskult-webapp/src/services/login_service.py +++ b/ecs/jskult-webapp/src/services/login_service.py @@ -50,9 +50,9 @@ class LoginService(BaseService): return user_record def incorrect_login_password_attempt(self, user_id: str): - self.user_repository.increase_login_retry_count({'user_id': user_id}) + self.user_repository.increase_login_failed_count({'user_id': user_id}) - def on_retry_limit_exceeded(self, user_id: str): + def on_login_fail_limit_exceeded(self, user_id: str): self.user_repository.disable_mnt_user({'user_id': user_id}) def __secret_hash(self, username: str): diff --git a/ecs/jskult-webapp/src/system_var/constants.py b/ecs/jskult-webapp/src/system_var/constants.py index 8758d585..6422fdd5 100644 --- a/ecs/jskult-webapp/src/system_var/constants.py +++ b/ecs/jskult-webapp/src/system_var/constants.py @@ -63,7 +63,7 @@ LOGOUT_REASON_BACKUP_PROCESSING = 'dump_processing' LOGOUT_REASON_NOT_LOGIN = 'not_login' LOGOUT_REASON_DB_ERROR = 'db_error' LOGOUT_REASON_UNEXPECTED = 'unexpected' -LOGOUT_REASON_RETRY_LIMIT_EXCEEDED = 'retry_limit_exceeded' +LOGOUT_REASON_LOGIN_FAILED_LIMIT_EXCEEDED = 'retry_limit_exceeded' LOGOUT_REASON_MESSAGE_MAP = { LOGOUT_REASON_DO_LOGOUT: 'Logoutしました。', @@ -74,7 +74,7 @@ LOGOUT_REASON_MESSAGE_MAP = { LOGOUT_REASON_NOT_LOGIN: 'Loginしてからページにアクセスしてください。', LOGOUT_REASON_DB_ERROR: 'DB接続に失敗しました。
再度Loginするか、
管理者にお問い合わせください。', LOGOUT_REASON_UNEXPECTED: '予期しないエラーが発生しました。
再度Loginするか、
管理者に問い合わせてください。', - LOGOUT_REASON_RETRY_LIMIT_EXCEEDED: 'ログイン失敗回数の上限を超えましたので
アカウントをロックしました。
管理者に連絡してください' + LOGOUT_REASON_LOGIN_FAILED_LIMIT_EXCEEDED: 'ログイン失敗回数の上限を超えましたので
アカウントをロックしました。
管理者に連絡してください' } # 新規施設担当者登録CSV(マスターメンテ) From 000e9c006fccbbb2f8e65a80c18097506d9021ef Mon Sep 17 00:00:00 2001 From: "nik.n" Date: Wed, 3 Apr 2024 10:57:54 +0900 Subject: [PATCH 03/13] =?UTF-8?q?=E4=BB=95=E6=A7=98=E3=81=AB=E5=90=88?= =?UTF-8?q?=E3=82=8F=E3=81=9B=E3=81=A6=E3=83=AD=E3=82=B8=E3=83=83=E3=82=AF?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ecs/jskult-webapp/src/controller/login.py | 10 +++++++--- ecs/jskult-webapp/src/model/db/user_master.py | 3 +++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/ecs/jskult-webapp/src/controller/login.py b/ecs/jskult-webapp/src/controller/login.py index 6eee5b31..f2c44559 100644 --- a/ecs/jskult-webapp/src/controller/login.py +++ b/ecs/jskult-webapp/src/controller/login.py @@ -70,8 +70,8 @@ def login( pre_login_user_record = login_service.logged_in_user(request.username) # ログイン失敗回数が10回以上あれば、ログアウト画面にリダイレクトする if pre_login_user_record is not None and pre_login_user_record.is_login_failed_limit_exceeded(): - logger.info(f'ログイン失敗回数が10回以上: {request.username}') - login_service.on_login_fail_limit_exceeded(request.username) + logger.info(f'ログイン失敗回数が10回以上: {pre_login_user_record.user_id}') + login_service.incorrect_login_password_attempt(pre_login_user_record.user_id) raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=constants.LOGOUT_REASON_LOGIN_FAILED_LIMIT_EXCEEDED) try: @@ -79,7 +79,11 @@ def login( except NotAuthorizeException as e: logger.info(f'ログイン失敗:{e}') login_service.incorrect_login_password_attempt(request.username) - raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=constants.LOGOUT_REASON_LOGIN_ERROR) + if pre_login_user_record is not None and pre_login_user_record.is_on_login_failed_limit(): + login_service.on_login_fail_limit_exceeded(pre_login_user_record.user_id) + raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=constants.LOGOUT_REASON_LOGIN_FAILED_LIMIT_EXCEEDED) + else: + raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=constants.LOGOUT_REASON_LOGIN_ERROR) except JWTTokenVerifyException as e: logger.info(f'ログイン失敗:{e}') raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED) diff --git a/ecs/jskult-webapp/src/model/db/user_master.py b/ecs/jskult-webapp/src/model/db/user_master.py index b8dee115..711fe366 100644 --- a/ecs/jskult-webapp/src/model/db/user_master.py +++ b/ecs/jskult-webapp/src/model/db/user_master.py @@ -39,3 +39,6 @@ class UserMasterModel(BaseDBModel): def is_login_failed_limit_exceeded(self): return self.mntuser_login_failed_cnt >= constants.LOGIN_FAIL_LIMIT + + def is_on_login_failed_limit(self): + return self.mntuser_login_failed_cnt == constants.LOGIN_FAIL_LIMIT - 1 \ No newline at end of file From 7a65e2b46ea448fc0c1d2f6091b0cb885e097327 Mon Sep 17 00:00:00 2001 From: "nik.n" Date: Wed, 3 Apr 2024 16:05:41 +0900 Subject: [PATCH 04/13] =?UTF-8?q?=E3=83=AD=E3=82=B8=E3=83=83=E3=82=AF?= =?UTF-8?q?=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ecs/jskult-webapp/src/controller/login.py | 12 +++++++----- ecs/jskult-webapp/src/services/login_service.py | 2 +- ecs/jskult-webapp/src/system_var/constants.py | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/ecs/jskult-webapp/src/controller/login.py b/ecs/jskult-webapp/src/controller/login.py index f2c44559..d64a80fd 100644 --- a/ecs/jskult-webapp/src/controller/login.py +++ b/ecs/jskult-webapp/src/controller/login.py @@ -71,19 +71,21 @@ def login( # ログイン失敗回数が10回以上あれば、ログアウト画面にリダイレクトする if pre_login_user_record is not None and pre_login_user_record.is_login_failed_limit_exceeded(): logger.info(f'ログイン失敗回数が10回以上: {pre_login_user_record.user_id}') - login_service.incorrect_login_password_attempt(pre_login_user_record.user_id) + login_service.increase_login_failed_count(pre_login_user_record.user_id) raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=constants.LOGOUT_REASON_LOGIN_FAILED_LIMIT_EXCEEDED) try: jwt_token = login_service.login(request.username, request.password) except NotAuthorizeException as e: logger.info(f'ログイン失敗:{e}') - login_service.incorrect_login_password_attempt(request.username) - if pre_login_user_record is not None and pre_login_user_record.is_on_login_failed_limit(): + login_service.increase_login_failed_count(request.username) + + # pre_login_user_recordのデータ更新 + pre_login_user_record = login_service.logged_in_user(request.username) + if pre_login_user_record is not None and pre_login_user_record.is_login_failed_limit_exceeded(): login_service.on_login_fail_limit_exceeded(pre_login_user_record.user_id) raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=constants.LOGOUT_REASON_LOGIN_FAILED_LIMIT_EXCEEDED) - else: - raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=constants.LOGOUT_REASON_LOGIN_ERROR) + raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=constants.LOGOUT_REASON_LOGIN_ERROR) except JWTTokenVerifyException as e: logger.info(f'ログイン失敗:{e}') raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED) diff --git a/ecs/jskult-webapp/src/services/login_service.py b/ecs/jskult-webapp/src/services/login_service.py index ded8b7b7..ae7849b0 100644 --- a/ecs/jskult-webapp/src/services/login_service.py +++ b/ecs/jskult-webapp/src/services/login_service.py @@ -49,7 +49,7 @@ class LoginService(BaseService): user_record: UserMasterModel = self.user_repository.fetch_one({'user_id': user_id}) return user_record - def incorrect_login_password_attempt(self, user_id: str): + def increase_login_failed_count(self, user_id: str): self.user_repository.increase_login_failed_count({'user_id': user_id}) def on_login_fail_limit_exceeded(self, user_id: str): diff --git a/ecs/jskult-webapp/src/system_var/constants.py b/ecs/jskult-webapp/src/system_var/constants.py index 6422fdd5..962ed7d6 100644 --- a/ecs/jskult-webapp/src/system_var/constants.py +++ b/ecs/jskult-webapp/src/system_var/constants.py @@ -63,7 +63,7 @@ LOGOUT_REASON_BACKUP_PROCESSING = 'dump_processing' LOGOUT_REASON_NOT_LOGIN = 'not_login' LOGOUT_REASON_DB_ERROR = 'db_error' LOGOUT_REASON_UNEXPECTED = 'unexpected' -LOGOUT_REASON_LOGIN_FAILED_LIMIT_EXCEEDED = 'retry_limit_exceeded' +LOGOUT_REASON_LOGIN_FAILED_LIMIT_EXCEEDED = 'login_failed_limit_exceeded' LOGOUT_REASON_MESSAGE_MAP = { LOGOUT_REASON_DO_LOGOUT: 'Logoutしました。', From fa3100b830e74a085ae3524566e814feec1eb71f Mon Sep 17 00:00:00 2001 From: "nik.n" Date: Wed, 3 Apr 2024 16:20:18 +0900 Subject: [PATCH 05/13] =?UTF-8?q?=E3=82=AF=E3=83=A9=E3=82=B9=E9=96=A2?= =?UTF-8?q?=E6=95=B0=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ecs/jskult-webapp/src/model/db/user_master.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ecs/jskult-webapp/src/model/db/user_master.py b/ecs/jskult-webapp/src/model/db/user_master.py index 711fe366..5c58cddb 100644 --- a/ecs/jskult-webapp/src/model/db/user_master.py +++ b/ecs/jskult-webapp/src/model/db/user_master.py @@ -38,7 +38,4 @@ class UserMasterModel(BaseDBModel): return self.mntuser_flg == '0' or self.mntuser_flg is None def is_login_failed_limit_exceeded(self): - return self.mntuser_login_failed_cnt >= constants.LOGIN_FAIL_LIMIT - - def is_on_login_failed_limit(self): - return self.mntuser_login_failed_cnt == constants.LOGIN_FAIL_LIMIT - 1 \ No newline at end of file + return self.mntuser_login_failed_cnt >= constants.LOGIN_FAIL_LIMIT \ No newline at end of file From ac5cfc4d0f8eecd12ad65707737b61f91e7e443e Mon Sep 17 00:00:00 2001 From: "nik.n" Date: Wed, 3 Apr 2024 17:16:08 +0900 Subject: [PATCH 06/13] =?UTF-8?q?=E3=83=AD=E3=82=B0=E3=82=A4=E3=83=B3?= =?UTF-8?q?=E5=A4=B1=E6=95=97=E5=88=A4=E5=AE=9A=E3=83=AD=E3=82=B8=E3=83=83?= =?UTF-8?q?=E3=82=AF=E3=82=AF=E3=83=A9=E3=82=B9=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ecs/jskult-webapp/src/controller/login.py | 17 ++++++----------- ecs/jskult-webapp/src/model/db/user_master.py | 6 +----- ecs/jskult-webapp/src/services/login_service.py | 8 +++++++- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/ecs/jskult-webapp/src/controller/login.py b/ecs/jskult-webapp/src/controller/login.py index d64a80fd..153156f8 100644 --- a/ecs/jskult-webapp/src/controller/login.py +++ b/ecs/jskult-webapp/src/controller/login.py @@ -66,12 +66,10 @@ def login( request: LoginModel = Depends(LoginModel.as_form), login_service: LoginService = Depends(get_service(LoginService)) ): - # ユーザーマスタ検索 - pre_login_user_record = login_service.logged_in_user(request.username) - # ログイン失敗回数が10回以上あれば、ログアウト画面にリダイレクトする - if pre_login_user_record is not None and pre_login_user_record.is_login_failed_limit_exceeded(): - logger.info(f'ログイン失敗回数が10回以上: {pre_login_user_record.user_id}') - login_service.increase_login_failed_count(pre_login_user_record.user_id) + # ログイン成功問わず、DBのログイン失敗回数が10回以上あれば、ログアウト画面にリダイレクトする + if login_service.is_login_failed_limit_exceeded(request.username): + logger.info(f'ログイン失敗回数が10回以上: {request.username}') + login_service.increase_login_failed_count(request.username) raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=constants.LOGOUT_REASON_LOGIN_FAILED_LIMIT_EXCEEDED) try: @@ -79,11 +77,8 @@ def login( except NotAuthorizeException as e: logger.info(f'ログイン失敗:{e}') login_service.increase_login_failed_count(request.username) - - # pre_login_user_recordのデータ更新 - pre_login_user_record = login_service.logged_in_user(request.username) - if pre_login_user_record is not None and pre_login_user_record.is_login_failed_limit_exceeded(): - login_service.on_login_fail_limit_exceeded(pre_login_user_record.user_id) + if login_service.is_login_failed_limit_exceeded(request.username): + login_service.on_login_fail_limit_exceeded(request.username) raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=constants.LOGOUT_REASON_LOGIN_FAILED_LIMIT_EXCEEDED) raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=constants.LOGOUT_REASON_LOGIN_ERROR) except JWTTokenVerifyException as e: diff --git a/ecs/jskult-webapp/src/model/db/user_master.py b/ecs/jskult-webapp/src/model/db/user_master.py index 5c58cddb..879cd008 100644 --- a/ecs/jskult-webapp/src/model/db/user_master.py +++ b/ecs/jskult-webapp/src/model/db/user_master.py @@ -2,7 +2,6 @@ from datetime import datetime from typing import Optional from src.model.db.base_db_model import BaseDBModel -from src.system_var import constants class UserMasterModel(BaseDBModel): user_id: Optional[str] @@ -35,7 +34,4 @@ class UserMasterModel(BaseDBModel): return self.mntuser_flg == '1' def is_groupware_user(self): - return self.mntuser_flg == '0' or self.mntuser_flg is None - - def is_login_failed_limit_exceeded(self): - return self.mntuser_login_failed_cnt >= constants.LOGIN_FAIL_LIMIT \ No newline at end of file + return self.mntuser_flg == '0' or self.mntuser_flg is None \ No newline at end of file diff --git a/ecs/jskult-webapp/src/services/login_service.py b/ecs/jskult-webapp/src/services/login_service.py index ae7849b0..fa75b5bf 100644 --- a/ecs/jskult-webapp/src/services/login_service.py +++ b/ecs/jskult-webapp/src/services/login_service.py @@ -11,7 +11,7 @@ from src.repositories.base_repository import BaseRepository from src.repositories.user_master_repository import UserMasterRepository from src.services.base_service import BaseService from src.system_var import environment - +from src.system_var import constants class LoginService(BaseService): REPOSITORIES = { @@ -55,6 +55,12 @@ class LoginService(BaseService): def on_login_fail_limit_exceeded(self, user_id: str): self.user_repository.disable_mnt_user({'user_id': user_id}) + def is_login_failed_limit_exceeded(self, user_id: str): + user_record: UserMasterModel = self.user_repository.fetch_one({'user_id': user_id}) + if user_record is None: + return False + return user_record.mntuser_login_failed_cnt >= constants.LOGIN_FAIL_LIMIT + def __secret_hash(self, username: str): # see - https://aws.amazon.com/jp/premiumsupport/knowledge-center/cognito-unable-to-verify-secret-hash/ # noqa message = bytes(username + environment.COGNITO_CLIENT_ID, 'utf-8') From cfdac2b9f424a5c9e3d534b2dfdcd9f2ed93a085 Mon Sep 17 00:00:00 2001 From: "nik.n" Date: Thu, 4 Apr 2024 10:08:08 +0900 Subject: [PATCH 07/13] =?UTF-8?q?SQL=E6=9B=B4=E6=96=B0=E3=83=AD=E3=82=B8?= =?UTF-8?q?=E3=83=83=E3=82=AF=E5=A4=89=E6=9B=B4=E3=83=BB=E5=A4=B1=E6=95=97?= =?UTF-8?q?=E5=88=A4=E5=AE=9A=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ecs/jskult-webapp/src/model/db/user_master.py | 6 +++++- .../src/repositories/user_master_repository.py | 10 ++++++++-- ecs/jskult-webapp/src/services/login_service.py | 2 +- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/ecs/jskult-webapp/src/model/db/user_master.py b/ecs/jskult-webapp/src/model/db/user_master.py index 879cd008..d86253ae 100644 --- a/ecs/jskult-webapp/src/model/db/user_master.py +++ b/ecs/jskult-webapp/src/model/db/user_master.py @@ -2,6 +2,7 @@ from datetime import datetime from typing import Optional from src.model.db.base_db_model import BaseDBModel +from src.system_var import constants class UserMasterModel(BaseDBModel): user_id: Optional[str] @@ -34,4 +35,7 @@ class UserMasterModel(BaseDBModel): return self.mntuser_flg == '1' def is_groupware_user(self): - return self.mntuser_flg == '0' or self.mntuser_flg is None \ No newline at end of file + return self.mntuser_flg == '0' or self.mntuser_flg is None + + def is_login_failed_limit_exceeded(self): + return self.mntuser_login_failed_cnt >= constants.LOGIN_FAIL_LIMIT \ No newline at end of file diff --git a/ecs/jskult-webapp/src/repositories/user_master_repository.py b/ecs/jskult-webapp/src/repositories/user_master_repository.py index 0516ec79..dcb10aa9 100644 --- a/ecs/jskult-webapp/src/repositories/user_master_repository.py +++ b/ecs/jskult-webapp/src/repositories/user_master_repository.py @@ -35,8 +35,14 @@ class UserMasterRepository(BaseRepository): SET mntuser_login_failed_cnt = CASE - WHEN DATE(mntuser_last_login_failed_datetime) = CURRENT_DATE() THEN mntuser_login_failed_cnt + 1 - ELSE 1 + WHEN + DATE(mntuser_last_login_failed_datetime) = CURRENT_DATE() + OR + mntuser_login_failed_cnt >= 10 + THEN + mntuser_login_failed_cnt + 1 + ELSE + 1 END, mntuser_last_login_failed_datetime = CURRENT_TIMESTAMP() WHERE diff --git a/ecs/jskult-webapp/src/services/login_service.py b/ecs/jskult-webapp/src/services/login_service.py index fa75b5bf..2ea0724a 100644 --- a/ecs/jskult-webapp/src/services/login_service.py +++ b/ecs/jskult-webapp/src/services/login_service.py @@ -59,7 +59,7 @@ class LoginService(BaseService): user_record: UserMasterModel = self.user_repository.fetch_one({'user_id': user_id}) if user_record is None: return False - return user_record.mntuser_login_failed_cnt >= constants.LOGIN_FAIL_LIMIT + return user_record.is_login_failed_limit_exceeded() def __secret_hash(self, username: str): # see - https://aws.amazon.com/jp/premiumsupport/knowledge-center/cognito-unable-to-verify-secret-hash/ # noqa From 4d09f9973a02dd14ab1012f96d4db6b28ac6099d Mon Sep 17 00:00:00 2001 From: "nik.n" Date: Thu, 4 Apr 2024 16:41:54 +0900 Subject: [PATCH 08/13] =?UTF-8?q?=E4=B8=8D=E8=A6=81=E3=81=AADB=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E5=87=A6=E7=90=86=E3=82=92=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ecs/jskult-webapp/src/controller/login.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ecs/jskult-webapp/src/controller/login.py b/ecs/jskult-webapp/src/controller/login.py index 153156f8..6d0e5343 100644 --- a/ecs/jskult-webapp/src/controller/login.py +++ b/ecs/jskult-webapp/src/controller/login.py @@ -69,7 +69,6 @@ def login( # ログイン成功問わず、DBのログイン失敗回数が10回以上あれば、ログアウト画面にリダイレクトする if login_service.is_login_failed_limit_exceeded(request.username): logger.info(f'ログイン失敗回数が10回以上: {request.username}') - login_service.increase_login_failed_count(request.username) raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=constants.LOGOUT_REASON_LOGIN_FAILED_LIMIT_EXCEEDED) try: From fb04d6fc4846e834c95898769b0934754768b52f Mon Sep 17 00:00:00 2001 From: "nik.n" Date: Thu, 4 Apr 2024 16:53:43 +0900 Subject: [PATCH 09/13] =?UTF-8?q?10=E5=9B=9E=E3=83=AD=E3=82=B0=E3=82=A4?= =?UTF-8?q?=E3=83=B3=E5=A4=B1=E6=95=97=E5=88=A4=E5=AE=9A=E6=9D=A1=E4=BB=B6?= =?UTF-8?q?=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ecs/jskult-webapp/src/controller/login.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ecs/jskult-webapp/src/controller/login.py b/ecs/jskult-webapp/src/controller/login.py index 6d0e5343..99f4a389 100644 --- a/ecs/jskult-webapp/src/controller/login.py +++ b/ecs/jskult-webapp/src/controller/login.py @@ -66,11 +66,6 @@ def login( request: LoginModel = Depends(LoginModel.as_form), login_service: LoginService = Depends(get_service(LoginService)) ): - # ログイン成功問わず、DBのログイン失敗回数が10回以上あれば、ログアウト画面にリダイレクトする - if login_service.is_login_failed_limit_exceeded(request.username): - logger.info(f'ログイン失敗回数が10回以上: {request.username}') - raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=constants.LOGOUT_REASON_LOGIN_FAILED_LIMIT_EXCEEDED) - try: jwt_token = login_service.login(request.username, request.password) except NotAuthorizeException as e: @@ -84,6 +79,11 @@ def login( logger.info(f'ログイン失敗:{e}') raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED) + # ログイン成功問わず、DBのログイン失敗回数が10回以上あれば、ログアウト画面にリダイレクトする + if login_service.is_login_failed_limit_exceeded(request.username): + logger.info(f'ログイン失敗回数が10回以上: {request.username}') + raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=constants.LOGOUT_REASON_LOGIN_FAILED_LIMIT_EXCEEDED) + verified_token = jwt_token.verify_token() # 普通の認証だと、`cognito:username`に入る。 user_id = verified_token.user_id From eb7d8bfb3914e25f02520d6e3913ac0d7e49b27c Mon Sep 17 00:00:00 2001 From: "nik.n" Date: Tue, 9 Apr 2024 14:10:28 +0900 Subject: [PATCH 10/13] =?UTF-8?q?=E6=97=A5=E4=BB=98=E8=A8=98=E9=8C=B2GMT?= =?UTF-8?q?=EF=BC=8B9=E3=81=AB=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ecs/jskult-webapp/src/repositories/user_master_repository.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ecs/jskult-webapp/src/repositories/user_master_repository.py b/ecs/jskult-webapp/src/repositories/user_master_repository.py index dcb10aa9..51a9935f 100644 --- a/ecs/jskult-webapp/src/repositories/user_master_repository.py +++ b/ecs/jskult-webapp/src/repositories/user_master_repository.py @@ -36,7 +36,7 @@ class UserMasterRepository(BaseRepository): mntuser_login_failed_cnt = CASE WHEN - DATE(mntuser_last_login_failed_datetime) = CURRENT_DATE() + DATE(mntuser_last_login_failed_datetime) = DATE(CONVERT_TZ(CURRENT_TIMESTAMP() ,'Etc/GMT-0','Asia/Tokyo')) OR mntuser_login_failed_cnt >= 10 THEN @@ -44,7 +44,7 @@ class UserMasterRepository(BaseRepository): ELSE 1 END, - mntuser_last_login_failed_datetime = CURRENT_TIMESTAMP() + mntuser_last_login_failed_datetime = CONVERT_TZ(CURRENT_TIMESTAMP() ,'Etc/GMT-0','Asia/Tokyo') WHERE user_id = :user_id AND From 166dde48488d26d48a0275e4a8b1c3f4ac118ce6 Mon Sep 17 00:00:00 2001 From: "nik.n" Date: Thu, 11 Apr 2024 09:06:18 +0900 Subject: [PATCH 11/13] =?UTF-8?q?=E4=BB=95=E6=A7=98=E3=81=AB=E5=90=88?= =?UTF-8?q?=E3=82=8F=E3=81=9B=E3=81=A6=E6=9D=A1=E4=BB=B6=E9=A0=86=E5=93=A1?= =?UTF-8?q?=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ecs/jskult-webapp/src/repositories/user_master_repository.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/ecs/jskult-webapp/src/repositories/user_master_repository.py b/ecs/jskult-webapp/src/repositories/user_master_repository.py index 51a9935f..3024afe0 100644 --- a/ecs/jskult-webapp/src/repositories/user_master_repository.py +++ b/ecs/jskult-webapp/src/repositories/user_master_repository.py @@ -37,8 +37,6 @@ class UserMasterRepository(BaseRepository): CASE WHEN DATE(mntuser_last_login_failed_datetime) = DATE(CONVERT_TZ(CURRENT_TIMESTAMP() ,'Etc/GMT-0','Asia/Tokyo')) - OR - mntuser_login_failed_cnt >= 10 THEN mntuser_login_failed_cnt + 1 ELSE From db0e28db3e07c3060e1ba1f53c5efea77dd7f7be Mon Sep 17 00:00:00 2001 From: "shimoda.m@nds-tyo.co.jp" Date: Mon, 15 Apr 2024 15:29:10 +0900 Subject: [PATCH 12/13] =?UTF-8?q?fix:=20=E3=83=A6=E3=83=BC=E3=82=B6?= =?UTF-8?q?=E3=83=BC=E3=83=9E=E3=82=B9=E3=82=BF=E6=9B=B4=E6=96=B0=E6=99=82?= =?UTF-8?q?=E3=81=AE=E3=82=BF=E3=82=A4=E3=83=A0=E3=82=BE=E3=83=BC=E3=83=B3?= =?UTF-8?q?=E3=82=92JST=E3=81=AB=E5=A4=89=E6=9B=B4=EF=BC=88=E5=85=B1?= =?UTF-8?q?=E9=80=9A=E9=96=A2=E6=95=B0=E3=82=92=E4=BD=BF=E7=94=A8=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ecs/jskult-webapp/src/controller/login.py | 2 + ecs/jskult-webapp/src/db/database.py | 4 +- .../repositories/user_master_repository.py | 43 ++++++++++++------- .../src/services/login_service.py | 13 +++++- 4 files changed, 44 insertions(+), 18 deletions(-) diff --git a/ecs/jskult-webapp/src/controller/login.py b/ecs/jskult-webapp/src/controller/login.py index 99f4a389..9b2c808e 100644 --- a/ecs/jskult-webapp/src/controller/login.py +++ b/ecs/jskult-webapp/src/controller/login.py @@ -70,7 +70,9 @@ def login( jwt_token = login_service.login(request.username, request.password) except NotAuthorizeException as e: logger.info(f'ログイン失敗:{e}') + # ログイン失敗回数をカウント login_service.increase_login_failed_count(request.username) + # ログイン失敗回数を超過した場合はメッセージを変える if login_service.is_login_failed_limit_exceeded(request.username): login_service.on_login_fail_limit_exceeded(request.username) raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=constants.LOGOUT_REASON_LOGIN_FAILED_LIMIT_EXCEEDED) diff --git a/ecs/jskult-webapp/src/db/database.py b/ecs/jskult-webapp/src/db/database.py index c729faf5..7dab8455 100644 --- a/ecs/jskult-webapp/src/db/database.py +++ b/ecs/jskult-webapp/src/db/database.py @@ -189,7 +189,9 @@ class DatabaseClient: self.__session = None def to_jst(self): - self.execute('SET time_zone = "+9:00"') + # self.session.begin() + self.execute('SET SESSION time_zone = "Asia/Tokyo"') + # self.session.commit() def __execute_with_transaction(self, query: str, parameters: dict): # トランザクションを開始してクエリを実行する diff --git a/ecs/jskult-webapp/src/repositories/user_master_repository.py b/ecs/jskult-webapp/src/repositories/user_master_repository.py index 3024afe0..3acbc105 100644 --- a/ecs/jskult-webapp/src/repositories/user_master_repository.py +++ b/ecs/jskult-webapp/src/repositories/user_master_repository.py @@ -6,6 +6,19 @@ logger = get_logger('ユーザー取得') class UserMasterRepository(BaseRepository): + + def to_jst(self): + self._database.to_jst() + + def begin(self): + self._database.begin() + + def commit(self): + self._database.commit() + + def rollback(self): + self._database.rollback() + FETCH_SQL = """\ SELECT * @@ -30,29 +43,29 @@ class UserMasterRepository(BaseRepository): def increase_login_failed_count(self, parameter: dict) -> UserMasterModel: try: query = """\ - UPDATE - src05.user_mst - SET - mntuser_login_failed_cnt = - CASE - WHEN - DATE(mntuser_last_login_failed_datetime) = DATE(CONVERT_TZ(CURRENT_TIMESTAMP() ,'Etc/GMT-0','Asia/Tokyo')) - THEN + UPDATE + src05.user_mst + SET + mntuser_login_failed_cnt = + CASE + WHEN + DATE(mntuser_last_login_failed_datetime) = DATE(CURRENT_TIMESTAMP()) + THEN mntuser_login_failed_cnt + 1 - ELSE + ELSE 1 - END, - mntuser_last_login_failed_datetime = CONVERT_TZ(CURRENT_TIMESTAMP() ,'Etc/GMT-0','Asia/Tokyo') - WHERE + END, + mntuser_last_login_failed_datetime = CURRENT_TIMESTAMP() + WHERE user_id = :user_id - AND + AND mntuser_flg = 1;\ """ self._database.execute(query, parameter) except Exception as e: logger.exception(f"DB Error : Exception={e}") raise e - + def disable_mnt_user(self, parameter: dict) -> UserMasterModel: try: query = """\ @@ -68,4 +81,4 @@ class UserMasterRepository(BaseRepository): self._database.execute(query, parameter) except Exception as e: logger.exception(f"DB Error : Exception={e}") - raise e \ No newline at end of file + raise e diff --git a/ecs/jskult-webapp/src/services/login_service.py b/ecs/jskult-webapp/src/services/login_service.py index 2ea0724a..3a2715b2 100644 --- a/ecs/jskult-webapp/src/services/login_service.py +++ b/ecs/jskult-webapp/src/services/login_service.py @@ -11,7 +11,7 @@ from src.repositories.base_repository import BaseRepository from src.repositories.user_master_repository import UserMasterRepository from src.services.base_service import BaseService from src.system_var import environment -from src.system_var import constants + class LoginService(BaseService): REPOSITORIES = { @@ -50,7 +50,16 @@ class LoginService(BaseService): return user_record def increase_login_failed_count(self, user_id: str): - self.user_repository.increase_login_failed_count({'user_id': user_id}) + + try: + # セッション内のタイムゾーン変更のため、明示的にトランザクションを開始する + self.user_repository.begin() + self.user_repository.to_jst() + self.user_repository.increase_login_failed_count({'user_id': user_id}) + self.user_repository.commit() + except Exception as e: + self.user_repository.rollback() + raise e def on_login_fail_limit_exceeded(self, user_id: str): self.user_repository.disable_mnt_user({'user_id': user_id}) From 240945b8d5c975dbc4d71ce16bcfbbcf63852cdc Mon Sep 17 00:00:00 2001 From: "shimoda.m@nds-tyo.co.jp" Date: Mon, 15 Apr 2024 17:38:37 +0900 Subject: [PATCH 13/13] =?UTF-8?q?style:=20=E4=B8=8D=E8=A6=81=E3=81=AA?= =?UTF-8?q?=E3=82=B3=E3=83=A1=E3=83=B3=E3=83=88=E3=82=92=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ecs/jskult-webapp/src/db/database.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/ecs/jskult-webapp/src/db/database.py b/ecs/jskult-webapp/src/db/database.py index 7dab8455..bd828db3 100644 --- a/ecs/jskult-webapp/src/db/database.py +++ b/ecs/jskult-webapp/src/db/database.py @@ -189,9 +189,7 @@ class DatabaseClient: self.__session = None def to_jst(self): - # self.session.begin() self.execute('SET SESSION time_zone = "Asia/Tokyo"') - # self.session.commit() def __execute_with_transaction(self, query: str, parameters: dict): # トランザクションを開始してクエリを実行する