fixing rbac

This commit is contained in:
mike12345567 2024-10-16 17:26:48 +01:00
parent edf6d95eec
commit 02d4c2d607
4 changed files with 54 additions and 17 deletions

View File

@ -63,6 +63,12 @@ export class Role implements RoleDoc {
} }
addInheritance(inherits?: string | string[]) { addInheritance(inherits?: string | string[]) {
// make sure IDs are correct format
if (inherits && typeof inherits === "string") {
inherits = prefixRoleIDNoBuiltin(inherits)
} else if (inherits && Array.isArray(inherits)) {
inherits = inherits.map(inherit => prefixRoleIDNoBuiltin(inherit))
}
if (inherits) { if (inherits) {
this.inherits = inherits this.inherits = inherits
} }
@ -128,7 +134,15 @@ export function getBuiltinRoles(): { [key: string]: RoleDoc } {
} }
export function isBuiltin(role: string) { export function isBuiltin(role: string) {
return getBuiltinRole(role) !== undefined return Object.values(BUILTIN_ROLE_IDS).includes(role)
}
export function prefixRoleIDNoBuiltin(roleId: string) {
if (isBuiltin(roleId)) {
return roleId
} else {
return prefixRoleID(roleId)
}
} }
export function getBuiltinRole(roleId: string): Role | undefined { export function getBuiltinRole(roleId: string): Role | undefined {
@ -536,3 +550,16 @@ export function getExternalRoleID(roleId: string, version?: string) {
} }
return roleId return roleId
} }
export function getExternalRoleIDs(
roleIds: string | string[] | undefined,
version?: string
) {
if (!roleIds) {
return roleIds
} else if (typeof roleIds === "string") {
return getExternalRoleID(roleIds, version)
} else {
return roleIds.map(roleId => getExternalRoleID(roleId, version))
}
}

View File

@ -28,6 +28,18 @@ const UpdateRolesOptions = {
REMOVED: "removed", REMOVED: "removed",
} }
function externalRole(role: Role): Role {
let _id: string | undefined
if (role._id) {
_id = roles.getExternalRoleID(role._id)
}
return {
...role,
_id,
inherits: roles.getExternalRoleIDs(role.inherits, role.version),
}
}
async function updateRolesOnUserTable( async function updateRolesOnUserTable(
db: Database, db: Database,
roleId: string, roleId: string,
@ -54,7 +66,7 @@ async function updateRolesOnUserTable(
} }
export async function fetch(ctx: UserCtx<void, FetchRolesResponse>) { export async function fetch(ctx: UserCtx<void, FetchRolesResponse>) {
ctx.body = await roles.getAllRoles() ctx.body = (await roles.getAllRoles()).map(role => externalRole(role))
} }
export async function find(ctx: UserCtx<void, FindRoleResponse>) { export async function find(ctx: UserCtx<void, FindRoleResponse>) {
@ -62,7 +74,7 @@ export async function find(ctx: UserCtx<void, FindRoleResponse>) {
if (!role) { if (!role) {
ctx.throw(404, { message: "Role not found" }) ctx.throw(404, { message: "Role not found" })
} else { } else {
ctx.body = role ctx.body = externalRole(role)
} }
} }
@ -136,10 +148,7 @@ export async function save(ctx: UserCtx<SaveRoleRequest, SaveRoleResponse>) {
role.version role.version
) )
role._rev = result.rev role._rev = result.rev
ctx.body = { ctx.body = externalRole(role)
...role,
_id: roles.getExternalRoleID(role._id!, role.version),
}
const devDb = context.getDevAppDB() const devDb = context.getDevAppDB()
const prodDb = context.getProdAppDB() const prodDb = context.getProdAppDB()
@ -199,15 +208,14 @@ export async function accessible(ctx: UserCtx<void, AccessibleRolesResponse>) {
if (!roleId) { if (!roleId) {
roleId = roles.BUILTIN_ROLE_IDS.PUBLIC roleId = roles.BUILTIN_ROLE_IDS.PUBLIC
} }
let roleIds: string[] = []
if (ctx.user && sharedSdk.users.isAdminOrBuilder(ctx.user)) { if (ctx.user && sharedSdk.users.isAdminOrBuilder(ctx.user)) {
const appId = context.getAppId() const appId = context.getAppId()
if (!appId) { if (appId) {
ctx.body = [] roleIds = await roles.getAllRoleIds(appId)
} else {
ctx.body = await roles.getAllRoleIds(appId)
} }
} else { } else {
ctx.body = await roles.getUserRoleIdHierarchy(roleId!) roleIds = await roles.getUserRoleIdHierarchy(roleId!)
} }
// If a custom role is provided in the header, filter out higher level roles // If a custom role is provided in the header, filter out higher level roles
@ -215,7 +223,7 @@ export async function accessible(ctx: UserCtx<void, AccessibleRolesResponse>) {
if (roleHeader && !Object.keys(roles.BUILTIN_ROLE_IDS).includes(roleHeader)) { if (roleHeader && !Object.keys(roles.BUILTIN_ROLE_IDS).includes(roleHeader)) {
const role = await roles.getRole(roleHeader) const role = await roles.getRole(roleHeader)
const inherits = role?.inherits const inherits = role?.inherits
const orderedRoles = ctx.body.reverse() const orderedRoles = roleIds.reverse()
let filteredRoles = [roleHeader] let filteredRoles = [roleHeader]
for (let role of orderedRoles) { for (let role of orderedRoles) {
filteredRoles = [role, ...filteredRoles] filteredRoles = [role, ...filteredRoles]
@ -227,6 +235,8 @@ export async function accessible(ctx: UserCtx<void, AccessibleRolesResponse>) {
} }
} }
filteredRoles.pop() filteredRoles.pop()
ctx.body = [roleHeader, ...filteredRoles] roleIds = [roleHeader, ...filteredRoles]
} }
ctx.body = roleIds.map(roleId => roles.getExternalRoleID(roleId))
} }

View File

@ -105,7 +105,7 @@ describe("/roles", () => {
inherits: [BUILTIN_ROLE_IDS.POWER, role1._id!, role2._id!], inherits: [BUILTIN_ROLE_IDS.POWER, role1._id!, role2._id!],
}) })
// go back to role1 // go back to role1
role1 = await config.api.roles.save( await config.api.roles.save(
{ {
...role1, ...role1,
inherits: [BUILTIN_ROLE_IDS.POWER, role2._id!, role3._id!], inherits: [BUILTIN_ROLE_IDS.POWER, role2._id!, role3._id!],
@ -113,7 +113,7 @@ describe("/roles", () => {
{ status: 400, body: { message: LOOP_ERROR } } { status: 400, body: { message: LOOP_ERROR } }
) )
// go back to role2 // go back to role2
role2 = await config.api.roles.save( await config.api.roles.save(
{ {
...role2, ...role2,
inherits: [BUILTIN_ROLE_IDS.POWER, role1._id!, role3._id!], inherits: [BUILTIN_ROLE_IDS.POWER, role1._id!, role3._id!],

View File

@ -1,4 +1,4 @@
import { Role } from "@budibase/types" import { Role, SEPARATOR, DocumentType } from "@budibase/types"
// Function to detect loops in roles // Function to detect loops in roles
export function checkForRoleInheritanceLoops(roles: Role[]): boolean { export function checkForRoleInheritanceLoops(roles: Role[]): boolean {