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:

Example request to a User Information Service
{
    "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):

Example response from a User Information Service
{
    "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.

Configuration example
{
    "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:

Disable globally enabled extension
{
    "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

OWNER = '${user.email}'

Number

LEVEL_MIN <= ${user.level}

Boolean

ACTIVE_ONLY_STRING = '${user.enabled}'

Array

PROJECT_ID IN ${user.projects}

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

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:

Feature restriction sample
{
    ...
    "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.

Spatial restriction sample
{
    ...
    "restrictions": {
        "sales_area_only": {
            "type": "spatial",
            "featuretypeurl": "https://gis.example.com:6443/arcgis/rest/services/RestrictedArea/FeatureServer/0",
            "featurequery": "SECURITY_LEVEL_MIN <= ${user.securityLevel}"
        }
    }
}