Pro Tip: How to Seamlessly Move Cloud Rules Across Tenants

In any deployment, you will end up writing a couple of cloud rules that need to be sent to SailPoint Expert Services (ES) for uploading to your tenant.

Typically, we deploy to the sandbox tenant, test the rules, and then move them to the production tenant. Traditionally, this involved emailing ES to request the rule transfer across tenants.

However, there is a quick and easy alternative if you don’t want to wait for ES deployment in the next tenant. I will explain the sp-config API available for moving code across environments.

Many may not be aware that this API can also export and import deployed rules. The number of supported objects has increased since I last wrote my article.

This list is continually growing, but the main object we currently care about is RULE.

Here are the simple steps:

  • Get your rule approved and deployed into your sandbox environment
  • Export the rule from sandbox environment via sp-config 

  • Once exported, import the rule into the production environment. It will allow you to move rules so long as you don’t change it in transit or edit the JSON.

This method is great for moving rules across tenants. However, I still recommend deploying the rules via the normal process for consistency.

Tokenisation for Environments

When moving rules across environments, we often need to make changes because there are different values for variables, such as the AD OU structure that might be referenced. How can we make the process seamless, allowing you to copy and deploy the same rule without any changes in all environments?

Let’s go through each cloud rule type and see how we can solve this issue. Please note that this may not work for very complex rules but should be effective most of the time.

  • Generic Rule: These rules are always referred to via a transform, so the code inside is easy to maintain. Pass the variables via transform, which can remain the same across tenants.
  • Identity Attribute Rule: For example, LCS rules which uses source names to refer to attributes and retrieve their values. Keep the same source name across environments, ensuring that the backend source name remains consistent and can be referred to in the rule. This will also help in transform moves since source names they are referring to are same.
  • Manager Correlation / Correlation / Account Profile / Before Provisioning Rule: All of these rule types are attached to a source, which means they have an input of application class. Here’s what I typically do

Let’s say a Before Provisioning (BP) rule is created for the AD connector in the sandbox and needs to be moved to production. There might be some subtle changes in the rule between both environments, such as the AD Disabled OU

AD Dev Disabled OU: OU=Disabled,DC=abc,DC=dev,DC=local

AD Prod Disabled OU: OU=Disabled,DC=abc,DC=local

Rest all your logic may be similar but you need to change these between environments. To handle this, I use the following code within the rule

As you can see, I use the application.getId() method to retrieve the ID of the application the rule is attached to. Since we would have created the source in both the sandbox and production environments, you can obtain the ID via the /v3/sources API and set them accordingly. By knowing which environment my rule is attached to, I can then set the variables for AD_SOURCE and AD_DISABLED_OU (and other logics), allowing me to copy the same rule into both the sandbox and production environments.

This approach minimizes code maintenance for both environments and ensures that the same rule can be easily copied to both environments. As long as we have set the correct variables for each environment, our logic will work when tested in the sandbox and in production. This also eliminates the need to inject such values into the source JSON (an old method).

I hope this explanation makes sense and helps simplify your rule development, maintenance, and deployment across tenants.

Happy coding!!!

IdentityNow Rule Validator 3.0 + Generic Rules

As you may know, for IdentityNow Cloud Rules – they have to be submitted to SailPoint for upload to the tenant. We have a rule validator tool to validate IdentityNow rules for malformed or incorrect code fragments, and help make sure they conform to the SailPoint IdentityNow Rule Guide before rule submission.

We have had a great release of a brand new IdentityNow Rule Validator v3.0 (currently sitting on 3.0.23 at the time of writing). This is a major jump forward with mention in release notes (many more enhancements than what it states 🙂 ) 

  • BeanShell linter will now validate syntax and usage to help discover issues in your code before you deploy
  • A watch option which continually monitors and validate/lint  your code while you develop.


Please download and use the latest one when submitting rules for deployment otherwise you rule will get rejected for using the old version.

What I wanted to point out was that Generic Rules may start failing validation as it is doing much strict linting check for variables coming from transform which are not defined in the rule. You will need to add them to <Signature> tag for it to now pass validator.


You will see two inputs 

  • identity – this is the identity context which every cloud rule has access to but not predefined as input in the Generic Rule type.
  • identityEndDate – this is an input coming from a transform which is calling the rule

If I run this on the rule validator, it will fail with the following errors

As you can see – it couldn’t retrieve the definition for both the attributes 


You need to define them under the Signature XML tag so that the validator allows it through

As you can see the Signature tag is defined with Argument name and type. This will allow the rule validator to understand what they are. So the rule will now look like

Now the rule will pass

You are good to submit your rule now… 

Happy coding!!!

How to Search Non-Indexed Account Attributes in IDN Rules

Hey Folks!!!

Anyone well versed with IDN Rules will know that there has been some historic limitations on what attributes we can and can’t use for uniqueness search or for other such methods. We were generally tied to “Account ID” and “Account Name” attribute in each source which were indexed in the DB which could be used in rules to do so. 

Workaround till date had been to promote these attributes to an identity attribute and index them (which again had limitations of it own in terms on number of attributes and size of attribute).

Now we have a way to do this. Personally been involved with the product team and engineers in getting this shaped and delivered so a bit proud of this work. It is a great first start and will help you in doing so many use cases much simpler now. 

Lets take a use case and a walkthrough on how you can set this up

Use Case – I

We want to generate a new email address which must have a unique prefix (firstname.lastname@) by checking against the “mail”, “userPrincipalName”, “proxyAddresses” attributes across 3 x AD connectors. 

Note: Sources don’t have to be AD explicitly and can be virtually any source (AAD, ServiceNow, Okta, Workday etc) 


Now anyone who has worked with rules before would have known that this use case was not very easy to implement. You would have to promote these attributes, index identity attribute and then use it in the rule. Now we can create searchable attributes in the backend via API and use these in the rule. 

High Level Steps are

  • Identify Source ID and attributes
  • Create Searchable Attributes
  • Do an unoptimised aggregation if source already exists (like production tenant) to populate these searchable attributes.
  • Use new methods in rules to search for uniqueness

Identify Source ID and Attributes

Now we have 3 x AD source in our design. For each of them we need to get their sourceID. You can fetch them with an API call


  • {{api-url}}: This is your tenant URL in form of
  • {{source-id}}: This is the number you see in your browser URL when visiting the source via UI

In the response you will get an externalId with a value like 2c9180867745f3b10177469563be7451d

Gather the externalId for all three sources you want to build it for. 

Create Searchable Attributes

Now when you have all the SourceID’s we need to map and create searchable attributes. We will design 3 attributes (one for each – mail, userPrincipalName, proxyAddresses). It takes care of multivalued attributes as well (like proxyAddresses). The below table explains the design 

Search Attribute NameAccount AttributeSource IDSource Name
allMailAddressesmail2c9180867745f3b10177469563be7451dAD Source 1
2c9180867745f3b10177469563be7451eAD Source 2
2c9180867745f3b10177469563be7451fAD Source 3
allProxyAddressesproxyAddresses2c9180867745f3b10177469563be7451dAD Source 1
2c9180867745f3b10177469563be7451eAD Source 2
2c9180867745f3b10177469563be7451fAD Source 3
allUserPrincipalNamesuserPrincipalName2c9180867745f3b10177469563be7451dAD Source 1
2c9180867745f3b10177469563be7451eAD Source 2
2c9180867745f3b10177469563be7451fAD Source 3

Create each of the attribute via Create Search Attribute Config API

Similarly do it for other 2 attributes as well

Once all are created you can do a GET call to check all attributes

You should see all the above listed. 

Populate Searchable Attributes

Now if these are existing sources with accounts in them, simply do a once off unpotimized aggregation of each source via the following API call. 

Once done for all sources, the search attributes get populated in the backend. Currently you can’t check them with the UI or API calls. Any new accounts which get created after this or come as aggregation (delta or full) will automatically keep updating the search attribute. So once set, you don’t have to do anything. Also new account created is populated immediately. So no need of aggregation of it. So if you are creating multiple users in concurrent – uniqueness check will still capture the previous value calculated – no need to wait for aggregation.

Use New Methods in the Rules

Our IDNRuleUtil guide has been updated with few new methods. Two in particular which use these attributes are 

attrSearchCountAccounts(): This will be helpful to use for uniqueness search

attrSearchGetIdentityName(): This will be helpful in say a correlation rule. 

The link above has a bit more technical in-depth on what parameters are required by these methods and what is the return. But I will show you how to use the attrSerachCountAccounts() method in an example of uniqueness search. 

AttributeGenerator Rule

Will short type the logic what I have followed here. 

  • Create a list of 3 attributes with sourceID in them. This is required to pass the list to the new method.
  • Get the firstName and lastName from identity attribute, sanitise it and pass it to generateUniqueEmail() method
  • emailSuffix is also brought from identity attribute. This logic is already done via Transforms on what user email domain or suffix is suppose to be
  • In generateUniqueEmail() create a emailPrefix attribute and call isUnique() method.
  • isUnique() is where the magic happens
    • We are using StartsWith option (there is Equals also available). Reason being all the data coming from AD will be in some form of “[email protected], [email protected]”. We want to match “firstname.lastname@” only as we don’t care about exact match or equals match. Remember both are case-insensitive checks.
    • First check with proxyAddressSources in the idn.attrSearchCountAccounts() call
      • Here we have appended SMTP / SIP to do a startsWith check as we know that these are the known values we need to check in proxy address. We don’t have a contains. Also since its case-insensitive we don’t need to worry about camel casing or other such things. Data normally looks like “smtp:[email protected]” , “SIP:[email protected]”.
      • There are other such prefix found if proxyAddress attribute which we didn’t care about check but if your use case does, just add them and search as above.
      • If return == 0 means nothing is found, thus unique and move on to next check
      • Else isUnique == false and will return that value
    • Else check with upnSources source. Same logic as above
    • Else check with mailSources source. Same logic as above
      • If no account found here, isUnique is set to true and thus isUnique() has passed and the new email address is generated
    • If still a value is found, isUnique is set to false and thus isUnique() failed and new iteration starts
  • Max Iteration is set to 99 and then fail

Use Case – II

Rehire an account who comes back after 5 years with the same AD account. 


Now the account could be sitting as an uncorrelated account in IDN and we want to resurrect it. We can only search against the accountID or accountName as discussed previously and say if the correlating factor is employeeID which is not a part of either of these attributes.

Correlation Rule

  • We create an attribute like above called “allADEmployeeNumbers” and populate that with AD – employeeID (or whatever you may have)
  • We do an unoptimised aggregation to populate the search attribute
  • On an aggregation of an authoritative source, we have a correlation rule attached
    • It grabs the “employeeNumber” coming in from the source
    • Calls attrSearchGetIdentityName() to find that employeeNumber in the searchable attribute.
      • If found it returns an IdentityName of the cube and this can be used to correlate
      • If not found it returns an empty returnMap i.e. creates a new identity.
  • During design we took care of the following scenarios
    • It should return null if it found multiple names or no names. 
    • It should return one identityName even if multiple links were found but single identityName (i.e. say if you had multiple employeeNumbers in links but all are attached to cube). Like in a daisy chain scenario.


You can see the power of these new methods and how you can use them. Some of my thoughts here on possibilities. 

  • We can daisy chain them like above to search for multiple attributes in multiple sources as per your pattern.
  • We can use these for more attributes from accounts without the need to identity attribute creation and hitting limits on indexing.
  • Resurrections with attributes not indexed is also now pretty easy. 

Hope this really help you in your future implementations!!!

How to upload Connector Rules into IDN via API

So I did a post couple of days ago that now we are allowed to upload some rule types via API

Here is a quick guide on how to do so. In this example, I will take a very basic BuildMap rule

Previously we would submit the rule like above to ES team to upload. Now you just need to take the code and upload yourself.

Now the real trick – You need to escape the actual java code else you will not be able to upload it and postman will show errors.

So head down to and paste the code part of above. There are other such websites or can be some easier local method in your editor.

You will get some output like

Rest is then easy as per the API links

You should get a 201 Created and see a similar output

That is it. You should be able to see and use this rule now on your source. 

Please remember to follow the IDN Rule Guide on what is allowed and what is not.

And if you want you can reverse the process by getting existing rules via API, unescape it via the URL above and get the neat looking java code.

ProTip – Create Quick Postman Collection for IDN APIs

As you may already know we have a developer portal which is now the central repository for all public APIs for IDN (and other products). We all use Postman as a tool for using these APIs. Currently there isn’t an official Postman collection for SailPoint but you can easily build one from the developer portal via swagger imports. 

Quick guide on how to do so





  • Open Postman and click on File -> Import
  • Click on Upload File and select the previously downloaded swagger.json file

  • Click on Import

  • Once imported, you will have a collection of yours ready to go

Advance Tips: To make your life easier for administration, I highly recommend doing the following

Hope this help get you started in the API world with IDN & SailPoint.

%d bloggers like this: