4.2.4 • Published 3 months ago

cidaas-interceptor-nodejs v4.2.4

Weekly downloads
4
License
ISC
Repository
-
Last release
3 months ago

About cidaas:

cidaas is a fast and secure Cloud Identity & Access Management solution that standardises what’s important and simplifies what’s complex. The cidaas feature set includes:

  • Single Sign On (SSO) based on OAuth 2.0, OpenID Connect, SAML 2.0
  • Multi-Factor-Authentication with more than 14 authentication methods, including TOTP and FIDO2
  • Passwordless Authentication
  • Social Login (e.g. Facebook, Google, LinkedIn and more) as well as Enterprise Identity Provider (e.g. SAML or AD)
  • Security in Machine-to-Machine (M2M) and IoT

Installation

npm install cidaas-interceptor-nodejs --save

Check your package.json to verify the changes.

Breaking Changes

Since version 4.0.0 please make sure that you are not cross-validating tokens from different domains pointing to the same cidaas instance. By design, it should not be possible to validate tokens which were issued by the same instance from domain A against domain B. This was possible earlier when pointing to the same cidaas instance with different CNames and running the interceptor in local mode only.

Instead of using interceptorConfig.use_local_validation & interceptorConfig.use_local_validation_async in the global interceptorconfiguration, we introduced the validation_procedure property. With this it is now more easy to switch between the three different validation procedures: offline, bulk_introspect & introspect. See Configuration for more detailed information. It is still possible to overwrite this behaviour per route like before Options

Usage

Cidaas Interceptor can be used in Express or Fastify

IntrospectLocal
Authorization of scopesYesYes
Authorization of rolesYesYes
Authorization of groupsYesNo

More information about this table can be found at the advanced section

Configuration

The configuration of the interceptor will be same for Express and Fastify

import { CidaasInterceptor, CidaasInterceptorConfig } from "cidaas-interceptor-nodejs";

let interceptorConfig = new CidaasInterceptorConfig();

// add your cidaas base url to dicover the urls for you. It will internally discover the URL from <cidaas-base-url>/.well-known/openid-configuration
interceptorConfig.baseUrl = "https://<cidaas-base-url>";
// The tenantKey of your cidaas instance 
interceptorConfig.tenantKey = "your-tenantkey";
// The key path to the keyfile used to decrypt a JWE token. Only needed if a JWE token is expected
interceptorConfig.privateKeyPath = "";
// If a JWE token is expected, but there is no privateKeyPath which can be configured, the private key needed to decrypt the token needs to be given here
interceptorConfig.privateKey = "";
// Configure client_id and client_secret, This client must be a non-interactive client 
interceptorConfig.client_id = "your client id";
interceptorConfig.client_secret = "your client secret";
/** 
 * The validation procedure to be used globally for all routes. Can be overwritten by the more specific CidaasOptions configurable for each route. 
 *   Set to 'offline' per default - here the server will check the token signature, expiry_time, baseUrl, scopes & roles. This is the fastest method available.
 *   Note: It is not entirely offline, as the service will need to fetch the JWKs to be able to validate the token signatures. 
 *   
 *   When set to 'bulk_introspect', a local validation will be executed, but the token will be stored in a list, which will be periodically sent to cidaas to validate. 
 *   This validation is done async and the interceptor will not wait for the result. Because of this, this is as fast as the offline mode.
 *   But it also means it will not have any impact on the access decision - if the introspect validation in the backend fails, access has already been granted.
 *   It will however give insights into the usage of the tokens, which will be used by the fraud detection system if enabled.
 *   
 *   'introspect' executes a real-time check and queries the Backend System, so it is the most secure check which can be executed.
 *   This check can also catch revoked access tokens. But as it needs to query cidaas and wait for the result, it is also the slowest option available.
 */
interceptorConfig.validation_procedure = "offline";

//Create the cidaas interceptor with the config
cidaas_interceptor = new CidaasInterceptor(interceptorConfig);

//Or update its config later
cidaas_interceptor.setConfig(interceptorConfig);

Express js

var express = require('express');
var app = express();
var bodyParser = require("body-parser");
    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({
        extended: true
    })
);

Check Scope

app.get("/serviceurl", cidaas_interceptor.checkAccess({ scopes: ["cidaas:write"] }), function (req, res) {

// your code

});

Check Role

app.post("/serviceurl", cidaas_interceptor.checkAccess({ roles: ["Admin"] }), function (req, res) {

// your code

});

Check Group

app.post("/serviceurl", cidaas_interceptor.checkAccess({ groups: [{groupId : "mygroup"}]}), function (req, res) {

// your code

});

Check Role and Scope

app.get("/serviceurl", cidaas_interceptor.checkAccess({ scopes: ["cidaas:write"], roles: ["Admin"] }), function (req, res) {

// your code

});

DenyAll

app.get("/serviceurl", cidaas_interceptor.checkAccess({denyAll : true}), function (req, res) {

// your code

});

PermitAll

app.get("/serviceurl", cidaas_interceptor.checkAccess({permitAll : true}), function (req, res) {
 
// your code
 
});

Or just ignore the inceptor code

app.get("/serviceurl", function (req, res) {
 
// your code
 
});

Fastify

In Fastify, you have to register your routes to an express router.

const router = require('express').Router()
    router.get("/write", async (request: any, reply: any) => {
      reply.status(StatusCodes.OK).send({ status: "success" }
    )})
    router.get("/delete", async (request: any, reply: any) => {
        reply.status(StatusCodes.OK).send({ status: "success" }
    )})

Then register fastify-express and then add the interceptorOptions to your routes. This allows for different accessConfigurations for each route.

var fInstance = require("fastify")
await fInstance.register(require('fastify-express'))
.after(() => {
    fastify.use(
      "/write",
      cidaas_interceptor.checkAccess({
          scopes: ["write"],
          use_local_validation : true,
          interceptorConfig: interceptorConfig
      }))
    fastify.use(
        "/delete",
        cidaas_interceptor.checkAccess({
            scopes: ["delete"],
            interceptorConfig: interceptorConfig
      }))
    fastify.use(router)
})

Complete server.js example with configuration:

const fastify = require("fastify")({
  logger: true
});

let interceptorConfig = new CidaasInterceptorConfig();

// Add your cidaas base url to dicover the urls for you. It will internally discover the URL from <cidaas-base-url>/.well-known/openid-configuration
interceptorConfig.baseUrl = "https://<cidaas-base-url>";

 // use_local_validation : enables the offline token validation, which will improve performance.
interceptorConfig.use_local_validation = true; 

// use_local_validation_async: enables the transfer of locally validated tokens to the bulk-introspection endpoint
interceptorConfig.use_local_validation_async = true; 

//Create the cidaas interceptor with the config
global.cidaas_interceptor = new CidaasInterceptor(interceptorConfig);

//Or update its config later
global.cidaas_interceptor.setConfig(interceptorConfig);

//declare  routes on express router
const router = require('express').Router()
    router.get("/write", async (request: any, reply: any) => {
      reply.status(StatusCodes.OK).send({ status: "success" }
    )})
    router.get("/delete", async (request: any, reply: any) => {
        reply.status(StatusCodes.OK).send({ status: "success" }
    )})

// instantiate fastify
var fInstance = require("fastify")

//register fastify-express plugin and add interceptorOptions to the routes
await fInstance.register(require('fastify-express'))
.after(() => {
    fastify.use(
      "/write",
      cidaas_interceptor.checkAccess({
          scopes: ["write"],
          use_local_validation : true,
          interceptorConfig: interceptorConfig
      }))
    fastify.use(
        "/delete",
        cidaas_interceptor.checkAccess({
            scopes: ["delete"],
            interceptorConfig: interceptorConfig
      }))
    fastify.use(router)
})

// Run the server!
fastify.listen(3000, function(err: any, address: any) {
  if (err) {
    fastify.log.error(err);
    process.exit(1);
  }
  fastify.log.info(`server listening on ${address}`);
});

The usage of the parameters for the fastfy interceptor are exactly the same as with the express examples

Advanced

Config

The interceptorconfig contains the basic information for the interceptor to work. The interceptorconfig can contain the following options:

KeyDescriptionDefaultRequired
base_urlThe base URL of the cidaas instance.-Yes
tenantkeyThe tenantkey of the cidaas instance.-Yes
privateKeyPathThis property is needed if the use_local_validation property is set to true in order to decrypt a JWE token. Here the path to the keyfile has to be given.-Depending on validation procedure
privateKeyThis property is needed if the use_local_validation property is set to true in order to decrypt a JWE token if privateKeyPath is not set. Here a key has to be given.-Depending on validation procedure
validation_procedureThe validation procedure to use. Either 'offline', 'bulk_introspect' or 'introspect'offlineNo

Options

The interceptor options can be different for each route. The interceptor options can contain the following keys:

KeyDescriptionDefaultRequired
interceptorConfigThe base URL of the cidaas instance.nullYes
use_local_validationIf set to true, the interceptor will validate locally. Local mode will check the signature, expiry time, scopes, roles. If set to false, the interceptor will validate with Introspect. Introspect will perform an online validation which checks if the token is in the DB of cidaas, expiry time, scopes, roles and groups.falseNo
use_local_validation_asyncIf set to true, the interceptor will validate locally with an async bulk_introspect. Bulk_introspect will perform the offline validation and stores the requested access tokens in a cache. Periodically, a part the of requests will be sent to cidaas for the fraud detection. Requires use_local_validation to be truefalseNo
rolesDefines the roles that the interceptor will check for in the token.-No
scopesDefines the scopes that the interceptor will check for in the token.-No
groupsDefines the groups that the interceptor will check for in the token.-No
strictScopeValidationPlease check this section.falseNo
strictRoleValidationPlease check this section.falseNo
strictGroupValidationPlease check this section.falseNo
strictValidationPlease check this section.falseNo
denyAllDenies access to this route no matter which authorization.falseNo
permitAllAllows access to this route no matter which authentication.falseNo
Further explanation about the strict validation feature:
  • strictValidation, if true at least one scope, role and group of the access_token has to match your annotations.
  • strictScopeValidation, if true all scopes of the access_token have to match your annotations.
  • strictRoleValidation, if true at all roles of the access_token have to match your annotations.
  • strictGroupValidation, if true at all groups of the access_token have to match your annotations.
  • if none of these is set and at least one type is given, at least one scope, role, group of the access_token has to match your annotations.
  • if no scopes, roles and groups annotations are given no further checks will be performed except validity and expiry time of the token.

Note:
If an anonymous (client credential grant) token is passed to an API which is secured by strict validation which requires scopes, roles and groups, only the scopes will be matched. For any client credential grant token, there is no user who could be part of any group or who has any role set.
This way it is possible to secure the same API by user roles, groups and scopes and still be able to consume it with any backend server which does have the required scopes.

custom group validation

Make sure to set the interceptor to online / introspect mode, if you want to validate against custom groups.

For validating groups, the following entity can be passed as an array to specify the groups check:

GroupValidationEntity {
    groupId: string;
    groupType: string;
    roles: string[];
    strictRoleValidation: boolean;
    strictValidation: boolean;
}

Check Role in custom group

app.post("/serviceurl", cidaas_interceptor.checkAccess({ groups: [{groupId : "mygroup", roles: ["Admin"]}]}), function (req, res) {

// your code

});

When strictRoleValidation is enabled for a group check, the token has to have all specified roles in the group. Also, the groupId and the groupType have to be specified in the interceptoroptions

app.post("/serviceurl", cidaas_interceptor.checkAccess(
       {
         groups: [{
           groupId : "mygroup",
           groupType : "customers", // The groupType can be applied to any cidaas group. For more info, see in the cidaas docs.
           roles : ["myrole1","myrole2"]
           strictValidation : true, // The given groupId 'mygroup' must be of type "customers"
           strictRoleValidation: true // The user must have 'myrole1' & 'myrole2' inside the group 'mygroup' to get access.
       },
       {
           groupId : "secondgroup",
           roles : ["myrole1"]
       }],
         strictGroupValidation: true // Both group validations must be successful to get access. If false, if either of the group validations is succeful the user will get access
       }), function (req, res) {

// your code

});
4.2.4

3 months ago

4.2.3

4 months ago

4.2.2

1 year ago

4.2.1

1 year ago

4.2.0

1 year ago

4.1.0

1 year ago

4.0.1

2 years ago

4.0.0

2 years ago

3.0.0

3 years ago

2.4.0

4 years ago

2.3.2

5 years ago

2.3.1

5 years ago

2.3.0

5 years ago

2.2.4

6 years ago

2.2.3

6 years ago

2.2.2

6 years ago