diff --git a/README.md b/README.md index 026cb87..4c6ce55 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ docker-compose up --build - `OIDC_REDIRECT_URI`: 콜백 URL - `BARON_API_BASE_URL`: Baron Backend/Public Gateway 기준 URL. 기본적으로 `OIDC_ISSUER_URL`에서 `/oidc`를 제거한 값을 사용합니다. - `BARON_BACKCHANNEL_JWKS_URL`: Baron이 서명한 `logout_token` 검증용 JWKS URL. 기본값은 `/api/v1/auth/backchannel/jwks.json` 입니다. +- `BARON_SESSION_VALIDATION_ENABLED`: `false`로 두면 기존의 요청 시 Baron 세션 재검증을 끄고, Back-Channel Logout만으로 세션 종료를 확인할 수 있습니다. 기본값은 `true`입니다. ## 세션 종료 / 연동 해지 동작 diff --git a/app.js b/app.js index ef61428..37803da 100644 --- a/app.js +++ b/app.js @@ -33,7 +33,9 @@ app.set('views', path.join(__dirname, 'views')); app.use(express.urlencoded({ extended: false })); +const sessionStore = new session.MemoryStore(); const sessionMiddleware = session({ + store: sessionStore, name: 'baron.demo.sid', secret: process.env.SESSION_SECRET || 'demo-session-secret', resave: true, @@ -306,6 +308,8 @@ async function setupOIDC() { const redirectUri = process.env.OIDC_REDIRECT_URI || 'http://localhost:3000/callback'; const backchannelJwksUrl = deriveBackchannelJwksUrl(); const backchannelJwks = createRemoteJWKSet(new URL(backchannelJwksUrl)); + const sessionValidationEnabled = + String(process.env.BARON_SESSION_VALIDATION_ENABLED || 'true').toLowerCase() !== 'false'; console.log(`OIDC Issuer 조회: ${issuerUrl}`); console.log(`백채널 로그아웃 JWKS 주소: ${backchannelJwksUrl}`); @@ -322,40 +326,45 @@ async function setupOIDC() { clientId, redirectUri, authorizationEndpoint, + sessionValidationEnabled, }); - app.use(async (req, res, next) => { - const skipPaths = new Set(['/login', '/callback', '/logout', '/backchannel-logout']); - if (skipPaths.has(req.path)) { - return next(); - } - - const accessToken = req.session?.user?.tokenset?.access_token; - if (!accessToken) { - return next(); - } - - try { - const validation = await validateBaronSession(accessToken); - if (validation.ok) { - if (validation.profile) { - req.session.user.userinfo = validation.profile; - } + if (sessionValidationEnabled) { + app.use(async (req, res, next) => { + const skipPaths = new Set(['/login', '/callback', '/logout', '/backchannel-logout']); + if (skipPaths.has(req.path)) { return next(); } - console.warn('[세션 검증] Baron 세션이 유효하지 않아 로컬 세션을 정리합니다.', { - path: req.path, - reason: validation.reason, - }); - await destroyDemoSession(req, res); - return res.redirect('/'); - } catch (error) { - console.error('[세션 검증] Baron 세션 확인 실패로 로컬 세션을 정리합니다.', error); - await destroyDemoSession(req, res); - return res.redirect('/'); - } - }); + const accessToken = req.session?.user?.tokenset?.access_token; + if (!accessToken) { + return next(); + } + + try { + const validation = await validateBaronSession(accessToken); + if (validation.ok) { + if (validation.profile) { + req.session.user.userinfo = validation.profile; + } + return next(); + } + + console.warn('[세션 검증] Baron 세션이 유효하지 않아 로컬 세션을 정리합니다.', { + path: req.path, + reason: validation.reason, + }); + await destroyDemoSession(req, res); + return res.redirect('/'); + } catch (error) { + console.error('[세션 검증] Baron 세션 확인 실패로 로컬 세션을 정리합니다.', error); + await destroyDemoSession(req, res); + return res.redirect('/'); + } + }); + } else { + console.log('[시스템] Baron 세션 재검증 미들웨어를 비활성화했습니다. 백채널 로그아웃 테스트 전용 모드입니다.'); + } app.get('/', (req, res) => { res.render('index', { user: req.session.user }); @@ -480,7 +489,7 @@ async function setupOIDC() { jwks: backchannelJwks, }); - const result = await destroySessionsForLogout(sessionMiddleware.store, claims); + const result = await destroySessionsForLogout(sessionStore, claims); console.log('[백채널 로그아웃] 처리 완료', { sid: claims.sid || '(없음)', sub: claims.sub || '(없음)', diff --git a/docker-compose.yml b/docker-compose.yml index bf09270..f0ac87c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,6 +11,7 @@ services: - OIDC_CLIENT_ID=f5cdd938-a3ae-4e47-ab83-4c13e59949f5 - OIDC_REDIRECT_URI=http://localhost:3333/callback - BARON_API_BASE_URL=https://sso-test.hmac.kr + - BARON_SESSION_VALIDATION_ENABLED=false extra_hosts: - "localhost:host-gateway" networks: