Rate this page

Searching for resources

A SCIM search request involves three elements:

  1. The base search path. This designates a resource type that constrains the scope of the search. It may be a SCIM resource type (e.g., /scim/v2/Users) or a sub-resource type (e.g., /scim/v2/Users/{userId}/sessions). It may not be a specific SCIM resource (e.g., /scim/v2/Users/{userId}).
  2. A filter. The search filter constrains the results of the query to those resources matching an attribute value asserted by the filter.
  3. Pagination controls. Pagination parameters can be used to split a large number of search results into multiple result sets.

Let’s get right to an example before going over the details.

Filter filter = Filter.and(
    Filter.ew("emails.value", "example.com"), // ew == "ends with"
    Filter.eq("name.familyName", "Lem") // eq == "equals"
);

ListResponse<GenericScimResource> result =
    scimService.searchRequest("Users")
        .filter(filter.toString())
        .page(1, 1) // (Pagination start index, results per page)
        .attributes("name", "emails")
        .invoke(GenericScimResource.class);

System.out.println("Total results: " + result.getTotalResults());
for (GenericScimResource matchingResource : result.getResources()) {
  System.out.println(matchingResource.getStringValue("name.givenName"));
}

What does this example do?

  • It builds a search filter: emails.value ew "example.com" and name.familyName eq "Lem"
  • It searches for any matches under the “Users” resource type. If there are any matches, one result will be returned with the attributes name and emails The return type will be GenericScimResource.
  • Prints out information from the search result.

Filters

A search filter typically takes the form <attribute> <operator> <value>. For example:

filter=userName eq "pkd"

filter=attribute operator value

Operators are listed in the SCIM API reference.

As with everything else in SCIM, attributes must be prefixed with a schema URN if they do not belong to the resource type’s core schema.

Another form of search filter is a complex filter. This takes the form <complex attribute>[<simple filter>]. For example:

filter=name[givenName eq "Philip"]

This example means: Find resources where the name attribute has the sub-attribute givenName with a value of “Philip”.

The Filter class

When using the SCIM 2 SDK, filters can either be specified as strings or built using the Filter class. The Filter class provides various static methods corresponding to filter operators; you build search filters by nesting method calls. A few examples should make this clear.

The following performs an equality search for the userName attribute and a specific value:

Filter.eq("userName", "slem")

The following performs a ‘starts with’ search for the name.givenName attribute and a specific string:

Filter.sw("name.givenName", "Stan")

And the following uses the and operator to combine the above two searches:

Filter.and(
  Filter.eq("userName", "slem"),
  Filter.sw("name.givenName", "Stan")
)

Complex filters are specified using the hasComplexValue(...) method. The following expression is equivalent to the filter emails[name eq "slem@example.com"]:

Filter.hasComplexValue(
  "emails",
  Filter.eq("value", "slem@example.com")
)

Caveats

If you’re accustomed to RDBMS query languages like SQL, SCIM filters may take you by surprise. A SCIM search expression acts strictly as a filter. Given a base resource type, it filters out any non-matching resources — it does not offer the ability to join data across related but distinct resources, for example.

Another difference is that SCIM search results are returned by resource, not by value. Let’s explain this with an example. Say that you search using the filter emails[type eq "work" and value ew "work.com"]. This means give me any resources with an emails attribute of type “work” and a value that ends with “work.com”. The search result will include any resources that match this filter, and each resource will include all email address values, not just those with type “work”.

Pagination

A client may request that the server segment search results into pages. Pagination is handled using the following search parameters:

Parameter Description
startIndex The 1-based index of the first query result.
count A non-negative integer specifying the maximum number of matching resources to return per page.

A client can get the total number of matches for a particular filter without actually downloading a result set by specifying a count of 0.

ListResponse<GenericScimResource> result =
    scimService.searchRequest("Users")
        .filter(filter.toString())
        .page(1, 0) // (Pagination start index, results per page)
        .attributes("name", "emails")
        .invoke(GenericScimResource.class);

System.out.println("Total results: " + result.getTotalResults());
// result.getResources() will be empty.

Authorization

The kind of scope that you need to perform a search varies depending on what you’re searching.

  • If you are searching across resource types, then you should use a resource scope.
  • If you are searching sub-resources belonging to the logged in user, then you should use an authenticated identity scope.
  • If you are searching sub-resources across all users, then you should use a resource scope.

All other considerations of scope configuration apply, of course. For example, you will need to set a resource-operation value of “search”.

Let’s look at some concrete examples.

The following scope grants the ability to search for any user.

dsconfig create-oauth2-scope \
  --scope-name search_users \
  --type resource \
  --set "consent-prompt-text:Search the Users resource type." \
  --set scim-resource-type:Users \
  --set resource-operation:search \
  --set resource-operation:retrieve \
  --set 'resource-attribute:*'

The following scope grants the ability to search for consent records belonging to the currently authenticated user.

dsconfig create-oauth2-scope \
  --scope-name search_current_user_consents \
  --type authenticated-identity \
  --set "consent-prompt-text:Search and read your OAuth 2 consent data." \
  --set scim-sub-resource-type:Consent \
  --set resource-operation:retrieve \
  --set resource-operation:search \
  --set 'resource-attribute:*'

The following scope grants the ability to search for consent records belonging to any user.

dsconfig create-oauth2-scope \
  --scope-name search_user_consent \
  --type resource \
  --set "consent-prompt-text:Search all OAuth 2 consent data." \
  --set scim-resource-type:Users \
  --set scim-sub-resource-type:Consent \
  --set resource-operation:retrieve \
  --set resource-operation:search \
  --set 'resource-attribute:*'