From 137e9c2f1375bfe41cc9c9a5490d7eb25b3bcc22 Mon Sep 17 00:00:00 2001 From: Jez Higgins Date: Thu, 23 Aug 2018 10:16:34 +0100 Subject: [PATCH] feat: RBAC service removed - it's pulled out into tymly-rbac-plugin --- .../rbac/apply-default-blueprint-docs.js | 139 ---------- .../services/rbac/apply-default-roles.js | 34 --- .../components/services/rbac/doc/content.md | 0 .../components/services/rbac/doc/index.js | 5 - .../services/rbac/find-user-roles.js | 25 -- lib/plugin/components/services/rbac/index.js | 133 ---------- .../services/rbac/refresh-index/index.js | 36 --- .../components/services/statebox/index.js | 6 +- .../blueprint.json | 14 - .../state-machines/admin.json | 21 -- .../authenticated-heart-beat.json | 25 -- .../state-machines/authenticated.json | 21 -- .../state-machines/everyone-heart-beat.json | 20 -- .../state-machines/everyone.json | 21 -- .../state-machines/owner-heart-beat.json | 25 -- .../website-blueprint/blueprint.json | 14 - .../website-blueprint/categories/posts.json | 8 - .../website-blueprint/categories/website.json | 8 - .../state-machines/create-post.json | 30 --- .../state-machines/delete-post.json | 22 -- .../state-machines/purge-site.json | 21 -- .../state-machines/read-post.json | 30 --- .../state-machines/update-post.json | 31 --- .../template-roles/boss.json | 21 -- .../template-roles/developer.json | 11 - .../template-roles/team-leader.json | 14 - .../template-roles/tymly-test-admin.json | 11 - .../template-roles/tymly-test-read-only.json | 11 - .../state-resources/success/index.js | 12 - test/fixtures/plugins/success-plugin/index.js | 8 - .../services/test-service3/index.js | 2 +- test/rbac-service-spec.js | 231 ----------------- test/shutdown-services-spec.js | 3 +- test/statebox-service-rbac-tests.js | 241 ------------------ 34 files changed, 4 insertions(+), 1250 deletions(-) delete mode 100644 lib/plugin/components/services/rbac/apply-default-blueprint-docs.js delete mode 100644 lib/plugin/components/services/rbac/apply-default-roles.js delete mode 100644 lib/plugin/components/services/rbac/doc/content.md delete mode 100644 lib/plugin/components/services/rbac/doc/index.js delete mode 100644 lib/plugin/components/services/rbac/find-user-roles.js delete mode 100644 lib/plugin/components/services/rbac/index.js delete mode 100644 lib/plugin/components/services/rbac/refresh-index/index.js delete mode 100644 test/fixtures/blueprints/access-controlled-blueprint/blueprint.json delete mode 100644 test/fixtures/blueprints/access-controlled-blueprint/state-machines/admin.json delete mode 100644 test/fixtures/blueprints/access-controlled-blueprint/state-machines/authenticated-heart-beat.json delete mode 100644 test/fixtures/blueprints/access-controlled-blueprint/state-machines/authenticated.json delete mode 100644 test/fixtures/blueprints/access-controlled-blueprint/state-machines/everyone-heart-beat.json delete mode 100644 test/fixtures/blueprints/access-controlled-blueprint/state-machines/everyone.json delete mode 100644 test/fixtures/blueprints/access-controlled-blueprint/state-machines/owner-heart-beat.json delete mode 100644 test/fixtures/blueprints/website-blueprint/blueprint.json delete mode 100644 test/fixtures/blueprints/website-blueprint/categories/posts.json delete mode 100644 test/fixtures/blueprints/website-blueprint/categories/website.json delete mode 100644 test/fixtures/blueprints/website-blueprint/state-machines/create-post.json delete mode 100644 test/fixtures/blueprints/website-blueprint/state-machines/delete-post.json delete mode 100644 test/fixtures/blueprints/website-blueprint/state-machines/purge-site.json delete mode 100644 test/fixtures/blueprints/website-blueprint/state-machines/read-post.json delete mode 100644 test/fixtures/blueprints/website-blueprint/state-machines/update-post.json delete mode 100644 test/fixtures/blueprints/website-blueprint/template-roles/boss.json delete mode 100644 test/fixtures/blueprints/website-blueprint/template-roles/developer.json delete mode 100644 test/fixtures/blueprints/website-blueprint/template-roles/team-leader.json delete mode 100644 test/fixtures/blueprints/website-blueprint/template-roles/tymly-test-admin.json delete mode 100644 test/fixtures/blueprints/website-blueprint/template-roles/tymly-test-read-only.json delete mode 100644 test/fixtures/plugins/success-plugin/components/state-resources/success/index.js delete mode 100644 test/fixtures/plugins/success-plugin/index.js delete mode 100644 test/rbac-service-spec.js delete mode 100644 test/statebox-service-rbac-tests.js diff --git a/lib/plugin/components/services/rbac/apply-default-blueprint-docs.js b/lib/plugin/components/services/rbac/apply-default-blueprint-docs.js deleted file mode 100644 index 035be3a8..00000000 --- a/lib/plugin/components/services/rbac/apply-default-blueprint-docs.js +++ /dev/null @@ -1,139 +0,0 @@ -function makeTemplateRoleDoc (docId, docSource) { - return { - roleId: docId, - label: docSource.label, - description: docSource.description - } -} // makeTemplateRoleDoc - -function makePermissionDoc (docId, docSource) { - return { - stateMachineName: docSource.stateMachineName, - roleId: docSource.roleId, - allows: docSource.allows - } -} // makePermissionDoc - -function makeRoleMembershipDoc (docId, docSource) { - return { - roleId: docSource.templateRoleId, - memberType: 'role', - memberId: docSource.roleMemberId - } -} // makeRoleMembershipDoc - -function gatherRoleTemplates (templateRoles, roleModel, roleMembershipModel, permissionModel) { - // Grab role-templates, default role-memberships and default role-grants - // --------------------------------------------------------------------- - - const docTasks = [] - - if (!templateRoles) { - return docTasks - } - - for (const [templateRoleId, templateRole] of Object.entries(templateRoles)) { - docTasks.push({ - domain: 'templateRole', - docId: templateRoleId, - docSource: templateRole, - dao: roleModel, - docMaker: makeTemplateRoleDoc - }) - - for (const grant of (templateRole.grants || [])) { - grant.roleId = templateRoleId - docTasks.push({ - domain: 'roleGrant', - docId: templateRoleId + '_' + grant.stateMachineName, - docSource: grant, - dao: permissionModel, - docMaker: makePermissionDoc - }) - } - - for (const roleMemberId of (templateRole.roleMemberships || [])) { - docTasks.push({ - domain: 'roleMembership', - docId: templateRoleId + '_' + roleMemberId, - docSource: { - templateRoleId: templateRoleId, - roleMemberId: templateRole.namespace + '_' + roleMemberId - }, - dao: roleMembershipModel, - docMaker: makeRoleMembershipDoc - }) - } - } - - return docTasks -} // gatherRoleTemplates - -function gatherStateMachineRestrictions (stateMachines, permissionModel) { - // Grab restrictions from state machines - // ------------------------------------- - - const docTasks = [] - - if (!stateMachines) { - return docTasks - } - - for (const [name, stateMachine] of Object.entries(stateMachines)) { - for (const restriction of (stateMachine.restrictions || [])) { - restriction.stateMachineName = name - docTasks.push({ - domain: 'stateMachineRestriction', - docId: name + '_' + restriction.roleId, - docSource: restriction, - dao: permissionModel, - docMaker: makePermissionDoc - }) - } - } - - return docTasks -} // gatherStateMachineRestrictions - -async function collectKnownDocs (blueprintDocs) { - const knownDocs = {} - const domains = ['templateRole', 'roleGrant', 'stateMachineRestriction', 'roleMembership'] - for (const domain of domains) { - const docIds = await blueprintDocs.getDomainDocIds(domain) - knownDocs[domain] = docIds - } - return knownDocs -} // collectKnownDocs - -module.exports = async function applyBlueprintDocs ( - blueprintDocs, - blueprintComponents, - roleModel, - roleMembershipModel, - permissionModel) { - const roleTemplateTasks = gatherRoleTemplates( - blueprintComponents.templateRoles, - roleModel, - roleMembershipModel, - permissionModel - ) - - const restrictionTasks = gatherStateMachineRestrictions( - blueprintComponents.stateMachines, - permissionModel - ) - - const docTasks = [...roleTemplateTasks, ...restrictionTasks] - const knownDocs = await collectKnownDocs(blueprintDocs) - - // the known docIds, grouped by domain, and all - // docs required from the blueprints... so for all unknown docs, go make them. - for (const task of docTasks) { - if (knownDocs[task.domain].indexOf(task.docId) === -1) { - // Unknown! - const doc = task.docMaker(task.docId, task.docSource) - await task.dao.create(doc, {}) - await blueprintDocs.registerDocument(task.domain, task.docId) - } - } -} diff --git a/lib/plugin/components/services/rbac/apply-default-roles.js b/lib/plugin/components/services/rbac/apply-default-roles.js deleted file mode 100644 index f04da1f6..00000000 --- a/lib/plugin/components/services/rbac/apply-default-roles.js +++ /dev/null @@ -1,34 +0,0 @@ -const debug = require('debug')('rbac') - -function ensureUserRoles (userId, roleIds, roleMembershipModel) { - if (!Array.isArray(roleIds)) { - return - } - - const roleUpserts = roleIds.map(roleId => { - debug(`Adding user '${userId}' into role '${roleId}'`) - return roleMembershipModel.upsert({ - roleId: roleId, - memberType: 'user', - memberId: userId - }, - {} - ) - }) - - return Promise.all(roleUpserts) -} // ensureUserRoles - -function applyDefaultRoles (defaultUsers, roleMembershipModel) { - if (!defaultUsers) { - return - } // if ... - - const roleUpdates = - Object.entries(defaultUsers) - .map(([userId, roles]) => ensureUserRoles(userId, roles, roleMembershipModel)) - - return Promise.all(roleUpdates) -} // applyDefaultRoles - -module.exports = { applyDefaultRoles, ensureUserRoles } diff --git a/lib/plugin/components/services/rbac/doc/content.md b/lib/plugin/components/services/rbac/doc/content.md deleted file mode 100644 index e69de29b..00000000 diff --git a/lib/plugin/components/services/rbac/doc/index.js b/lib/plugin/components/services/rbac/doc/index.js deleted file mode 100644 index 911d3d3d..00000000 --- a/lib/plugin/components/services/rbac/doc/index.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict' - -module.exports = { - description: 'Provides Rbac-based authorization capabilities' -} diff --git a/lib/plugin/components/services/rbac/find-user-roles.js b/lib/plugin/components/services/rbac/find-user-roles.js deleted file mode 100644 index 742a656f..00000000 --- a/lib/plugin/components/services/rbac/find-user-roles.js +++ /dev/null @@ -1,25 +0,0 @@ -async function findUserRoles (userId, roleMembershipModel, rbac) { - const roleIds = await findRoleIds(userId, roleMembershipModel) - - const applicableRoles = [] - for (const roleId of roleIds) { - const roles = rbac.inherits[roleId] || [roleId] - - applicableRoles.push(...roles) - } - applicableRoles.push('$everyone') - - return [...new Set(applicableRoles)] // uniqify -} // findUserRoles - -async function findRoleIds (userId, roleMembershipModel) { - const roles = await roleMembershipModel.find({ - where: { - memberType: {equals: 'user'}, - memberId: {equals: userId} - } - }) - return roles.map(r => r.roleId) -} // findRoleIds - -module.exports = findUserRoles diff --git a/lib/plugin/components/services/rbac/index.js b/lib/plugin/components/services/rbac/index.js deleted file mode 100644 index d1c6bab0..00000000 --- a/lib/plugin/components/services/rbac/index.js +++ /dev/null @@ -1,133 +0,0 @@ -const { applyDefaultRoles, ensureUserRoles } = require('./apply-default-roles') -const applyDefaultBlueprintDocs = require('./apply-default-blueprint-docs') -const loadRbacIndex = require('./refresh-index') -const findUserRoles = require('./find-user-roles') - -class RbacService { - async boot (options, callback) { - try { - this.messages = options.messages - this.roleModel = options.bootedServices.storage.models.tymly_role - this.roleMembershipModel = options.bootedServices.storage.models.tymly_roleMembership - this.permissionModel = options.bootedServices.storage.models.tymly_permission - - const caches = options.bootedServices.caches - caches.defaultIfNotInConfig('userMemberships', 500) - this.userMembershipsCache = caches.userMemberships - - this.messages.info('Applying default roles') - await applyDefaultRoles( - options.config.defaultUsers, - this.roleMembershipModel - ) - - this.messages.info('Applying unknown Blueprint documents') - await applyDefaultBlueprintDocs( - options.bootedServices.blueprintDocs, - options.blueprintComponents, - this.roleModel, - this.roleMembershipModel, - this.permissionModel - ) - - await this.refreshRbacIndex() - - callback(null) - } catch (err) { - return callback(err) - } - } // boot - - async ensureUserRoles (userId, roleIds) { - return ensureUserRoles(userId, roleIds, this.roleMembershipModel) - } // ensureUserRoles - - async refreshRbacIndex () { - this.messages.info('Refreshing RBAC index') - this.rbac = await loadRbacIndex( - this.roleModel, - this.roleMembershipModel, - this.permissionModel - ) - } - - /** - * Returns with all the roles currently assigned to the specified userId - * @param {string} userId Specifies which useId to return a list of roles for - * @param {Function} callback Called with an array of roleId strings that are assigned to the specified userId - * @returns {Promise} - * @example - * users.getUserRoles('Dave').then(roles => { - * // roles === ['tymlyTest_tymlyTestAdmin'] - * } - * ) - */ - async getUserRoles (userId) { - const cachedRoles = this.userMembershipsCache.get(userId) - if (Array.isArray(cachedRoles)) return cachedRoles - - const roles = await findUserRoles(userId, this.roleMembershipModel, this.rbac) - this.userMembershipsCache.set(userId, roles) - return roles - } // getUserRoles - - /** - * Checks the supplied credentials against the internal RBAC index - * @param {string} userId A userId to check (used for dynamic checks such as _'allow update as long as userId matches with the author of target document'_) - * @param {Object} ctx A Tymly context (optional) - * @param {Array} roles An array of roleIds - * @param {string} resourceType The type of resource to authorize against (e.g. `flow`) - * @param {string} resourceName The name of the resource that the credentials are being checked against (e.g. `flow tymlyTest_cat_1_0 startNewTymly`) - * @param {string} action And the name of action these credentials are wanting to perform (e.g. `startNewTymly`) - * @returns {boolean} Indicates if the provided credentials allow the specified action to be applied to the named resource (`true`) or not (`false`) - * @example - * var allowed = rbac.getUserIdFromContext( - * 'Dave', // userId - * null, // ctx - * 'flow', // resourceType, - * 'tymlyTest_cat_1_0', // resourceName, - * 'startNewTymly' // action - * ) // Returns true/false - */ - async checkAuthorization (userId, ctx, resourceType, resourceName, action) { - const uid = cleanUserId(userId) - const ownerId = cleanUserId(ctx) - const roles = await this.getUserRoles(userId) - - return this.rbac.checkRoleAuthorization(uid, ownerId, roles, resourceType, resourceName, action) - } // checkRoleAuthorization - - resetCache () { - this.userMembershipsCache.reset() - } - - debug () { - console.log('') - console.log('RBAC Index') - console.log('----------') - - for (const [domainName, domain] of Object.entries(this.rbac.index)) { - for (const [stateMachineName, stateMachine] of Object.entries(domain)) { - for (const [actionName, action] of Object.entries(stateMachine)) { - const path = [domainName, stateMachineName, actionName, JSON.stringify(action)].join(' -> ') - console.log(' ', path) - } - } - } - - console.log('') - } // debug -} // RbacService - -function cleanUserId (userId) { - if (userId && userId.userId) { - return cleanUserId(userId.userId) - } - - return (typeof userId === 'string') ? userId : null -} // cleanUserId - -module.exports = { - serviceClass: RbacService, - bootAfter: ['statebox', 'caches', 'storage'] -} diff --git a/lib/plugin/components/services/rbac/refresh-index/index.js b/lib/plugin/components/services/rbac/refresh-index/index.js deleted file mode 100644 index 86acd213..00000000 --- a/lib/plugin/components/services/rbac/refresh-index/index.js +++ /dev/null @@ -1,36 +0,0 @@ -'use strict' - -const Rbac = require('@wmfs/rbac') - -module.exports = async function refreshRbacIndex ( - roleModel, - roleMembershipModel, - permissionModel) { - const data = await loader( - roleModel, - roleMembershipModel, - permissionModel - ) - - return new Rbac(data) -} // refreshRbacIndex - -async function loader ( - roleModel, - roleMembershipModel, - permissionModel) { - const roleMemberships = - await roleMembershipModel.find({ - where: { - memberType: {equals: 'role'} - } - }) - - const permissions = - await permissionModel.find({}) - - const roles = - await roleModel.find({}) - - return { roleMemberships, permissions, roles } -} // loader diff --git a/lib/plugin/components/services/statebox/index.js b/lib/plugin/components/services/statebox/index.js index b635c597..697e9b37 100644 --- a/lib/plugin/components/services/statebox/index.js +++ b/lib/plugin/components/services/statebox/index.js @@ -6,8 +6,6 @@ const _ = require('lodash') const cls = require('cls-hooked') const session = cls.createNamespace('statebox') -const ENABLE_RBAC = false - function promiseOrCallback (p, callback) { if (callback) { p @@ -208,8 +206,8 @@ class StateboxService { } // processIfAuthorised authorisationCheck (userId, stateMachineName, executionOptions, action) { - if (!ENABLE_RBAC) { - return [true] // STUB! + if (!this.services.rbac) { + return [true] // No RBAC service installed. Just continue. } return this.doAuthorisationCheck(userId, stateMachineName, executionOptions, action) diff --git a/test/fixtures/blueprints/access-controlled-blueprint/blueprint.json b/test/fixtures/blueprints/access-controlled-blueprint/blueprint.json deleted file mode 100644 index b256c12b..00000000 --- a/test/fixtures/blueprints/access-controlled-blueprint/blueprint.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - - "namespace": "tymlyTest", - "name": "acccess controlled", - "version": "1.0", - - "label": "Cats", - "author": "Tim Needham", - - "organisation": "Tymly", - "description": "An example Tymly Blueprint to help model cat behaviour...", - "categories": ["cats"] - -} diff --git a/test/fixtures/blueprints/access-controlled-blueprint/state-machines/admin.json b/test/fixtures/blueprints/access-controlled-blueprint/state-machines/admin.json deleted file mode 100644 index 5c60cabd..00000000 --- a/test/fixtures/blueprints/access-controlled-blueprint/state-machines/admin.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "Comment": "Blueprint to do a thing", - "version": "1.0", - "StartAt": "Success", - "States": { - "Success": { - "Type": "Task", - "Resource": "module:success", - "ResultPath": "$.success", - "End": true - } - }, - "restrictions": [ - { - "roleId": "admin", - "allows": [ - "*" - ] - } - ] -} diff --git a/test/fixtures/blueprints/access-controlled-blueprint/state-machines/authenticated-heart-beat.json b/test/fixtures/blueprints/access-controlled-blueprint/state-machines/authenticated-heart-beat.json deleted file mode 100644 index e375e6cb..00000000 --- a/test/fixtures/blueprints/access-controlled-blueprint/state-machines/authenticated-heart-beat.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "Comment": "State machine to test heartbeat functionality.", - "version": "1.0", - "StartAt": "Heartbeat", - "States": { - "Heartbeat": { - "Type": "Task", - "Resource": "module:heartBeat", - "End": true - } - }, - "restrictions": [ - { - "roleId": "$everyone", - "allows": [ - "create" - ] - }, - { "roleId": "$authenticated", - "allows": [ - "*" - ] - } - ] -} diff --git a/test/fixtures/blueprints/access-controlled-blueprint/state-machines/authenticated.json b/test/fixtures/blueprints/access-controlled-blueprint/state-machines/authenticated.json deleted file mode 100644 index da110c1b..00000000 --- a/test/fixtures/blueprints/access-controlled-blueprint/state-machines/authenticated.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "Comment": "Blueprint to do a thing", - "version": "1.0", - "StartAt": "Success", - "States": { - "Success": { - "Type": "Task", - "Resource": "module:success", - "ResultPath": "$.success", - "End": true - } - }, - "restrictions": [ - { - "roleId": "$authenticated", - "allows": [ - "*" - ] - } - ] -} diff --git a/test/fixtures/blueprints/access-controlled-blueprint/state-machines/everyone-heart-beat.json b/test/fixtures/blueprints/access-controlled-blueprint/state-machines/everyone-heart-beat.json deleted file mode 100644 index db778cfc..00000000 --- a/test/fixtures/blueprints/access-controlled-blueprint/state-machines/everyone-heart-beat.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "Comment": "State machine to test heartbeat functionality.", - "version": "1.0", - "StartAt": "Heartbeat", - "States": { - "Heartbeat": { - "Type": "Task", - "Resource": "module:heartBeat", - "End": true - } - }, - "restrictions": [ - { - "roleId": "$everyone", - "allows": [ - "*" - ] - } - ] -} diff --git a/test/fixtures/blueprints/access-controlled-blueprint/state-machines/everyone.json b/test/fixtures/blueprints/access-controlled-blueprint/state-machines/everyone.json deleted file mode 100644 index 87a76f8d..00000000 --- a/test/fixtures/blueprints/access-controlled-blueprint/state-machines/everyone.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "Comment": "Blueprint to do a thing", - "version": "1.0", - "StartAt": "Success", - "States": { - "Success": { - "Type": "Task", - "Resource": "module:success", - "ResultPath": "$.success", - "End": true - } - }, - "restrictions": [ - { - "roleId": "$everyone", - "allows": [ - "*" - ] - } - ] -} diff --git a/test/fixtures/blueprints/access-controlled-blueprint/state-machines/owner-heart-beat.json b/test/fixtures/blueprints/access-controlled-blueprint/state-machines/owner-heart-beat.json deleted file mode 100644 index c28be342..00000000 --- a/test/fixtures/blueprints/access-controlled-blueprint/state-machines/owner-heart-beat.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "Comment": "State machine to test heartbeat functionality.", - "version": "1.0", - "StartAt": "Heartbeat", - "States": { - "Heartbeat": { - "Type": "Task", - "Resource": "module:heartBeat", - "End": true - } - }, - "restrictions": [ - { - "roleId": "$everyone", - "allows": [ - "create" - ] - }, - { "roleId": "$owner", - "allows": [ - "*" - ] - } - ] -} diff --git a/test/fixtures/blueprints/website-blueprint/blueprint.json b/test/fixtures/blueprints/website-blueprint/blueprint.json deleted file mode 100644 index e2a8a344..00000000 --- a/test/fixtures/blueprints/website-blueprint/blueprint.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - - "namespace": "tymlyTest", - "name": "website", - "version": "1.0", - - "label": "Website", - "author": "Tim Needham", - - "organisation": "Tymlys", - "description": "An example Tymly Blueprint to help test ACL roles.", - "categories": ["acl", "roles", "permissions"] - -} diff --git a/test/fixtures/blueprints/website-blueprint/categories/posts.json b/test/fixtures/blueprints/website-blueprint/categories/posts.json deleted file mode 100644 index 3e10a7da..00000000 --- a/test/fixtures/blueprints/website-blueprint/categories/posts.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "label": "Posts", - "description": "Posts category", - "styling": { - "icon": "post", - "backgroundColor": "#00GG00" - } -} diff --git a/test/fixtures/blueprints/website-blueprint/categories/website.json b/test/fixtures/blueprints/website-blueprint/categories/website.json deleted file mode 100644 index 20dcbf18..00000000 --- a/test/fixtures/blueprints/website-blueprint/categories/website.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "label": "Website", - "description": "Website category", - "styling": { - "icon": "website", - "backgroundColor": "#FFFF00" - } -} diff --git a/test/fixtures/blueprints/website-blueprint/state-machines/create-post.json b/test/fixtures/blueprints/website-blueprint/state-machines/create-post.json deleted file mode 100644 index 0e91efe4..00000000 --- a/test/fixtures/blueprints/website-blueprint/state-machines/create-post.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "Comment": "Add a pearl-of-wisdom to a thread", - "version": "1.0", - "StartAt": "Logging", - "instigators": [ - "user" - ], - "categories": [ - "website", - "posts" - ], - "States": { - "Logging": { - "Type": "Task", - "Resource": "module:logging", - "ResourceConfig": { - "template": "Create post!" - }, - "End": true - } - }, - "restrictions": [ - { - "roleId": "$authenticated", - "allows": [ - "create" - ] - } - ] -} diff --git a/test/fixtures/blueprints/website-blueprint/state-machines/delete-post.json b/test/fixtures/blueprints/website-blueprint/state-machines/delete-post.json deleted file mode 100644 index 03243cf5..00000000 --- a/test/fixtures/blueprints/website-blueprint/state-machines/delete-post.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "Comment": "Workflow to remove a website post", - "version": "1.0", - "StartAt": "Logging", - "instigators": [ - "user" - ], - "categories": [ - "website", - "posts" - ], - "States": { - "Logging": { - "Type": "Task", - "Resource": "module:logging", - "ResourceConfig": { - "template": "Delete post!" - }, - "End": true - } - } -} diff --git a/test/fixtures/blueprints/website-blueprint/state-machines/purge-site.json b/test/fixtures/blueprints/website-blueprint/state-machines/purge-site.json deleted file mode 100644 index 18279afb..00000000 --- a/test/fixtures/blueprints/website-blueprint/state-machines/purge-site.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "Comment": "Take it all down... NOW!!!", - "version": "1.0", - "StartAt": "Logging", - "instigators": [ - "user" - ], - "categories": [ - "website" - ], - "States": { - "Logging": { - "Type": "Task", - "Resource": "module:logging", - "ResourceConfig": { - "template": "Purge site!" - }, - "End": true - } - } -} diff --git a/test/fixtures/blueprints/website-blueprint/state-machines/read-post.json b/test/fixtures/blueprints/website-blueprint/state-machines/read-post.json deleted file mode 100644 index be64d282..00000000 --- a/test/fixtures/blueprints/website-blueprint/state-machines/read-post.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "Comment": "Read a post in its entirety", - "version": "1.0", - "StartAt": "Logging", - "instigators": [ - "user" - ], - "categories": [ - "website", - "posts" - ], - "States": { - "Logging": { - "Type": "Task", - "Resource": "module:logging", - "ResourceConfig": { - "template": "Read post!" - }, - "End": true - } - }, - "restrictions": [ - { - "roleId": "$everyone", - "allows": [ - "create" - ] - } - ] -} diff --git a/test/fixtures/blueprints/website-blueprint/state-machines/update-post.json b/test/fixtures/blueprints/website-blueprint/state-machines/update-post.json deleted file mode 100644 index cc8293d2..00000000 --- a/test/fixtures/blueprints/website-blueprint/state-machines/update-post.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "label": "Update website post", - "Comment": "Change an existing post", - "version": "1.0", - "StartAt": "Logging", - "instigators": [ - "user" - ], - "categories": [ - "website", - "posts" - ], - "States": { - "Logging": { - "Type": "Task", - "Resource": "module:logging", - "ResourceConfig": { - "template": "Update post!" - }, - "End": true - } - }, - "restrictions": [ - { - "roleId": "$owner", - "allows": [ - "create" - ] - } - ] -} diff --git a/test/fixtures/blueprints/website-blueprint/template-roles/boss.json b/test/fixtures/blueprints/website-blueprint/template-roles/boss.json deleted file mode 100644 index 16ee905b..00000000 --- a/test/fixtures/blueprints/website-blueprint/template-roles/boss.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "label": "Boss", - "description": "Like a Boss!", - "roleMemberships": [ - "teamLeader" - ], - "grants": [ - { - "stateMachineName": "purgeSite", - "allows": [ - "create" - ] - }, - { - "stateMachineName": "deletePost", - "allows": [ - "cancel" - ] - } - ] -} diff --git a/test/fixtures/blueprints/website-blueprint/template-roles/developer.json b/test/fixtures/blueprints/website-blueprint/template-roles/developer.json deleted file mode 100644 index 4226d434..00000000 --- a/test/fixtures/blueprints/website-blueprint/template-roles/developer.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "label": "Developer", - "grants": [ - { - "stateMachineName": "createPost", - "allows": [ - "cancel" - ] - } - ] -} diff --git a/test/fixtures/blueprints/website-blueprint/template-roles/team-leader.json b/test/fixtures/blueprints/website-blueprint/template-roles/team-leader.json deleted file mode 100644 index 39b8e9e3..00000000 --- a/test/fixtures/blueprints/website-blueprint/template-roles/team-leader.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "label": "Team leader", - "roleMemberships": [ - "developer" - ], - "grants": [ - { - "stateMachineName": "deletePost", - "allows": [ - "create" - ] - } - ] -} diff --git a/test/fixtures/blueprints/website-blueprint/template-roles/tymly-test-admin.json b/test/fixtures/blueprints/website-blueprint/template-roles/tymly-test-admin.json deleted file mode 100644 index c2ddac27..00000000 --- a/test/fixtures/blueprints/website-blueprint/template-roles/tymly-test-admin.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "label": "tymlyTest Admin", - "description": "Do anything in the TymlyTest namespace", - - "grants": [ - { - "stateMachineName": "*", - "allows": ["*"] - } - ] -} diff --git a/test/fixtures/blueprints/website-blueprint/template-roles/tymly-test-read-only.json b/test/fixtures/blueprints/website-blueprint/template-roles/tymly-test-read-only.json deleted file mode 100644 index 64b2f3e1..00000000 --- a/test/fixtures/blueprints/website-blueprint/template-roles/tymly-test-read-only.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "label": "Get anything in the TymlyTest namespace... useful for dashboards", - "grants": [ - { - "stateMachineName": "*", - "allows": [ - "get" - ] - } - ] -} diff --git a/test/fixtures/plugins/success-plugin/components/state-resources/success/index.js b/test/fixtures/plugins/success-plugin/components/state-resources/success/index.js deleted file mode 100644 index 9414f857..00000000 --- a/test/fixtures/plugins/success-plugin/components/state-resources/success/index.js +++ /dev/null @@ -1,12 +0,0 @@ - -class Success { - init (resourceConfig, env, callback) { - callback(null) - } - - run (event, context) { - context.sendTaskSuccess('Yes boys!') - } // run -} // Success - -module.exports = Success diff --git a/test/fixtures/plugins/success-plugin/index.js b/test/fixtures/plugins/success-plugin/index.js deleted file mode 100644 index b3c8f283..00000000 --- a/test/fixtures/plugins/success-plugin/index.js +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = { - label: 'Success', - author: 'Jez Higgins', - version: '1.0', - - organisation: 'Tymly', - description: 'Provides a state resource to help test flows' -} diff --git a/test/fixtures/plugins/test-services-plugin/components/services/test-service3/index.js b/test/fixtures/plugins/test-services-plugin/components/services/test-service3/index.js index 665e9256..22ca37c0 100644 --- a/test/fixtures/plugins/test-services-plugin/components/services/test-service3/index.js +++ b/test/fixtures/plugins/test-services-plugin/components/services/test-service3/index.js @@ -14,6 +14,6 @@ class TestService3 { module.exports = { serviceClass: TestService3, - bootBefore: ['testService1', 'rbac'], + bootBefore: ['testService1', 'statebox'], bootAfter: ['inventory'] } diff --git a/test/rbac-service-spec.js b/test/rbac-service-spec.js deleted file mode 100644 index 3aebaa66..00000000 --- a/test/rbac-service-spec.js +++ /dev/null @@ -1,231 +0,0 @@ -/* eslint-env mocha */ - -const expect = require('chai').expect -const tymly = require('./../lib') -const path = require('path') - -xdescribe('RBAC service tests', function () { - // TODO: MORE! MORE! MORE! - - this.timeout(process.env.TIMEOUT || 5000) - - let tymlyService - let rbac - - describe('setup', () => { - it('should get the ACL service for testing purposes', function (done) { - tymly.boot( - { - pluginPaths: [], - blueprintPaths: [ - path.resolve(__dirname, './fixtures/blueprints/website-blueprint') - ], - - config: { - caches: { - userMemberships: {max: 500} - } - } - }, - function (err, tymlyServices) { - expect(err).to.eql(null) - tymlyService = tymlyServices.tymly - rbac = tymlyServices.rbac - rbac.debug() - done() - } - ) - }) - }) - - describe('checkRoleAuthorization', () => { - it('Should authorize something $everyone can do', function () { - expect( - rbac.checkRoleAuthorization( - null, // userId - null, // ctx - [], // roles - 'stateMachine', // resourceType - 'tymlyTest_readPost_1_0', // resourceName - 'create' // action - )).to.equal(true) - }) - - it('Should authorize something an $authenticated user can do', function () { - expect( - rbac.checkRoleAuthorization( - 'john.smith', // userId - null, // ctx - [], // roles - 'stateMachine', // resourceType - 'tymlyTest_createPost_1_0', // resourceName - 'create' // action - )).to.equal(true) - }) - - it('Should deny something if user is not authenticated, when they need to be', function () { - expect( - rbac.checkRoleAuthorization( - undefined, // userId - null, // ctx - [], // roles - 'stateMachine', // resourceType - 'tymlyTest_createPost_1_0', // resourceName - 'create' // action - )).to.equal(false) - }) - - it('Should authorize an $owner', function () { - expect( - rbac.checkRoleAuthorization( - 'molly', // userId - {userId: 'molly'}, // ctx - [], // roles - 'stateMachine', // resourceType - 'tymlyTest_updatePost_1_0', // resourceName - 'create' // action - )).to.equal(true) - }) - - it('Should authorize something directly allowed via a role', function () { - expect( - rbac.checkRoleAuthorization( - 'john.doe', // userId - null, // ctx - ['tymlyTest_developer'], // roles - 'stateMachine', // resourceType - 'tymlyTest_createPost_1_0', // resourceName - 'cancel' // action - )).to.equal(true) - }) - - it('Should deny if no matching role', function () { - expect( - rbac.checkRoleAuthorization( - 'john.doe', // userId - null, // ctx - ['spaceCadet', 'IRRELEVANT!'], // roles - 'stateMachine', // resourceType - 'tymlyTest_createPost_1_0', // resourceName - 'cancel' // action - )).to.equal(false) - }) - - it('Should deny if no appropriate role', function () { - expect( - rbac.checkRoleAuthorization( - null, // userId - null, // ctx - ['tymly_developer'], // roles - 'stateMachine', // resourceType - 'tymlyTest_deletePost_1_0', // resourceName - 'create' // action - )).to.equal(false) - }) - - it('Should authorize something because of role inheritance', function () { - expect( - rbac.checkRoleAuthorization( - null, // userId - null, // ctx - ['tymlyTest_boss'], // roles - 'stateMachine', // resourceType - 'tymlyTest_createPost_1_0', // resourceName - 'cancel' // action - )).to.equal(true) - }) - - it('Should authorize something with resource and action wildcards', function () { - expect( - rbac.checkRoleAuthorization( - 'molly', // userId - null, // ctx - ['tymlyTest_tymlyTestAdmin'], // roles - 'stateMachine', // resourceType - 'tymlyTest_purgeSite_1_0', // resourceName - 'create' // action - )).to.equal(true) - }) - - it('Should authorize something with just an action wildcard', function () { - expect( - rbac.checkRoleAuthorization( - 'molly', // userId - null, // ctx - ['tymlyTest_tymlyTestReadOnly'], // roles - 'stateMachine', // resourceType - 'tymlyTest_purgeSite_1_0', // resourceName - 'get' // action - )).to.equal(true) - }) - - it('Should fail to authorize if irrelevant action wildcard', function () { - expect( - rbac.checkRoleAuthorization( - 'molly', // userId - null, // ctx - ['tymlyTest_tymlyTestReadOnly'], // roles - 'stateMachine', // resourceType - 'tymlyTest_purgeSite_1_0', // resourceName - 'create' // action - )).to.equal(false) - }) - }) - - describe('getUserRoles', () => { - const allUserRoles = [ - [ - 'mommy', - ['tymlyTest_boss'], - ['tymlyTest_boss', 'tymlyTest_teamLeader', 'tymlyTest_developer', '$everyone'] - ], - [ - 'daddy', - ['tymlyTest_tymlyTestAdmin'], - ['tymlyTest_tymlyTestAdmin', '$everyone'] - ], - [ - 'lucy', - ['tymlyTest_tymlyTestReadOnly', 'tymlyTest_teamLeader'], - ['tymlyTest_tymlyTestReadOnly', '$everyone', 'tymlyTest_teamLeader', 'tymlyTest_developer'] - ], - [ - 'molly', - ['tymlyTest_developer'], - ['tymlyTest_developer', '$everyone'] - ], - [ - 'just-some-dude', - null, - ['$everyone'] - ] - ] - - for (const [user, roles] of allUserRoles) { - it(`ensure ${user} roles`, async () => { - await rbac.ensureUserRoles(user, roles) - }) - } - - for (const [user, , expectedRoles] of allUserRoles) { - it(`verify ${user} roles via storage`, async () => { - const roles = await rbac.getUserRoles(user) - expect(roles).to.eql(expectedRoles) - }) - it(`verify ${user} roles via cache`, async () => { - const roles = await rbac.getUserRoles(user) - expect(roles).to.eql(expectedRoles) - }) - } // for ... - }) - - describe('shutdown', () => { - it('should reset cache', function () { - rbac.resetCache() - }) - - it('should shutdown Tymly', async () => { - await tymlyService.shutdown() - }) - }) -}) diff --git a/test/shutdown-services-spec.js b/test/shutdown-services-spec.js index 2da99dd6..bb07dfcc 100644 --- a/test/shutdown-services-spec.js +++ b/test/shutdown-services-spec.js @@ -36,11 +36,10 @@ describe('Shutdown services tests', function () { 'storage', 'functions', 'blueprintDocs', + 'testService3', 'registry', 'categories', 'statebox', - 'testService3', - 'rbac', 'testService1', 'testService2' ] diff --git a/test/statebox-service-rbac-tests.js b/test/statebox-service-rbac-tests.js deleted file mode 100644 index 2121576a..00000000 --- a/test/statebox-service-rbac-tests.js +++ /dev/null @@ -1,241 +0,0 @@ -/* eslint-env mocha */ - -const path = require('path') -const expect = require('chai').expect -const tymly = require('../lib') - -const startTests = [ - { - label: 'everyone', - blueprint: 'tymlyTest_everyone_1_0', - allowed: [null, 'jim.smith', 'administrator'], - disallowed: [] - }, - { - label: 'authenticated', - blueprint: 'tymlyTest_authenticated_1_0', - allowed: ['jim.smith', 'administrator'], - disallowed: [null] - } /* , - { - label: 'admin', - blueprint: 'tymlyTest_admin_1_0', - allowed: ['administrator'], - disallowed: [null, 'jim.smith'] - } */ -] - -const heartBeatBlueprints = [ - { - label: 'everyone', - blueprint: 'tymlyTest_everyoneHeartBeat_1_0', - allowed: [null, 'jim.smith', 'administrator'], - disallowed: [] - }, - { - label: 'authenticated', - blueprint: 'tymlyTest_authenticatedHeartBeat_1_0', - allowed: ['jim.smith', 'administrator'], - disallowed: [null] - }, - { - label: 'owner', - blueprint: 'tymlyTest_ownerHeartBeat_1_0', - allowed: ['the-stopper'], - disallowed: [null, 'jim.smith', 'administrator'] - } -] - -const heartBeatTests = [ - { - label: 'stopExecution', - testFn: (statebox, executionName, user) => statebox.stopExecution( - 'Form cancelled by user', - 'CANCELLED', - executionName, - { userId: user } - ), - status: 'STOPPED' - }, - { - label: 'sendTaskSuccess', - testFn: (statebox, executionName, user) => statebox.sendTaskSuccess( - executionName, - {}, - { userId: user } - ), - status: 'SUCCEEDED' - }, - { - label: 'sendTaskFailure', - testFn: (statebox, executionName, user) => statebox.sendTaskFailure( - executionName, - { - error: 'FAIL', - cause: 'Brexit' - }, - { userId: user } - ), - status: 'FAILED' - }, - { - label: 'sendTaskHeartbeat', - testFn: (statebox, executionName, user) => statebox.sendTaskHeartbeat( - executionName, - { }, - { userId: user } - ), - status: 'RUNNING' - } -] - -xdescribe('Statebox service RBAC authorisation', function () { - this.timeout(process.env.TIMEOUT || 5000) - - let tymlyService - let statebox - let rbac - - describe('setup', () => { - it('boot Tymly', function (done) { - tymly.boot( - { - blueprintPaths: [ - path.resolve(__dirname, './fixtures/blueprints/access-controlled-blueprint') - ], - pluginPaths: [ - path.resolve(__dirname, './fixtures/plugins/success-plugin'), - path.resolve(__dirname, './fixtures/plugins/heartbeat-plugin') - ] - }, - function (err, tymlyServices) { - if (err) return done(err) - tymlyService = tymlyServices.tymly - statebox = tymlyServices.statebox - rbac = tymlyServices.rbac - - rbac.debug() - - done() - } - ) - }) - - it('grant \'admin\' permission to \'administrator\'', async () => { - await rbac.ensureUserRoles('administrator', ['admin']) - await rbac.refreshRbacIndex() - - rbac.debug() - }) - }) - - describe('startExecution', () => { - for (const test of startTests) { - describe(test.label, () => { - describe('allowed', () => { - for (const allowed of test.allowed) { - it(`${allowed}`, async () => { - const execDesc = await statebox.startExecution( - { }, - test.blueprint, - { - sendResponse: 'COMPLETE', - userId: allowed - } - ) - expect(execDesc.status).to.eql('SUCCEEDED') - expect(execDesc.ctx.success).to.eql('Yes boys!') - }) - } // allowed - }) - - describe('disallowed', () => { - for (const disallowed of test.disallowed) { - it(`${disallowed}`, async () => { - const execDesc = await statebox.startExecution( - { }, - test.blueprint, - { - sendResponse: 'COMPLETE', - userId: disallowed - } - ) - expect(execDesc.status).to.eql('NOAUTH') - expect(execDesc.stateMachineName).to.eql(test.blueprint) - expect(execDesc.errorCode).to.eql('401') - }) - } // allowed - }) - }) - } // for ... - }) // start execution tests - - for (const testAction of heartBeatTests) { - describe(testAction.label, () => { - for (const test of heartBeatBlueprints) { - describe(test.label, () => { - describe('allowed', () => { - for (const allowed of test.allowed) { - describe(`${allowed}`, () => { - let executionName - - it('startExecution', async () => { - const execDesc = await statebox.startExecution( - {}, - test.blueprint, - { - sendResponse: 'AFTER_RESOURCE_CALLBACK.TYPE:heartBeat', - userId: 'the-stopper' - } - ) - expect(execDesc.status).to.eql('RUNNING') - executionName = execDesc.executionName - }) - - it(testAction.label, async () => { - const execDesc = await testAction.testFn(statebox, executionName, allowed) - - expect(execDesc.status).to.eql(testAction.status) - }) - }) - } // for allowed ... - }) - describe('disallowed', () => { - for (const disallowed of test.disallowed) { - describe(`${disallowed}`, () => { - let executionName - - it('startExecution', async () => { - const execDesc = await statebox.startExecution( - {}, - test.blueprint, - { - sendResponse: 'AFTER_RESOURCE_CALLBACK.TYPE:heartBeat', - userId: 'the-stopper' - } - ) - expect(execDesc.status).to.eql('RUNNING') - executionName = execDesc.executionName - }) - - it('stopExecution', async () => { - const execDesc = await testAction.testFn(statebox, executionName, disallowed) - - expect(execDesc.status).to.eql('NOAUTH') - expect(execDesc.stateMachineName).to.eql(test.blueprint) - expect(execDesc.errorCode).to.eql('401') - }) - }) - } // for disallowed ... - }) - }) - } // for stop tests ... - }) - } - - describe('cleanup', () => { - it('shutdown Tymly', async () => { - await tymlyService.shutdown() - }) - }) -})