How To

How do I configure specific managed objects to be case insensitive in IDM/OpenIDM (All versions)?

Last updated Apr 18, 2019

The purpose of this article is to provide information on making specific objects (such as user name or email) case insensitive to avoid duplicates being created where the name is the same but the case differs.


Background information

IDM/OpenIDM is case-sensitive. This can cause issues with search (where valid entries are not found due to their case) and also with duplicate objects being created. The search issue is addressed in the documentation: Integrator's Guide › Configuring Case Sensitivity For Data Stores and this article addresses the issue with duplicate objects.

This article provides a process which:

  1. Updates the object (user name in this example) so it is stored in lower case to ensure all entries are stored consistently.
  2. Adds a new policy that tests uniqueness by first converting the entry to lower case before doing the comparison.

Once these changes are implemented, any new or updated entries will be checked and stored in this way to prevent duplicates. However, existing entries for this object will not be affected, so you will need to convert them to lower case to ensure lower case comparisons are meaningful.

If you store email in lower case, you will encounter issues with the self-service password reset functionality where accounts cannot be found if users enter their email in mixed case. See Converting incoming password reset requests for further information.

Finding duplicate entries

If you already have duplicate entries, it is recommended you use the REST API to search for all users and look for duplicates (using SQL queries to search the repository is not recommended because userName is stored in many tables). Once you have identified duplicate entries, you can manually clean up the data. This example command is looking for duplicate userNames and uses  jq on the command line to prettify the result (you can install jq as outlined in Download jq or just exclude | jq. from the command): 

$ curl -X GET -H "X-OpenIDM-Username: openidm-admin" -H "X-OpenIDM-Password: openidm-admin" "http://localhost:8080/openidm/managed/user?_queryFilter=true&_fields=userName,mail" | jq . | sort | grep userName

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  1299    0  1299    0     0   4723      0 --:--:-- --:--:-- --:--:--  4723
      "userName": "bjensen@example.com",
      "userName": "BJENSEN@example.com",
      "userName": "user001",
      "userName": "USER001",
      "userName": "jdoe",
      "userName": "JDoe",
Note

Migrating and cleaning up old data is outside the scope of ForgeRock support; if you want more tailored advice, consider engaging Professional Services.

Configuring objects to be case insensitive

The following process updates the userName object to be case insensitive; the same concept can be used with other objects:

  1. Define a new uniqueLC policy in the policy.js file (located in the /path/to/idm/bin/defaults/script directory) to perform a lower case comparison for uniqueness:
    1. Add the following definition below the existing unique policyId in the policies definition section:
              {   "policyId" : "uniqueLC",
                  "policyExec" : "uniqueLC",
                  "policyRequirements" : ["UNIQUE_LC"]
              },
      
    2. Add the following function below the existing policyFunctions.unique function in the policies function section:
          policyFunctions.uniqueLC = function(fullObject, value, params, property) {
              var queryParams,existing,requestId,requestBaseArray;
              if (value && value.length) {
                  queryParams = {
                      "_queryFilter": property + ' eq "' + value.replace(/"/g, '\\"').toLowerCase() + '"'
                  };
      
                  requestId = resourceName.leaf();
                  existing = openidm.query(resourceName.parent().toString(), queryParams);
      
                  if (existing.result.length !== 0 && (!requestId || (existing.result[0]._id != requestId))) {
                      return [{"policyRequirement": "UNIQUE"}];
                  }
              }
              return [];
          };
      
  2. Update the object in the managed.json file (located in the /path/to/idm/conf directory) to use this new policy by replacing the unique policy with uniqueLC, for example:
                        "userName" : {
                            "description" : "",
                            "title" : "Username",
                            "viewable" : true,
                            "searchable" : true,
                            "userEditable" : false,
                            "policies" : [
                                {
                                    "policyId" : "uniqueLC",
                                    "params" : { }
                                },
    
  3. Update managed.json to store the object (userName in this example) in lower case in the repository by adding the following code to onStore:
                "onStore" : {
                    "type" : "text/javascript",
                    "globals" : { },
                    "source" : "if (typeof object.userName != "undefined" && object.userName != null) { object.userName = object.userName.toLowerCase();}"
                },
    

Converting incoming password reset requests

When a password reset request is submitted, a query is run to search for the user by email. If you store emails in lower case, you will also need to convert incoming password reset requests to lower case to prevent accounts not being found if users enter their email in mixed case.

The following process enables you to convert the email received in the incoming request to lower case to ensure it matches stored emails:

  1. Create a script (called submitEmail.js in this example) to convert the query string for email to lower case. For example:
    if (request.method == "action" && request.action == "submitRequirements" && request.content.input.queryFilter.indexOf("mail eq ") === 0) {
        request.content.input.queryFilter = request.content.input.queryFilter.toLowerCase();
    }
    
  2. Add the following block to router.json (located in the /path/to/idm/conf directory) to call this script when the request is made:
        {
          "pattern": "selfservice/reset",
          "onRequest": {
            "type": "text/javascript",
            "file": "script/submitEmail.js"
          }
        }
    

The query string for email will now be converted to lower case for all incoming requests that go through the router.

See Also

FAQ: Installing and configuring IDM/OpenIDM

FAQ: Scripts in IDM/OpenIDM

Installation Guide › Configuring Case Insensitivity For a JDBC Repository

Integrator's Guide › Configuring the Default Policy for Managed Objects

Related Training

N/A

Related Issue Tracker IDs

OPENIDM-6657 (Describe how to handle case sensitivity for queries)



Copyright and TrademarksCopyright © 2019 ForgeRock, all rights reserved.
Loading...