Custom authorization rules

Beyond the predefined authorization rules, new ones can be created to satisfy the special requirements of an application. A custom authorization rule must inherit the AuthorizationRule class. Each rule requires a descriptive and preferably unique name. The name identifies the rule in the collection of broken rules. The business-objects library follows the practice that the class name of the authorization rule is the name of the rule and the appended Rule string.

The parameters of the rule definition are passed in the constructor of the new rule:

  • action
    Required AuthorizationAction object.
    The action to be authorized.
  • target
    Required or optional depending on the action.
    Eventual parameter of the authorization action. See below.
  • arg1, arg2, ...
    Optional.
    Additional parameters required by the rule to authorize the current user.
  • message
    Optional string. The rule has to provide a default message.
    Human-readable description of the failure of the rule, or the key of the localizable description.
  • priority
    Optional integer. The default value is 100.
    The priority of the rule, greater number means higher priority. The authorization rules are evaluated in descending order of the priority.
  • stopsProcessing
    Optional Boolean. The default value is false.
    Indicates whether processing of the rules for a property stops when the rule fails.

The following table shows the possible values of the 'target' argument by actions:

Action Target Description  
fetchObject null -
createObject null -
updateObject null -
removeObject null -
executeCommand null -
executeMethod string The name of the custom fetch or execute method.
readProperty PropertyInfo The definition of the property the action relates to.
writeProperty PropertyInfo The definition of the property the action relates to.

If rule logic requires one or more additional parameters then their values shoul be stored in properties of the authorization rule object.

Each authorization rule has to be initialized in the constructor using the standard parameters.

The custom authorization rules has to override the execute() method of the base object. The logic of the authorization is implemented in that method. The method has one argument: the 'userInfo' object represents the current user. It inherits the UserInfo class. If authorization succeeds the method simply returns, otherwise it returns an AuthorizationResult object using result() method to indicate the failure of the authorization.

See API reference for the detailed description of AuthorizationRule's methods.

Example

The following example shows a custom authorization rule that ensures the age of the user is greater or equal than a specified value. The implemented user object should have an age property:

'use strict';

var util = require('util');
var bo = require('business-objects');
var UserInfo = bo.system.UserInfo;

function User (userCode, userName, email, age, roles) {
  User.super_.call(this, userCode);

  this.userName = userName;
  this.email = email;
  this.age = age;
  this.roles = roles;

  Object.freeze(this);
}
util.inherits(User, UserInfo);

User.prototype.isInRole = function (role) {
  return this.roles.some(function (userRole) {
    return userRole === role;
  });
};

module.exports = User;

For more information of how to implement a User class, see the User class page. Using this user object the creation of the IsAdultRule class is very simple:

'use strict';

var util = require('util');
var bo = require('business-objects');
var t = bo.i18n('', 'CustomRules');
var Argument = bo.system.Argument;
var AuthorizationRule = bo.rules.AuthorizationRule;
var RuleSeverity = bo.rules.RuleSeverity;

// Constructor of IsAdultRule class.
function IsAdultRule (action, target, ageLimit, message, priority, stopsProcessing) {
  // Define the name of the rule.
  AuthorizationRule.call(this, 'IsAdult');

  // Check and save the age limit.
  this.ageLimit = Argument.inConstructor('IsAdultRule').check(ageLimit)
      .forMandatory('ageLimit').asInteger();

  // Initialize base properties.
  this.initialize(
      action,
      target,
      message || t('isAdult', ageLimit),
      priority,
      stopsProcessing
  );

  // Immutable object.
  Object.freeze(this);
}
util.inherits(IsAdultRule, AuthorizationRule);

// Override execute() method.
IsAdultRule.prototype.execute = function (userInfo) {

  // Check argument.
  property = Argument.inMethod('IsAdultRule', 'execute').check(userInfo)
      .forOptional('userInfo').asType(UserInfo);

  // Determine entitlement.
  var hasPermission = userInfo && userInfo.age < this.ageLimit;

  if (!hasPermission)
    // Return a result object that indicates the failure of the rule.
    return this.result(this.message, RuleSeverity.error);
};

module.exports = IsAdultRule;

The default.json file in the directory of locales contains the default error message when the authorization fails:

{
  ...
  "CustomRules": {
    ...
    "isAdult": "You must be at least {0} year old to access this service.",
    ...
  },
  ...
}