Authorization & Authentication

This document describes the current implementation of authorization and authentication. The logic of the previous version of authentication and authorization was implemented in the control layer. Now, these implementations have been delegated to Tasks in the logic layer so that it can also be enforced in other layers. For example, with an option, the authorization can also be enforced in the logic layer.

The model

The current model in the PR as well as the XML model allows applicationUsers, applicationProfiles and applicationUsergroups to create, edit, delete and view certain dataElements. In the new implementation, we added commands and tasks as well.

Furthermore, the option [“useLogicSecurity”] (/component/options/useLogicSecurity) can be enabled at component level. This will ensure that logic layer security will be generated. The security in the view and control layer are now always generated in each component.

Tasks

Both authorization and authentication will run via NS tasks. Authorization is divided into data Authorization and task Authorization. These tasks can be used as usual in the custom code.

AuthenticationTask

The authenticationTask runs on the input-projection of the dataElement User of the account component. This projection contains name and password. This task will fail if the authentication fails. Otherwise, this task will return an (extended) UserContext as resultClass. This UserContext is an extension to the existing BasicUserContext.

public TaskResult<UserContext> perform(ParameterContext<UserInput> targetParameter)

Currently there are two AuthenticationTask Implementations. One goes to the database for the userData from the account component and will check the (encrypted) password. This will return an extendedUserContext with profile and usergroups. The second uses Jaas to authenticate. The LoginModule used can be configured in the usual way (via code or via config). This will add the Jaas Subject to the userContext so that it can be used. This can be extended with other implementations in the future. The implementation of this task can be configured based on the paramtargetValue

DataAuthorizationTask

This task runs over the query projection of DataAccess. This projection consists of element and an optional field. In this element represents the DataElement. The DataAccessRights will be obtained for this element. This contains the rights to view, modify, delete, create and the rights for each command for the element. The perform method of this task looks like this:

 public TaskResult<DataAccessRights> perform(ParameterContext<DataAccessQuery> targetParameter)

DataAccessRights is an extension to ProfileAccessRights. This distinguishes between modify and create and also contains the rights to each command. UserContext is known in the task. If this is the new extended UserContext, this will also contain the Subject of JAAS so that this can also be used in a possible implementation.

TaskAutorizationTask

The TaskAuthorizationTask works the same way. Hereby we get TaskAccessRights back that show whether or not the user is allowed to perform the task.

 public TaskResult<TaskAccessRights> perform(ParameterContext<DataAccessQuery> targetParameter)

Control-layer

Authentication

The authentication is no longer directly validated in the control layer, but via the task in the logic layer. This task will return the userContext which is then stored in the session in the control-layer.

Authorization

The existing AccessInfoRetrieverAction is modified to request the Authorization via the DataAuthorizationTask and the TaskAutorizationTask. This is cached in the session per task- or dataElement. Here, too, the functionalities are always validated against the accessRights, so that they are only executed if there are rights for that action.

Front-end

UI

The existing access-rights.js is modified and is extended with accessrights for commands and fields. For commands, the rights are added per command in the actions. These can then be used to keep the buttons in the frontend:

var AccessRights = require('nsx/config/access-rights');
var accessRightsController = AccessRights.getAccessRightsController();
var actionRightsRequest = accessRightsController.requestRight({
  element: CarElement,
  requestedRight: AccessRights.Right.ACTION,
  target: input.commandName
});
...
toolbar.defineButton({
  trigger: trigger,
  icon: "icon-file",
  label: input.commandName,
  visible: ifBoth(
    actionRightsRequest.approved,
    isDataRefDefined(input.selection)
  )
});

Old UI

The nsx-profile-access has been extended with the taskAccessRights, as can be seen in the following example: Furthermore, the jsonResult of the dataAccess will also contain the commandAccessRights.

var dataUrl = nsxApplication.getApplicationUrl() + "/account/getProfileAccessRights-json";
var taskUrl = nsxApplication.getApplicationUrl() + "/accouont/getTaskAccessRights-json"

/*
  callback: function(jsonResult)
 */
function getDataAccessRightsForElement(element, callback) {
    var data = {
        component: element.getComponentName(),
        element: element.getElementName()
    };

    $.get(dataUrl, data, callback);
}
/*
 callback: function(jsonResult)
*/
function getTaskAccessRightsForElement(element, callback) {
    var data = {
        component: element.getComponentName(),
        element: element.getElementName()
    };

    $.get(taskUrl, data, callback);
}

Logic-layer

The logic layer can also validate whether the user has rights. This is done by using the [“useLogicSecurity”] (/component/options/useLogicSecurity) component option.

An example of the generated code in the TaskBean perform method:

DataAccessQuery dataAccessQuery = new DataAccessQuery();
dataAccessQuery.setElement(taskName);
AuthorizationManager authorizationManager = new AuthorizationManager(dataAccessQuery, userContext);
if (!authorizationManager.isTaskAuthorized()) {
    return TaskResult.error(Diagnostic.error("testComponent","CarTask", "NO_ACCESS"));
}

taskResult = mImplementation.perform(targetParameter);

An example of the generated code in the DataBean create method:

DataAccessQuery dataAccessQuery = new DataAccessQuery();
dataAccessQuery.setElement(elementName);
AuthorizationManager authorizationManager = new AuthorizationManager(dataAccessQuery,userContext);
if (!authorizationManager.isDataAuthorized(DataAccessFunctionality.CREATE)) {
   return getDiagnosticHelper().createCrudsError("not authorized");
}

An example of the generated code in the DataBean performCommand method:

DataAccessQuery dataAccessQuery = new DataAccessQuery();
dataAccessQuery.setElement(elementName);
AuthorizationManager authorizationManager = new AuthorizationManager(dataAccessQuery,commandParameter.getUserContext());
if (!authorizationManager.isDataAuthorized(commandName))) {
 return CommandResult.error(command, "not authorized");
}

dataAccess population

It was already possible to populate the application dataAccess from the accessRights configured in the PrimeRadiant. This functionality is extended with commands and tasks. Furthermore, the “edit” functionality is split into “create” and “modify”.

References