From 4f5c0e285c909081a88a7ebf7386b65d9707e356 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Thu, 16 Jul 2020 19:34:16 +0000 Subject: [PATCH] [CORL-1192] Reduced Security Mode (#3027) * feat: add support for disabling persisted query requirements * fix: fixed type errors * fix: rename flag * fix: fixed logic around validation Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../graphql/persistedQueryMiddleware.ts | 56 +++++++++++-------- src/core/server/graph/schema/schema.graphql | 6 ++ src/core/server/models/tenant/helpers.ts | 2 +- 3 files changed, 40 insertions(+), 24 deletions(-) diff --git a/src/core/server/app/middleware/graphql/persistedQueryMiddleware.ts b/src/core/server/app/middleware/graphql/persistedQueryMiddleware.ts index 45d9c0fb5..9e3c4946c 100644 --- a/src/core/server/app/middleware/graphql/persistedQueryMiddleware.ts +++ b/src/core/server/app/middleware/graphql/persistedQueryMiddleware.ts @@ -1,9 +1,13 @@ import { AppOptions } from "coral-server/app"; import { RawQueryNotAuthorized } from "coral-server/errors"; import { getPersistedQuery } from "coral-server/graph/persisted"; +import { hasFeatureFlag } from "coral-server/models/tenant"; import { RequestHandler } from "coral-server/types/express"; -import { GQLUSER_ROLE } from "coral-server/graph/schema/__generated__/types"; +import { + GQLFEATURE_FLAG, + GQLUSER_ROLE, +} from "coral-server/graph/schema/__generated__/types"; type PersistedQueryMiddlewareOptions = Pick< AppOptions, @@ -19,33 +23,14 @@ const persistedQueryMiddleware = ({ next ) => { try { - if (!req.coral) { - throw new Error("coral was not set"); - } - - // Pull out some useful properties from Coral. - const { tenant } = req.coral; - if (!tenant) { + if (!req.coral || !req.coral.tenant) { throw new Error("tenant was not set"); } // Handle the payload if it is a persisted query. const body = req.method === "GET" ? req.query : req.body; const persisted = await getPersistedQuery(persistedQueryCache, body); - if (!persisted) { - // Check to see if this is from an ADMIN token which is allowed to run - // un-persisted queries. - if ( - persistedQueriesRequired && - (!req.user || req.user.role !== GQLUSER_ROLE.ADMIN) - ) { - throw new RawQueryNotAuthorized( - tenant.id, - body && body.query ? body.query : null, - req.user ? req.user.id : null - ); - } - } else { + if (persisted) { // The query was found for this operation, replace the query with the one // provided. body.query = persisted.query; @@ -53,9 +38,34 @@ const persistedQueryMiddleware = ({ // Associate the persisted query with the request so it can be attached to // the context. req.coral.persisted = persisted; + + return next(); } - return next(); + // If persisted queries are not required, then it's ok that we're not + // submitting a persisted query. + if (!persistedQueriesRequired) { + return next(); + } + + // If the feature flag for reduced security mode is enabled, then we will + // allow non-persisted queries. + if ( + hasFeatureFlag(req.coral.tenant, GQLFEATURE_FLAG.REDUCED_SECURITY_MODE) + ) { + return next(); + } + + // If the user is an administrator, then permit the non-persisted query. + if (req.user?.role === GQLUSER_ROLE.ADMIN) { + return next(); + } + + throw new RawQueryNotAuthorized( + req.coral.tenant.id, + body.query || null, + req.user?.id || null + ); } catch (err) { return next(err); } diff --git a/src/core/server/graph/schema/schema.graphql b/src/core/server/graph/schema/schema.graphql index f8680c425..eec1e31d6 100644 --- a/src/core/server/graph/schema/schema.graphql +++ b/src/core/server/graph/schema/schema.graphql @@ -396,6 +396,12 @@ enum FEATURE_FLAG { modeartion scope to a user. """ SITE_MODERATOR + + """ + REDUCED_SECURITY_MODE when true will allow unpersisted queries to be executed + in production environments. + """ + REDUCED_SECURITY_MODE } # The moderation mode of the site. diff --git a/src/core/server/models/tenant/helpers.ts b/src/core/server/models/tenant/helpers.ts index 5a1f31188..7d6673967 100644 --- a/src/core/server/models/tenant/helpers.ts +++ b/src/core/server/models/tenant/helpers.ts @@ -43,7 +43,7 @@ export function hasFeatureFlag( tenant: Pick, flag: GQLFEATURE_FLAG ) { - if (tenant.featureFlags && tenant.featureFlags.includes(flag)) { + if (tenant.featureFlags?.includes(flag)) { return true; }