From 09ff4327eec613dbee63c2922394cac6b2f6f187 Mon Sep 17 00:00:00 2001 From: "oura.a" Date: Wed, 8 Nov 2023 02:55:28 +0000 Subject: [PATCH] =?UTF-8?q?Merged=20PR=20564:=20Revert=20"Merged=20PR=2054?= =?UTF-8?q?8:=20=E3=83=AD=E3=82=B0=E3=82=A4=E3=83=B3=E5=9B=9E=E3=82=8A?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Revert "Merged PR 548: ログイン回り修正 ## 概要 [Task1828: IDトークンを一度しか使えないようにする](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/1828) - 元PBI or タスクへのリンク(内容・目的などはそちらにあるはず) ログイン時にRedisを参照し、同じIDトークンでアクセスされていた場合はアクセスを拒否する。 初めて認証で使われるIDトークンの場合は、Redisに保存する(有効期限は300秒(IDトークンの有効期限の最小値)) ログイン後、クライアントはローカルストレージの不要な情報を破棄する(accessToken,refreshToken,displayInfo以外) - 影響範囲(他の機能にも影響があるか) 新規機能のため、なし。 ## レビューポイント - keyの形式id-token:{idトークンの中身}は想定通りか。 - ログイン後のローカルストレージの状態が想定通りか。 - controllerやservice層の実装箇所が妥当か。 - stg環境、本番環境のIDトークンの有効期限を最小値に設定するタスクを備忘用PBIに切り出しました。 https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/OMDSDictation/_sprints/taskboard/OMDSDictation%20%E3%83%81%E3%83%BC%E3%83%A0/OMDSDictation/%E3%82%B9%E3%83%97%E3%83%AA%E3%83%B3%E3%83%88%2021-1?workitem=3041 ## UIの変更 https://ndstokyo.sharepoint.com/:f:/r/sites/Piranha/Shared%20Documents/General/OMDS/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88/Task1828?csf=1&web=1&e=1Sc1VP ## 動作確認状況 - ローカルで確認 ## 補足 - 相談、参考資料などがあれば" Reverted commit `0cdb0f42`. --- .../src/components/auth/constants.ts | 6 ---- .../src/features/login/operations.ts | 31 +++++++------------ .../src/common/cache/constants.ts | 2 -- dictation_server/src/common/cache/index.ts | 11 +------ dictation_server/src/common/test/modules.ts | 4 --- .../src/features/auth/auth.controller.ts | 17 ++-------- .../src/features/auth/auth.module.ts | 11 +++++-- .../src/features/auth/auth.service.spec.ts | 1 + .../src/gateways/adb2c/adb2c.service.ts | 2 +- 9 files changed, 24 insertions(+), 61 deletions(-) diff --git a/dictation_client/src/components/auth/constants.ts b/dictation_client/src/components/auth/constants.ts index 649d569..34f51b0 100644 --- a/dictation_client/src/components/auth/constants.ts +++ b/dictation_client/src/components/auth/constants.ts @@ -39,12 +39,6 @@ export const UNAUTHORIZED_TO_CONTINUE_ERROR_CODES = [ "E10501", ]; -/** - * ローカルストレージに残すキー類 - * @const {string[]} - */ -export const KEYS_TO_PRESERVE = ["accessToken", "refreshToken", "displayInfo"]; - /** * アクセストークンを更新する基準の秒数 * @const {number} diff --git a/dictation_client/src/features/login/operations.ts b/dictation_client/src/features/login/operations.ts index f320ac2..07185ba 100644 --- a/dictation_client/src/features/login/operations.ts +++ b/dictation_client/src/features/login/operations.ts @@ -1,15 +1,17 @@ import { createAsyncThunk } from "@reduxjs/toolkit"; import type { RootState } from "app/store"; -import { setToken } from "features/auth/authSlice"; -import { KEYS_TO_PRESERVE } from "components/auth/constants"; -import { AuthApi, UsersApi, GetMyUserResponse } from "../../api/api"; +import { getAccessToken, setToken } from "features/auth"; +import { + AuthApi, + UsersApi, + GetMyUserResponse, + TokenResponse, +} from "../../api/api"; import { Configuration } from "../../api/configuration"; import { ErrorObject, createErrorObject } from "../../common/errors"; export const loginAsync = createAsyncThunk< - { - // - }, + TokenResponse, { idToken: string; }, @@ -33,7 +35,6 @@ export const loginAsync = createAsyncThunk< idToken, type: "web", }); - // アクセストークン・リフレッシュトークンをlocalStorageに保存 thunkApi.dispatch( setToken({ @@ -41,19 +42,8 @@ export const loginAsync = createAsyncThunk< refreshToken: data.refreshToken, }) ); - // ローカルストレージに残すキー - const keysToPreserve = KEYS_TO_PRESERVE; - // すべてのローカルストレージキーを取得 - const allKeys = Object.keys(localStorage); - - // 特定のキーを除外して削除 - allKeys.forEach((key) => { - if (!keysToPreserve.includes(key)) { - localStorage.removeItem(key); - } - }); - return {}; + return data; } catch (e) { // e ⇒ errorObjectに変換" const error = createErrorObject(e); @@ -76,7 +66,8 @@ export const getUserInfoAsync = createAsyncThunk< // apiのConfigurationを取得する const { getState } = thunkApi; const state = getState() as RootState; - const { configuration, accessToken } = state.auth; + const { configuration } = state.auth; + const accessToken = getAccessToken(state.auth); const config = new Configuration(configuration); const usersApi = new UsersApi(config); diff --git a/dictation_server/src/common/cache/constants.ts b/dictation_server/src/common/cache/constants.ts index 9f588f6..b79dd78 100644 --- a/dictation_server/src/common/cache/constants.ts +++ b/dictation_server/src/common/cache/constants.ts @@ -1,3 +1 @@ export const ADB2C_PREFIX = 'adb2c-external-id:'; - -export const IDTOKEN_PREFIX = 'id-token:'; diff --git a/dictation_server/src/common/cache/index.ts b/dictation_server/src/common/cache/index.ts index 4985492..3355a54 100644 --- a/dictation_server/src/common/cache/index.ts +++ b/dictation_server/src/common/cache/index.ts @@ -1,4 +1,4 @@ -import { ADB2C_PREFIX, IDTOKEN_PREFIX } from './constants'; +import { ADB2C_PREFIX } from './constants'; /** * ADB2Cのユーザー格納用のキーを生成する @@ -17,12 +17,3 @@ export const makeADB2CKey = (externalId: string): string => { export const restoreAdB2cID = (key: string): string => { return key.replace(ADB2C_PREFIX, ''); }; - -/** - * ADB2CのIDトークン格納用のキーを生成する - * @param idToken IDトークン - * @returns キャッシュのキー - */ -export const makeIDTokenKey = (idToken: string): string => { - return `${IDTOKEN_PREFIX}${idToken}`; -}; diff --git a/dictation_server/src/common/test/modules.ts b/dictation_server/src/common/test/modules.ts index 61c0396..9c3d578 100644 --- a/dictation_server/src/common/test/modules.ts +++ b/dictation_server/src/common/test/modules.ts @@ -38,8 +38,6 @@ import { TermsService } from '../../features/terms/terms.service'; import { TermsRepositoryModule } from '../../repositories/terms/terms.repository.module'; import { TermsModule } from '../../features/terms/terms.module'; import { CacheModule } from '@nestjs/common'; -import { RedisModule } from '../../gateways/redis/redis.module'; -import { RedisService } from '../../gateways/redis/redis.service'; export const makeTestingModule = async ( datasource: DataSource, @@ -79,7 +77,6 @@ export const makeTestingModule = async ( SortCriteriaRepositoryModule, WorktypesRepositoryModule, TermsRepositoryModule, - RedisModule, CacheModule.register({ isGlobal: true }), ], providers: [ @@ -93,7 +90,6 @@ export const makeTestingModule = async ( TemplatesService, WorkflowsService, TermsService, - RedisService, ], }) .useMocker(async (token) => { diff --git a/dictation_server/src/features/auth/auth.controller.ts b/dictation_server/src/features/auth/auth.controller.ts index 89e4de6..a07b666 100644 --- a/dictation_server/src/features/auth/auth.controller.ts +++ b/dictation_server/src/features/auth/auth.controller.ts @@ -33,15 +33,14 @@ import { RoleGuard } from '../../common/guards/role/roleguards'; import { ADMIN_ROLES, TIERS } from '../../constants'; import jwt from 'jsonwebtoken'; import { AccessToken, RefreshToken } from '../../common/token'; -import { makeIDTokenKey } from '../../common/cache'; -import { RedisService } from '../../gateways/redis/redis.service'; @ApiTags('auth') @Controller('auth') export class AuthController { constructor( + // TODO「タスク 1828: IDトークンを一度しか使えないようにする」で使用する予定 + // private readonly redisService: RedisService, private readonly authService: AuthService, - private readonly redisService: RedisService, ) {} @Post('token') @@ -77,18 +76,6 @@ export class AuthController { } const context = makeContext(uuidv4()); - const key = makeIDTokenKey(body.idToken); - const isTokenExists = await this.redisService.get(key); - if (!isTokenExists) { - // IDトークンがキャッシュに存在しない場合(idTokenの有効期限をADB2Cの有効期限と合わせる(300秒)) - await this.redisService.set(key, true, 300); - } else { - // IDトークンがキャッシュに存在する場合エラー - throw new HttpException( - makeErrorResponse('E000106'), - HttpStatus.UNAUTHORIZED, - ); - } // 同意済み利用規約バージョンが最新かチェック const isAcceptedLatestVersion = diff --git a/dictation_server/src/features/auth/auth.module.ts b/dictation_server/src/features/auth/auth.module.ts index d86bf30..2e3dc4c 100644 --- a/dictation_server/src/features/auth/auth.module.ts +++ b/dictation_server/src/features/auth/auth.module.ts @@ -4,10 +4,15 @@ import { AdB2cModule } from '../../gateways/adb2c/adb2c.module'; import { UsersRepositoryModule } from '../../repositories/users/users.repository.module'; import { AuthController } from './auth.controller'; import { AuthService } from './auth.service'; -import { RedisService } from '../../gateways/redis/redis.service'; +import { TermsRepositoryModule } from '../../repositories/terms/terms.repository.module'; @Module({ - imports: [ConfigModule, AdB2cModule, UsersRepositoryModule], + imports: [ + ConfigModule, + AdB2cModule, + UsersRepositoryModule, + TermsRepositoryModule, + ], controllers: [AuthController], - providers: [AuthService, RedisService], + providers: [AuthService], }) export class AuthModule {} diff --git a/dictation_server/src/features/auth/auth.service.spec.ts b/dictation_server/src/features/auth/auth.service.spec.ts index abeaf61..1be5e40 100644 --- a/dictation_server/src/features/auth/auth.service.spec.ts +++ b/dictation_server/src/features/auth/auth.service.spec.ts @@ -723,6 +723,7 @@ describe('updateDelegationAccessToken', () => { } }); }); + const idTokenPayload = { exp: 9000000000, nbf: 1000000000, diff --git a/dictation_server/src/gateways/adb2c/adb2c.service.ts b/dictation_server/src/gateways/adb2c/adb2c.service.ts index 947148a..69bd890 100644 --- a/dictation_server/src/gateways/adb2c/adb2c.service.ts +++ b/dictation_server/src/gateways/adb2c/adb2c.service.ts @@ -4,7 +4,7 @@ import { TokenCredentialAuthenticationProvider } from '@microsoft/microsoft-grap import { CACHE_MANAGER, Inject, Injectable, Logger } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import axios from 'axios'; -import { B2cMetadata, IDToken, JwkSignKey } from '../../common/token'; +import { B2cMetadata, JwkSignKey } from '../../common/token'; import { AdB2cResponse, AdB2cUser } from './types/types'; import { isPromiseRejectedResult } from './utils/utils'; import { Context } from '../../common/log';