From 684c214b396996e30cbedc5e4135b17fab89a7aa Mon Sep 17 00:00:00 2001 From: Matheus-Aguilar <43484640+Matheus-Aguilar@users.noreply.github.com> Date: Mon, 15 Jul 2024 13:20:10 -0300 Subject: [PATCH 1/2] fix: admin and api token validation (#148) * fix: admin and api token validation * chore: update CHANGELOG * fix: add more token validation metrics --- CHANGELOG.md | 3 ++ node/directives/checkAdminAccess.ts | 17 ++++++++-- node/directives/checkUserAccess.ts | 17 ++++++++-- node/directives/helper.ts | 38 +++++++++++++++++++--- node/directives/validateStoreUserAccess.ts | 17 ++++++---- node/metrics/auth.ts | 2 ++ 6 files changed, 77 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index af8091f..cf40e25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] +### Added +- Add validation metrics for admin and api tokens + ## [1.41.0] - 2024-07-01 ### Added diff --git a/node/directives/checkAdminAccess.ts b/node/directives/checkAdminAccess.ts index dd44b03..dd35144 100644 --- a/node/directives/checkAdminAccess.ts +++ b/node/directives/checkAdminAccess.ts @@ -20,10 +20,15 @@ export class CheckAdminAccess extends SchemaDirectiveVisitor { vtex: { adminUserAuthToken, storeUserAuthToken, logger }, } = context - const { hasAdminToken, hasValidAdminToken, hasCurrentValidAdminToken } = - await validateAdminToken(context, adminUserAuthToken as string) + const { + hasAdminToken, + hasValidAdminToken, + hasCurrentValidAdminToken, + hasValidAdminTokenFromStore, + } = await validateAdminToken(context, adminUserAuthToken as string) - const { hasApiToken, hasValidApiToken } = await validateApiToken(context) + const { hasApiToken, hasValidApiToken, hasValidApiTokenFromStore } = + await validateApiToken(context) const hasStoreToken = !!storeUserAuthToken // we don't need to validate store token @@ -47,6 +52,8 @@ export class CheckAdminAccess extends SchemaDirectiveVisitor { hasApiToken, hasValidApiToken, hasStoreToken, + hasValidAdminTokenFromStore, + hasValidApiTokenFromStore, }, 'CheckAdminAccessAudit' ) @@ -65,6 +72,8 @@ export class CheckAdminAccess extends SchemaDirectiveVisitor { hasApiToken, hasValidApiToken, hasStoreToken, + hasValidAdminTokenFromStore, + hasValidApiTokenFromStore, }) throw new AuthenticationError('No token was provided') } @@ -81,6 +90,8 @@ export class CheckAdminAccess extends SchemaDirectiveVisitor { hasApiToken, hasValidApiToken, hasStoreToken, + hasValidAdminTokenFromStore, + hasValidApiTokenFromStore, }) throw new ForbiddenError('Unauthorized Access') } diff --git a/node/directives/checkUserAccess.ts b/node/directives/checkUserAccess.ts index f8c233f..ed0cd72 100644 --- a/node/directives/checkUserAccess.ts +++ b/node/directives/checkUserAccess.ts @@ -24,10 +24,15 @@ export class CheckUserAccess extends SchemaDirectiveVisitor { vtex: { adminUserAuthToken, storeUserAuthToken, logger }, } = context - const { hasAdminToken, hasValidAdminToken, hasCurrentValidAdminToken } = - await validateAdminToken(context, adminUserAuthToken as string) + const { + hasAdminToken, + hasValidAdminToken, + hasCurrentValidAdminToken, + hasValidAdminTokenFromStore, + } = await validateAdminToken(context, adminUserAuthToken as string) - const { hasApiToken, hasValidApiToken } = await validateApiToken(context) + const { hasApiToken, hasValidApiToken, hasValidApiTokenFromStore } = + await validateApiToken(context) const { hasStoreToken, hasValidStoreToken, hasCurrentValidStoreToken } = await validateStoreToken(context, storeUserAuthToken as string) @@ -53,6 +58,8 @@ export class CheckUserAccess extends SchemaDirectiveVisitor { hasValidApiToken, hasStoreToken, hasValidStoreToken, + hasValidAdminTokenFromStore, + hasValidApiTokenFromStore, }, 'CheckUserAccessAudit' ) @@ -71,6 +78,8 @@ export class CheckUserAccess extends SchemaDirectiveVisitor { hasApiToken, hasValidApiToken, hasStoreToken, + hasValidAdminTokenFromStore, + hasValidApiTokenFromStore, }) throw new AuthenticationError('No token was provided') } @@ -88,6 +97,8 @@ export class CheckUserAccess extends SchemaDirectiveVisitor { hasValidApiToken, hasStoreToken, hasValidStoreToken, + hasValidAdminTokenFromStore, + hasValidApiTokenFromStore, }) throw new ForbiddenError('Unauthorized Access') } diff --git a/node/directives/helper.ts b/node/directives/helper.ts index 524eeeb..df93939 100644 --- a/node/directives/helper.ts +++ b/node/directives/helper.ts @@ -7,10 +7,11 @@ export const validateAdminToken = async ( hasAdminToken: boolean hasValidAdminToken: boolean hasCurrentValidAdminToken: boolean + hasValidAdminTokenFromStore: boolean }> => { const { clients: { identity, lm }, - vtex: { logger }, + vtex: { account, logger }, } = context // check if has admin token and if it is valid @@ -18,6 +19,8 @@ export const validateAdminToken = async ( let hasValidAdminToken = false // this is used to check if the token is valid by current standards let hasCurrentValidAdminToken = false + // this is used to check if the token is valid and from this store + let hasValidAdminTokenFromStore = false if (hasAdminToken) { try { @@ -35,6 +38,15 @@ export const validateAdminToken = async ( authUser.id ) } + + // check if the token is from this store. Currently used for metrics + // in future we should merge this with the previous check + if (authUser?.audience === 'admin' && authUser?.account === account) { + hasValidAdminTokenFromStore = await lm.getUserAdminPermissions( + account, + authUser.id + ) + } } catch (err) { // noop so we leave hasValidAdminToken as false logger.warn({ @@ -44,7 +56,12 @@ export const validateAdminToken = async ( } } - return { hasAdminToken, hasValidAdminToken, hasCurrentValidAdminToken } + return { + hasAdminToken, + hasValidAdminToken, + hasCurrentValidAdminToken, + hasValidAdminTokenFromStore, + } } export const validateApiToken = async ( @@ -52,10 +69,11 @@ export const validateApiToken = async ( ): Promise<{ hasApiToken: boolean hasValidApiToken: boolean + hasValidApiTokenFromStore: boolean }> => { const { - clients: { identity }, - vtex: { logger }, + clients: { identity, lm }, + vtex: { account, logger }, } = context // check if has api token and if it is valid @@ -63,6 +81,7 @@ export const validateApiToken = async ( const appKey = context?.headers['vtex-api-appkey'] as string const hasApiToken = !!(apiToken?.length && appKey?.length) let hasValidApiToken = false + let hasValidApiTokenFromStore = false if (hasApiToken) { try { @@ -78,6 +97,15 @@ export const validateApiToken = async ( if (authUser?.audience === 'admin') { hasValidApiToken = true } + + // check if the token is from this store. Currently used for metrics + // in future we should merge this with the previous check + if (authUser?.audience === 'admin' && authUser?.account === account) { + hasValidApiTokenFromStore = await lm.getUserAdminPermissions( + account, + authUser.id + ) + } } catch (err) { // noop so we leave hasValidApiToken as false logger.warn({ @@ -87,7 +115,7 @@ export const validateApiToken = async ( } } - return { hasApiToken, hasValidApiToken } + return { hasApiToken, hasValidApiToken, hasValidApiTokenFromStore } } export const validateStoreToken = async ( diff --git a/node/directives/validateStoreUserAccess.ts b/node/directives/validateStoreUserAccess.ts index 24ef80e..6020880 100644 --- a/node/directives/validateStoreUserAccess.ts +++ b/node/directives/validateStoreUserAccess.ts @@ -41,13 +41,16 @@ export class ValidateStoreUserAccess extends SchemaDirectiveVisitor { userAgent, } - const { hasAdminToken, hasValidAdminToken } = await validateAdminToken( - context, - adminUserAuthToken as string - ) + const { hasAdminToken, hasValidAdminToken, hasValidAdminTokenFromStore } = + await validateAdminToken(context, adminUserAuthToken as string) // add admin token metrics - metricFields = { ...metricFields, hasAdminToken, hasValidAdminToken } + metricFields = { + ...metricFields, + hasAdminToken, + hasValidAdminToken, + hasValidAdminTokenFromStore, + } // allow access if has valid admin token if (hasValidAdminToken) { @@ -63,13 +66,15 @@ export class ValidateStoreUserAccess extends SchemaDirectiveVisitor { return resolve(root, args, context, info) } - const { hasApiToken, hasValidApiToken } = await validateApiToken(context) + const { hasApiToken, hasValidApiToken, hasValidApiTokenFromStore } = + await validateApiToken(context) // add API token metrics metricFields = { ...metricFields, hasApiToken, hasValidApiToken, + hasValidApiTokenFromStore, } // allow access if has valid API token diff --git a/node/metrics/auth.ts b/node/metrics/auth.ts index f58f0a6..36293f5 100644 --- a/node/metrics/auth.ts +++ b/node/metrics/auth.ts @@ -16,6 +16,8 @@ export interface AuthAuditMetric { hasValidStoreToken?: boolean hasApiToken?: boolean hasValidApiToken?: boolean + hasValidAdminTokenFromStore?: boolean + hasValidApiTokenFromStore?: boolean } export class AuthMetric implements Metric { From 632984c0b2f8d401d5e2b6ba0199a947729521d3 Mon Sep 17 00:00:00 2001 From: Matheus-Aguilar <43484640+Matheus-Aguilar@users.noreply.github.com> Date: Mon, 15 Jul 2024 16:20:15 +0000 Subject: [PATCH 2/2] Release v1.41.1 --- CHANGELOG.md | 2 ++ manifest.json | 2 +- node/package.json | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf40e25..3695109 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] +## [1.41.1] - 2024-07-15 + ### Added - Add validation metrics for admin and api tokens diff --git a/manifest.json b/manifest.json index b99c977..62b1cd9 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "name": "storefront-permissions", "vendor": "vtex", - "version": "1.41.0", + "version": "1.41.1", "title": "Storefront Permissions", "description": "Manage User's permissions on apps that relates to this app", "mustUpdateAt": "2022-08-28", diff --git a/node/package.json b/node/package.json index f6e20b2..0ad6e42 100644 --- a/node/package.json +++ b/node/package.json @@ -1,6 +1,6 @@ { "name": "vtex.checkout-ui-custom", - "version": "1.41.0", + "version": "1.41.1", "dependencies": { "@vtex/api": "6.46.1", "atob": "^2.1.2",