Writing permissioning rules in Java

Rules define which permissions are required in order to perform an operation. A single rule may determine that many permissions are required. A single operation may trigger many rules - each of which may require many permissions. In this context an 'operation' means any user interaction with the Liberator.

When does a rule fire?

When one of the Liberator's Streamlink clients sends a contribution to the Liberator, all known rules in the system are checked for applicability. Applicability is determined by comparing the subject of the RTTP message and the message fields to a rule subjectNameMatch and fieldMatchCriteria, respectively. All rules that are applicable are then fired to see if the operation should be permitted or not.

When one of the Liberator's Streamlink clients sends a request to the Liberator, an implicit rule that requires the user to have the VIEW permission in the default permissionNamespace for the requested subject. This implicit rule is hardcoded into the Permissioning Auth Module so no rule should be created for this.

The criteria that determine rule applicability are:

  1. First, the subjectNameMatch, which may be a regexp pattern or exact string value, is compared to the incoming RTTP message subjectName. If they do not match, the rule will not fire for this incoming message. If they match, we move on to the next step.
  2. Next the fields from the incoming message are checked against the fieldMatchCriteria. For the fieldMatchCriteria to match the incoming message fields, all mappings present in the fieldMatchCriteria must also be present (and map to the same value) in the incoming message fields. The operation may contain additional field mappings and these have no affect on the match. If fieldMatchCriteria is empty or null then the operation fields are not required to have any specific keys or values and in that case only the subjectNameMatch is required to match for the rule to be deemed applicable.
Note: If no rules are applicable, then the operation is not permitted.

Example of a rule firing

An example of a message being received and which rule is matched is given below.

RTTP Client message sent to Liberator:

>CONTRIB /FT/TRADE?MsgType=Execute&Trading-Type=SPOT&Amount=1000000&ISIN=12345

The rule described in the following table fires on contributions to RTTP subjects matching /FT/TRADE and it requires the RTTP client User to be permitted for the SPOT-TRADE action in the TradePermissions permissionNamespace for the product extracted from the contribution field ISIN.

Rule
Field Value
SubjectNameMatch /FT/TRADE
FieldMatchCriteria Trading-Type=SPOT
Type WRITE
ProductRef ASIN
ActionRef -
Type WRITE
PermissionNamespace

TradePermissions

Action SPOT-TRADE

This rule matches because of the following reasons:

  • It is a contribution message, which is a WRITE type
  • The subject being contributed to is /FT/TRADE, which matches the subjectNameMatch
  • The message field Trading-Type=SPOT matches the fieldMatchCriteria

This rule requires the User to have the SPOT-TRADE permission in the TradePermissions permissionNamespace for the product 12345 as the value of the contributed ISIN field is 12345.

The effect of firing a rule

A fired rule will provide input to the permissioning check for the operation the user is performing. If the user has all the permissions needed for the rules fired for the operation, then the user will be permitted to perform the operation. If the user is lacking one or more of the required permissions, then the user will not be permitted to perform the operation.

The permissioning-check-input that is returned by the rule firing will be a permissionNameSpace, an action, and a product. The purpose and meaning of these terms is as follows:

  • PermissionNameSpace: scopes the permissions that are applied to Users and Groups. A permission resides in a specific permissionNameSpace and the firing rule dictates in which permissionNameSpace the required permission must be in order that the user is permitted.
  • action: the permission that user must have in the given permissionNameSpace in order that they will be permitted to perform the operation.
  • product: this is typically a financial instrument. Users' (and Groups') permissions must also be associated with a product, thereby allowing the system to allow certain operations and deny others based upon the product involved in the operation. For example: the system can be configured to allow SPOT-TRADE for, say, /FX/GBPUSD and deny if they tried the same operation on a different financial instrument, say /FX/GBPJPY.

How a rule derives the input for the permissioning check

The permissioning check will verify that the user has a permission with the same action in the same permissionNameSpace for the product as those determined by a firing rule.

The permission (a triplet of product, action and permissionNameSpace) that the user is required to have for in order for the operation to complete (be permitted) is derived in one of a number of ways depending on how the rule has been set up. Before talking about how a rule derives which permission is required it may be useful to clarify the concepts of permissionNameSpace, product and action.

Permission Name Spaces

permissionNameSpaces provide scope for applying and, thus, checking permissions. They can be used by the system configurer in any way they see fit to divide permissions into natural or logical groupings that help them to manage the system in a way appropriate to them. Typically one might use them to permission different facets of an operation. For example; the TradeType permissionNamespace might be used to hold trade-type oriented permissions (such as "SPOT-TRADE", "SWAP-TRADE", etc) while the Tenors that a user is allowed to use on the trade operation may reside in a Tenor permissionNameSpace that has been created soley for tenors. In such a scenario one would expect one rule to require the user to have the trade permission in the TradeType permissionNameSpace and another rule (independently to the first rule) to require the User to have a Tenor permission (the value of which will be implied by the fields of the operation message) in the Tenor permissionNameSpace.

Products and ProductRefs

The product is derived in one of a number of ways depending on the rule's productRef (which may never be null):

  • If productRef is the special value Constants.ALL_PRODUCTS: any product is matched in the permission check, so only the action and permissionNameSpace will determine if a permission matches this rule.
  • If productRef is any other non-null value: it is the name of the field where the product string will be found in the operation fields.
  • If productRef is not Constants.ALL_PRODUCTS, then a field mapping that is keyed by productRef must exist in the operation fields in order that the operation may be permitted. Furthermore, the value mapped to by the productRef field will be the product that the permission must be applied for. So, in order to be permitted, the user must have the action permitted in the permissionNameSpace for the product extracted from the operation fields by the productRef.

Actions and ActionRefs

As indicated above, a rule will dictate the permissionNameSpace in which the user must have the action permitted, the action that must be permitted for the user will be determined in one of the following ways, depending on how the rule is constructed:

  • if the rule is created with the one of the PermissioningDataSource.createActionRefRule methods: the action parameter will be interpreted as a field name from where the action to be permitted can be read from the incoming operation fields (in a way similar to the way the productRef is found in the operation fields). That is, the parameter action string is the name of a field that must contain the action that the user must be permitted for. If such a rule fires and the field mapping does not exist then the user will not be permitted to perform the operation.
  • if the rule is created with the one of the PermissioningDataSource.createActionRule methods: the action parameter will be interpreted as the explicit action to be permitted. That is, the fields are not used to derive the action - the rule dictates the action that the user must be permitted for.

Furthermore, as stated previously, all of the User's permission reside in permissionNameSpaces and the firing rule will determine in which permissionNameSpace the User's permission must be. If the user is permitted for the action in the same permissionNameSpace that the rule requires then the user will be permitted to perform the operation. If the user in permitted for the action in a different permissionNameSpace then (unless they're also permitted in the required permissionNameSpace) they will not be permitted to perform the action. That is, permissionNameSpaces isolate the scope of rules and permissions applicability.

In the example above the permissioning check will use the action SPOT-TRADE in the permissionNameSpace TradePermissions and product 12345 (matched from the ISIN field in the message) to look up whether the user is authorised in the hierarchy of Users and Groups.

Ensuring rules are enforced

It is essential that the fieldMatchCriteria, productRef or actionRef include field references or mappings that are mandatory for the action to be performed by the back-end system (e.g Trading System). If this is not true an action may be allowed by the permissioning auth module which should be denied. An example of not enforcing a rule is given below.

RTTP Client message sent to Liberator:

>CONTRIB/FT/TRADE?MsgType=Execute&TRADING-TYPE=SPOT&Amount=1000000&ISIN=12345

Rules configured:

SubjectMatch FieldMatch ProductRef Type Action
/FT/TRADE TradingType=SPOT, Side=Buy ISIN WRITE BUY-SIDE-SPOT-TRADE
/FT/TRADE null ISIN WRITE TRADE

In this example only one rule fires because the rule for the action BUY-SIDE-SPOT-TRADE does not fire as the rule does not find the field mapping SIDE=Buy in the contribution fields. This field mapping was required by the rule fieldMatchCriteria.

In this scenario the Trading System should always check to see if the fields SIDE and TRADING-TYPE exists and reject the message if only one of these fields exists, thereby defending itself against such malconfiguration of the permissioning system or malformed RTTP messages (the problem in this case being that it was desired that both rules fire). This (the external system, or its integration, mandating both fields be present) also defends against rogue trading client applications attempting to be allowed to perform actions that the user should not be permitted to do by sending messages deficient in some field mapping (so causing one of the rules not to fire).


See also: