Skip to main content

Customizing authorization

Tasks​

Both authorization and authentication will run via NS tasks. Authorization is divided into data Authorization and task Authorization. Alternative implementations of these tasks can be provided as custom code by adding a file account.ns.properties to the resources folder in the logic layerLayerLogical separation of functionality within a single system/application, focused on code organization. of any component:

authentication.implementation=com.example.AuthenticationImpl
authorization.data.implementation=com.example.DataAuthorizationImpl
authorization.task.implementation=com.example.TaskAuthorizationImpl

AuthenticationTask​

The authenticationTask runs on the input-projectionProjectionA tailored subset of fields on a DataElement designed to encapsulate data for a specific technical or functional view. of the dataElement User of the account component. This projectionProjectionA tailored subset of fields on a DataElement designed to encapsulate data for a specific technical or functional view. 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)

By default, the account component uses the implementation in net.democritus.acl.AuthenticationImpl. It 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.

DataAuthorization task​

By default the account component uses the implementation in net.democritus.acl.DataAuthorizationImpl. This implementation defaults to an "allow-all" policy and queries the DataAccess element where exclusions can be defined (see Authorization). 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 CRUDs operations and also contains the rights to each command. UserContext is known in the task.

An improved and more secure implementation is now also available, but is not the default for backwards compatibility. For more information see configurable task implementations.

TaskAuthorization task​

By default the account component uses the implementation in net.democritus.acl.TaskAuthorizationImpl. It works similar to the DataAuthorization task. 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)

An improved and more secure implementation is now also available, but is not the default for backwards compatibility. For more information see configurable task implementations.

Configurable task implementations​

An additional task implementation is available that will default to a deny-all policy and requires the definition of rights in the DataAccess component to enable them. They can also be reconfigured to use an allow-all policy instead, similar to the default implementation by setting the ParamTargetValue (name: defaultAccessRights, target: default) to value allowAll.

The new implementation can be enabled with the following account.ns.properties file:

authorization.data.implementation=net.democritus.acl.ConfigurableDataAuthorizationImpl
authorization.task.implementation=net.democritus.acl.ConfigurableTaskAuthorizationImpl

Control-layer​

Authentication​

The authentication is no longer directly validated in the control layerLayerLogical separation of functionality within a single system/application, focused on code organization., but via the task in the logic layerLayerLogical separation of functionality within a single system/application, focused on code organization.. This task will return the userContext which is then stored in the session in the control-layerLayerLogical separation of functionality within a single system/application, focused on code organization..

Authorization​

The existing AccessInfoRetrieverAction is modified to request the Authorization via the DataAuthorizationTask and the TaskAuthorizationTask. 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 fieldsFieldA property of a DataElement expanded to a database column and user interface input element.. 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)
)
});

Logic-layer​

The logic layerLayerLogical separation of functionality within a single system/application, focused on code organization. can also validate whether the user has rights. This is done by using the 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");
}

AuthorizationManager

The AuthorizationManager is a custom class in the logic-layerLayerLogical separation of functionality within a single system/application, focused on code organization. of the account component. It is used in the generated code of the useLogicSecurity option and it can be used in your custom code. The purpose of this class is to know if the logged in user is authorized to perform a certain task or command or is authorized to use a CRUD-operation.

Caching​

The dataAccessRights and taskAccessRights are cached in the userContext. Therefore, The AuthorizationManager will first look into this cache to see if there is already some accessRights present. If not, it will perform the authorizationTask again.

Methods​

In the constructor of the AuthorizationManager you provide the data- or taskElement used for the authorization and the usercontext which contains information of the logged in user. This info is needed for the 3 public methods defined in the AuthorizationManager.

  • public boolean isDataAuthorized (DataAccessFunctionality dataAccessFunctionality): DataAccessFunctionality is an enumeration of the possible CRUD-operations which describes which CRUD action the user is attempting. It returns whether or not the logged in user has permission to perform the given CRUD action on the dataElement provided in the constructor.
  • public boolean isDataAuthorized (String commandName): This method can be used to query if a user is authorized to perform a certain command on the dataElement provided in the constructor.
  • public boolean isTaskAuthorized (): This method can be used to query if a user is authorized to perform the task given in the constructor.