Extensions
The policy format of security.manager NEXT allows it to configure extension points to extend the capabilities of policies.
User Information Service Extension
security.manager NEXT already allows to reference username and roles of the requesting user as user attributes in restrictions. But in some situations you might want to define restrictions based on other user attributes that are available in some component of your system like an LDAP. Maybe users are assigned to projects or grouped by some other organizational attribute and you would like to define a restriction like this:
{
...
"restrictions": {
"project_features_only": {
"type": "feature",
"query": "PROJECT_ID in ${user.projects}"
}
}
}
The User Information Service extension defines a REST API for services that the SOI can use to fetch additional attributes of a user.
By providing such service you can define policies that rely on additional user data like the projects
attribute in the example above.
The service interface also allows implementors to return a set of extra roles for a user.
These are then added to the list of regular roles that a user already has, based on ArcGIS Enterprise role or group assignments.
In the same way as with regular roles you can reference the extra roles in a policy’s "roles"
array to bind policies to them.
REST Service API
A User Information Service is an additional infrastructure component that you have to provide. It must implement the API specification described in the OpenAPI format.
API overview
When the extension is enabled for a policy, the SOI will send a POST request to the configured URL with every incoming user request.
The posted data looks like this:
{
"userId": "gisuser1",
"anonymous": false,
"roles": ["editor", "authenticated"]
}
Based on this data the User Information Service implementation decides which data to return.
If successful the response contains a single "data"
property that enumerates all additional user attributes (and roles):
{
"data": {
"projectIds": ["project_a", "Project_b"],
"activeUser": true,
"securityLevel": 42,
"roles": ["x-role-department-a", "x-role-department-b"]
}
}
For a complete reference, please visit the API specification .
Implementation considerations
When the extension is enabled for a map service, the SOI will request the User Information Service with every user request. Currently, there is no caching of user data implemented in the SOI itself. As requesting the service consumes time that adds to the overall request time the user experiences, it is in the responsibility of the User Information Service implementor to make sure that the service responds in a timely manner.
Sample implementation
A sample implementation of the interface is available on GitHub.
It demonstrates the integration of user data
-
based on an LDAP service, and
-
based on a JSON file.
The sample implementation only serves for illustration purposes and may not be suited for productive deployments. You can, however, use it as a starting point for your custom solution.
Extension configuration
To reference additional data about a user from a User Information Service in a policy, you need to configure it in the policy’s "extensions"
section.
The configuration consists of the following properties:
url
-
URL of the User Information Service that provides additional user information.
enabled
(optional)-
Activates or deactivates this extension.
If set to
false
, additional user attributes are not fetched.Default:
true
insecure
(optional)-
Accept or reject insecure HTTPS connections to the User Information Service.
If set to
true
connections using certificates that are not issued by a trusted CA are accepted.Default:
false
headers
(optional)-
A list of static HTTP header fields that will be sent to the User Information Service.
This property allows to transmit security tokens if required by the service. Make sure to use HTTPS for the User Information Service URL when transmitting sensitive information.
{
"policies": [...],
...
"extensions": {
"userInfoService": {
"url": "https://localhost:3333/userinfo-json/fetch",
"enabled": true, // optional
"insecure": false, // optional
"headers": { // optional
"Authorization": "Bearer 123"
}
}
}
}
Alternatively, when using the CLI with a policies working directory, you can configure the User Information Service extension globally. This way you don’t have to repeat the configuration in every policy file. If you do both, a local configuration inside a policy file overrides the global configuration.
You can disable a globally enabled User Information Service extension for a protected service by using the following configuration in the service’s policy file:
{
"policies": [...],
...
"extensions": {
"userInfoService": {
"enabled": false
}
}
}
Referencing user attributes
User attributes returned by the User Information Service can be Strings, booleans, numbers, or arrays of these. When referencing attributes in query expressions you need to respect the type of the attributes. The following table shows how to use attributes of different types:
Type | Example |
---|---|
String |
|
Number |
|
Boolean |
|
Array |
|
When an error occurs while fetching user attributes, the policy enforcement will be interrupted. As a consequence, the map server request will be denied.
Restriction examples
The following example restricts feature access to features where the PROJECT_ID
field value is an element of the "projects"
array that was returned by the User Information Service for the requesting user:
{
...
"restrictions": {
"project_features_only": {
"type": "feature",
"query": "PROJECT_ID in ${user.projects}"
}
}
}
In the following example, user attributes are used as part of a spatial restriction to define the area a user is allowed to get data for.
The allowed area consists only of those geometries, where the SECURITY_LEVEL_MIN
is smaller than or equal to the securityLevel
user attribute returned by the User Information Service.
{
...
"restrictions": {
"sales_area_only": {
"type": "spatial",
"featuretypeurl": "https://gis.example.com:6443/arcgis/rest/services/RestrictedArea/FeatureServer/0",
"featurequery": "SECURITY_LEVEL_MIN <= ${user.securityLevel}"
}
}
}