From 263813adc97e319588555a7501408879748b222d Mon Sep 17 00:00:00 2001 From: Tim Leslie Date: Tue, 7 Jul 2020 09:28:34 +1000 Subject: [PATCH] Update access control functions --- .changeset/pretty-radios-obey.md | 5 +++ packages/keystone/lib/Keystone/index.js | 17 +++++++--- packages/keystone/lib/ListTypes/list.js | 36 +++++++++++++++------ packages/keystone/lib/providers/listAuth.js | 5 ++- packages/keystone/tests/List.test.js | 5 +-- 5 files changed, 50 insertions(+), 18 deletions(-) create mode 100644 .changeset/pretty-radios-obey.md diff --git a/.changeset/pretty-radios-obey.md b/.changeset/pretty-radios-obey.md new file mode 100644 index 00000000000..eb80163cd1f --- /dev/null +++ b/.changeset/pretty-radios-obey.md @@ -0,0 +1,5 @@ +--- +'@keystonejs/keystone': patch +--- + +Updated internal access control functions to directly accept access control definition. diff --git a/packages/keystone/lib/Keystone/index.js b/packages/keystone/lib/Keystone/index.js index 1d056f289f9..4bc1a4efee6 100644 --- a/packages/keystone/lib/Keystone/index.js +++ b/packages/keystone/lib/Keystone/index.js @@ -128,9 +128,15 @@ module.exports = class Keystone { ); const getListAccessControlForUser = memoize( - async (listKey, originalInput, operation, { gqlName, itemId, itemIds, context } = {}) => { + async ( + access, + listKey, + originalInput, + operation, + { gqlName, itemId, itemIds, context } = {} + ) => { return validateListAccessControl({ - access: this.lists[listKey].access[schemaName], + access: access[schemaName], originalInput, operation, authentication, @@ -146,6 +152,7 @@ module.exports = class Keystone { const getFieldAccessControlForUser = memoize( async ( + access, listKey, fieldKey, originalInput, @@ -154,7 +161,7 @@ module.exports = class Keystone { { gqlName, itemId, itemIds, context } = {} ) => { return validateFieldAccessControl({ - access: this.lists[listKey].fieldsByPath[fieldKey].access[schemaName], + access: access[schemaName], originalInput, existingItem, operation, @@ -171,9 +178,9 @@ module.exports = class Keystone { ); const getAuthAccessControlForUser = memoize( - async (listKey, { gqlName, context } = {}) => { + async (access, listKey, { gqlName, context } = {}) => { return validateAuthAccessControl({ - access: this.lists[listKey].access[schemaName], + access: access[schemaName], authentication, listKey, gqlName, diff --git a/packages/keystone/lib/ListTypes/list.js b/packages/keystone/lib/ListTypes/list.js index 8e9da992091..27beb8d7074 100644 --- a/packages/keystone/lib/ListTypes/list.js +++ b/packages/keystone/lib/ListTypes/list.js @@ -377,6 +377,7 @@ module.exports = class List { // Check access const operation = 'read'; const access = await context.getFieldAccessControlForUser( + field.access, this.key, field.path, undefined, @@ -410,6 +411,7 @@ module.exports = class List { for (const field of fields) { const access = await context.getFieldAccessControlForUser( + field.access, this.key, field.path, data, @@ -430,11 +432,17 @@ module.exports = class List { } async checkListAccess(context, originalInput, operation, { gqlName, ...extraInternalData }) { - const access = await context.getListAccessControlForUser(this.key, originalInput, operation, { - gqlName, - context, - ...extraInternalData, - }); + const access = await context.getListAccessControlForUser( + this.access, + this.key, + originalInput, + operation, + { + gqlName, + context, + ...extraInternalData, + } + ); if (!access) { graphqlLogger.debug( { operation, access, gqlName, ...extraInternalData }, @@ -1416,14 +1424,22 @@ module.exports = class List { // declarative syntax) getAccess: () => ({ getCreate: () => - context.getListAccessControlForUser(this.key, undefined, 'create', { context }), + context.getListAccessControlForUser(this.access, this.key, undefined, 'create', { + context, + }), getRead: () => - context.getListAccessControlForUser(this.key, undefined, 'read', { context }), + context.getListAccessControlForUser(this.access, this.key, undefined, 'read', { + context, + }), getUpdate: () => - context.getListAccessControlForUser(this.key, undefined, 'update', { context }), + context.getListAccessControlForUser(this.access, this.key, undefined, 'update', { + context, + }), getDelete: () => - context.getListAccessControlForUser(this.key, undefined, 'delete', { context }), - getAuth: () => context.getAuthAccessControlForUser(this.key, { context }), + context.getListAccessControlForUser(this.access, this.key, undefined, 'delete', { + context, + }), + getAuth: () => context.getAuthAccessControlForUser(this.access, this.key, { context }), }), getSchema: () => { diff --git a/packages/keystone/lib/providers/listAuth.js b/packages/keystone/lib/providers/listAuth.js index bfee9af35ff..cfbc9e4e1fb 100644 --- a/packages/keystone/lib/providers/listAuth.js +++ b/packages/keystone/lib/providers/listAuth.js @@ -138,7 +138,10 @@ class ListAuthProvider { async checkAccess(context, type, { gqlName }) { const operation = 'auth'; - const access = await context.getAuthAccessControlForUser(this.list.key, { gqlName, context }); + const access = await context.getAuthAccessControlForUser(this.list.access, this.list.key, { + gqlName, + context, + }); if (!access) { graphqlLogger.debug({ operation, access, gqlName }, 'Access statically or implicitly denied'); graphqlLogger.info({ operation, gqlName }, 'Access Denied'); diff --git a/packages/keystone/tests/List.test.js b/packages/keystone/tests/List.test.js index bd98a331ece..504a7c76358 100644 --- a/packages/keystone/tests/List.test.js +++ b/packages/keystone/tests/List.test.js @@ -25,7 +25,7 @@ Relationship.adapters['mock'] = {}; const context = { getListAccessControlForUser: () => true, - getFieldAccessControlForUser: (listKey, fieldPath, originalInput, existingItem) => + getFieldAccessControlForUser: (access, listKey, fieldPath, originalInput, existingItem) => !(existingItem && existingItem.makeFalse && fieldPath === 'name'), getAuthAccessControlForUser: () => true, authedItem: { @@ -786,7 +786,8 @@ test('checkListAccess', async () => { const newContext = { ...context, - getListAccessControlForUser: (listKey, originalInput, operation) => operation === 'update', + getListAccessControlForUser: (access, listKey, originalInput, operation) => + operation === 'update', }; await expect( list.checkListAccess(newContext, originalInput, 'update', { gqlName: 'testing' })