Changing the role system to have permissions integrated rather than the permissions being per user.

This commit is contained in:
mike12345567 2020-12-02 17:08:25 +00:00
parent fa8d8fcfea
commit 65302e1dd9
14 changed files with 182 additions and 141 deletions

View File

@ -34,7 +34,6 @@ exports.authenticate = async ctx => {
userId: dbUser._id, userId: dbUser._id,
roleId: dbUser.roleId, roleId: dbUser.roleId,
version: app.version, version: app.version,
permissions: dbUser.permissions || [],
} }
// if in cloud add the user api key // if in cloud add the user api key
if (env.CLOUD) { if (env.CLOUD) {

View File

@ -0,0 +1,6 @@
const { BUILTIN_PERMISSIONS } = require("../../utilities/security/permissions")
exports.fetch = async function(ctx) {
// TODO: need to build out custom permissions
ctx.body = Object.values(BUILTIN_PERMISSIONS)
}

View File

@ -25,9 +25,13 @@ exports.find = async function(ctx) {
exports.save = async function(ctx) { exports.save = async function(ctx) {
const db = new CouchDB(ctx.user.appId) const db = new CouchDB(ctx.user.appId)
let { _id, name, inherits, permissionId } = ctx.request.body
let id = ctx.request.body._id || generateRoleID() if (!_id) {
const role = new Role(id, ctx.request.body.name, ctx.request.body.inherits) _id = generateRoleID()
}
const role = new Role(_id, name)
.addPermission(permissionId)
.addInheritance(inherits)
if (ctx.request.body._rev) { if (ctx.request.body._rev) {
role._rev = ctx.request.body._rev role._rev = ctx.request.body._rev
} }

View File

@ -1,10 +1,7 @@
const CouchDB = require("../../db") const CouchDB = require("../../db")
const bcrypt = require("../../utilities/bcrypt") const bcrypt = require("../../utilities/bcrypt")
const { generateUserID, getUserParams, ViewNames } = require("../../db/utils") const { generateUserID, getUserParams, ViewNames } = require("../../db/utils")
const { BUILTIN_ROLE_ID_ARRAY } = require("../../utilities/security/roles") const { getRole } = require("../../utilities/security/roles")
const {
BUILTIN_PERMISSION_NAMES,
} = require("../../utilities/security/permissions")
exports.fetch = async function(ctx) { exports.fetch = async function(ctx) {
const database = new CouchDB(ctx.user.appId) const database = new CouchDB(ctx.user.appId)
@ -18,13 +15,13 @@ exports.fetch = async function(ctx) {
exports.create = async function(ctx) { exports.create = async function(ctx) {
const db = new CouchDB(ctx.user.appId) const db = new CouchDB(ctx.user.appId)
const { username, password, name, roleId, permissions } = ctx.request.body const { username, password, name, roleId } = ctx.request.body
if (!username || !password) { if (!username || !password) {
ctx.throw(400, "Username and Password Required.") ctx.throw(400, "Username and Password Required.")
} }
const role = await checkRole(db, roleId) const role = await getRole(ctx.user.appId, roleId)
if (!role) ctx.throw(400, "Invalid Role") if (!role) ctx.throw(400, "Invalid Role")
@ -35,7 +32,6 @@ exports.create = async function(ctx) {
name: name || username, name: name || username,
type: "user", type: "user",
roleId, roleId,
permissions: permissions || [BUILTIN_PERMISSION_NAMES.POWER],
tableId: ViewNames.USERS, tableId: ViewNames.USERS,
} }
@ -88,15 +84,3 @@ exports.find = async function(ctx) {
_rev: user._rev, _rev: user._rev,
} }
} }
const checkRole = async (db, roleId) => {
if (!roleId) return
if (BUILTIN_ROLE_ID_ARRAY.indexOf(roleId) !== -1) {
return {
_id: roleId,
name: roleId,
permissions: [],
}
}
return await db.get(roleId)
}

View File

@ -16,6 +16,7 @@ const apiKeysRoutes = require("./apikeys")
const templatesRoutes = require("./templates") const templatesRoutes = require("./templates")
const analyticsRoutes = require("./analytics") const analyticsRoutes = require("./analytics")
const routingRoutes = require("./routing") const routingRoutes = require("./routing")
const permissionRoutes = require("./permission")
exports.mainRoutes = [ exports.mainRoutes = [
deployRoutes, deployRoutes,
@ -32,6 +33,7 @@ exports.mainRoutes = [
analyticsRoutes, analyticsRoutes,
webhookRoutes, webhookRoutes,
routingRoutes, routingRoutes,
permissionRoutes,
// these need to be handled last as they still use /api/:tableId // these need to be handled last as they still use /api/:tableId
// this could be breaking as koa may recognise other routes as this // this could be breaking as koa may recognise other routes as this
tableRoutes, tableRoutes,

View File

@ -0,0 +1,10 @@
const Router = require("@koa/router")
const controller = require("../controllers/permission")
const authorized = require("../../middleware/authorized")
const { BUILDER } = require("../../utilities/security/permissions")
const router = Router()
router.get("/api/permissions", authorized(BUILDER), controller.fetch)
module.exports = router

View File

@ -2,11 +2,27 @@ const Router = require("@koa/router")
const controller = require("../controllers/role") const controller = require("../controllers/role")
const authorized = require("../../middleware/authorized") const authorized = require("../../middleware/authorized")
const { BUILDER } = require("../../utilities/security/permissions") const { BUILDER } = require("../../utilities/security/permissions")
const Joi = require("joi")
const joiValidator = require("../../middleware/joi-validator")
const {
BUILTIN_PERMISSION_IDS,
} = require("../../utilities/security/permissions")
const router = Router() const router = Router()
function generateValidator() {
// prettier-ignore
return joiValidator.body(Joi.object({
_id: Joi.string().optional(),
_rev: Joi.string().optional(),
name: Joi.string().required(),
permissionId: Joi.string().valid(...Object.values(BUILTIN_PERMISSION_IDS)).required(),
inherits: Joi.string().optional(),
}).unknown(true))
}
router router
.post("/api/roles", authorized(BUILDER), controller.save) .post("/api/roles", authorized(BUILDER), generateValidator(), controller.save)
.get("/api/roles", authorized(BUILDER), controller.fetch) .get("/api/roles", authorized(BUILDER), controller.fetch)
.get("/api/roles/:roleId", authorized(BUILDER), controller.find) .get("/api/roles/:roleId", authorized(BUILDER), controller.find)
.delete("/api/roles/:roleId/:rev", authorized(BUILDER), controller.destroy) .delete("/api/roles/:roleId/:rev", authorized(BUILDER), controller.destroy)

View File

@ -1,9 +1,6 @@
const CouchDB = require("../../../db") const CouchDB = require("../../../db")
const supertest = require("supertest") const supertest = require("supertest")
const { BUILTIN_ROLE_IDS } = require("../../../utilities/security/roles") const { BUILTIN_ROLE_IDS } = require("../../../utilities/security/roles")
const {
BUILTIN_PERMISSION_NAMES,
} = require("../../../utilities/security/permissions")
const packageJson = require("../../../../package") const packageJson = require("../../../../package")
const jwt = require("jsonwebtoken") const jwt = require("jsonwebtoken")
const env = require("../../../environment") const env = require("../../../environment")
@ -131,49 +128,7 @@ exports.createUser = async (
return res.body return res.body
} }
const createUserWithOnePermission = async (request, appId, permName) => { const createUserWithRole = async (request, appId, roleId, username) => {
let permissions = [permName]
return await createUserWithPermissions(
request,
appId,
permissions,
"onePermOnlyUser"
)
}
const createUserWithAdminPermissions = async (request, appId) => {
let permissions = [BUILTIN_PERMISSION_NAMES.ADMIN]
return await createUserWithPermissions(
request,
appId,
permissions,
"adminUser"
)
}
const createUserWithAllPermissionExceptOne = async (
request,
appId,
permName
) => {
let permissions = [permName]
return await createUserWithPermissions(
request,
appId,
permissions,
"allPermsExceptOneUser"
)
}
const createUserWithPermissions = async (
request,
appId,
permissions,
username
) => {
const password = `password_${username}` const password = `password_${username}`
await request await request
.post(`/api/users`) .post(`/api/users`)
@ -182,8 +137,7 @@ const createUserWithPermissions = async (
name: username, name: username,
username, username,
password, password,
roleId: BUILTIN_ROLE_IDS.POWER, roleId,
permissions,
}) })
const anonUser = { const anonUser = {
@ -216,23 +170,29 @@ exports.testPermissionsForEndpoint = async ({
url, url,
body, body,
appId, appId,
permName1, passRole,
permName2, failRole,
}) => { }) => {
const headers = await createUserWithOnePermission(request, appId, permName1) const passHeader = await createUserWithRole(
await createRequest(request, method, url, body)
.set(headers)
.expect(200)
const noPermsHeaders = await createUserWithAllPermissionExceptOne(
request, request,
appId, appId,
permName2 passRole,
"passUser"
) )
await createRequest(request, method, url, body) await createRequest(request, method, url, body)
.set(noPermsHeaders) .set(passHeader)
.expect(200)
const failHeader = await createUserWithRole(
request,
appId,
failRole,
"failUser"
)
await createRequest(request, method, url, body)
.set(failHeader)
.expect(403) .expect(403)
} }
@ -243,7 +203,12 @@ exports.builderEndpointShouldBlockNormalUsers = async ({
body, body,
appId, appId,
}) => { }) => {
const headers = await createUserWithAdminPermissions(request, appId) const headers = await createUserWithRole(
request,
appId,
BUILTIN_ROLE_IDS.BASIC,
"basicUser"
)
await createRequest(request, method, url, body) await createRequest(request, method, url, body)
.set(headers) .set(headers)

View File

@ -8,8 +8,9 @@ const {
const { const {
BUILTIN_ROLE_IDS, BUILTIN_ROLE_IDS,
} = require("../../../utilities/security/roles") } = require("../../../utilities/security/roles")
const { BUILTIN_PERMISSION_IDS } = require("../../../utilities/security/permissions")
const roleBody = { name: "user", inherits: BUILTIN_ROLE_IDS.BASIC } const roleBody = { name: "NewRole", inherits: BUILTIN_ROLE_IDS.BASIC, permissionId: BUILTIN_PERMISSION_IDS.READ_ONLY }
describe("/roles", () => { describe("/roles", () => {
let server let server
@ -43,7 +44,7 @@ describe("/roles", () => {
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect(200) .expect(200)
expect(res.res.statusMessage).toEqual("Role 'user' created successfully.") expect(res.res.statusMessage).toEqual("Role 'NewRole' created successfully.")
expect(res.body._id).toBeDefined() expect(res.body._id).toBeDefined()
expect(res.body._rev).toBeDefined() expect(res.body._rev).toBeDefined()
}) })
@ -71,16 +72,19 @@ describe("/roles", () => {
expect(res.body.length).toBe(3) expect(res.body.length).toBe(3)
const adminRole = res.body.find(r => r._id === BUILTIN_ROLE_IDS.ADMIN) const adminRole = res.body.find(r => r._id === BUILTIN_ROLE_IDS.ADMIN)
expect(adminRole.inherits).toEqual(BUILTIN_ROLE_IDS.POWER)
expect(adminRole).toBeDefined() expect(adminRole).toBeDefined()
expect(adminRole.inherits).toEqual(BUILTIN_ROLE_IDS.POWER)
expect(adminRole.permissionId).toEqual(BUILTIN_PERMISSION_IDS.ADMIN)
const powerUserRole = res.body.find(r => r._id === BUILTIN_ROLE_IDS.POWER) const powerUserRole = res.body.find(r => r._id === BUILTIN_ROLE_IDS.POWER)
expect(powerUserRole.inherits).toEqual(BUILTIN_ROLE_IDS.BASIC)
expect(powerUserRole).toBeDefined() expect(powerUserRole).toBeDefined()
expect(powerUserRole.inherits).toEqual(BUILTIN_ROLE_IDS.BASIC)
expect(powerUserRole.permissionId).toEqual(BUILTIN_PERMISSION_IDS.POWER)
const customRoleFetched = res.body.find(r => r._id === customRole._id) const customRoleFetched = res.body.find(r => r._id === customRole._id)
expect(customRoleFetched.inherits).toEqual(BUILTIN_ROLE_IDS.BASIC)
expect(customRoleFetched).toBeDefined() expect(customRoleFetched).toBeDefined()
expect(customRoleFetched.inherits).toEqual(BUILTIN_ROLE_IDS.BASIC)
expect(customRoleFetched.permissionId).toEqual(BUILTIN_PERMISSION_IDS.READ_ONLY)
}) })
}); });
@ -89,7 +93,7 @@ describe("/roles", () => {
it("should delete custom roles", async () => { it("should delete custom roles", async () => {
const createRes = await request const createRes = await request
.post(`/api/roles`) .post(`/api/roles`)
.send({ name: "user" }) .send({ name: "user", permissionId: BUILTIN_PERMISSION_IDS.READ_ONLY })
.set(defaultHeaders(appId)) .set(defaultHeaders(appId))
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
.expect(200) .expect(200)

View File

@ -5,12 +5,16 @@ const {
createUser, createUser,
testPermissionsForEndpoint, testPermissionsForEndpoint,
} = require("./couchTestUtils") } = require("./couchTestUtils")
const {
BUILTIN_PERMISSION_NAMES,
} = require("../../../utilities/security/permissions")
const { const {
BUILTIN_ROLE_IDS, BUILTIN_ROLE_IDS,
} = require("../../../utilities/security/roles") } = require("../../../utilities/security/roles")
const { cloneDeep } = require("lodash/fp")
const baseBody = {
name: "brandNewUser",
password: "yeeooo",
roleId: BUILTIN_ROLE_IDS.POWER
}
describe("/users", () => { describe("/users", () => {
let request let request
@ -20,12 +24,12 @@ describe("/users", () => {
beforeAll(async () => { beforeAll(async () => {
({ request, server } = await supertest(server)) ({ request, server } = await supertest(server))
}); })
beforeEach(async () => { beforeEach(async () => {
app = await createApplication(request) app = await createApplication(request)
appId = app.instance._id appId = app.instance._id
}); })
afterAll(() => { afterAll(() => {
server.close() server.close()
@ -54,38 +58,40 @@ describe("/users", () => {
method: "GET", method: "GET",
url: `/api/users`, url: `/api/users`,
appId: appId, appId: appId,
permName1: BUILTIN_PERMISSION_NAMES.POWER, passRole: BUILTIN_ROLE_IDS.ADMIN,
permName2: BUILTIN_PERMISSION_NAMES.WRITE, failRole: BUILTIN_ROLE_IDS.PUBLIC,
}) })
}) })
}) })
describe("create", () => { describe("create", () => {
it("returns a success message when a user is successfully created", async () => { it("returns a success message when a user is successfully created", async () => {
const body = cloneDeep(baseBody)
body.username = "bill"
const res = await request const res = await request
.post(`/api/users`) .post(`/api/users`)
.set(defaultHeaders(appId)) .set(defaultHeaders(appId))
.send({ name: "Bill", username: "bill", password: "bills_password", roleId: BUILTIN_ROLE_IDS.POWER }) .send(body)
.expect(200) .expect(200)
.expect('Content-Type', /json/) .expect('Content-Type', /json/)
expect(res.res.statusMessage).toEqual("User created successfully."); expect(res.res.statusMessage).toEqual("User created successfully.")
expect(res.body._id).toBeUndefined() expect(res.body._id).toBeUndefined()
}) })
it("should apply authorization to endpoint", async () => { it("should apply authorization to endpoint", async () => {
const body = cloneDeep(baseBody)
body.username = "brandNewUser"
await testPermissionsForEndpoint({ await testPermissionsForEndpoint({
request, request,
method: "POST", method: "POST",
body: { name: "brandNewUser", username: "brandNewUser", password: "yeeooo", roleId: BUILTIN_ROLE_IDS.POWER }, body,
url: `/api/users`, url: `/api/users`,
appId: appId, appId: appId,
permName1: BUILTIN_PERMISSION_NAMES.ADMIN, passRole: BUILTIN_ROLE_IDS.ADMIN,
permName2: BUILTIN_PERMISSION_NAMES.POWER, failRole: BUILTIN_ROLE_IDS.PUBLIC,
}) })
}) })
})
});
}) })

View File

@ -1,4 +1,7 @@
const { BUILTIN_ROLE_IDS } = require("../utilities/security/roles") const {
BUILTIN_ROLE_IDS,
getUserPermissionIds,
} = require("../utilities/security/roles")
const { const {
PermissionTypes, PermissionTypes,
doesHavePermission, doesHavePermission,
@ -48,7 +51,7 @@ module.exports = (permType, permLevel = null) => async (ctx, next) => {
} }
const role = ctx.user.role const role = ctx.user.role
const permissions = ctx.user.permissions const permissions = await getUserPermissionIds(ctx.appId, role._id)
if (ADMIN_ROLES.indexOf(role._id) !== -1) { if (ADMIN_ROLES.indexOf(role._id) !== -1) {
return next() return next()
} }

View File

@ -1,5 +1,4 @@
const { BUILTIN_ROLE_IDS } = require("../security/roles") const { BUILTIN_ROLE_IDS } = require("../security/roles")
const { BUILTIN_PERMISSION_NAMES } = require("../security/permissions")
const env = require("../../environment") const env = require("../../environment")
const CouchDB = require("../../db") const CouchDB = require("../../db")
const jwt = require("jsonwebtoken") const jwt = require("jsonwebtoken")
@ -11,7 +10,6 @@ module.exports = async (ctx, appId, version) => {
const builderUser = { const builderUser = {
userId: "BUILDER", userId: "BUILDER",
roleId: BUILTIN_ROLE_IDS.BUILDER, roleId: BUILTIN_ROLE_IDS.BUILDER,
permissions: [BUILTIN_PERMISSION_NAMES.ADMIN],
version, version,
} }
if (env.BUDIBASE_API_KEY) { if (env.BUDIBASE_API_KEY) {

View File

@ -45,7 +45,7 @@ function getAllowedLevels(userPermLevel) {
} }
} }
exports.BUILTIN_PERMISSION_NAMES = { exports.BUILTIN_PERMISSION_IDS = {
READ_ONLY: "read_only", READ_ONLY: "read_only",
WRITE: "write", WRITE: "write",
ADMIN: "admin", ADMIN: "admin",
@ -54,21 +54,24 @@ exports.BUILTIN_PERMISSION_NAMES = {
exports.BUILTIN_PERMISSIONS = { exports.BUILTIN_PERMISSIONS = {
READ_ONLY: { READ_ONLY: {
name: exports.BUILTIN_PERMISSION_NAMES.READ_ONLY, _id: exports.BUILTIN_PERMISSION_IDS.READ_ONLY,
name: "Read only",
permissions: [ permissions: [
new Permission(PermissionTypes.TABLE, PermissionLevels.READ), new Permission(PermissionTypes.TABLE, PermissionLevels.READ),
new Permission(PermissionTypes.VIEW, PermissionLevels.READ), new Permission(PermissionTypes.VIEW, PermissionLevels.READ),
], ],
}, },
WRITE: { WRITE: {
name: exports.BUILTIN_PERMISSION_NAMES.WRITE, _id: exports.BUILTIN_PERMISSION_IDS.WRITE,
name: "Read/Write",
permissions: [ permissions: [
new Permission(PermissionTypes.TABLE, PermissionLevels.WRITE), new Permission(PermissionTypes.TABLE, PermissionLevels.WRITE),
new Permission(PermissionTypes.VIEW, PermissionLevels.READ), new Permission(PermissionTypes.VIEW, PermissionLevels.READ),
], ],
}, },
POWER: { POWER: {
name: exports.BUILTIN_PERMISSION_NAMES.POWER, _id: exports.BUILTIN_PERMISSION_IDS.POWER,
name: "Power",
permissions: [ permissions: [
new Permission(PermissionTypes.TABLE, PermissionLevels.WRITE), new Permission(PermissionTypes.TABLE, PermissionLevels.WRITE),
new Permission(PermissionTypes.USER, PermissionLevels.READ), new Permission(PermissionTypes.USER, PermissionLevels.READ),
@ -78,7 +81,8 @@ exports.BUILTIN_PERMISSIONS = {
], ],
}, },
ADMIN: { ADMIN: {
name: exports.BUILTIN_PERMISSION_NAMES.ADMIN, _id: exports.BUILTIN_PERMISSION_IDS.ADMIN,
name: "Admin",
permissions: [ permissions: [
new Permission(PermissionTypes.TABLE, PermissionLevels.ADMIN), new Permission(PermissionTypes.TABLE, PermissionLevels.ADMIN),
new Permission(PermissionTypes.USER, PermissionLevels.ADMIN), new Permission(PermissionTypes.USER, PermissionLevels.ADMIN),
@ -89,11 +93,11 @@ exports.BUILTIN_PERMISSIONS = {
}, },
} }
exports.doesHavePermission = (permType, permLevel, userPermissionNames) => { exports.doesHavePermission = (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
.filter(builtin => userPermissionNames.indexOf(builtin.name) !== -1) .filter(builtin => permissionIds.indexOf(builtin._id) !== -1)
.map(builtin => builtin.permissions) .map(builtin => builtin.permissions)
) )
for (let permission of permissions) { for (let permission of permissions) {

View File

@ -1,5 +1,6 @@
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_IDS = { const BUILTIN_IDS = {
ADMIN: "ADMIN", ADMIN: "ADMIN",
@ -9,20 +10,37 @@ const BUILTIN_IDS = {
BUILDER: "BUILDER", BUILDER: "BUILDER",
} }
function Role(id, name, inherits) { function Role(id, name) {
this._id = id this._id = id
this.name = name this.name = name
if (inherits) { }
this.inherits = inherits
} Role.prototype.addPermission = function(permissionId) {
this.permissionId = permissionId
return this
}
Role.prototype.addInheritance = function(inherits) {
this.inherits = inherits
return this
} }
exports.BUILTIN_ROLES = { exports.BUILTIN_ROLES = {
ADMIN: new Role(BUILTIN_IDS.ADMIN, "Admin", BUILTIN_IDS.POWER), ADMIN: new Role(BUILTIN_IDS.ADMIN, "Admin")
POWER: new Role(BUILTIN_IDS.POWER, "Power", BUILTIN_IDS.BASIC), .addPermission(BUILTIN_PERMISSION_IDS.ADMIN)
BASIC: new Role(BUILTIN_IDS.BASIC, "Basic", BUILTIN_IDS.PUBLIC), .addInheritance(BUILTIN_IDS.POWER),
PUBLIC: new Role(BUILTIN_IDS.PUBLIC, "Public"), POWER: new Role(BUILTIN_IDS.POWER, "Power")
BUILDER: new Role(BUILTIN_IDS.BUILDER, "Builder"), .addPermission(BUILTIN_PERMISSION_IDS.POWER)
.addInheritance(BUILTIN_IDS.BASIC),
BASIC: new Role(BUILTIN_IDS.BASIC, "Basic")
.addPermission(BUILTIN_PERMISSION_IDS.WRITE)
.addInheritance(BUILTIN_IDS.PUBLIC),
PUBLIC: new Role(BUILTIN_IDS.PUBLIC, "Public").addPermission(
BUILTIN_PERMISSION_IDS.READ_ONLY
),
BUILDER: new Role(BUILTIN_IDS.BUILDER, "Builder").addPermission(
BUILTIN_PERMISSION_IDS.ADMIN
),
} }
exports.BUILTIN_ROLE_ID_ARRAY = Object.values(exports.BUILTIN_ROLES).map( exports.BUILTIN_ROLE_ID_ARRAY = Object.values(exports.BUILTIN_ROLES).map(
@ -60,6 +78,29 @@ exports.getRole = async (appId, roleId) => {
return role return role
} }
/**
* Simple function to get all the roles based on the top level user role ID.
*/
async function getAllUserRoles(appId, userRoleId) {
if (!userRoleId) {
return [BUILTIN_IDS.PUBLIC]
}
let currentRole = await exports.getRole(appId, userRoleId)
let roles = currentRole ? [currentRole] : []
let roleIds = [userRoleId]
// get all the inherited roles
while (
currentRole &&
currentRole.inherits &&
roleIds.indexOf(currentRole.inherits) === -1
) {
roleIds.push(currentRole.inherits)
currentRole = await exports.getRole(appId, currentRole.inherits)
roles.push(currentRole)
}
return roles
}
/** /**
* Returns an ordered array of the user's inherited role IDs, this can be used * Returns an ordered array of the user's inherited role IDs, this can be used
* to determine if a user can access something that requires a specific role. * to determine if a user can access something that requires a specific role.
@ -70,22 +111,21 @@ exports.getRole = async (appId, roleId) => {
*/ */
exports.getUserRoleHierarchy = async (appId, userRoleId) => { exports.getUserRoleHierarchy = async (appId, userRoleId) => {
// special case, if they don't have a role then they are a public user // special case, if they don't have a role then they are a public user
if (!userRoleId) { return (await getAllUserRoles(appId, userRoleId)).map(role => role._id)
return [BUILTIN_IDS.PUBLIC] }
}
let roleIds = [userRoleId] /**
let userRole = await exports.getRole(appId, userRoleId) * Get all of the user permissions which could be found across the role hierarchy
// check if inherited makes it possible * @param appId The ID of the application from which roles should be obtained.
while ( * @param userRoleId The user's role ID, this can be found in their access token.
userRole && * @returns {Promise<string[]>} A list of permission IDs these should all be unique.
userRole.inherits && */
roleIds.indexOf(userRole.inherits) === -1 exports.getUserPermissionIds = async (appId, userRoleId) => {
) { return [
roleIds.push(userRole.inherits) ...new Set(
// go to get the inherited incase it inherits anything (await getAllUserRoles(appId, userRoleId)).map(role => role.permissionId)
userRole = await exports.getRole(appId, userRole.inherits) ),
} ]
return roleIds
} }
class AccessController { class AccessController {