restify-role-based-auth

1.0.11 • Public • Published

restify-role-based-auth

Is a role-based authorization middleware for Restify API applications. This middleware allows you to manage the authorization of all requests to your Restify API through the use of an Unix-style access control list also known as an ACL. In the API's ACL you define the roles that users belong to, the resources (URL paths) those roles have permissions to access, and the HTTP methods that can be used on said resources.

This Authorization Middleware is meant to be used in conjunction with an Authentication Middleware such as Passport.

Installation

You can add restify-role-based-auth as a dependency through NPM

 
$ npm i restify-role-based-auth --save
 

in your project require restify-role-based-auth

 
// Using default configuration
const roleBasedAuth =  require('restify-role-based-auth')();
 

or GitLab

$ git clone git@gitlab.com:graphicnetdesign/restify-role-based-auth.git

copy the lib folder to your project, rename it to restify-role-based-auth, and then require index.js

 
const roleBasedAuth =  require('./restify-role-based-auth/lib/index');
 

Usage

ACL Policy Definition + Requirements

The Access Control List or ACL is an array of Policy objects which make up the access rules by which the API will be bound. The ACL is a single file written in the JSON syntax and must adhere to the following rules:

  • root of the file must be an array
  • array must contain at least one policy object
  • policy objects are JOSN objects each containing the folloing properties:
    • 'role' a String that identifies the user role to which the policy is to be applied
    • 'action' a String that specifying whether the policy is 'allow'ing or 'deny'ing the 'permissions' in the policy
    • 'permissions' an Array of permission objects each containing the following properties:
      • 'resource' a String that identifies the resource route being protected
      • 'methods' an Array of Strings that identifies all of the HTTP verbs that are being protected on the identified resource route

Example

[
  {
    "role": "user",
    "permissions": [{
      "resource": "users",
      "methods": [
        "POST",
        "GET",
        "PUT"
      ],
      "action": "allow",
    }]
  }
]
 

ACL File + Writing Policies

First step is to create your ACL file, name it acl.json and place this in the config folder in the root of your application. This is the file where you will define all of the role policies that restrict or give access to certain resources within your application.

This middleware will iterate through the ACL in an attempt to match:

  1. the authenticated user's role with a role in one of the ACL's policies
  2. the resource requested (the URI path in the HTTP request) with a resource in one of the permissions objects in the policy
  3. the HTTP method from the request with a method in the methods array within the permission object

If all matches can be found the action in the policy is then checked:

  1. if allow, the middleware will call next() and allow the application to move to the next middleware in the middleware stack
  2. if deny, the middleware will call next() passing it a restify-errors UnauthorizedError with either the default message or the error message supplied in the config object

In the example below, we are:

  • allowing the admin role the rights to all resources (routes) and all methods (HTTP verbs) within the API. This is done through the use of the * (wildcard symbol), we want admins to be able to do anything
  • denying the user role the rights to call the POST method (HTTP verb) on the user resource (route), we do not want logged in users to create more users

Example

 
[
  {
    "role": "admin",
    "permissions": [{
      "resource": "*",
      "methods": "*",
      "action": "allow"
    }]
  }, 
  {
    "role": "user",
    "permissions": [{
      "resource": "users",
      "methods": [
        "POST"
      ],
      "action": "deny"
    }]
  }
]
 

Proper Middleware Placement

This middleware depends on each Restify request object having an authenticated user object already attached to it by an authentication middleware like Passport.

The middleware looks for a user object on the restify req object like this req.user. Keep in mind, with the generic use of hasOwnProperty on the user object, you are required to attach a POJO (plain old JavaScript object) to the req object at the point of authentication by your authentication middleware (such as passport). If you attach a complex object, such as a Mongoose model object, this middleware will not be able to find the role(s) property on that user object.

The middleware looks for req.user with a role or roles property that is either a single role as a String or an Array of multiple String roles respectively, from which it can grab the current user's role(s) for verification within the ACL policies list.

This means that the call to server.use(roleBasedAuth()); must come after your call to your authentication middleware or custom code that authenticates the user and adds a user object to the current request.

Example

  // Passport using middleware using passport-jwt strategy
  // attaches a user object to the request if successful
  // authentication occurs
  server.use(passport.initialize());
 
  // restify-role-based-auth middleware depends on the user 
  // obect and its role property
  server.use(roleBasedAuth);
 

Customize Middleware

The restify-role-based-auth middleware function can take two parameters:

  • config object with custom values for available configuration properties
Middleware require + invocation signature

require('restify-role-based-auth')([config])

Configuration Object

When requiring the middleware into your application you have the opportunity to use either the default or a custom configuration object.

Default: the middleware will use presets and expects to find your acl.json file in the config folder at the root of your application (./config/acl.json).

  • config object's properties:
    • aclFilename: the name of the ACL Policy file (default: acl.json)
    • aclPath: the file path to the folder containing the ACL Policy file (default: ./config)
    • baseApiUrl: the base URL of the API the middleware is protecting, prepended to all Policy protected resources (default: /)
    • errorMessage: the message to be returned with the 401 Unauthorized Error

Using a custom configuration, in the example below, the middleware will look for your ACL file at the path ./security/custom.json

Example: Custom Config

 
const customConfig = {
    aclFilename:   'custom.json',
    aclPath:       './security',
    baseApiUrl:    '/api',
    errorMessage:  'You are not authorized to access this resource'
};
 
const roleBasedAuth =  require('restify-role-based-auth')(customConfig);
 

Error Response Object: 401 Unauthorized

By default, the middleware will utilize the restify-errors library when determining an error to use and return to the API caller.


## Other Features

### Unless to Bypass
In order to maintain the highest security possible, this middleware takes the lockdown approach, 
that is it blocks all resources (routes) to begin with and only allows resources to be accessed 
if-and-only-if that resources has a defined policy with in the ACL Policy file.

This of course, means that even your authentication resources are locked down, making it so that 
users cannot login or register for the API. To mitigate this effect, the middleware utilizes the 
[express-unless](https://github.com/jfromaniello/express-unless/blob/master/README.md) package 
to allow you to unlock certain resources without the need to setup crazy policies in your ACL. 


```js

const openResources = {
    path: [
      {
        url: '/auth', 
        methods: [
          'POST'
        ]
      },
      {
        url: '/auth/login', 
        methods: [
          'POST'
        ]
      }
    ]
  };

server.use(roleBasedAuth).unless(openResources);

Debug

This middleware supports debug mode through the use of the debug NPM module. Please refer to debug's documentation for turning on and off debugging and adjusting environment variables.

Through the use of debug, the middleware allows you to pull output for all execution paths with the middleware or for specific portions of execution using the following named debug groups.

All namespaced debug statements will be prefixed with 'RRBA:' for easy identification of debug output originating from this middleware.

Debugging can be activated by setting the DEBUG environment variable at application startup.

In development

 
DEBUG=* node your-apps-index.js
 

On a server, such as staging or production, you can use a NPM package like dotenv to manage the loading of your environment variables based on the current environment using a .env file placed at the root of your application.

Debug Key Description
* All output from the entire middleware as it executes
RRBA:processors:authorizationProcessor output from only the Authorization Processor
RRBA:index output from only the root of the middleware

Package Sidebar

Install

npm i restify-role-based-auth

Weekly Downloads

4

Version

1.0.11

License

MIT

Unpacked Size

110 kB

Total Files

31

Last publish

Collaborators

  • schleichermann