Making use of the resourceId in the middleware package.
This commit is contained in:
parent
9752263e25
commit
7a65a59c78
|
@ -1,10 +1,11 @@
|
||||||
const {
|
const {
|
||||||
BUILTIN_ROLE_IDS,
|
BUILTIN_ROLE_IDS,
|
||||||
getUserPermissionIds,
|
getUserPermissions,
|
||||||
} = require("../utilities/security/roles")
|
} = require("../utilities/security/roles")
|
||||||
const {
|
const {
|
||||||
PermissionTypes,
|
PermissionTypes,
|
||||||
doesHavePermission,
|
doesHaveResourcePermission,
|
||||||
|
doesHaveBasePermission,
|
||||||
} = require("../utilities/security/permissions")
|
} = require("../utilities/security/permissions")
|
||||||
const env = require("../environment")
|
const env = require("../environment")
|
||||||
const { isAPIKeyValid } = require("../utilities/security/apikey")
|
const { isAPIKeyValid } = require("../utilities/security/apikey")
|
||||||
|
@ -14,6 +15,10 @@ const ADMIN_ROLES = [BUILTIN_ROLE_IDS.ADMIN, BUILTIN_ROLE_IDS.BUILDER]
|
||||||
|
|
||||||
const LOCAL_PASS = new RegExp(["webhooks/trigger", "webhooks/schema"].join("|"))
|
const LOCAL_PASS = new RegExp(["webhooks/trigger", "webhooks/schema"].join("|"))
|
||||||
|
|
||||||
|
function hasResource(ctx) {
|
||||||
|
return ctx.resourceId != null
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = (permType, permLevel = null) => async (ctx, next) => {
|
module.exports = (permType, permLevel = null) => async (ctx, next) => {
|
||||||
// webhooks can pass locally
|
// webhooks can pass locally
|
||||||
if (!env.CLOUD && LOCAL_PASS.test(ctx.request.url)) {
|
if (!env.CLOUD && LOCAL_PASS.test(ctx.request.url)) {
|
||||||
|
@ -47,7 +52,10 @@ module.exports = (permType, permLevel = null) => async (ctx, next) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const role = ctx.user.role
|
const role = ctx.user.role
|
||||||
const permissions = await getUserPermissionIds(ctx.appId, role._id)
|
const { basePermissions, permissions } = await getUserPermissions(
|
||||||
|
ctx.appId,
|
||||||
|
role._id
|
||||||
|
)
|
||||||
if (ADMIN_ROLES.indexOf(role._id) !== -1) {
|
if (ADMIN_ROLES.indexOf(role._id) !== -1) {
|
||||||
return next()
|
return next()
|
||||||
}
|
}
|
||||||
|
@ -56,7 +64,14 @@ module.exports = (permType, permLevel = null) => async (ctx, next) => {
|
||||||
ctx.throw(403, "Not Authorized")
|
ctx.throw(403, "Not Authorized")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!doesHavePermission(permType, permLevel, permissions)) {
|
if (
|
||||||
|
hasResource(ctx) &&
|
||||||
|
doesHaveResourcePermission(permissions, permLevel, ctx)
|
||||||
|
) {
|
||||||
|
return next()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!doesHaveBasePermission(permType, permLevel, basePermissions)) {
|
||||||
ctx.throw(403, "User does not have permission")
|
ctx.throw(403, "User does not have permission")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -97,7 +97,35 @@ exports.BUILTIN_PERMISSIONS = {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.doesHavePermission = (permType, permLevel, permissionIds) => {
|
exports.doesHaveResourcePermission = (
|
||||||
|
permissions,
|
||||||
|
permLevel,
|
||||||
|
{ resourceId, subResourceId }
|
||||||
|
) => {
|
||||||
|
// set foundSub to not subResourceId, incase there is no subResource
|
||||||
|
let foundMain = false,
|
||||||
|
foundSub = !subResourceId
|
||||||
|
for (let [resource, level] of Object.entries(permissions)) {
|
||||||
|
const levels = getAllowedLevels(level)
|
||||||
|
if (resource === resourceId && levels.indexOf(permLevel) !== -1) {
|
||||||
|
foundMain = true
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
subResourceId &&
|
||||||
|
resource === subResourceId &&
|
||||||
|
levels.indexOf(permLevel) !== -1
|
||||||
|
) {
|
||||||
|
foundSub = true
|
||||||
|
}
|
||||||
|
// this will escape if foundMain only when no sub resource
|
||||||
|
if (foundMain && foundSub) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return foundMain && foundSub
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.doesHaveBasePermission = (permType, permLevel, permissionIds) => {
|
||||||
const builtins = Object.values(exports.BUILTIN_PERMISSIONS)
|
const builtins = Object.values(exports.BUILTIN_PERMISSIONS)
|
||||||
let permissions = flatten(
|
let permissions = flatten(
|
||||||
builtins
|
builtins
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
const CouchDB = require("../../db")
|
const CouchDB = require("../../db")
|
||||||
const { cloneDeep } = require("lodash/fp")
|
const { cloneDeep } = require("lodash/fp")
|
||||||
const { BUILTIN_PERMISSION_IDS } = require("./permissions")
|
const {
|
||||||
|
BUILTIN_PERMISSION_IDS,
|
||||||
|
higherPermission,
|
||||||
|
doesHaveBasePermission,
|
||||||
|
} = require("./permissions")
|
||||||
|
|
||||||
const BUILTIN_IDS = {
|
const BUILTIN_IDS = {
|
||||||
ADMIN: "ADMIN",
|
ADMIN: "ADMIN",
|
||||||
|
@ -127,14 +131,26 @@ exports.getUserRoleHierarchy = async (appId, userRoleId) => {
|
||||||
* Get all of the user permissions which could be found across the role hierarchy
|
* Get all of the user permissions which could be found across the role hierarchy
|
||||||
* @param appId The ID of the application from which roles should be obtained.
|
* @param appId The ID of the application from which roles should be obtained.
|
||||||
* @param userRoleId The user's role ID, this can be found in their access token.
|
* @param userRoleId The user's role ID, this can be found in their access token.
|
||||||
* @returns {Promise<string[]>} A list of permission IDs these should all be unique.
|
* @returns {Promise<{basePermissions: string[], permissions: Object}>} the base
|
||||||
|
* permission IDs as well as any custom resource permissions.
|
||||||
*/
|
*/
|
||||||
exports.getUserPermissionIds = async (appId, userRoleId) => {
|
exports.getUserPermissions = async (appId, userRoleId) => {
|
||||||
return [
|
const rolesHierarchy = await getAllUserRoles(appId, userRoleId)
|
||||||
...new Set(
|
const basePermissions = [
|
||||||
(await getAllUserRoles(appId, userRoleId)).map(role => role.permissionId)
|
...new Set(rolesHierarchy.map(role => role.permissionId)),
|
||||||
),
|
|
||||||
]
|
]
|
||||||
|
const permissions = {}
|
||||||
|
for (let role of rolesHierarchy) {
|
||||||
|
if (role.permissions) {
|
||||||
|
for (let [resource, level] of Object.entries(role.permissions)) {
|
||||||
|
permissions[resource] = higherPermission(permissions[resource], level)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
basePermissions,
|
||||||
|
permissions,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AccessController {
|
class AccessController {
|
||||||
|
|
Loading…
Reference in New Issue