LUSID controls access to data stored in LUSID using data policies.
You can write a data policy that restricts access to a particular entity in LUSID (such as a portfolio, instrument or person) using one of its identifiers.
As an alternative, for some types of entity (see below), you can write a data policy that restricts access using access metadata (AMD) that has been applied to that entity instead. This might make for a more dynamic entitlement system. Rather than relying on hard-coded attributes of real-world concepts that can change over time, you can base restrictions on attributes encoded within AMD that can be dynamically updated without rewriting existing data policies.
For more information on data policies, how they control access to LUSID in conjunction with feature policies, the order in which all your policies are evaluated, and current support for data policy checks, start with this explanatory article.
Current support for AMD
The following types of entity currently support AMD:
- Portfolios
- Portfolio groups
- Quotes
- Legal entities
- Persons
- Custom entities
We are working to extend support to other types.
How it works
AMD is associated with the identifier of an entity. You can write a data policy that controls access to a particular piece of data through the identifier associated with that AMD.
Note: This is especially useful for entities that support multiple identifiers such as persons. Access can be allowed via one of its identifiers but not other(s).
An AMD object consists of a metadataKey
mapped to an array of AccessMetadataValue
objects. The JSON schema is as follows:
{
"type": "object",
"additionalProperties":
{
"type": "array",
"items":
{
"$ref": "#/definitions/AccessMetadataValue"
}
},
"definitions":
{
"AccessMetadataValue":
{
"required":
[
"value"
],
"type": "object",
"properties":
{
"value":
{
"maxLength": 2048,
"minLength": 0,
"type": "string"
},
"provider":
{
"maxLength": 50,
"minLength": 0,
"type": "string",
"nullable": true
}
},
"additionalProperties": false,
"description": "An access control value. Provider should only be used if you are a service provide licensing data. In that case the provider value must match your domain."
}
}
}
For example, this AMD object for a portfolio has a metadataKey
of FundGroup
that is mapped to the fund groups FG1
and FG2
:
{
"FundGroup":
[
{
"value": "FG1",
"provider": "InternalSystem"
},
{
"value": "FG2",
"provider": "InternalSystem"
}
]
}
Applying and maintaining AMD for an entity
The following API endpoints are available for all types of entity that support AMD:
Operation | Description | Example API endpoint for portfolios |
Upsert AMD | Associate AMD with the identifier of an entity | UpsertPortfolioAccessMetadata |
Patch AMD | Patch AMD associated with the identifier of an entity | PatchPortfolioAccessMetadata |
Get all AMD | Get all AMD for an entity | GetPortfolioMetadata |
Get AMD by key | Get AMD associated with the identifier of an entity | GetPortfoliosAccessMetadataByKey |
Delete AMD | Delete AMD associated with the identifier of an entity | DeleteKeyFromPortfolioAccessMetadata |
Note that access control for applying and maintaining AMD can itself be set up separately.
Writing a data policy based on AMD
You can write a data policy based on AMD using metadata selectors (MetadataSelectorDefinition
). This is in contrast to a data policy based on identifiers, which use identifier selectors (idSelectorDefinition
).
A metadata selector allows for matching based on the AMD associated with an identifier. This matching is defined by one or more metadata expressions
. All expressions
in the same MetadataSelectorDefinition
must match (logical AND
) for the data policy to take effect.
The following expression operators can be used in MetadataSelectorDefinition
:
Expression operator | Description |
equals | Matches if textValue is equal to the AMD. |
notEquals | Matches if textValue is not equal to the AMD. |
in | textValue must be a comma-separated list of strings, for example FG1,FG2,FG3 . Matches if any of the textValue strings in the list are equal to the AMD. |
Metadata selectors only work with AMD. Matching of metadata selectors cannot be done on fields, properties, or other data associated with an entity.
Example 1
The following metadata selector matches when a user is attempting to read a portfolio where the array of AccessMetadataValue
objects associated with a metadataKey
of FundGroup
has at least one value of FG1
:
{ "metadataSelectorDefinition": { "expressions": [ { "metadataKey": "FundGroup", "operator": "equals", "textValue": "FG1" } ], "actions": [ { "scope": "default", "activity": "Read", "entity": "Portfolio" } ], "name": "matches-FG1-Portfolios", "description": "Grants read-only access to portfolios in FG1" } }
Example 2
The following metadata selector matches when a user is attempting to read a portfolio where the array of AccessMetadataValue
objects associated with a metadataKey
of FundGroup
has at least one value of FG1
and at least one other value of FG2
:
{ "metadataSelectorDefinition": { "expressions": [ { "metadataKey": "FundGroup", "operator": "equals", "textValue": "FG1" }, { "metadataKey": "FundGroup", "operator": "equals", "textValue": "FG2" } ], "actions": [ { "scope": "default", "activity": "Read", "entity": "Portfolio" } ], "name": "matches-FG1-and-FG2-Portfolios", "description": "Grants read-only access to portfolios in both FG1 and FG2" } }
Example 3
The following metadata selector matches when a user is attempting to read a portfolio where the array of AccessMetadataValue
objects associated with a metadataKey
of FundGroup
has at least one value of FG1
or FG2
:
{ "metadataSelectorDefinition": { "expressions": [ { "metadataKey": "FundGroup", "operator": "in", "textValue": "FG1,FG2" } ], "actions": [ { "scope": "default", "activity": "Read", "entity": "Portfolio" } ], "name": "matches-FG1-or-FG2-Portfolios", "description": "Grants read-only access to portfolios in both FG1 and FG2" } }