-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add new directive to validate auth token with feature flag #138
Changes from all commits
6db09d3
e65892f
1101d2e
576db3f
e0bd2ab
2a0cdb5
cf9f0c0
e8cdfb2
9326eb4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,15 @@ | ||
import { WithSession } from './directives/withSession' | ||
import { WithPermissions } from './directives/withPermissions' | ||
import { AuditAccess } from './directives/auditAccess' | ||
import { CheckAccessWithFeatureFlag } from './directives/checkAccessWithFeatureFlag' | ||
import { CheckAdminAccess } from './directives/checkAdminAccess' | ||
import { CheckUserAccess } from './directives/checkUserAccess' | ||
import { AuditAccess } from './directives/auditAccess' | ||
import { WithPermissions } from './directives/withPermissions' | ||
import { WithSession } from './directives/withSession' | ||
|
||
export const schemaDirectives = { | ||
auditAccess: AuditAccess as any, | ||
checkAccessWithFeatureFlag: CheckAccessWithFeatureFlag as any, | ||
checkAdminAccess: CheckAdminAccess as any, | ||
checkUserAccess: CheckUserAccess as any, | ||
withPermissions: WithPermissions as any, | ||
withSession: WithSession as any, | ||
auditAccess: AuditAccess as any, | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import type { GraphQLField } from 'graphql' | ||
import { defaultFieldResolver } from 'graphql' | ||
import { SchemaDirectiveVisitor } from 'graphql-tools' | ||
|
||
import { checkUserOrAdminTokenAccess } from './checkUserAccess' | ||
|
||
export class CheckAccessWithFeatureFlag extends SchemaDirectiveVisitor { | ||
public visitFieldDefinition(field: GraphQLField<any, any>) { | ||
const { resolve = defaultFieldResolver } = field | ||
|
||
field.resolve = async ( | ||
root: any, | ||
args: any, | ||
context: Context, | ||
info: any | ||
) => { | ||
const { | ||
vtex: { adminUserAuthToken }, | ||
clients: { masterdata }, | ||
} = context | ||
|
||
const config: { enable: boolean } = await masterdata.getDocument({ | ||
dataEntity: 'auth_validation_config', | ||
fields: ['enable'], | ||
id: 'b2b-organizations-graphql', | ||
}) | ||
|
||
if (config?.enable) { | ||
await checkUserOrAdminTokenAccess(context, adminUserAuthToken) | ||
} | ||
|
||
return resolve(root, args, context, info) | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,65 @@ | ||
import { SchemaDirectiveVisitor } from 'graphql-tools' | ||
import { AuthenticationError, ForbiddenError } from '@vtex/api' | ||
import type { GraphQLField } from 'graphql' | ||
import { defaultFieldResolver } from 'graphql' | ||
import { AuthenticationError, ForbiddenError } from '@vtex/api' | ||
import { SchemaDirectiveVisitor } from 'graphql-tools' | ||
|
||
export async function checkUserOrAdminTokenAccess( | ||
ctx: Context, | ||
token?: string, | ||
operation?: string | ||
) { | ||
const { | ||
vtex: { storeUserAuthToken, logger }, | ||
clients: { identity, vtexId }, | ||
} = ctx | ||
|
||
if (!token && !storeUserAuthToken) { | ||
logger.warn({ | ||
message: `CheckUserAccess: No admin or store token was provided for ${operation}`, | ||
operation, | ||
}) | ||
throw new AuthenticationError('No admin or store token was provided') | ||
} | ||
|
||
if (token) { | ||
try { | ||
await identity.validateToken({ token }) | ||
} catch (err) { | ||
logger.warn({ | ||
error: err, | ||
message: `CheckUserAccess: Invalid admin token for ${operation}`, | ||
operation, | ||
token, | ||
}) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This PR is just missing the changes you made on that other similar for storefront-permissions, where you removed the |
||
throw new ForbiddenError('Unauthorized Access') | ||
} | ||
} else if (storeUserAuthToken) { | ||
let authUser = null | ||
|
||
try { | ||
authUser = await vtexId.getAuthenticatedUser(storeUserAuthToken) | ||
if (!authUser?.user) { | ||
logger.warn({ | ||
message: `CheckUserAccess: No valid user found by store user token for ${operation}`, | ||
operation, | ||
}) | ||
authUser = null | ||
} | ||
} catch (err) { | ||
logger.warn({ | ||
error: err, | ||
message: `CheckUserAccess: Invalid store user token for ${operation}`, | ||
operation, | ||
token: storeUserAuthToken, | ||
}) | ||
authUser = null | ||
} | ||
|
||
if (!authUser) { | ||
throw new ForbiddenError('Unauthorized Access') | ||
} | ||
} | ||
} | ||
|
||
export class CheckUserAccess extends SchemaDirectiveVisitor { | ||
public visitFieldDefinition(field: GraphQLField<any, any>) { | ||
|
@@ -14,8 +72,8 @@ export class CheckUserAccess extends SchemaDirectiveVisitor { | |
info: any | ||
) => { | ||
const { | ||
vtex: { adminUserAuthToken, storeUserAuthToken, logger }, | ||
clients: { identity, vtexId }, | ||
vtex: { adminUserAuthToken }, | ||
clients: { identity }, | ||
} = context | ||
|
||
let token = adminUserAuthToken | ||
|
@@ -31,42 +89,11 @@ export class CheckUserAccess extends SchemaDirectiveVisitor { | |
context.vtex.adminUserAuthToken = token | ||
} | ||
|
||
if (!token && !storeUserAuthToken) { | ||
throw new AuthenticationError('No admin or store token was provided') | ||
} | ||
|
||
if (token) { | ||
try { | ||
await identity.validateToken({ token }) | ||
} catch (err) { | ||
logger.warn({ | ||
error: err, | ||
message: 'CheckUserAccess: Invalid admin token', | ||
token, | ||
}) | ||
throw new ForbiddenError('Unauthorized Access') | ||
} | ||
} else if (storeUserAuthToken) { | ||
let authUser = null | ||
|
||
try { | ||
authUser = await vtexId.getAuthenticatedUser(storeUserAuthToken) | ||
if (!authUser?.user) { | ||
authUser = null | ||
} | ||
} catch (err) { | ||
logger.warn({ | ||
error: err, | ||
message: 'CheckUserAccess: Invalid store user token', | ||
token: storeUserAuthToken, | ||
}) | ||
authUser = null | ||
} | ||
|
||
if (!authUser) { | ||
throw new ForbiddenError('Unauthorized Access') | ||
} | ||
} | ||
await checkUserOrAdminTokenAccess( | ||
context, | ||
token, | ||
field.astNode?.name?.value | ||
) | ||
|
||
return resolve(root, args, context, info) | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
import axios from 'axios' | ||
|
||
const ANALYTICS_URL = 'https://rc.vtex.com/api/analytics/schemaless-events' | ||
const ANALYTICS_URL = | ||
'https://analytics.vtex.com/api/analytics/schemaless-events' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why did this change? What is the difference between There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I found some issues with using "This can be done by sending events to the following endpoint: https://analytics.vtex.com/api/analytics/schemaless-events (For applications on the VTEX Network) or to https://rc.vtex.com/api/analytics/schemaless-events (For applications outside the VTEX Network, such as Front End Applications)" |
||
|
||
export const B2B_METRIC_NAME = 'b2b-suite-buyerorg-data' | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getOrganizationsByEmail
is on https://vtex-dev.atlassian.net/browse/B2BTEAM-1285 but we did not add the@checkAccessWithFeatureFlag
for itThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not necessary because there is already a directive
@checkUserAccess
. I am removing it from the task.