Some more fixes for RBAC as well as fixing the duplication of roles.
This commit is contained in:
parent
2c8696b8f0
commit
fcc683cf99
|
@ -29,6 +29,7 @@
|
||||||
|
|
||||||
<div class="popover">
|
<div class="popover">
|
||||||
<h5>Who Can Access This Data?</h5>
|
<h5>Who Can Access This Data?</h5>
|
||||||
|
<Label extraSmall grey>Specify the minimum access level role for this data.</Label>
|
||||||
<Spacer large />
|
<Spacer large />
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<Label extraSmall grey>Level</Label>
|
<Label extraSmall grey>Level</Label>
|
||||||
|
|
|
@ -1,72 +1,42 @@
|
||||||
const {
|
const {
|
||||||
BUILTIN_PERMISSIONS,
|
BUILTIN_PERMISSIONS,
|
||||||
PermissionLevels,
|
PermissionLevels,
|
||||||
PermissionTypes,
|
|
||||||
higherPermission,
|
|
||||||
getBuiltinPermissionByID,
|
|
||||||
isPermissionLevelHigherThanRead,
|
isPermissionLevelHigherThanRead,
|
||||||
|
higherPermission,
|
||||||
} = 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 } = require("../../db/utils")
|
||||||
const CouchDB = require("../../db")
|
const CouchDB = require("../../db")
|
||||||
const { cloneDeep } = require("lodash/fp")
|
const { cloneDeep } = require("lodash/fp")
|
||||||
|
const {
|
||||||
|
CURRENTLY_SUPPORTED_LEVELS,
|
||||||
|
getBasePermissions,
|
||||||
|
} = require("../../utilities/security/utilities")
|
||||||
|
|
||||||
const PermissionUpdateType = {
|
const PermissionUpdateType = {
|
||||||
REMOVE: "remove",
|
REMOVE: "remove",
|
||||||
ADD: "add",
|
ADD: "add",
|
||||||
}
|
}
|
||||||
|
|
||||||
const SUPPORTED_LEVELS = [PermissionLevels.WRITE, PermissionLevels.READ]
|
const SUPPORTED_LEVELS = CURRENTLY_SUPPORTED_LEVELS
|
||||||
|
|
||||||
function getPermissionType(resourceId) {
|
// quick function to perform a bit of weird logic, make sure fetch calls
|
||||||
const docType = Object.values(DocumentTypes).filter(docType =>
|
// always say a write role also has read permission
|
||||||
resourceId.startsWith(docType)
|
function fetchLevelPerms(permissions, level, roleId) {
|
||||||
)[0]
|
if (!permissions) {
|
||||||
switch (docType) {
|
permissions = {}
|
||||||
case DocumentTypes.TABLE:
|
|
||||||
case DocumentTypes.ROW:
|
|
||||||
return PermissionTypes.TABLE
|
|
||||||
case DocumentTypes.AUTOMATION:
|
|
||||||
return PermissionTypes.AUTOMATION
|
|
||||||
case DocumentTypes.WEBHOOK:
|
|
||||||
return PermissionTypes.WEBHOOK
|
|
||||||
case DocumentTypes.QUERY:
|
|
||||||
case DocumentTypes.DATASOURCE:
|
|
||||||
return PermissionTypes.QUERY
|
|
||||||
default:
|
|
||||||
// views don't have an ID, will end up here
|
|
||||||
return PermissionTypes.VIEW
|
|
||||||
}
|
}
|
||||||
}
|
permissions[level] = roleId
|
||||||
|
|
||||||
function getBasePermissions(resourceId) {
|
|
||||||
const type = getPermissionType(resourceId)
|
|
||||||
const permissions = {}
|
|
||||||
for (let [roleId, role] of Object.entries(BUILTIN_ROLES)) {
|
|
||||||
if (!role.permissionId) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
const perms = getBuiltinPermissionByID(role.permissionId)
|
|
||||||
const typedPermission = perms.permissions.find(perm => perm.type === type)
|
|
||||||
if (
|
if (
|
||||||
typedPermission &&
|
isPermissionLevelHigherThanRead(level) &&
|
||||||
SUPPORTED_LEVELS.indexOf(typedPermission.level) !== -1
|
!permissions[PermissionLevels.READ]
|
||||||
) {
|
) {
|
||||||
const level = typedPermission.level
|
permissions[PermissionLevels.READ] = roleId
|
||||||
permissions[level] = lowerBuiltinRoleID(permissions[level], roleId)
|
|
||||||
if (isPermissionLevelHigherThanRead(level)) {
|
|
||||||
permissions[PermissionLevels.READ] = lowerBuiltinRoleID(
|
|
||||||
permissions[PermissionLevels.READ],
|
|
||||||
roleId
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return permissions
|
return permissions
|
||||||
}
|
}
|
||||||
|
@ -118,7 +88,10 @@ async function updatePermissionOnRole(
|
||||||
}
|
}
|
||||||
// handle the adding, we're on the correct role, at it to this
|
// handle the adding, we're on the correct role, at it to this
|
||||||
if (!remove && role._id === dbRoleId) {
|
if (!remove && role._id === dbRoleId) {
|
||||||
rolePermissions[resourceId] = level
|
rolePermissions[resourceId] = higherPermission(
|
||||||
|
rolePermissions[resourceId],
|
||||||
|
level
|
||||||
|
)
|
||||||
updated = true
|
updated = true
|
||||||
}
|
}
|
||||||
// handle the update, add it to bulk docs to perform at end
|
// handle the update, add it to bulk docs to perform at end
|
||||||
|
@ -156,13 +129,20 @@ exports.fetch = async function(ctx) {
|
||||||
}
|
}
|
||||||
const roleId = getExternalRoleID(role._id)
|
const roleId = getExternalRoleID(role._id)
|
||||||
for (let [resource, level] of Object.entries(role.permissions)) {
|
for (let [resource, level] of Object.entries(role.permissions)) {
|
||||||
if (permissions[resource] == null) {
|
permissions[resource] = fetchLevelPerms(
|
||||||
permissions[resource] = getBasePermissions(resource)
|
permissions[resource],
|
||||||
}
|
level,
|
||||||
permissions[resource][level] = roleId
|
roleId
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctx.body = permissions
|
// apply the base permissions
|
||||||
|
const finalPermissions = {}
|
||||||
|
for (let [resource, permission] of Object.entries(permissions)) {
|
||||||
|
const basePerms = getBasePermissions(resource)
|
||||||
|
finalPermissions[resource] = Object.assign(basePerms, permission)
|
||||||
|
}
|
||||||
|
ctx.body = finalPermissions
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.getResourcePerms = async function(ctx) {
|
exports.getResourcePerms = async function(ctx) {
|
||||||
|
@ -174,16 +154,20 @@ exports.getResourcePerms = async function(ctx) {
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
const roles = body.rows.map(row => row.doc)
|
const roles = body.rows.map(row => row.doc)
|
||||||
const resourcePerms = getBasePermissions(resourceId)
|
let permissions = {}
|
||||||
for (let level of SUPPORTED_LEVELS) {
|
for (let level of SUPPORTED_LEVELS) {
|
||||||
// update the various roleIds in the resource permissions
|
// update the various roleIds in the resource permissions
|
||||||
for (let role of roles) {
|
for (let role of roles) {
|
||||||
if (role.permissions && role.permissions[resourceId] === level) {
|
if (role.permissions && role.permissions[resourceId] === level) {
|
||||||
resourcePerms[level] = getExternalRoleID(role._id)
|
permissions = fetchLevelPerms(
|
||||||
|
permissions,
|
||||||
|
level,
|
||||||
|
getExternalRoleID(role._id)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctx.body = resourcePerms
|
ctx.body = Object.assign(getBasePermissions(resourceId), permissions)
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.addPermission = async function(ctx) {
|
exports.addPermission = async function(ctx) {
|
||||||
|
|
|
@ -57,7 +57,7 @@ exports.fetch = async function(ctx) {
|
||||||
include_docs: true,
|
include_docs: true,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
const roles = body.rows.map(row => row.doc)
|
let roles = body.rows.map(row => row.doc)
|
||||||
|
|
||||||
// need to combine builtin with any DB record of them (for sake of permissions)
|
// need to combine builtin with any DB record of them (for sake of permissions)
|
||||||
for (let builtinRoleId of EXTERNAL_BUILTIN_ROLE_IDS) {
|
for (let builtinRoleId of EXTERNAL_BUILTIN_ROLE_IDS) {
|
||||||
|
@ -68,6 +68,8 @@ exports.fetch = async function(ctx) {
|
||||||
if (dbBuiltin == null) {
|
if (dbBuiltin == null) {
|
||||||
roles.push(builtinRole)
|
roles.push(builtinRole)
|
||||||
} else {
|
} else {
|
||||||
|
// remove role and all back after combining with the builtin
|
||||||
|
roles = roles.filter(role => role._id !== dbBuiltin._id)
|
||||||
dbBuiltin._id = getExternalRoleID(dbBuiltin._id)
|
dbBuiltin._id = getExternalRoleID(dbBuiltin._id)
|
||||||
roles.push(Object.assign(builtinRole, dbBuiltin))
|
roles.push(Object.assign(builtinRole, dbBuiltin))
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
const {
|
||||||
|
PermissionLevels,
|
||||||
|
PermissionTypes,
|
||||||
|
getBuiltinPermissionByID,
|
||||||
|
isPermissionLevelHigherThanRead,
|
||||||
|
} = require("../../utilities/security/permissions")
|
||||||
|
const {
|
||||||
|
lowerBuiltinRoleID,
|
||||||
|
BUILTIN_ROLES,
|
||||||
|
} = require("../../utilities/security/roles")
|
||||||
|
const { DocumentTypes } = require("../../db/utils")
|
||||||
|
|
||||||
|
const CURRENTLY_SUPPORTED_LEVELS = [
|
||||||
|
PermissionLevels.WRITE,
|
||||||
|
PermissionLevels.READ,
|
||||||
|
]
|
||||||
|
|
||||||
|
exports.getPermissionType = resourceId => {
|
||||||
|
const docType = Object.values(DocumentTypes).filter(docType =>
|
||||||
|
resourceId.startsWith(docType)
|
||||||
|
)[0]
|
||||||
|
switch (docType) {
|
||||||
|
case DocumentTypes.TABLE:
|
||||||
|
case DocumentTypes.ROW:
|
||||||
|
return PermissionTypes.TABLE
|
||||||
|
case DocumentTypes.AUTOMATION:
|
||||||
|
return PermissionTypes.AUTOMATION
|
||||||
|
case DocumentTypes.WEBHOOK:
|
||||||
|
return PermissionTypes.WEBHOOK
|
||||||
|
case DocumentTypes.QUERY:
|
||||||
|
case DocumentTypes.DATASOURCE:
|
||||||
|
return PermissionTypes.QUERY
|
||||||
|
default:
|
||||||
|
// views don't have an ID, will end up here
|
||||||
|
return PermissionTypes.VIEW
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* works out the basic permissions based on builtin roles for a resource, using its ID
|
||||||
|
* @param resourceId
|
||||||
|
* @returns {{}}
|
||||||
|
*/
|
||||||
|
exports.getBasePermissions = resourceId => {
|
||||||
|
const type = exports.getPermissionType(resourceId)
|
||||||
|
const permissions = {}
|
||||||
|
for (let [roleId, role] of Object.entries(BUILTIN_ROLES)) {
|
||||||
|
if (!role.permissionId) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
const perms = getBuiltinPermissionByID(role.permissionId)
|
||||||
|
const typedPermission = perms.permissions.find(perm => perm.type === type)
|
||||||
|
if (
|
||||||
|
typedPermission &&
|
||||||
|
CURRENTLY_SUPPORTED_LEVELS.indexOf(typedPermission.level) !== -1
|
||||||
|
) {
|
||||||
|
const level = typedPermission.level
|
||||||
|
permissions[level] = lowerBuiltinRoleID(permissions[level], roleId)
|
||||||
|
if (isPermissionLevelHigherThanRead(level)) {
|
||||||
|
permissions[PermissionLevels.READ] = lowerBuiltinRoleID(
|
||||||
|
permissions[PermissionLevels.READ],
|
||||||
|
roleId
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return permissions
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.CURRENTLY_SUPPORTED_LEVELS = CURRENTLY_SUPPORTED_LEVELS
|
Loading…
Reference in New Issue