From d015aa934cee6619814b8b3d928e34a6ce798515 Mon Sep 17 00:00:00 2001 From: Charles Zhao Date: Wed, 9 Nov 2022 15:38:07 +0800 Subject: [PATCH] feat(core,phrases): add re-authentication check function for protected access (#2327) --- packages/core/src/lib/session.ts | 25 ++++++++++++++++++++ packages/phrases/src/locales/de/errors.ts | 1 + packages/phrases/src/locales/en/errors.ts | 1 + packages/phrases/src/locales/fr/errors.ts | 1 + packages/phrases/src/locales/ko/errors.ts | 1 + packages/phrases/src/locales/pt-pt/errors.ts | 1 + packages/phrases/src/locales/tr-tr/errors.ts | 1 + packages/phrases/src/locales/zh-cn/errors.ts | 1 + 8 files changed, 32 insertions(+) diff --git a/packages/core/src/lib/session.ts b/packages/core/src/lib/session.ts index 86ff51ba4..7d2508675 100644 --- a/packages/core/src/lib/session.ts +++ b/packages/core/src/lib/session.ts @@ -3,6 +3,7 @@ import { getUnixTime } from 'date-fns'; import type { Context } from 'koa'; import type { InteractionResults, Provider } from 'oidc-provider'; +import RequestError from '@/errors/RequestError'; import { findUserById, updateUserById } from '@/queries/user'; export const assignInteractionResults = async ( @@ -44,6 +45,30 @@ export const assignInteractionResults = async ( ctx.body = { redirectTo, ts }; }; +export const checkSessionHealth = async ( + ctx: Context, + provider: Provider, + tolerance = 10 * 60 // 10 mins +) => { + const { result } = await provider.interactionDetails(ctx.req, ctx.res); + + if (!result?.login?.accountId) { + throw new RequestError('auth.unauthorized'); + } + + if (!result.login.ts || result.login.ts < getUnixTime(new Date()) - tolerance) { + const { passwordEncrypted, primaryPhone, primaryEmail } = await findUserById( + result.login.accountId + ); + + // No authenticated method configured for this user. Pass! + if (!passwordEncrypted && !primaryPhone && !primaryEmail) { + return; + } + throw new RequestError('auth.require_re_authentication'); + } +}; + export const saveUserFirstConsentedAppId = async (userId: string, applicationId: string) => { const { applicationId: firstConsentedAppId } = await findUserById(userId); diff --git a/packages/phrases/src/locales/de/errors.ts b/packages/phrases/src/locales/de/errors.ts index 48c9e4ec6..0fb3545ca 100644 --- a/packages/phrases/src/locales/de/errors.ts +++ b/packages/phrases/src/locales/de/errors.ts @@ -7,6 +7,7 @@ const errors = { expected_role_not_found: 'Erwartete Rolle nicht gefunden. Bitte überprüfe deine Rollen und Berechtigungen.', jwt_sub_missing: '`sub` fehlt in JWT.', + require_re_authentication: 'Re-authentication is required to perform a protected action.', // UNTRANSLATED }, guard: { invalid_input: 'Die Anfrage {{type}} ist ungültig.', diff --git a/packages/phrases/src/locales/en/errors.ts b/packages/phrases/src/locales/en/errors.ts index 66450f599..79f0add52 100644 --- a/packages/phrases/src/locales/en/errors.ts +++ b/packages/phrases/src/locales/en/errors.ts @@ -7,6 +7,7 @@ const errors = { expected_role_not_found: 'Expected role not found. Please check your user roles and permissions.', jwt_sub_missing: 'Missing `sub` in JWT.', + require_re_authentication: 'Re-authentication is required to perform a protected action.', }, guard: { invalid_input: 'The request {{type}} is invalid.', diff --git a/packages/phrases/src/locales/fr/errors.ts b/packages/phrases/src/locales/fr/errors.ts index 3e81986cc..d96ef481c 100644 --- a/packages/phrases/src/locales/fr/errors.ts +++ b/packages/phrases/src/locales/fr/errors.ts @@ -8,6 +8,7 @@ const errors = { expected_role_not_found: 'Expected role not found. Please check your user roles and permissions.', jwt_sub_missing: '`sub` manquant dans JWT.', + require_re_authentication: 'Re-authentication is required to perform a protected action.', // UNTRANSLATED }, guard: { invalid_input: "La requête {{type}} n'est pas valide.", diff --git a/packages/phrases/src/locales/ko/errors.ts b/packages/phrases/src/locales/ko/errors.ts index 0ea74901d..6f6d15043 100644 --- a/packages/phrases/src/locales/ko/errors.ts +++ b/packages/phrases/src/locales/ko/errors.ts @@ -7,6 +7,7 @@ const errors = { expected_role_not_found: 'Expected role not found. Please check your user roles and permissions.', jwt_sub_missing: 'JWT에서 `sub`를 찾을 수 없어요.', + require_re_authentication: 'Re-authentication is required to perform a protected action.', // UNTRANSLATED }, guard: { invalid_input: '{{type}} 요청 타입은 유효하지 않아요.', diff --git a/packages/phrases/src/locales/pt-pt/errors.ts b/packages/phrases/src/locales/pt-pt/errors.ts index 224728440..1b8b58ef3 100644 --- a/packages/phrases/src/locales/pt-pt/errors.ts +++ b/packages/phrases/src/locales/pt-pt/errors.ts @@ -6,6 +6,7 @@ const errors = { forbidden: 'Proibido. Verifique os seus cargos e permissões.', expected_role_not_found: 'Role esperado não encontrado. Verifique os seus cargos e permissões.', jwt_sub_missing: 'Campo `sub` está ausente no JWT.', + require_re_authentication: 'Re-authentication is required to perform a protected action.', // UNTRANSLATED }, guard: { invalid_input: 'O pedido {{type}} é inválido.', diff --git a/packages/phrases/src/locales/tr-tr/errors.ts b/packages/phrases/src/locales/tr-tr/errors.ts index 7234df25a..b3b8269bf 100644 --- a/packages/phrases/src/locales/tr-tr/errors.ts +++ b/packages/phrases/src/locales/tr-tr/errors.ts @@ -7,6 +7,7 @@ const errors = { expected_role_not_found: 'Expected role not found. Please check your user roles and permissions.', jwt_sub_missing: 'JWTde `sub` eksik.', + require_re_authentication: 'Re-authentication is required to perform a protected action.', // UNTRANSLATED }, guard: { invalid_input: 'İstek {{type}} geçersiz.', diff --git a/packages/phrases/src/locales/zh-cn/errors.ts b/packages/phrases/src/locales/zh-cn/errors.ts index 3cdf5263d..fd8e4c270 100644 --- a/packages/phrases/src/locales/zh-cn/errors.ts +++ b/packages/phrases/src/locales/zh-cn/errors.ts @@ -6,6 +6,7 @@ const errors = { forbidden: '禁止访问。请检查用户 role 与权限。', expected_role_not_found: '未找到期望的 role。请检查用户 role 与权限。', jwt_sub_missing: 'JWT 缺失 `sub`', + require_re_authentication: '需要重新认证以进行受保护操作。', }, guard: { invalid_input: '请求中 {{type}} 无效',