From 73067e0d1deb2b7d6be3a4633d3db55441a90000 Mon Sep 17 00:00:00 2001 From: petruki <31597636+petruki@users.noreply.github.com> Date: Sat, 13 Aug 2022 19:54:22 -0700 Subject: [PATCH] Closes #348 - Added permission query to GraphQL endpoint --- requests/Switcher API.postman_collection.json | 24 +++++++ src/client/permission-resolvers.js | 35 ++++++++++ src/client/permission-type.js | 28 ++++++++ src/client/schema.js | 22 ++++++ tests/client-api.test.js | 68 +++++++++++++++++++ tests/graphql-utils/index.js | 21 ++++++ 6 files changed, 198 insertions(+) create mode 100644 src/client/permission-resolvers.js create mode 100644 src/client/permission-type.js diff --git a/requests/Switcher API.postman_collection.json b/requests/Switcher API.postman_collection.json index ebcf877..b79282c 100644 --- a/requests/Switcher API.postman_collection.json +++ b/requests/Switcher API.postman_collection.json @@ -5602,6 +5602,30 @@ } }, "response": [] + }, + { + "name": "Client - Permission (Adm-GraphQL)", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "graphql", + "graphql": { + "query": "{\r\n # permission(domain: \"5e0ece606f4f994eac9007ae\", actions: [\"UPDATE\", \"DELETE\"], router: \"GROUP\") {\r\n permission(\r\n domain: \"5e0ece606f4f994eac9007ae\", \r\n parent: \"5e0ece916f4f994eac9007b0\", \r\n actions: [\"UPDATE\", \"DELETE\"],\r\n router: \"SWITCHER\") {\r\n id\r\n name\r\n permissions {\r\n action\r\n result\r\n }\r\n }\r\n}", + "variables": "" + } + }, + "url": { + "raw": "{{url}}/adm-graphql", + "host": [ + "{{url}}" + ], + "path": [ + "adm-graphql" + ] + } + }, + "response": [] } ] }, diff --git a/src/client/permission-resolvers.js b/src/client/permission-resolvers.js new file mode 100644 index 0000000..19905c0 --- /dev/null +++ b/src/client/permission-resolvers.js @@ -0,0 +1,35 @@ +import { verifyOwnership } from '../helpers'; +import { RouterTypes } from '../models/permission'; +import { getConfigs } from '../services/config'; +import { getGroupConfigs } from '../services/group-config'; + +export async function resolvePermission(args, admin) { + let elements; + if (args.router === RouterTypes.GROUP) { + elements = await getGroupConfigs({ domain: args.domain }, true); + } else if (args.router === RouterTypes.CONFIG) { + elements = await getConfigs({ domain: args.domain, group: args.parent }, true); + } else { + return []; + } + + let result = []; + for (const element of elements) { + result.push({ + id: element._id, + name: element.name || element.key, + permissions: [] + }); + + for (const action_perm of args.actions) { + try { + await verifyOwnership(admin, element, args.domain, action_perm, args.router); + result[result.length - 1].permissions.push({ action: action_perm.toString(), result: 'ok' }); + } catch (e) { + result[result.length - 1].permissions.push({ action: action_perm.toString(), result: 'nok' }); + } + } + } + + return result; +} \ No newline at end of file diff --git a/src/client/permission-type.js b/src/client/permission-type.js new file mode 100644 index 0000000..37bc97c --- /dev/null +++ b/src/client/permission-type.js @@ -0,0 +1,28 @@ +import { GraphQLObjectType, GraphQLString, GraphQLList } from 'graphql'; + +const elementPermissionsType = new GraphQLObjectType({ + name: 'permissions', + fields: { + action: { + type: GraphQLString + }, + result: { + type: GraphQLString + } + } +}); + +export const permissionType = new GraphQLObjectType({ + name: 'permission', + fields: { + id: { + type: GraphQLString + }, + name: { + type: GraphQLString + }, + permissions: { + type: GraphQLList(elementPermissionsType) + } + } +}); \ No newline at end of file diff --git a/src/client/schema.js b/src/client/schema.js index bef4100..d96dccd 100644 --- a/src/client/schema.js +++ b/src/client/schema.js @@ -4,6 +4,8 @@ import { EnvType } from '../models/environment'; import { strategyInputType, criteriaType } from './criteria-type'; import { resolveConfigByKey, resolveDomain } from './resolvers'; import { resolveConfiguration } from './configuration-resolvers'; +import { permissionType } from './permission-type'; +import { resolvePermission } from './permission-resolvers'; const queryType = new GraphQLObjectType({ name: 'Query', @@ -85,6 +87,26 @@ const queryType = new GraphQLObjectType({ return resolveConfiguration(args, context); } }, + permission: { + type: new GraphQLList(permissionType), + args: { + domain: { + type: GraphQLString + }, + parent: { + type: GraphQLString + }, + actions: { + type: new GraphQLList(GraphQLString) + }, + router: { + type: GraphQLString + } + }, + resolve: async (_source, args, context) => { + return resolvePermission(args, context.admin); + } + } } }); diff --git a/tests/client-api.test.js b/tests/client-api.test.js index debb047..14a6ec7 100644 --- a/tests/client-api.test.js +++ b/tests/client-api.test.js @@ -28,6 +28,7 @@ import { adminAccountId, slack } from './fixtures/db_client'; +import { RouterTypes } from '../src/models/permission'; const changeStrategy = async (strategyId, newOperation, status, environment) => { const strategy = await ConfigStrategy.findById(strategyId); @@ -928,4 +929,71 @@ describe('Testing domain [Adm-GraphQL] ', () => { expect(req.statusCode).toBe(200); expect(JSON.parse(req.text)).toMatchObject(JSON.parse(expected)); }); + + test('CLIENT_SUITE - Should return list of Groups permissions', async () => { + const req = await request(app) + .post('/adm-graphql') + .set('Authorization', `Bearer ${adminMasterAccountToken}`) + .send(graphqlUtils.permissionsQuery(domainId, undefined, `"UPDATE","DELETE"`, RouterTypes.GROUP)); + + const exptected = '[{"action":"UPDATE","result":"ok"},{"action":"DELETE","result":"ok"}]'; + expect(req.statusCode).toBe(200); + expect(JSON.parse(req.text)).not.toBe(null); + expect(JSON.parse(req.text).data.permission[0].name).toBe("Group Test"); + expect(JSON.parse(req.text).data.permission[0].permissions).toMatchObject(JSON.parse(exptected)); + }); + + test('CLIENT_SUITE - Should return list of Groups permissions - Unauthorized access', async () => { + const req = await request(app) + .post('/adm-graphql') + .set('Authorization', `Bearer ${adminAccountToken}`) + .send(graphqlUtils.permissionsQuery(domainId, undefined, `"UPDATE","DELETE"`, RouterTypes.GROUP)); + + const exptected = '[{"action":"UPDATE","result":"nok"},{"action":"DELETE","result":"nok"}]'; + expect(req.statusCode).toBe(200); + expect(JSON.parse(req.text)).not.toBe(null); + expect(JSON.parse(req.text).data.permission[0].name).toBe("Group Test"); + expect(JSON.parse(req.text).data.permission[0].permissions).toMatchObject(JSON.parse(exptected)); + }); + + test('CLIENT_SUITE - Should return list of Configs permissions', async () => { + const req = await request(app) + .post('/adm-graphql') + .set('Authorization', `Bearer ${adminMasterAccountToken}`) + .send(graphqlUtils.permissionsQuery(domainId, groupConfigId, `"UPDATE","DELETE"`, RouterTypes.CONFIG)); + + const exptected = '[{"action":"UPDATE","result":"ok"},{"action":"DELETE","result":"ok"}]'; + expect(req.statusCode).toBe(200); + expect(JSON.parse(req.text)).not.toBe(null); + expect(JSON.parse(req.text).data.permission[0].name).toBe("TEST_CONFIG_KEY"); + expect(JSON.parse(req.text).data.permission[1].name).toBe("TEST_CONFIG_KEY_PRD_QA"); + expect(JSON.parse(req.text).data.permission[0].permissions).toMatchObject(JSON.parse(exptected)); + expect(JSON.parse(req.text).data.permission[1].permissions).toMatchObject(JSON.parse(exptected)); + }); + + test('CLIENT_SUITE - Should return list of Configs permissions - Unauthorized access', async () => { + const req = await request(app) + .post('/adm-graphql') + .set('Authorization', `Bearer ${adminAccountToken}`) + .send(graphqlUtils.permissionsQuery(domainId, groupConfigId, `"UPDATE","DELETE"`, RouterTypes.CONFIG)); + + const exptected = '[{"action":"UPDATE","result":"nok"},{"action":"DELETE","result":"nok"}]'; + expect(req.statusCode).toBe(200); + expect(JSON.parse(req.text)).not.toBe(null); + expect(JSON.parse(req.text).data.permission[0].name).toBe("TEST_CONFIG_KEY"); + expect(JSON.parse(req.text).data.permission[1].name).toBe("TEST_CONFIG_KEY_PRD_QA"); + expect(JSON.parse(req.text).data.permission[0].permissions).toMatchObject(JSON.parse(exptected)); + expect(JSON.parse(req.text).data.permission[1].permissions).toMatchObject(JSON.parse(exptected)); + }); + + test('CLIENT_SUITE - Should NOT return list of permissions - Invalid router', async () => { + const req = await request(app) + .post('/adm-graphql') + .set('Authorization', `Bearer ${adminAccountToken}`) + .send(graphqlUtils.permissionsQuery(domainId, undefined, `"UPDATE","DELETE"`, RouterTypes.DOMAIN)); + + expect(req.statusCode).toBe(200); + expect(JSON.parse(req.text)).not.toBe(null); + expect(JSON.parse(req.text).data.permission).toStrictEqual([]); + }); }); \ No newline at end of file diff --git a/tests/graphql-utils/index.js b/tests/graphql-utils/index.js index 374a4c6..b2c63eb 100644 --- a/tests/graphql-utils/index.js +++ b/tests/graphql-utils/index.js @@ -63,6 +63,27 @@ export const buildEntries = (entries) => { return `${entries.map(createStrategyInput)}`; }; +export const permissionsQuery = (domainId, parentId, actions, router) => { + return { + query: ` + { + permission( + domain: "${domainId}", + parent: "${parentId}", + actions: [${actions}], + router: "${router}" + ) { + id, + name, + permissions { + action + result + } + } + } + `}; +}; + export const expected100 = ` { "data": {