From 7b098c8b969a1d283a94391d9d8050ad0c5a4d13 Mon Sep 17 00:00:00 2001 From: Christian Hofmaier Date: Mon, 25 Feb 2019 03:25:08 +0000 Subject: [permissionmanager] rework for blacklist system - integrate PM into PM itself - wildcard function for hasPermission() --- server/lib/permissions/permissions.json | 35 +++--- server/lib/permissions/permissionutil.js | 192 ++++++++++++++++++++++++------- 2 files changed, 169 insertions(+), 58 deletions(-) (limited to 'server/lib/permissions') diff --git a/server/lib/permissions/permissions.json b/server/lib/permissions/permissions.json index 96c971d..f574367 100644 --- a/server/lib/permissions/permissions.json +++ b/server/lib/permissions/permissions.json @@ -1,17 +1,22 @@ [ - { - "name": "permissions.saverole", - "descr": "For saving a role", - "groupdependent": false - }, - { - "name": "permissions.editrole", - "descr": "For editing a role", - "groupdependent": false - }, - { - "name": "permissions.deleterole", - "descr": "For deleting a role", - "groupdependent": false - } + { + "name": "superadmin", + "descr": "Can do anything. Is like superman.", + "groupdependent": false + }, + { + "name": "permissions.viewrole", + "descr": "For viewing the role list.", + "groupdependent": false + }, + { + "name": "permissions.editrole", + "descr": "For save/edit/delete roles.", + "groupdependent": false + }, + { + "name": "permissions.grantrevoke", + "descr": "For grant/revoke roles to/from users.", + "groupdependent": false + } ] \ No newline at end of file diff --git a/server/lib/permissions/permissionutil.js b/server/lib/permissions/permissionutil.js index 709cd29..532af6c 100644 --- a/server/lib/permissions/permissionutil.js +++ b/server/lib/permissions/permissionutil.js @@ -14,15 +14,39 @@ function exportFunctions (req, res, next) { next() } -async function hasPermission (userid, permissionName) { +async function isSuperadmin (userid) { var user = await db.user.findOne({ - where: { id: userid, '$roles.permissions.name$': permissionName }, + where: { id: userid, '$roles.permissions.name$': 'superadmin' }, include: [{ as: 'roles', model: db.role, include: ['permissions'] }] }) return user !== null } +// Check if the user has given permission. +async function hasPermission (userid, permissionName) { + var superAdmin = await isSuperadmin(userid) + if (superAdmin) return true + var permission = permissionName.split('.') + // Wildcards + var user + if (permission[1] === '*') { + user = await db.user.findOne({ + where: { id: userid, '$roles.permissions.name$': { $like: permission[0] + '%' } }, + include: [{ as: 'roles', model: db.role, include: ['permissions'] }] + }) + } else { + user = await db.user.findOne({ + where: { id: userid, '$roles.permissions.name$': permissionName }, + include: [{ as: 'roles', model: db.role, include: ['permissions'] }] + }) + } + return user !== null +} + +// Get a list of GroupIDs the user has the given permission for. 0 means for all groups. async function getAllowedGroups (userid, permissionName) { + var superAdmin = await isSuperadmin(userid) + if (superAdmin) return [0] var user = await db.user.findOne({ where: { id: userid, '$roles.permissions.name$': permissionName }, include: [{ as: 'roles', model: db.role, include: ['permissions', 'groups'] }] @@ -35,12 +59,33 @@ async function getAllowedGroups (userid, permissionName) { else { var permGrps = [] for (let i = 0; i < user.roles.length; i++) { - // Add groups of the roles to the result - permGrps = permGrps.concat(user.roles[i].groups.map(g => g.id)) - if (user.roles[i].recursiveGroups) { - // The role is flagged recursive, so add child ids to result - var subChilds = await groupUtil.getAllChildren(user.roles[i].groups) - permGrps = permGrps.concat(subChilds.subgroups.map(s => s.id)) + var whitelist = [] + var blacklist = [] + // Fill in white- and blacklist + for (let j = 0; j < user.roles[i].groups.length; j++) { + if (user.roles[i].groups[j].role_x_group.blacklist) { + blacklist.push(user.roles[i].groups[j]) + } else { + whitelist.push(user.roles[i].groups[j]) + } + } + + // Get childs of white and blacklist groups + var whiteSubChilds = await groupUtil.getAllChildren(whitelist) + var blackSubChilds = await groupUtil.getAllChildren(blacklist) + + // Add all whitelist-ids to result. + permGrps = permGrps.concat(whitelist.map(x => x.id)) + permGrps = permGrps.concat(whiteSubChilds.subgroups.map(s => s.id)) + + // Filter out blacklist-ids from the result. + blacklist = blacklist.map(x => x.id) + blacklist = blacklist.concat(blackSubChilds.subgroups.map(x => x.id)) + for (let k = 0; k < blacklist.length; k++) { + var index = permGrps.indexOf(blacklist[k]) + if (index > -1) { + permGrps.splice(index, 1) + } } } // Filter result for unique entries @@ -48,7 +93,10 @@ async function getAllowedGroups (userid, permissionName) { } } +// Check if the user has a given permission for a given group. async function hasPermissionForGroup (userid, permissionName, groupId) { + var superAdmin = await isSuperadmin(userid) + if (superAdmin) return true var user = await db.user.findOne({ where: { id: userid, '$roles.permissions.name$': permissionName }, include: [{ as: 'roles', model: db.role, include: ['permissions', 'groups'] }] @@ -59,19 +107,37 @@ async function hasPermissionForGroup (userid, permissionName, groupId) { else if (!user.roles[0].permissions[0].groupdependent) return true // User has permission, permission is groupdependent, check for group else { - if (user.roles.map(r => r.groups.map(g => g.id)).includes(groupId)) return true - var permGrps = [] + var result = false + var whitelist = [] + var blacklist = [] + // Fill in white- and blacklist for (let i = 0; i < user.roles.length; i++) { - if (user.roles[i].recursiveGroups) permGrps = permGrps.concat(user.roles[i].groups.map(g => g.id)) + for (let j = 0; j < user.roles[i].groups.length; j++) { + if (user.roles[i].groups[j].role_x_group.blacklist) { + blacklist.push(user.roles[i].groups[j].id) + } else { + whitelist.push(user.roles[i].groups[j].id) + } + } + } + // Shortcut + if (blacklist.includes(groupId)) { + return false + } + // Remember it was found, check if any parent is in the blacklist tho. + if (whitelist.includes(groupId)) { + result = true } - permGrps = permGrps.filter(function (elem, pos, arr) { return arr.indexOf(elem) === pos }) - // get all parents of groupId and check if any parentid is in the list of groups of RECURSIVE flagged roles. - var result = await checkParentsForIds(groupId, permGrps) + // Check parents for white-/blacklist entries. + result = await checkParents(groupId, whitelist, blacklist, result) return result } } +// Get a list of ClientIDs the user has the given permission for. 0 means for all clients. async function getAllowedClients (userid, permissionName) { + var superAdmin = await isSuperadmin(userid) + if (superAdmin) return [0] var user = await db.user.findOne({ where: { id: userid, '$roles.permissions.name$': permissionName }, include: [{ as: 'roles', model: db.role, include: ['permissions', { as: 'groups', model: db.group, include: ['clients'] }] }] @@ -84,13 +150,30 @@ async function getAllowedClients (userid, permissionName) { else { var permClients = [] for (let i = 0; i < user.roles.length; i++) { - if (user.roles[i].recursiveGroups) { - // The role is flagged recursive, so add clients of childs to result - var subChilds = await groupUtil.getAllChildren(user.roles[i].groups) - permClients = permClients.concat(subChilds.clients.map(c => c.id)) - } else { - for (let j = 0; j < user.roles[i].groups.length; j++) { - permClients = permClients.concat(user.roles[i].groups[j].clients.map(c => c.id)) + var whitelist = [] + var blacklist = [] + // Fill in white- and blacklist + for (let j = 0; j < user.roles[i].groups.length; j++) { + if (user.roles[i].groups[j].role_x_group.blacklist) { + blacklist.push(user.roles[i].groups[j]) + } else { + whitelist.push(user.roles[i].groups[j]) + } + } + + // Get childs of white and blacklist groups + var whiteSubChilds = await groupUtil.getAllChildren(whitelist) + var blackSubChilds = await groupUtil.getAllChildren(blacklist) + + // Add all whitelist-ids to result. + permClients = permClients.concat(whiteSubChilds.clients.map(s => s.id)) + + // Filter out blacklist-ids from the result. + blackSubChilds = blackSubChilds.clients.map(x => x.id) + for (let k = 0; k < blackSubChilds.length; k++) { + var index = permClients.indexOf(blackSubChilds[k]) + if (index > -1) { + permClients.splice(index, 1) } } } @@ -99,49 +182,72 @@ async function getAllowedClients (userid, permissionName) { } } +// Check if the user has a given permission for a given client. async function hasPermissionForClient (userid, permissionName, clientId) { + var superAdmin = await isSuperadmin(userid) + if (superAdmin) return true var user = await db.user.findOne({ where: { id: userid, '$roles.permissions.name$': permissionName }, include: [{ as: 'roles', model: db.role, include: ['permissions', { as: 'groups', model: db.group, include: ['clients'] }] }] }) + // User doesn't have permission if (user === null) return false + // User has permission, permission is not groupdependent else if (!user.roles[0].permissions[0].groupdependent) return true + // User has permission, permission is groupdependent, check for client else { - var permGrps = [] + var result = false + var whitelist = [] + var blacklist = [] + // Fill in white- and blacklist for (let i = 0; i < user.roles.length; i++) { for (let j = 0; j < user.roles[i].groups.length; j++) { - var groupClients = user.roles[i].groups[j].clients.map(c => c.id) - if (groupClients.includes(clientId)) return true + var clients = user.roles[i].groups[j].clients.map(c => c.id) + if (user.roles[i].groups[j].role_x_group.blacklist) { + // Shortcut + if (clients.includes(clientId)) return false + blacklist.push(user.roles[i].groups[j].id) + } else { + // Remember it was found, check if any parent is in the blacklist tho. + if (clients.includes(clientId)) result = true + whitelist.push(user.roles[i].groups[j].id) + } } - if (user.roles[i].recursiveGroups) permGrps = permGrps.concat(user.roles[i].groups.map(g => g.id)) } - permGrps = permGrps.filter(function (elem, pos, arr) { return arr.indexOf(elem) === pos }) + // Get groups the client is assigned to var client = await db.client.findOne({ where: { id: clientId }, include: [{ as: 'groups', model: db.group }] }) var groupIds = client.groups.map(g => g.id) - var result = await checkParentsForIds(groupIds, permGrps) + // Check parents for white-/blacklist entries. + result = await checkParents(groupIds, whitelist, blacklist, result) return result } } -async function checkParentsForIds (groupIds, listOfIds) { - if (listOfIds.length === 0) return false - if (groupIds.length === 0) return false +// Check if parents of groupIds are in the whitelist / blacklist +async function checkParents (groupIds, whitelist, blacklist, result) { + // No whitelist means the group cant be in one + if (whitelist.length === 0) return false + // No blacklist means the result can't be changed once it's true + if (blacklist.length === 0 && result) return true var parentIds = [] - return db.group.findAll({ where: { id: groupIds }, include: ['parents'] }).then(groups => { - for (let i = 0; i < groups.length; i++) { - for (let j = 0; j < groups[i].parents.length; j++) { - var id = groups[i].parents[j].id - if (listOfIds.includes(id)) return true - if (!parentIds.includes(id)) parentIds.push(id) - } + var groups = await db.group.findAll({ where: { id: groupIds }, include: ['parents'] }) + for (let i = 0; i < groups.length; i++) { + for (let j = 0; j < groups[i].parents.length; j++) { + var id = groups[i].parents[j].id + // blacklisted + if (blacklist.includes(id)) return false + // Remember, but a further parent can still be blacklisted, so continue. + if (whitelist.includes(id)) result = true + if (!parentIds.includes(id)) parentIds.push(id) } - if (parentIds.length === 0) return false - return checkParentsForIds(parentIds, listOfIds).then(response => { - return response - }) - }) -} \ No newline at end of file + } + // No further parents found, result is the result. + if (parentIds.length === 0) return result + // Check next layer of parents + result = await checkParents(parentIds, whitelist, blacklist, result) + return result +} -- cgit v1.2.3-55-g7522