From a8e8006e10e02b6b20b8e5cde2361e1290da1162 Mon Sep 17 00:00:00 2001 From: Filip Skokan Date: Tue, 7 Nov 2023 20:14:44 +0100 Subject: [PATCH] refactor(DPoP): move the accepted timespan into a constant --- lib/actions/authorization/check_dpop_jkt.js | 4 ++-- lib/actions/authorization/process_request_object.js | 4 ++-- lib/actions/grants/authorization_code.js | 4 ++-- lib/actions/grants/ciba.js | 4 ++-- lib/actions/grants/client_credentials.js | 8 ++++++-- lib/actions/grants/device_code.js | 4 ++-- lib/actions/grants/refresh_token.js | 8 ++++++-- lib/actions/userinfo.js | 4 ++-- lib/helpers/validate_dpop.js | 4 +++- 9 files changed, 27 insertions(+), 17 deletions(-) diff --git a/lib/actions/authorization/check_dpop_jkt.js b/lib/actions/authorization/check_dpop_jkt.js index f01e80bb4..01282d388 100644 --- a/lib/actions/authorization/check_dpop_jkt.js +++ b/lib/actions/authorization/check_dpop_jkt.js @@ -1,5 +1,5 @@ import { InvalidRequest } from '../../helpers/errors.js'; -import dpopValidate from '../../helpers/validate_dpop.js'; +import dpopValidate, { DPOP_OK_WINDOW } from '../../helpers/validate_dpop.js'; import epochTime from '../../helpers/epoch_time.js'; /* @@ -16,7 +16,7 @@ export default async function checkDpopJkt(ctx, next) { const unique = await ReplayDetection.unique( ctx.oidc.client.clientId, dPoP.jti, - epochTime() + 300, + epochTime() + DPOP_OK_WINDOW, ); ctx.assert(unique, new InvalidRequest('DPoP proof JWT Replay detected')); diff --git a/lib/actions/authorization/process_request_object.js b/lib/actions/authorization/process_request_object.js index 8d30b8a4c..018ab5484 100644 --- a/lib/actions/authorization/process_request_object.js +++ b/lib/actions/authorization/process_request_object.js @@ -2,7 +2,7 @@ import * as JWT from '../../helpers/jwt.js'; import instance from '../../helpers/weak_cache.js'; import { InvalidRequest, InvalidRequestObject, OIDCProviderError } from '../../helpers/errors.js'; import isPlainObject from '../../helpers/_/is_plain_object.js'; -import dpopValidate from '../../helpers/validate_dpop.js'; +import dpopValidate, { DPOP_OK_WINDOW } from '../../helpers/validate_dpop.js'; import epochTime from '../../helpers/epoch_time.js'; /* @@ -198,7 +198,7 @@ export default async function processRequestObject(PARAM_LIST, rejectDupesMiddle const unique = await ReplayDetection.unique( ctx.oidc.client.clientId, dPoP.jti, - epochTime() + 300, + epochTime() + DPOP_OK_WINDOW, ); ctx.assert(unique, new InvalidRequest('DPoP proof JWT Replay detected')); diff --git a/lib/actions/grants/authorization_code.js b/lib/actions/grants/authorization_code.js index 34e5aedaa..6ab648927 100644 --- a/lib/actions/grants/authorization_code.js +++ b/lib/actions/grants/authorization_code.js @@ -4,7 +4,7 @@ import instance from '../../helpers/weak_cache.js'; import checkPKCE from '../../helpers/pkce.js'; import revoke from '../../helpers/revoke.js'; import filterClaims from '../../helpers/filter_claims.js'; -import dpopValidate from '../../helpers/validate_dpop.js'; +import dpopValidate, { DPOP_OK_WINDOW } from '../../helpers/validate_dpop.js'; import resolveResource from '../../helpers/resolve_resource.js'; import epochTime from '../../helpers/epoch_time.js'; @@ -132,7 +132,7 @@ export const handler = async function authorizationCodeHandler(ctx, next) { const unique = await ReplayDetection.unique( ctx.oidc.client.clientId, dPoP.jti, - epochTime() + 300, + epochTime() + DPOP_OK_WINDOW, ); ctx.assert(unique, new InvalidGrant('DPoP proof JWT Replay detected')); diff --git a/lib/actions/grants/ciba.js b/lib/actions/grants/ciba.js index 83a2fe019..82d92e3ac 100644 --- a/lib/actions/grants/ciba.js +++ b/lib/actions/grants/ciba.js @@ -5,7 +5,7 @@ import presence from '../../helpers/validate_presence.js'; import instance from '../../helpers/weak_cache.js'; import filterClaims from '../../helpers/filter_claims.js'; import revoke from '../../helpers/revoke.js'; -import dpopValidate from '../../helpers/validate_dpop.js'; +import dpopValidate, { DPOP_OK_WINDOW } from '../../helpers/validate_dpop.js'; import resolveResource from '../../helpers/resolve_resource.js'; import epochTime from '../../helpers/epoch_time.js'; @@ -133,7 +133,7 @@ export const handler = async function cibaHandler(ctx, next) { const unique = await ReplayDetection.unique( ctx.oidc.client.clientId, dPoP.jti, - epochTime() + 300, + epochTime() + DPOP_OK_WINDOW, ); ctx.assert(unique, new InvalidGrant('DPoP proof JWT Replay detected')); diff --git a/lib/actions/grants/client_credentials.js b/lib/actions/grants/client_credentials.js index 4f5e79fac..035b06ebe 100644 --- a/lib/actions/grants/client_credentials.js +++ b/lib/actions/grants/client_credentials.js @@ -1,6 +1,6 @@ import instance from '../../helpers/weak_cache.js'; import { InvalidGrant, InvalidTarget, InvalidScope } from '../../helpers/errors.js'; -import dpopValidate from '../../helpers/validate_dpop.js'; +import dpopValidate, { DPOP_OK_WINDOW } from '../../helpers/validate_dpop.js'; import checkResource from '../../shared/check_resource.js'; import epochTime from '../../helpers/epoch_time.js'; @@ -54,7 +54,11 @@ export const handler = async function clientCredentialsHandler(ctx, next) { } if (dPoP) { - const unique = await ReplayDetection.unique(client.clientId, dPoP.jti, epochTime() + 300); + const unique = await ReplayDetection.unique( + client.clientId, + dPoP.jti, + epochTime() + DPOP_OK_WINDOW, + ); ctx.assert(unique, new InvalidGrant('DPoP proof JWT Replay detected')); diff --git a/lib/actions/grants/device_code.js b/lib/actions/grants/device_code.js index c0a6c6820..bf9ab6e5a 100644 --- a/lib/actions/grants/device_code.js +++ b/lib/actions/grants/device_code.js @@ -5,7 +5,7 @@ import presence from '../../helpers/validate_presence.js'; import instance from '../../helpers/weak_cache.js'; import filterClaims from '../../helpers/filter_claims.js'; import revoke from '../../helpers/revoke.js'; -import dpopValidate from '../../helpers/validate_dpop.js'; +import dpopValidate, { DPOP_OK_WINDOW } from '../../helpers/validate_dpop.js'; import resolveResource from '../../helpers/resolve_resource.js'; import epochTime from '../../helpers/epoch_time.js'; @@ -132,7 +132,7 @@ export const handler = async function deviceCodeHandler(ctx, next) { const unique = await ReplayDetection.unique( ctx.oidc.client.clientId, dPoP.jti, - epochTime() + 300, + epochTime() + DPOP_OK_WINDOW, ); ctx.assert(unique, new InvalidGrant('DPoP proof JWT Replay detected')); diff --git a/lib/actions/grants/refresh_token.js b/lib/actions/grants/refresh_token.js index a89af7aa4..fdfaad1ce 100644 --- a/lib/actions/grants/refresh_token.js +++ b/lib/actions/grants/refresh_token.js @@ -6,7 +6,7 @@ import revoke from '../../helpers/revoke.js'; import certificateThumbprint from '../../helpers/certificate_thumbprint.js'; import * as formatters from '../../helpers/formatters.js'; import filterClaims from '../../helpers/filter_claims.js'; -import dpopValidate from '../../helpers/validate_dpop.js'; +import dpopValidate, { DPOP_OK_WINDOW } from '../../helpers/validate_dpop.js'; import resolveResource from '../../helpers/resolve_resource.js'; import epochTime from '../../helpers/epoch_time.js'; @@ -90,7 +90,11 @@ export const handler = async function refreshTokenHandler(ctx, next) { } if (dPoP) { - const unique = await ReplayDetection.unique(client.clientId, dPoP.jti, epochTime() + 300); + const unique = await ReplayDetection.unique( + client.clientId, + dPoP.jti, + epochTime() + DPOP_OK_WINDOW, + ); ctx.assert(unique, new InvalidGrant('DPoP proof JWT Replay detected')); } diff --git a/lib/actions/userinfo.js b/lib/actions/userinfo.js index 11da89f6b..31919bda9 100644 --- a/lib/actions/userinfo.js +++ b/lib/actions/userinfo.js @@ -7,7 +7,7 @@ import noCache from '../shared/no_cache.js'; import certificateThumbprint from '../helpers/certificate_thumbprint.js'; import instance from '../helpers/weak_cache.js'; import filterClaims from '../helpers/filter_claims.js'; -import dpopValidate from '../helpers/validate_dpop.js'; +import dpopValidate, { DPOP_OK_WINDOW } from '../helpers/validate_dpop.js'; import epochTime from '../helpers/epoch_time.js'; import { InvalidToken, InsufficientScope, InvalidDpopProof, UseDpopNonce, @@ -89,7 +89,7 @@ export default [ const unique = await ctx.oidc.provider.ReplayDetection.unique( accessToken.clientId, dPoP.jti, - epochTime() + 300, + epochTime() + DPOP_OK_WINDOW, ); ctx.assert(unique, new InvalidToken('DPoP proof JWT Replay detected')); diff --git a/lib/helpers/validate_dpop.js b/lib/helpers/validate_dpop.js index 08058efc6..e3a6267ce 100644 --- a/lib/helpers/validate_dpop.js +++ b/lib/helpers/validate_dpop.js @@ -12,6 +12,8 @@ import * as base64url from './base64url.js'; import epochTime from './epoch_time.js'; const weakMap = new WeakMap(); +export const DPOP_OK_WINDOW = 300; + export default async (ctx, accessToken) => { if (weakMap.has(ctx)) { return weakMap.get(ctx); @@ -65,7 +67,7 @@ export default async (ctx, accessToken) => { if (!payload.nonce) { const now = epochTime(); const diff = Math.abs(now - payload.iat); - if (diff > 300) { + if (diff > DPOP_OK_WINDOW) { throw new InvalidDpopProof('DPoP proof iat is not recent enough'); } }