Some updates to RBAC backend, try to make switch to object support level -> roleID.

This commit is contained in:
mike12345567 2021-02-11 13:29:15 +00:00
parent a3ae17be8e
commit 091b4ee95d
3 changed files with 72 additions and 34 deletions

View File

@ -4,11 +4,13 @@ const {
PermissionTypes, PermissionTypes,
higherPermission, higherPermission,
getBuiltinPermissionByID, getBuiltinPermissionByID,
isPermissionLevelHigherThanRead,
} = require("../../utilities/security/permissions") } = require("../../utilities/security/permissions")
const { const {
isBuiltin, isBuiltin,
getDBRoleID, getDBRoleID,
getExternalRoleID, getExternalRoleID,
lowerBuiltinRoleID,
BUILTIN_ROLES, BUILTIN_ROLES,
} = require("../../utilities/security/roles") } = require("../../utilities/security/roles")
const { getRoleParams, DocumentTypes } = require("../../db/utils") const { getRoleParams, DocumentTypes } = require("../../db/utils")
@ -20,33 +22,31 @@ const PermissionUpdateType = {
ADD: "add", ADD: "add",
} }
function getBasePermissions(resourceId) { const SUPPORTED_LEVELS = [PermissionLevels.WRITE, PermissionLevels.READ]
function getPermissionType(resourceId) {
const docType = DocumentTypes.filter(docType => const docType = DocumentTypes.filter(docType =>
resourceId.startsWith(docType) resourceId.startsWith(docType)
)[0] )[0]
const levelsToFind = [PermissionLevels.WRITE, PermissionLevels.READ]
let type
switch (docType) { switch (docType) {
case DocumentTypes.TABLE: case DocumentTypes.TABLE:
case DocumentTypes.ROW: case DocumentTypes.ROW:
type = PermissionTypes.TABLE return PermissionTypes.TABLE
break
case DocumentTypes.AUTOMATION: case DocumentTypes.AUTOMATION:
type = PermissionTypes.AUTOMATION return PermissionTypes.AUTOMATION
break
case DocumentTypes.WEBHOOK: case DocumentTypes.WEBHOOK:
type = PermissionTypes.WEBHOOK return PermissionTypes.WEBHOOK
break
case DocumentTypes.QUERY: case DocumentTypes.QUERY:
case DocumentTypes.DATASOURCE: case DocumentTypes.DATASOURCE:
type = PermissionTypes.QUERY return PermissionTypes.QUERY
break
default: default:
// views don't have an ID, will end up here // views don't have an ID, will end up here
type = PermissionTypes.VIEW return PermissionTypes.VIEW
break
} }
}
async function getBasePermissions(resourceId) {
const type = getPermissionType(resourceId)
const permissions = {} const permissions = {}
for (let [roleId, role] of Object.entries(BUILTIN_ROLES)) { for (let [roleId, role] of Object.entries(BUILTIN_ROLES)) {
if (!role.permissionId) { if (!role.permissionId) {
@ -55,10 +55,17 @@ function getBasePermissions(resourceId) {
const perms = getBuiltinPermissionByID(role.permissionId) const perms = getBuiltinPermissionByID(role.permissionId)
const typedPermission = perms.permissions.find(perm => perm.type === type) const typedPermission = perms.permissions.find(perm => perm.type === type)
if (typedPermission) { if (typedPermission) {
// TODO: need to get the lowest role const level = typedPermission.level
// TODO: store the read/write with the lowest role permissions[level] = lowerBuiltinRoleID(permissions[level], roleId)
if (isPermissionLevelHigherThanRead(level)) {
permissions[PermissionLevels.READ] = lowerBuiltinRoleID(
permissions[PermissionLevels.READ],
roleId
)
}
} }
} }
return permissions
} }
// utility function to stop this repetition - permissions always stored under roles // utility function to stop this repetition - permissions always stored under roles
@ -132,7 +139,7 @@ exports.fetchBuiltin = function(ctx) {
exports.fetchLevels = function(ctx) { exports.fetchLevels = function(ctx) {
// for now only provide the read/write perms externally // for now only provide the read/write perms externally
ctx.body = [PermissionLevels.WRITE, PermissionLevels.READ] ctx.body = SUPPORTED_LEVELS
} }
exports.fetch = async function(ctx) { exports.fetch = async function(ctx) {
@ -167,11 +174,12 @@ exports.getResourcePerms = async function(ctx) {
) )
const roles = body.rows.map(row => row.doc) const roles = body.rows.map(row => row.doc)
const resourcePerms = {} const resourcePerms = {}
for (let role of roles) { for (let level of SUPPORTED_LEVELS) {
for (let role of roles)
// update the various roleIds in the resource permissions // update the various roleIds in the resource permissions
if (role.permissions && role.permissions[resourceId]) { if (role.permissions && role.permissions[resourceId]) {
const roleId = getExternalRoleID(role._id) const roleId = getExternalRoleID(role._id)
resourcePerms[roleId] = higherPermission( resourcePerms[level] = higherPermission(
resourcePerms[roleId], resourcePerms[roleId],
role.permissions[resourceId] role.permissions[resourceId]
) )

View File

@ -23,6 +23,22 @@ function Permission(type, level) {
this.type = type this.type = type
} }
function levelToNumber(perm) {
switch (perm) {
// not everything has execute privileges
case PermissionLevels.EXECUTE:
return 0
case PermissionLevels.READ:
return 1
case PermissionLevels.WRITE:
return 2
case PermissionLevels.ADMIN:
return 3
default:
return -1
}
}
/** /**
* Given the specified permission level for the user return the levels they are allowed to carry out. * Given the specified permission level for the user return the levels they are allowed to carry out.
* @param {string} userPermLevel The permission level of the user. * @param {string} userPermLevel The permission level of the user.
@ -149,22 +165,11 @@ exports.doesHaveBasePermission = (permType, permLevel, permissionIds) => {
} }
exports.higherPermission = (perm1, perm2) => { exports.higherPermission = (perm1, perm2) => {
function toNum(perm) { return levelToNumber(perm1) > levelToNumber(perm2) ? perm1 : perm2
switch (perm) { }
// not everything has execute privileges
case PermissionLevels.EXECUTE: exports.isPermissionLevelHigherThanRead = level => {
return 0 return levelToNumber(level) > 1
case PermissionLevels.READ:
return 1
case PermissionLevels.WRITE:
return 2
case PermissionLevels.ADMIN:
return 3
default:
return -1
}
}
return toNum(perm1) > toNum(perm2) ? perm1 : perm2
} }
// utility as a lot of things need simply the builder permission // utility as a lot of things need simply the builder permission

View File

@ -222,6 +222,31 @@ exports.getExternalRoleID = roleId => {
return roleId return roleId
} }
/**
* Returns whichever roleID is lower.
*/
exports.lowerRoleID = async (appId, roleId1, roleId2) => {
// TODO: need to make this function work
const MAX = Object.values(BUILTIN_IDS).length + 1
async function toNum(id) {
if (id === BUILTIN_IDS.ADMIN || id === BUILTIN_IDS.BUILDER) {
return MAX
}
let role = await exports.getRole(appId, id),
count = 0
do {
if (!role) {
break
}
role = exports.BUILTIN_ROLES[role.inherits]
count++
} while (role !== null)
return count
}
const [num1, num2] = Promise.all([toNum(roleId1), toNum(roleId2)])
return num1 > num2 ? roleId2 : roleId1
}
exports.AccessController = AccessController exports.AccessController = AccessController
exports.BUILTIN_ROLE_IDS = BUILTIN_IDS exports.BUILTIN_ROLE_IDS = BUILTIN_IDS
exports.isBuiltin = isBuiltin exports.isBuiltin = isBuiltin