From 4c0aee7425bf7beea4d904a934be72ab7d8f0d48 Mon Sep 17 00:00:00 2001 From: Markus Grigull <web@grigull.me> Date: Fri, 21 Oct 2016 19:37:21 +0200 Subject: [PATCH] Add user roles with validation on routes Removed adminLevel from users --- auth.js | 13 +++++++----- config.js | 2 +- models/user.js | 2 +- roles.js | 42 ++++++++++++++++++++++++++++++++++++++ routes/plots.js | 10 ++++----- routes/projects.js | 10 ++++----- routes/simulationModels.js | 10 ++++----- routes/simulations.js | 10 ++++----- routes/simulators.js | 10 ++++----- routes/users.js | 13 ++++++------ routes/visualizations.js | 10 ++++----- server.js | 2 +- 12 files changed, 90 insertions(+), 44 deletions(-) create mode 100644 roles.js diff --git a/auth.js b/auth.js index 50b6a3b..ff7666a 100644 --- a/auth.js +++ b/auth.js @@ -11,6 +11,7 @@ var jwt = require('jsonwebtoken'); var config = require('./config'); +var roles = require('./roles'); module.exports = { validateToken: function(req, res, next) { @@ -31,14 +32,16 @@ module.exports = { }); }, - validateAdminLevel: function(requiredLevel) { + validateRole: function(resource, action) { return function(req, res, next) { - // check admin level - var userLevel = req.decoded._doc.adminLevel; - if (userLevel >= requiredLevel) { + // get user role + var role = roles[req.decoded._doc.role]; + if (role.resource[resource].indexOf(action) > -1) { + // item found in list next(); } else { - return res.status(401).send({ success: false, message: 'Invalid authorization' }); + // item not found + return res.status(403).send({ success: false, message: 'Action not permitted' }); } } } diff --git a/config.js b/config.js index af5d65a..df76b99 100644 --- a/config.js +++ b/config.js @@ -9,7 +9,7 @@ module.exports = { databaseName: 'VILLAS', - databaseURL: 'mongodb://mongo:27017/', + databaseURL: 'mongodb://localhost:27017/', port: 3000, secret: 'longsecretislong', admin: { diff --git a/models/user.js b/models/user.js index 153a4a0..f4abbbf 100644 --- a/models/user.js +++ b/models/user.js @@ -20,7 +20,7 @@ var Schema = mongoose.Schema; var userSchema = new Schema({ username: { type: String, unique: true, required: true }, password: { type: String, required: true }, - adminLevel: { type: Number, default: 0 }, + role: { type: String, required: true, default: 'user' }, projects: [{ type: Schema.Types.ObjectId, ref: 'Project', default: [] }], mail: { type: String, default: "" }, simulations: [{ type: Schema.Types.ObjectId, ref: 'Simulation', default: [] }] diff --git a/roles.js b/roles.js new file mode 100644 index 0000000..c7530be --- /dev/null +++ b/roles.js @@ -0,0 +1,42 @@ +/** + * File: roles.js + * Author: Markus Grigull <mgrigull@eonerc.rwth-aachen.de> + * Date: 20.10.2016 + * Copyright: 2016, Institute for Automation of Complex Power Systems, EONERC + * This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential. + * Unauthorized copying of this file, via any medium is strictly prohibited. + **********************************************************************************/ + +module.exports = { + admin: { + id: 'admin', + name: 'Admin', + description: '', + resource: { + user: [ 'create', 'read', 'update', 'delete' ], + simulator: [ 'create', 'read', 'update', 'delete' ], + simulation: [ 'create', 'read', 'update', 'delete' ], + simulationModel: [ 'create', 'read', 'update', 'delete' ], + project: [ 'create', 'read', 'update', 'delete' ], + visualization: [ 'create', 'read', 'update', 'delete' ] + } + }, + user: { + id: 'user', + name: 'User', + description: '', + resource: { + project: [ 'create', 'read', 'update', 'delete' ], + visualization: [ 'create', 'read', 'update', 'delete' ] + } + }, + guest: { + id: 'guest', + name: 'Guest', + description: '', + resource: { + project: [ 'read' ], + visualization: [ 'read' ] + } + } +} diff --git a/routes/plots.js b/routes/plots.js index 5089c32..2d73504 100644 --- a/routes/plots.js +++ b/routes/plots.js @@ -20,7 +20,7 @@ var Visualization = require('../models/visualization') var router = express.Router(); // all plot routes need authentication -router.use('/plots', auth.validateToken); +router.use('/plots', auth.validateRole('visualization', 'read'), auth.validateToken); // routes router.get('/plots', function(req, res) { @@ -34,7 +34,7 @@ router.get('/plots', function(req, res) { }); }); -router.route('/plots').post(function(req, res) { +router.post('/plots', auth.validateRole('visualization', 'create'), function(req, res) { // create new plot var plot = new Plot(req.body.plot); @@ -62,7 +62,7 @@ router.route('/plots').post(function(req, res) { }); }); -router.route('/plots/:id').put(function(req, res) { +router.put('/plots/:id', auth.validateRole('visualization', 'update'), function(req, res) { // get plot Plot.findOne({ _id: req.params.id }, function(err, plot) { if (err) { @@ -85,7 +85,7 @@ router.route('/plots/:id').put(function(req, res) { }); }); -router.route('/plots/:id').get(function(req, res) { +router.get('/plots/:id', auth.validateRole('visualization', 'read'), function(req, res) { Plot.findOne({ _id: req.params.id }, function(err, plot) { if (err) { return res.send(err); @@ -95,7 +95,7 @@ router.route('/plots/:id').get(function(req, res) { }); }); -router.route('/plots/:id').delete(function(req, res) { +router.delete('/plots/:id', auth.validateRole('visualization', 'delete'), function(req, res) { Plot.findOne({ _id: req.params.id }, function(err, plot) { if (err) { return res.send(err); diff --git a/routes/projects.js b/routes/projects.js index 0c2557a..ebceaa0 100644 --- a/routes/projects.js +++ b/routes/projects.js @@ -24,7 +24,7 @@ var router = express.Router(); router.use('/projects', auth.validateToken); // routes -router.get('/projects', function(req, res) { +router.get('/projects', auth.validateRole('project', 'read'), function(req, res) { // get all projects Project.find(function(err, projects) { if (err) { @@ -35,7 +35,7 @@ router.get('/projects', function(req, res) { }); }); -router.post('/projects', function(req, res) { +router.post('/projects', auth.validateRole('project', 'create'), function(req, res) { // create new project var project = new Project(req.body.project); @@ -79,7 +79,7 @@ router.post('/projects', function(req, res) { }); }); -router.put('/projects/:id', function(req, res) { +router.put('/projects/:id', auth.validateRole('project', 'update'), function(req, res) { // get project Project.findOne({ _id: req.params.id }, function(err, project) { if (err) { @@ -175,7 +175,7 @@ router.put('/projects/:id', function(req, res) { }); }); -router.get('/projects/:id', function(req, res) { +router.get('/projects/:id', auth.validateRole('project', 'read'), function(req, res) { Project.findOne({ _id: req.params.id }, function(err, project) { if (err) { return res.status(400).send(err); @@ -185,7 +185,7 @@ router.get('/projects/:id', function(req, res) { }); }); -router.delete('/projects/:id', function(req, res) { +router.delete('/projects/:id', auth.validateRole('project', 'delete'), function(req, res) { Project.findOne({ _id: req.params.id }, function(err, project) { if (err) { return res.status(400).send(err); diff --git a/routes/simulationModels.js b/routes/simulationModels.js index ed13cbf..cdb00dc 100644 --- a/routes/simulationModels.js +++ b/routes/simulationModels.js @@ -23,7 +23,7 @@ var router = express.Router(); router.use('/simulationModels', auth.validateToken); // routes -router.get('/simulationModels', function(req, res) { +router.get('/simulationModels', auth.validateRole('simulationModel', 'read'), function(req, res) { // get all models SimulationModel.find(function(err, models) { if (err) { @@ -34,7 +34,7 @@ router.get('/simulationModels', function(req, res) { }); }); -router.post('/simulationModels', function(req, res) { +router.post('/simulationModels', auth.validateRole('simulationModel', 'create'), function(req, res) { // create new model var model = new SimulationModel(req.body.simulationModel); @@ -62,7 +62,7 @@ router.post('/simulationModels', function(req, res) { }); }); -router.put('/simulationModels/:id', function(req, res) { +router.put('/simulationModels/:id', auth.validateRole('simulationModel', 'update'), function(req, res) { // get model SimulationModel.findOne({ _id: req.params.id }, function(err, model) { if (err) { @@ -85,7 +85,7 @@ router.put('/simulationModels/:id', function(req, res) { }); }); -router.get('/simulationModels/:id', function(req, res) { +router.get('/simulationModels/:id', auth.validateRole('simulationModel', 'read'), function(req, res) { SimulationModel.findOne({ _id: req.params.id }, function(err, model) { if (err) { return res.status(400).send(err); @@ -95,7 +95,7 @@ router.get('/simulationModels/:id', function(req, res) { }); }); -router.delete('/simulationModels/:id', function(req, res) { +router.delete('/simulationModels/:id', auth.validateRole('simulationModel', 'delete'), function(req, res) { SimulationModel.findOne({ _id: req.params.id }, function(err, model) { if (err) { return res.status(400).send(err); diff --git a/routes/simulations.js b/routes/simulations.js index 022652f..d688681 100644 --- a/routes/simulations.js +++ b/routes/simulations.js @@ -23,7 +23,7 @@ var router = express.Router(); router.use('/simulations', auth.validateToken); // routes -router.get('/simulations', function(req, res) { +router.get('/simulations', auth.validateRole('simulation', 'read'), function(req, res) { // get all simulations Simulation.find(function(err, simulations) { if (err) { @@ -34,7 +34,7 @@ router.get('/simulations', function(req, res) { }); }); -router.post('/simulations', function(req, res) { +router.post('/simulations', auth.validateRole('simulation', 'create'), function(req, res) { // create new simulation var simulation = new Simulation(req.body.simulation); @@ -63,7 +63,7 @@ router.post('/simulations', function(req, res) { }); }); -router.put('/simulations/:id', function(req, res) { +router.put('/simulations/:id', auth.validateRole('simulation', 'update'), function(req, res) { // get simulation Simulation.findOne({ _id: req.params.id }, function(err, simulation) { if (err) { @@ -123,7 +123,7 @@ router.put('/simulations/:id', function(req, res) { }); }); -router.get('/simulations/:id', function(req, res) { +router.get('/simulations/:id', auth.validateRole('simulation', 'read'), function(req, res) { Simulation.findOne({ _id: req.params.id }, function(err, simulation) { if (err) { return res.send(err); @@ -133,7 +133,7 @@ router.get('/simulations/:id', function(req, res) { }); }); -router.delete('/simulations/:id', function(req, res) { +router.delete('/simulations/:id', auth.validateRole('simulation', 'delete'), function(req, res) { Simulation.findOne({ _id: req.params.id }, function(err, simulation) { if (err) { return res.status(400).send(err); diff --git a/routes/simulators.js b/routes/simulators.js index 4057285..3f5f36e 100644 --- a/routes/simulators.js +++ b/routes/simulators.js @@ -22,7 +22,7 @@ var router = express.Router(); router.use('/simulators', auth.validateToken); // routes -router.get('/simulators', function(req, res) { +router.get('/simulators', auth.validateRole('simulator', 'read'), function(req, res) { // get all simulators Simulator.find(function(err, simulators) { if (err) { @@ -33,7 +33,7 @@ router.get('/simulators', function(req, res) { }); }); -router.post('/simulators', function(req, res) { +router.post('/simulators', auth.validateRole('simulator', 'create'), function(req, res) { // create new simulator var simulator = new Simulator(req.body.simulator); @@ -46,7 +46,7 @@ router.post('/simulators', function(req, res) { }); }); -router.put('/simulators/:id', function(req, res) { +router.put('/simulators/:id', auth.validateRole('simulator', 'update'), function(req, res) { // get simulator Simulator.findOne({ _id: req.params.id }, function(err, simulator) { if (err) { @@ -69,7 +69,7 @@ router.put('/simulators/:id', function(req, res) { }); }); -router.get('/simulators/:id', function(req, res) { +router.get('/simulators/:id', auth.validateRole('simulator', 'read'), function(req, res) { Simulator.findOne({ _id: req.params.id }, function(err, simulator) { if (err) { return res.status(400).send(err); @@ -79,7 +79,7 @@ router.get('/simulators/:id', function(req, res) { }); }); -router.delete('/simulators/:id', function(req, res) { +router.delete('/simulators/:id', auth.validateRole('simulator', 'delete'), function(req, res) { Simulator.findOne({ _id: req.params.id }, function(err, simulator) { if (err) { return res.status(400).send(err); diff --git a/routes/users.js b/routes/users.js index 2a2a015..df985b3 100644 --- a/routes/users.js +++ b/routes/users.js @@ -24,7 +24,7 @@ var router = express.Router(); router.use('/users', auth.validateToken); // routes -router.route('/users').get(auth.validateAdminLevel(1), function(req, res) { +router.get('/users', auth.validateRole('user', 'read'), function(req, res) { // get all users User.find(function(err, users) { if (err) { @@ -35,7 +35,7 @@ router.route('/users').get(auth.validateAdminLevel(1), function(req, res) { }); }); -router.route('/users').post(auth.validateAdminLevel(1), function(req, res) { +router.post('/users', auth.validateRole('user', 'create'), function(req, res) { // create new user var user = new User(req.body.user); @@ -48,7 +48,7 @@ router.route('/users').post(auth.validateAdminLevel(1), function(req, res) { }); }); -router.route('/users/:id').put(function(req, res) { +router.put('/users/:id', auth.validateRole('user', 'update'), function(req, res) { // get user User.findOne({ _id: req.params.id }, function(err, user) { if (err) { @@ -90,7 +90,8 @@ router.route('/users/:id').put(function(req, res) { }); }); -router.route('/users/me').get(function(req, res) { +// This route needs no role validation, since it just requests the current user +router.get('/users/me', function(req, res) { // get the logged-in user ID var userId = req.decoded._doc._id; @@ -103,7 +104,7 @@ router.route('/users/me').get(function(req, res) { }); }); -router.route('/users/:id').get(auth.validateAdminLevel(1), function(req, res) { +router.get('/users/:id', auth.validateRole('user', 'read'), function(req, res) { User.findOne({ _id: req.params.id }, function(err, user) { if (err) { return res.send(err); @@ -113,7 +114,7 @@ router.route('/users/:id').get(auth.validateAdminLevel(1), function(req, res) { }); }); -router.route('/users/:id').delete(auth.validateAdminLevel(1), function(req, res) { +router.delete('/users/:id', auth.validateRole('user', 'delete'), function(req, res) { User.findOne({ _id: req.params.id }, function(err, user) { if (err) { return res.send(err); diff --git a/routes/visualizations.js b/routes/visualizations.js index 89aec59..4f5f1e0 100644 --- a/routes/visualizations.js +++ b/routes/visualizations.js @@ -23,7 +23,7 @@ var router = express.Router(); router.use('/visualizations', auth.validateToken); // routes -router.get('/visualizations', function(req, res) { +router.get('/visualizations', auth.validateRole('visualization', 'read'), function(req, res) { // get all visualizations Visualization.find(function(err, visualizations) { if (err) { @@ -34,7 +34,7 @@ router.get('/visualizations', function(req, res) { }); }); -router.route('/visualizations').post(function(req, res) { +router.post('/visualizations', auth.validateRole('visualization', 'create'), function(req, res) { // create new visualization var visualization = new Visualization(req.body.visualization); @@ -62,7 +62,7 @@ router.route('/visualizations').post(function(req, res) { }); }); -router.route('/visualizations/:id').put(function(req, res) { +router.put('/visualizations/:id', auth.validateRole('visualization', 'update'), function(req, res) { // get visualization Visualization.findOne({ _id: req.params.id }, function(err, visualization) { if (err) { @@ -85,7 +85,7 @@ router.route('/visualizations/:id').put(function(req, res) { }); }); -router.route('/visualizations/:id').get(function(req, res) { +router.get('/visualizations/:id', auth.validateRole('visualization', 'read'), function(req, res) { Visualization.findOne({ _id: req.params.id }, function(err, visualization) { if (err) { return res.send(err); @@ -95,7 +95,7 @@ router.route('/visualizations/:id').get(function(req, res) { }); }); -router.route('/visualizations/:id').delete(function(req, res) { +router.delete('/visualizations/:id', auth.validateRole('visualization', 'delete'), function(req, res) { Visualization.findOne({ _id: req.params.id }, function(err, visualization) { if (err) { return res.send(err); diff --git a/server.js b/server.js index 009969c..2fd484a 100644 --- a/server.js +++ b/server.js @@ -85,7 +85,7 @@ if (config.admin) { if (!user) { // create new admin user - var newUser = User({ username: config.admin.username, password: config.admin.password, adminLevel: 1}); + var newUser = User({ username: config.admin.username, password: config.admin.password, role: 'admin' }); newUser.save(function(err) { if (err) { console.log(err); -- GitLab