Skip to content

Commit

Permalink
B2BTEAM-1738 Merge branch 'master' into fix/TEAMB2B-1738-get-header-t…
Browse files Browse the repository at this point in the history
…oken
  • Loading branch information
Matheus-Aguilar committed Jul 16, 2024
2 parents 93dac59 + 632984c commit 0ab28b8
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 18 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
### Fixed
- Get tokens from headers when necessary

## [1.41.1] - 2024-07-15

### Added
- Add validation metrics for admin and api tokens

## [1.41.0] - 2024-07-01

### Added
Expand Down
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
17 changes: 14 additions & 3 deletions node/directives/checkAdminAccess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,21 @@ 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 {
hasAdminTokenOnHeader,
hasValidAdminTokenOnHeader,
hasCurrentValidAdminTokenOnHeader,
} = await validateAdminTokenOnHeader(context)

const { hasApiToken, hasValidApiToken } = await validateApiToken(context)
const { hasApiToken, hasValidApiToken, hasValidApiTokenFromStore } =
await validateApiToken(context)

const hasStoreToken = !!storeUserAuthToken // we don't need to validate store token

Expand All @@ -59,6 +64,8 @@ export class CheckAdminAccess extends SchemaDirectiveVisitor {
hasStoreToken,
hasAdminTokenOnHeader,
hasValidAdminTokenOnHeader,
hasValidAdminTokenFromStore,
hasValidApiTokenFromStore,
},
'CheckAdminAccessAudit'
)
Expand All @@ -79,6 +86,8 @@ export class CheckAdminAccess extends SchemaDirectiveVisitor {
hasStoreToken,
hasAdminTokenOnHeader,
hasValidAdminTokenOnHeader,
hasValidAdminTokenFromStore,
hasValidApiTokenFromStore,
})
throw new AuthenticationError('No token was provided')
}
Expand All @@ -101,6 +110,8 @@ export class CheckAdminAccess extends SchemaDirectiveVisitor {
hasStoreToken,
hasAdminTokenOnHeader,
hasValidAdminTokenOnHeader,
hasValidAdminTokenFromStore,
hasValidApiTokenFromStore,
})
throw new ForbiddenError('Unauthorized Access')
}
Expand Down
17 changes: 14 additions & 3 deletions node/directives/checkUserAccess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,21 @@ 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 {
hasAdminTokenOnHeader,
hasValidAdminTokenOnHeader,
hasCurrentValidAdminTokenOnHeader,
} = await validateAdminTokenOnHeader(context)

const { hasApiToken, hasValidApiToken } = await validateApiToken(context)
const { hasApiToken, hasValidApiToken, hasValidApiTokenFromStore } =
await validateApiToken(context)

const { hasStoreToken, hasValidStoreToken, hasCurrentValidStoreToken } =
await validateStoreToken(context, storeUserAuthToken as string)
Expand Down Expand Up @@ -62,6 +67,8 @@ export class CheckUserAccess extends SchemaDirectiveVisitor {
hasValidStoreToken,
hasAdminTokenOnHeader,
hasValidAdminTokenOnHeader,
hasValidAdminTokenFromStore,
hasValidApiTokenFromStore,
},
'CheckUserAccessAudit'
)
Expand All @@ -87,6 +94,8 @@ export class CheckUserAccess extends SchemaDirectiveVisitor {
hasStoreToken,
hasAdminTokenOnHeader,
hasValidAdminTokenOnHeader,
hasValidAdminTokenFromStore,
hasValidApiTokenFromStore,
})
throw new AuthenticationError('No token was provided')
}
Expand All @@ -111,6 +120,8 @@ export class CheckUserAccess extends SchemaDirectiveVisitor {
hasValidStoreToken,
hasAdminTokenOnHeader,
hasValidAdminTokenOnHeader,
hasValidAdminTokenFromStore,
hasValidApiTokenFromStore,
})
throw new ForbiddenError('Unauthorized Access')
}
Expand Down
38 changes: 33 additions & 5 deletions node/directives/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,20 @@ 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
const hasAdminToken = !!adminUserAuthToken
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 {
Expand All @@ -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({
Expand All @@ -44,25 +56,32 @@ export const validateAdminToken = async (
}
}

return { hasAdminToken, hasValidAdminToken, hasCurrentValidAdminToken }
return {
hasAdminToken,
hasValidAdminToken,
hasCurrentValidAdminToken,
hasValidAdminTokenFromStore,
}
}

export const validateApiToken = async (
context: Context
): 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
const apiToken = context?.headers['vtex-api-apptoken'] as string
const appKey = context?.headers['vtex-api-appkey'] as string
const hasApiToken = !!(apiToken?.length && appKey?.length)
let hasValidApiToken = false
let hasValidApiTokenFromStore = false

if (hasApiToken) {
try {
Expand All @@ -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({
Expand All @@ -87,7 +115,7 @@ export const validateApiToken = async (
}
}

return { hasApiToken, hasValidApiToken }
return { hasApiToken, hasValidApiToken, hasValidApiTokenFromStore }
}

export const validateStoreToken = async (
Expand Down
11 changes: 6 additions & 5 deletions node/directives/validateStoreUserAccess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,15 @@ 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,
hasValidAdminTokenFromStore,
}

// allow access if has valid admin token
Expand Down Expand Up @@ -93,13 +92,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
Expand Down
2 changes: 2 additions & 0 deletions node/metrics/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ export interface AuthAuditMetric {
hasValidApiToken?: boolean
hasAdminTokenOnHeader?: boolean
hasValidAdminTokenOnHeader?: boolean
hasValidAdminTokenFromStore?: boolean
hasValidApiTokenFromStore?: boolean
}

export class AuthMetric implements Metric {
Expand Down
2 changes: 1 addition & 1 deletion node/package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down

0 comments on commit 0ab28b8

Please sign in to comment.