From 79f09bacdc4bd515e135060226888b02e285d146 Mon Sep 17 00:00:00 2001 From: Jannik Schönartz Date: Tue, 2 Jun 2020 16:33:13 +0000 Subject: [users/ipxe/backends] PM integration --- server/api/backends.js | 33 ++++++++++++++++++++--- server/api/ipxe.js | 40 ++++++++++++++++++++++++---- server/api/users.js | 40 +++++++++++++++++++--------- server/lib/httpresponse.js | 13 +++++++++ server/lib/permissions/modules/backends.json | 12 +++++++++ server/lib/permissions/modules/ipxe.json | 12 +++++++++ server/lib/permissions/modules/users.json | 12 +++++++++ 7 files changed, 141 insertions(+), 21 deletions(-) create mode 100644 server/lib/permissions/modules/backends.json create mode 100644 server/lib/permissions/modules/ipxe.json create mode 100644 server/lib/permissions/modules/users.json (limited to 'server') diff --git a/server/api/backends.js b/server/api/backends.js index b75634f..872e0f6 100644 --- a/server/api/backends.js +++ b/server/api/backends.js @@ -9,18 +9,45 @@ var noAuthRouter = decorateApp(express.Router()) const HttpResponse = require(path.join(__appdir, 'lib', 'httpresponse')) const log = require(path.join(__appdir, 'lib', 'log')) -// GET requests. - // TODO DELETE noAuthRouter.getAsync('/:id/test', async (req, res) => { const id = req.params.id const backend = await db.backend.findOne({ where: { id: id } }) const externalBackends = new ExternalBackends() const instance = externalBackends.getInstance(backend.type) - const result = await instance.test(backend.credentials) + // const result = await instance.test(backend.credentials) + const result = await instance.checkIp(backend.credentials, '10.21.9.220') res.send(result) }) +// Permission check middleware +router.all(['', '/:id', '/:id/:function'], async (req, res, next) => { + console.log(req.params) + switch (req.method) { + case 'GET': + switch (req.params.function) { + case 'import': + if (!await req.user.hasPermission('backends.edit')) return res.status(403).send({ error: 'Missing permission', permission: 'backends.edit' }) + break + + default: + if (!await req.user.hasPermission('backends.view')) return res.status(403).send({ error: 'Missing permission', permission: 'backends.view' }) + break + } + break + + case 'POST': case 'PUT': + if (!await req.user.hasPermission('backends.edit')) return res.status(403).send({ error: 'Missing permission', permission: 'backends.edit' }) + break + + default: + return res.status(400).send() + } + + next() +}) + +// GET requests. /* * @return: Returns a list of all backends saved in the db. */ diff --git a/server/api/ipxe.js b/server/api/ipxe.js index b7e1970..b807c00 100644 --- a/server/api/ipxe.js +++ b/server/api/ipxe.js @@ -3,10 +3,40 @@ var path = require('path') const fs = require('fs') var shell = require(path.join(__appdir, 'lib', 'shell')) var express = require('express') -var router = express.Router() +const { decorateApp } = require('@awaitjs/express') +var router = decorateApp(express.Router()) var noAuthRouter = express.Router() const log = require(path.join(__appdir, 'lib', 'log')) +// Permission check middleware +router.all('/:x', async (req, res, next) => { + switch (req.method) { + case 'GET': + switch (req.params.x) { + case 'script': case 'certificate': case 'general': case 'console': case 'log': case 'config': case 'status': + if (!await req.user.hasPermission('ipxe.view')) return res.status(403).send({ error: 'Missing permission', permission: 'ipxe.view' }) + break + + case 'build': case 'cancel': case 'clean': + if (!await req.user.hasPermission('ipxe.edit')) return res.status(403).send({ error: 'Missing permission', permission: 'ipxe.edit' }) + break + + default: + return res.status(400).send() + } + break + + case 'PUT': case 'POST': + if (!await req.user.hasPermission('ipxe.edit')) return res.status(403).send({ error: 'Missing permission', permission: 'ipxe.edit' }) + break + + default: + return res.status(400).send() + } + + next() +}) + // GET requests. router.get('/script', (req, res) => { res.setHeader('content-type', 'text/plain') @@ -28,7 +58,7 @@ router.get('/console', (req, res) => { res.sendFile(path.join(__appdir, 'ipxe', 'console.h')) }) -router.get('/log', async (req, res) => { +router.get('/log', (req, res) => { const max = req.query.max ? req.query.max : -1 res.setHeader('content-type', 'text/plain') const filepath = path.join(__appdir, 'ipxe', 'ipxelog.txt') @@ -118,7 +148,7 @@ router.put('/:filename', (req, res) => { /* * @return: Rebuild the ipxe. */ -router.get('/build', async (req, res) => { +router.getAsync('/build', async (req, res) => { log({ category: 'IPXEBUILDER_BUILD', description: 'User initiated the ipxe building process.', @@ -131,7 +161,7 @@ router.get('/build', async (req, res) => { res.send(build) }) -router.get('/cancel', async (req, res) => { +router.getAsync('/cancel', async (req, res) => { log({ category: 'IPXEBUILDER_CANCEL', description: 'User canceled the ipxe building process.', @@ -141,7 +171,7 @@ router.get('/cancel', async (req, res) => { res.send(result) }) -router.get('/clean', async (req, res) => { +router.getAsync('/clean', async (req, res) => { log({ category: 'IPXEBUILDER_CLEAN', description: 'User initiated ipxe cleaning process.', diff --git a/server/api/users.js b/server/api/users.js index d69c776..a4940e0 100644 --- a/server/api/users.js +++ b/server/api/users.js @@ -7,6 +7,28 @@ var router = decorateApp(express.Router()) var authentication = require(path.join(__appdir, 'lib', 'authentication')) const log = require(path.join(__appdir, 'lib', 'log')) +// Permission check middleware +router.all(['', '/:id'], async (req, res, next) => { + // User is allowed to edit his own information even without any permissions. + let currentInfo = false + if (req.params.id && req.params.id === 'current') currentInfo = true + + switch (req.method) { + case 'GET': + if (!await req.user.hasPermission('users.view') && !currentInfo) return res.status(403).send({ error: 'Missing permission', permission: 'users.view' }) + break + + case 'POST': case 'DELETE': + if (!await req.user.hasPermission('users.edit') && !currentInfo) return res.status(403).send({ error: 'Missing permission', permission: 'users.edit' }) + break + + default: + return res.status(400).send() + } + + next() +}) + // ############################################################################ // ########################### GET requests ################################# @@ -36,8 +58,6 @@ router.getAsync('/:id', async (req, res) => { // Post request for adding roles to users. router.postAsync('/roles', async (req, res) => { - // if (!await req.user.hasPermission('permissions.grantrevoke')) return res.status(403).end() - const userIds = req.body.users const roleIds = req.body.roles const users = await db.user.findAll({ where: { id: userIds }, include: ['roles'] }) @@ -52,7 +72,7 @@ router.postAsync('/roles', async (req, res) => { if (count > 1) roleString += 's' log({ category: 'USER_REVOKE_ROLE', - description: '[' + user.id + '] ' + user.name + ': Successfully removed ' + count + ' ' + roleString + '.\n' + + description: '[' + user.id + '] ' + 'Successfully removed ' + count + ' ' + roleString + ' from' + user.name + '.\n' + 'ID: ' + user.id + '\n' + 'Name: ' + user.name + '\n' + 'Removed Roles: ' + roleIds.filter(y => { return roles.map(x => x.id).includes(y) }), @@ -85,13 +105,9 @@ router.postAsync('/roles', async (req, res) => { } }) -// Post request for creating new user accounts. +// Post request for creating / editing new user accounts. router.postAsync(['/', '/:id'], async (req, res) => { const body = req.body - if (req.params.id !== 'current') { - // TODO: Check for permission to delete / create / update user - } - // Delete request if (req.query.delete !== undefined && req.query.delete !== 'false') { const user = await db.user.findOne({ where: { id: req.user.id } }) @@ -152,6 +168,7 @@ router.postAsync(['/', '/:id'], async (req, res) => { return res.send({ deletionCounter }) } + // Create new user if (req.params.id === undefined) { const result = await authentication.signup(body) const code = result.code @@ -183,6 +200,7 @@ router.postAsync(['/', '/:id'], async (req, res) => { delete result.code return res.status(code).send(result) } else { + // Edit user const id = req.params.id === 'current' ? req.user.id : req.params.id let user = await db.user.findOne({ where: { id: id } }) @@ -289,7 +307,7 @@ router.postAsync(['/', '/:id'], async (req, res) => { // Post request for changing the password. router.postAsync('/:id/password', async (req, res) => { - const id = req.params.id + const id = req.params.id === 'current' ? req.user.id : req.params.id const body = req.body // Check if passwords are set. if (body.passwordCurrent && body.password) { @@ -317,10 +335,6 @@ router.postAsync('/:id/password', async (req, res) => { // Function for deleting a single user router.deleteAsync('/:id/', async (req, res) => { - if (req.params.id !== 'current') { - // Check if the user has the permission for changing those userdata. Else return. - // return res.status(500).end() - } const id = req.params.id === 'current' ? req.user.id : req.params.id const user = await db.user.findOne({ where: { id: id } }) // Every user can delete his own account. diff --git a/server/lib/httpresponse.js b/server/lib/httpresponse.js index cb4b216..c402e39 100644 --- a/server/lib/httpresponse.js +++ b/server/lib/httpresponse.js @@ -26,6 +26,18 @@ HttpResponse.successBatch = (action, type, count) => { return new HttpResponse(200, action.toUpperCase() + '_MULTIPLE', `Successfully ${action} ${count} ${type}.`, { count }) } +// ############################################################################ +// ############################## WARNING ##################################### + +HttpResponse.warningBatch = (action, type, successfull, count) => { + const failed = count - successfull + let tmpType = type + if (failed > 1) tmpType += 's' + if (Array.isArray(type)) type = type[successfull === 1 ? 0 : 1] + else if (successfull !== 1) type += 's' + return new HttpResponse(200, action.toUpperCase() + '_MULTIPLE', `Warning: ${action} ${successfull}/${count} ${type}. ${failed} ${tmpType} failed.`, { successfull, count }) +} + // ############################################################################ // ############################### ERROR ###################################### @@ -33,6 +45,7 @@ HttpResponse.successBatch = (action, type, count) => { HttpResponse.notFound = (id) => new HttpResponse(404, 'NOT_FOUND', 'ID ' + id + ' does not exist.') HttpResponse.invalidId = (zeroAllowed) => new HttpResponse(400, 'INVALID_ID', 'ID has to be an integer' + (zeroAllowed ? '' : ' greater than 0') + '.') HttpResponse.invalidBodyValue = (key, rule) => new HttpResponse(400, 'BAD_REQUEST', 'JSON body value for key "' + key + '" has to be ' + rule + '.') +HttpResponse.noPermission = (id, permission) => new HttpResponse(403, 'NO_PERMISSION', 'Missing permission ' + permission + ' for object ' + id + '.') // Authentication HttpResponse.invalidToken = () => new HttpResponse(401, 'INVALID_TOKEN', 'The provided token is invalid.') diff --git a/server/lib/permissions/modules/backends.json b/server/lib/permissions/modules/backends.json new file mode 100644 index 0000000..5143ec3 --- /dev/null +++ b/server/lib/permissions/modules/backends.json @@ -0,0 +1,12 @@ +[ + { + "name": "view", + "description": "View all backends including their informations.", + "groupdependent": false + }, + { + "name": "edit", + "description": "Edit and delete backends.", + "groupdependent": false + } +] \ No newline at end of file diff --git a/server/lib/permissions/modules/ipxe.json b/server/lib/permissions/modules/ipxe.json new file mode 100644 index 0000000..2375cbf --- /dev/null +++ b/server/lib/permissions/modules/ipxe.json @@ -0,0 +1,12 @@ +[ + { + "name": "view", + "description": "View all information for building ipxe.", + "groupdependent": false + }, + { + "name": "edit", + "description": "Edit informations, configs, scripts for building ipxe.", + "groupdependent": false + } +] \ No newline at end of file diff --git a/server/lib/permissions/modules/users.json b/server/lib/permissions/modules/users.json new file mode 100644 index 0000000..1818e7f --- /dev/null +++ b/server/lib/permissions/modules/users.json @@ -0,0 +1,12 @@ +[ + { + "name": "view", + "description": "View all users including their informations.", + "groupdependent": false + }, + { + "name": "edit", + "description": "Edit and delete users.", + "groupdependent": false + } +] \ No newline at end of file -- cgit v1.2.3-55-g7522