Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
js
https://blog.nodeswat.com/implement-access-control-in-node-js-8567e7b484d1 1/26
9/8/2017 Implement Access Control in Node.js – Security and Node.js
. . .
Relearn Access Control
When asking developers to name different access control methods, the
usual answer seems to be ACL and RBAC. If you answered this
question the same way, then you are also among the misinformed.
Let’s look at both of these in turn and then explain why.
In this table we can see how each user is a row and has specific
privileges assigned to them. Upon access control check, the user’s row
and the column in question are cross-checked — this determines if this
user has access or not.
https://blog.nodeswat.com/implement-access-control-in-node-js-8567e7b484d1 2/26
9/8/2017 Implement Access Control in Node.js – Security and Node.js
These are the common understandings of ACL and RBAC and they are
both incorrect. And here’s why:
That sounds very much like the ACL we described earlier. However,
ACL variations like ACLg can also be used to implement RBAC access
model. We simply substitute the individual for a group. As a result we
end up with:
https://blog.nodeswat.com/implement-access-control-in-node-js-8567e7b484d1 3/26
9/8/2017 Implement Access Control in Node.js – Security and Node.js
. . .
https://blog.nodeswat.com/implement-access-control-in-node-js-8567e7b484d1 4/26
9/8/2017 Implement Access Control in Node.js – Security and Node.js
In short MAC and DAC both focus on the data object or file, whereas
DAC allows me (the owner of the file) to determine who has access.
In MAC however the access rights are determined by the
administrator or general rule.
https://blog.nodeswat.com/implement-access-control-in-node-js-8567e7b484d1 5/26
9/8/2017 Implement Access Control in Node.js – Security and Node.js
https://blog.nodeswat.com/implement-access-control-in-node-js-8567e7b484d1 6/26
9/8/2017 Implement Access Control in Node.js – Security and Node.js
https://blog.nodeswat.com/implement-access-control-in-node-js-8567e7b484d1 7/26
9/8/2017 Implement Access Control in Node.js – Security and Node.js
Hope you found these detailed nuances useful? In the next section we
will take a closer look at the most popular access control method of
the web — RBAC.
. . .
Details of RBAC
RBAC or Role Based Access Control is an access control method
where each identity is assigned a role and the roles determine what
access rights the identity has. This is opposed to IBAC, where each
identity has separate privilege assignment. RBAC looses some
granularity compared to IBAC, however it gains better manageability
in environments with large amounts of users.
https://blog.nodeswat.com/implement-access-control-in-node-js-8567e7b484d1 8/26
9/8/2017 Implement Access Control in Node.js – Security and Node.js
https://blog.nodeswat.com/implement-access-control-in-node-js-8567e7b484d1 9/26
9/8/2017 Implement Access Control in Node.js – Security and Node.js
In short RBAC is the de-facto standard access control method for most
web applications. Mainly because building a web app means that you
expect to handle a vast amount of users — thousands, millions even
billions (one can dream). Implementing IBAC in this situation would
result in enormous data duplication for access rights.
Now that we are more familiar with the logic behind RBAC, we can
proceed with our plan to build a RBAC module.
. . .
Ready, Set, Build
Having theoretical knowledge about access control is nice, but unless
put to use, we could have spent our time watching pictures of cute
https://blog.nodeswat.com/implement-access-control-in-node-js-8567e7b484d1 10/26
9/8/2017 Implement Access Control in Node.js – Security and Node.js
kittens instead. So let’s not stop there and let’s start building
1 let roles = {
2 manager: {
3 can: ['read', 'write', 'publish']
4 },
5 writer: {
6 can: ['read', 'write']
7 },
8 guest: {
9 can: ['read']
10 }
11 }
https://blog.nodeswat.com/implement-access-control-in-node-js-8567e7b484d1 11/26
9/8/2017 Implement Access Control in Node.js – Security and Node.js
1 class RBAC {
2 constructor(roles) {
3 if(typeof roles !== 'object') {
4 throw new TypeError('Expected an object as input
5 }
6 this.roles = roles;
7 }
8
9 can(role, operation) {
10 return this.roles[role] && this.roles[role].can.indexOf
This leaves us with a very simple module for defining and checking
roles. Let’s not stop here — we will add hierarchy to the model so that
we can manage roles more easily when adding new operations to the
system.
This way there is no need to define rights to every operation for each
role separately.
It’ll allow the user to represent a list of child roles, where to inherit
permissions from.
1 let roles = {
2 manager: {
3 can: ['publish'],
4 inherits: ['writer']
5 },
6 writer: {
7 can: ['write'],
8 inherits: ['guest']
9 },
10 guest: {
https://blog.nodeswat.com/implement-access-control-in-node-js-8567e7b484d1 12/26
9/8/2017 Implement Access Control in Node.js – Security and Node.js
1 can(role, operation) {
2 // Check if role exists
3 if(!this.roles[role]) {
4 return false;
5 }
6 let $role = this.roles[role];
7 // Check if this role has access
8 if($role.can.indexOf(operation) !== ‐1) {
9 return true;
10 }
11 // Check if there are any parents
12 if(!$role.inherits || $role.inherits.length < 1) {
13 return false;
1 let roles = {
2 manager: {
3 can: ['publish'],
4 inherits: ['writer']
5 },
6 writer: {
7 can: ['write', {
8 name: 'edit',
9 when: function (params) {
10 return params.user.id === params.post.owner
11 }
12 }],
13 inherits: ['guest']
https://blog.nodeswat.com/implement-access-control-in-node-js-8567e7b484d1 13/26
9/8/2017 Implement Access Control in Node.js – Security and Node.js
1 class RBAC {
2 constructor(opts) {
3 this.init(opts);
4 }
5
6 init(roles) {
7 if(typeof roles !== 'object') {
8 throw new TypeError('Expected an object as input
9 }
10
11 this.roles = roles;
12 let map = {};
13 Object.keys(roles).forEach(role => {
14 map[role] = {
15 can: {}
16 };
17 if(roles[role].inherits) {
18 map[role].inherits = roles[role].inherits;
19 }
20
21 roles[role].can.forEach(operation => {
22 if(typeof operation === 'string') {
23 map[role].can[operation] = 1;
24 } else if(typeof operation.name === 'string
25 && typeof operation.when === 'function'
And now we can use the map we created in our check function:
https://blog.nodeswat.com/implement-access-control-in-node-js-8567e7b484d1 14/26
9/8/2017 Implement Access Control in Node.js – Security and Node.js
1 can(role, operation, params) {
2 // Check if role exists
3 if(!this.roles[role]) {
4 return false;
5 }
6 let $role = this.roles[role];
7 // Check if this role has this operation
8 if($role.can[operation]) {
9 // Not a function so we are good
10 if(typeof $role.can[operation] !== 'function') {
11 return true;
12 }
13 // If the function check passes return true
14 if($role.can[operation](params)) {
15 return true;
16 }
17 }
18
Awesome! We now have RBAC class that we can use to check our
defined hierarchy model. Additionally, we can also define functions to
do dynamic checks for specific access:
We are still not done. Let’s not forget that we are dealing with Node.js
so synchronous solutions are not the best way to go — we need async
so that we can instantiate the class with information found in the
database. Or we might want our access check to look something up
from the file system, other API or somewhere else. Point is — we need
it.
We’ll start our update with the check function. Let’s use the Q module
to provide backwards compatibility. We can just wrap the contents of
https://blog.nodeswat.com/implement-access-control-in-node-js-8567e7b484d1 15/26
9/8/2017 Implement Access Control in Node.js – Security and Node.js
1 let Q = require('q');
2
3 // ... //
4
5 can(role, operation, params) {
6 return Q.Promise((resolve, reject) => {
7 // our function
8 // ... //
9 });
1 let Q = require('q');
2 can(role, operation, params, cb) {
3 let callback = cb || () => {};
4 return Q.Promise((resolvePromise, rejectPromise) => {
5
6 // Collect resolve handling
7 function resolve(value) {
8 resolvePromise(result);
9 callback(undefined, result);
10 }
11
12 // Collect error handling
13 function reject(err) {
14 rejectPromise(err);
15 callback(err);
https://blog.nodeswat.com/implement-access-control-in-node-js-8567e7b484d1 16/26
9/8/2017 Implement Access Control in Node.js – Security and Node.js
1 $role.can[operation](params, function (err, result) {
2 if(err) {
3 return reject(err);
4 }
5 if(!result) {
6 return reject(false);
7 }
1 return Q.any($role.inherits.map(child => this.can(child, operation, params)))
2 .then(resolve, reject);
After adding some type checks, our can function could look
something like this:
https://blog.nodeswat.com/implement-access-control-in-node-js-8567e7b484d1 17/26
9/8/2017 Implement Access Control in Node.js – Security and Node.js
1 can(role, operation, params, cb) {
2
3 if(typeof params === 'function') {
4 cb = params;
5 params = undefined;
6 }
7
8 let callback = cb || () => {};
9
10 return Q.Promise((resolve, reject) => {
11
12 // Collect resolve handling
13 function resolve(value) {
14 resolvePromise(result);
15 callback(undefined, result);
16 }
17
18 // Collect error handling
19 function reject(err) {
20 rejectPromise(err);
21 callback(err);
22 }
23
24 if (typeof role !== 'string') {
25 throw new TypeError('Expected first parameter to be string : role
26 }
27
28 if (typeof operation !== 'string') {
29 throw new TypeError('Expected second parameter to be string : operation
30 }
31
32 let $role = $this.roles[role];
33
34 if (!$role) {
35 throw new Error('Undefined role');
36 }
37
38 // IF this operation is not defined at current level try higher
39 if (!$role.can[operation]) {
40 // If no parents reject
41 if (!$role.inherits) {
42 return reject(false);
https://blog.nodeswat.com/implement-access-control-in-node-js-8567e7b484d1 18/26
9/8/2017 Implement Access Control in Node.js – Security and Node.js
42 return reject(false);
43 }
44 // Return if any parent resolves true or all reject
45 return Q.any($role.inherits.map(parent => this.
if(!this._inited) {
return this._init
.then(() => this.can(role, operation, params,
cb));
}
. . .
https://blog.nodeswat.com/implement-access-control-in-node-js-8567e7b484d1 19/26
9/8/2017 Implement Access Control in Node.js – Security and Node.js
1 'use strict';
2
3 let express = require('express');
4 let session = require('express‐session');
5 let eSession = require('easy‐session');
6 let cookieParser = require('cookie‐parser');
7
8 let app = express();
9
10 app.use(cookieParser());
11 app.use(session({
12 secret: 'keyboard cat',
13 resave: false,
14 saveUninitialized: true
15 }));
16 app.use(eSession.main(session));
17
18 // Add a path to allow easy login to any role
19 app.get('/login/:role', function (req, res, next) {
20 req.session.login(req.params.role, function () {
21 res.redirect('/');
22 });
23 });
24
Now we have our base setup, but what if our application is expanding
— we are adding functionality to read and write blog posts; everyone
can read and writers can write? We could do it by checking the role
like this:
https://blog.nodeswat.com/implement-access-control-in-node-js-8567e7b484d1 20/26
9/8/2017 Implement Access Control in Node.js – Security and Node.js
1 // We need no authentication here
2 app.get('/blog', function (req, res, next) {
3 res.send('Cool blog post');
4 });
5
6 app.get('/blog/create', function (req, res, next) {
7 // Check if user is writer
8 if(!req.session.hasRole('writer')) {
9 res.sendStatus(403);
10 return;
1 app.use(eSession.main(session, {
2 rbac: {
3 guest: {
4 can: ['blog:read']
5 },
6 writer: {
7 can: ['blog:create'],
8 inherits: ['guest']
https://blog.nodeswat.com/implement-access-control-in-node-js-8567e7b484d1 21/26
9/8/2017 Implement Access Control in Node.js – Security and Node.js
1 app.use(eSession.main(session, {
2 rbac: function (cb) {
3 // Our async logic
4 setImmediate(cb, null, {
5 guest: {
6 can: ['blog:read']
7 },
8 writer: {
9 can: ['blog:create'],
10 inherits: ['guest']
And now we can check for the right to create blog posts.
1 app.get('/blog/create', function (req, res, next) {
2 // Check if user has access
3 req.session.can('blog:create')
4 .then(function () {
5 res.send('Blog edit');
6 })
7 .catch(function () {
8 res.sendStatus(403);
Even better, let’s move the validation into a middleware to keep our
logic clean.
1 app.get('/blog/create', eSession.can('blog:create'), function
2 res.send('Blog edit');
3 });
https://blog.nodeswat.com/implement-access-control-in-node-js-8567e7b484d1 22/26
9/8/2017 Implement Access Control in Node.js – Security and Node.js
1 app.use(eSession.main(session, {
2 rbac: {
3 guest: {
4 can: ['blog:read']
5 },
6 writer: {
7 can: ['blog:create', {
8 name: 'blog:edit',
9 when: function (params, cb) {
10 //check if user is the owner
11 setImmediate(cb, null, params.user.id ===
12 }
1 app.get('/login/:role', function (req, res, next) {
2 // Going to hardcode the user object
3 let extend = {
4 user: {
5 id: 2
6 }
7 };
8 req.session.login(req.params.role, extend, function () {
And finally we need a way to look up a blog object and test if we can
actually edit:
https://blog.nodeswat.com/implement-access-control-in-node-js-8567e7b484d1 23/26
9/8/2017 Implement Access Control in Node.js – Security and Node.js
1 let $q = require('q');
2 function findBlog(id) {
3 return $q({
4 ownerId: parseInt(id)
5 });
6 }
7
8 app.get('/blog/edit/:id', function (req, res, next) {
9 // look for blog
10 findBlog(req.params.id)
11 .then(function (blog) {
12 //check for access
13 return req.session.can('blog:edit', {user: req.
14 }, function (err) {
15 // Handling db errors
16 res.sendStatus(500);
17 })
1 function getParams(req, res, cb) {
2 findBlog(req.params.id)
3 .then(function (blog) {
4 cb(null, {
5 user: req.session.user,
6 blog: blog
7 });
8 }, cb);
9 }
10
And there we have it. A nice access control setup that we can easily
reuse throughout our application.
. . .
Wrapping Up
In this post we looked at various access control methods and
debunked some common misconceptions along the way. You should
https://blog.nodeswat.com/implement-access-control-in-node-js-8567e7b484d1 24/26
9/8/2017 Implement Access Control in Node.js – Security and Node.js
In the future, you should know to avoid checking roles directly and
focus on operations instead. Also, I sincerely hope that you won’t
forget to add access checks where needed.
. . .
If you found this post useful and want a more thorough overview of
authentication, access control methods and other Node.js security
topics, I recommend you read my book Secure Your Node.js Web
Application: Keep Attackers Out and Users Happy
https://blog.nodeswat.com/implement-access-control-in-node-js-8567e7b484d1 25/26
9/8/2017 Implement Access Control in Node.js – Security and Node.js
https://blog.nodeswat.com/implement-access-control-in-node-js-8567e7b484d1 26/26