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:

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. 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

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

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:

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

Spatial restriction example
{
    ...
    "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.

Project filter in the response of the User Information Service
{
    "data": {
        "projectFilter": ["PROJECT in ('Project1','Project2')"]
        ...
    }
}
Usage of filters in feature restrictions
{
    ...
    "restrictions": {
        "project_features_only": {
            "type": "feature",
            "query": "${user.projectFilter;insecure}"
        }
    }
}