Making use of the resourceId in the middleware package.

This commit is contained in:
mike12345567 2021-02-08 17:52:22 +00:00
parent 9752263e25
commit 7a65a59c78
3 changed files with 71 additions and 12 deletions

View File

@ -1,10 +1,11 @@
const {
BUILTIN_ROLE_IDS,
getUserPermissionIds,
getUserPermissions,
} = require("../utilities/security/roles")
const {
PermissionTypes,
doesHavePermission,
doesHaveResourcePermission,
doesHaveBasePermission,
} = require("../utilities/security/permissions")
const env = require("../environment")
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("|"))
function hasResource(ctx) {
return ctx.resourceId != null
}
module.exports = (permType, permLevel = null) => async (ctx, next) => {
// webhooks can pass locally
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 permissions = await getUserPermissionIds(ctx.appId, role._id)
const { basePermissions, permissions } = await getUserPermissions(
ctx.appId,
role._id
)
if (ADMIN_ROLES.indexOf(role._id) !== -1) {
return next()
}
@ -56,7 +64,14 @@ module.exports = (permType, permLevel = null) => async (ctx, next) => {
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")
}

View File

@ -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)
let permissions = flatten(
builtins

View File

@ -1,6 +1,10 @@
const CouchDB = require("../../db")
const { cloneDeep } = require("lodash/fp")
const { BUILTIN_PERMISSION_IDS } = require("./permissions")
const {
BUILTIN_PERMISSION_IDS,
higherPermission,
doesHaveBasePermission,
} = require("./permissions")
const BUILTIN_IDS = {
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
* @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.
* @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) => {
return [
...new Set(
(await getAllUserRoles(appId, userRoleId)).map(role => role.permissionId)
),
exports.getUserPermissions = async (appId, userRoleId) => {
const rolesHierarchy = await getAllUserRoles(appId, userRoleId)
const basePermissions = [
...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 {