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.
In the example above, a service provides the projects attribute.
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
trueconnections 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. For example, references to string attributes in comparisons must be enclosed in single quotes.
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.
Use the "insecure" flag to allow attribute values that are not SQL literals.
Restriction examples
In the following example, user attributes are used to restrict access to features based on their PROJECT_ID field.
Users can only access a feature if the value of PROJECT_ID is found in the list of values of the user attribute projects:
{
...
"restrictions": {
"project_features_only": {
"type": "feature",
"query": "PROJECT_ID in ${user.projects}"
}
}
}
You can also use user attributes when defining spatial restrictions.
In the following case, the allowed area of a spatial restriction is defined based on the value of the user attribute securityLevel:
{
...
"restrictions": {
"sales_area_only": {
"type": "spatial",
"featuretypeurl": "https://gis.example.com:6443/arcgis/rest/services/RestrictedArea/FeatureServer/0",
"featurequery": "SECURITY_LEVEL_MIN <= ${user.securityLevel}"
}
}
}
In the following example, the User Information Service returns a projectFilter that is used as a query expression in a feature restriction.
As described in the section User attributes, security.manager NEXT checks whether a user attribute is valid for use in a query expression.
The attribute user.projectFilter is marked as insecure in the feature restriction project_features_only and is therefore taken over unchanged into the feature restriction without being checked.
{
"data": {
"projectFilter": ["PROJECT in ('Project1','Project2')"]
...
}
}
{
...
"restrictions": {
"project_features_only": {
"type": "feature",
"query": "${user.projectFilter;insecure}"
}
}
}