cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Best Practices: Active Directory Account Moves

Best Practices: Active Directory Account Moves

Overview

There are many reasons for a company to need to move Active Directory (AD) accounts to different organizational units (OUs).

On Termination: Move to a "Disabled Users" OU

Many clients have a designated OU to hold terminated users. One reason to do this is to set specific AD policies on that OU. For example, accounts may be in held this OU for 90 days before they are automatically deleted. Alternatively, some clients who have integrations with AD, such as Azure, may sync users only in a particular branch and exclude the "Disabled Users" OU. This approach allows flexibility to continue to manage the user accounts, but also remove them from the scope of other applications.

On Mover: Move to the Designated OU

In the past, it was a good policy to have separate OUs for logical distribution of users. For example, some clients have specific department OUs to logically group users in a single department together. Other clients who have many subsidiaries might have company-specific OUs. By separating users, it's easy to give granular AD policies to users based on an OU. More recently, Microsoft has other tools to accomplish this and it is now best practice to use a flat structure with a single OU.

Because many older customers have not migrated their directories to match Microsoft’s guidance, using multiple OUs is still a common and valid use case.

Technical Complexities

The OU that an account resides in makes up the latter part of a user's distinguishedName. The first part is usually the CN, or common name. For example, if the user's CN is "John Smith" and the parent OU is "Services" in the "Users" OU of acme.com, then the distinguishedName will be

CN=John Smith,OU=Services,OU=Users,DC=acme,DC=com

A user's distinguishedName MUST be unique in an AD domain. That is to say if there is another John Smith in the Services OU, it will need a separate CN. A typical approach is to use serialization and add a number, e.g.

CN=John Smith 2,OU=Services,OU=Users,DC=acme,DC=com

Any time an account needs to be moved, it will require a uniqueness check. Otherwise, there may already exist a duplicate user in the other OU. There can be a "John Smith" in the "Services" OU and one in the "Support" OU. If you move the one in the "Support" OU to "Services," then there will be a clash on the CN and the moved account will require a different name, such as CN=John Smith 2.

IdentityNow Specifics

In IdentityNow, the AD source uses distinguishedName as the Account Id, a unique identifier, so moving users in AD appears to the system like deleting and adding separate accounts. In addition, IdentityNow cannot simply update the distinguishedName since it is an AD identifier.

The connector has the ability to move AD accounts using two key attributes.

  • AC_NewParent - This is the new parent OU where the account will reside. Using the same example from above, "OU=Services,OU=Users,DC=acme,DC=com"

  • AC_NewName - This is the new CN value of the distinguishedName that the account will have. It is rarely necessary to set this value, as the CN normally stays the same during OU moves. However, if the new OU location would result in a distinguishedName value which is identical to another pre-existing Active Directory object, then setting AC_NewName can help resolve the conflict. For example, "CN=John Smith 2"

These attributes need to be added to the provisioning plan during a Modify/Enable/Disable operation in order to move the AD account.

After Moving the Active Directory Account

When the AD account is moved to a different OU, it is unlinked from the identity. Because IdentityNow utilizes the distinguished name to execute provisioning requests and the distinguished name has changed, a delta aggregation will not suffice to read and update the account. It is necessary to fully aggregate Active Directory to re-link the account to the identity. Any modifications (Attribute Sync, Access Request) executed after the account move will fail until a full aggregation is run and completed. Until the connector seamlessly updates the distinguished name in IdentityNow, ensure that your automated processes account for the delay. 

If any attribute synchronizations need to occur in addition to moving the account, utilize the BeforeProvisioning rule to set the attributes at the same time as the account move. That way additional attribute synchronizations will not be necessary on the account and no provisioning attempts will fail.

The BeforeProvisioning rule sample below is one way in which attribute sync requests can be included within the same plan as the OU move operation:

 

 

 

import sailpoint.object.ProvisioningPlan;
import sailpoint.object.ProvisioningPlan.AccountRequest;
import sailpoint.object.ProvisioningPlan.AccountRequest.Operation;
import sailpoint.object.ProvisioningPlan.AttributeRequest;
import sailpoint.object.Identity;
import sailpoint.tools.Util;
import sailpoint.object.Link;
import sailpoint.object.Application;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import sailpoint.rule.Account;
import sailpoint.rule.ManagedAttributeDetails;
import sailpoint.rule.RuleObjectFactory;

if (plan != null) {

    Identity identity = plan.getIdentity();
	String destinationOU = "OU=Disabled,OU=Users,OU=Corporate,DC=company,DC=com";
    
    List accountRequests = plan.getAccountRequests();
    if (accountRequests != null) {
        for (AccountRequest accountRequest : accountRequests) {
            String accountNativeIdentity = accountRequest.getNativeIdentity();
            if(accountRequest.getOperation().equals(ProvisioningPlan.AccountRequest.Operation.Disable)) {
                log.debug( "Operation is a Disable. We want to move OUs." );
                accountRequest.add(new AttributeRequest("AC_NewParent", ProvisioningPlan.Operation.Set, destinationOU));

                Account link = idn.getAccountByNativeIdentity("Active Directory [source]", accountNativeIdentity);
                Map acctAttrs = link.getAttributes();

                //Adding an attribute request for extensionAttribute5, which is being kept in sync with identity attribute departmentCode, if the two values aren't equal
                if(!acctAttrs.get("extensionAttribute5").toString().equals(identity.getAttribute("departmentCode").toString())) {
                    accountRequest.add(new AttributeRequest("extensionAttribute5", ProvisioningPlan.Operation.Set, identity.getAttribute("departmentCode").toString()));
                }
            }
        }
    }
}

 

 

 

Recommendations

SailPoint recommends the following when dealing with Active Directory account moves through IdentityNow:

Use a Unique Value for CN

When dealing with unique values in IdentityNow, the best place is via an attribute generator rule. These are found in the AccountCreate Profile. Since this is not available during updates (modify/enable/disable), it's best to use a unique value for the CN attribute. That way account moves are less likely to clash. Possible unique values include:

  • sAMAccountName—This is already guaranteed to be unique in the domain.

  • HR Unique Identifier like employeeId—This should be unique per person. However, this could be difficult if users have multiple accounts. Privileged accounts could use a format such as employeeId-p.

  • Other unique values could be generated using a string randomization process, UUID generation, etc.

For Movers, Utilize Attribute Sync Triggers

It's best to only move accounts when necessary. The simplest way to do that is to trigger off an AttributeSync event when one of the attributes used in the OU calculation changes.

Use Identity Attributes for Parent OUs

The best way to calculate where a user should be is in an identity attribute rule. That way you can manage the parent OU via transforms. One suggestion is to use two attributes:

  • activeParentOU—This is the OU for when the user is active. Use this in the Create profile and the Before Provisioning Rule when handling active user moves and rehires.

  • disabledParentOU—This is the OU for terminated users. Use this in the Before Provisioning Rule when handling terminations.

Use the Before Provisioning Rule Instead of Account Profiles

IdentityNow allows two avenues for adding AC_NewName and AC_NewParent to the provisioning plan: AccountProfiles (modify, enable, or disable) and the Before Provisioning Rule. AccountProfiles can be updated through the APIs. Before Provisioning Rules can only be updated through SailPoint Professional Services.

It is not recommended to go through the account profiles because attributes set there go through a verification stage after provisioning. Since AC_NewParent and AC_NewName are not read via the connector, they can never be verified. This results in “stranded” account activity entries within the IdentityNow tenant.

Take Lifecycle State into Account

Account moves are handled by specific use cases. Make sure to think through other use cases that could trigger provisioning to ensure the account move occurs appropriately. In particular, with the recent introduction of event-based attribute sync, take into consideration that identity refreshes can trigger due to upstream changes in incoming account data, and these refreshes run independently of lifecycle state transitions. This means that, if an OU move needs to occur due to both attribute sync and lifecycle state transitions, all modifications should be encapsulated within a single BeforeProvisioning rule and no alternative operations such as enable and disable should be configured for lifecycle state provisioning.

Example Configurations

Example Identity Attribute Transform for OU

Handling OU moves is easiest to handle using an identity attribute. That way you can reference the identity attribute rather than calculate in the rule. This allows updates to be handled by transform updates, which can be handled solely by administrators rather than rule updates which rely on SailPoint assistance.

The transform below is a simple example of setting the OU based on the user's department. This can be tied to the identity attribute "Active Parent OU" where "activeParentOu" is the technical name.

 

 

 

{
    "attributes": {
        "input": {
            "attributes": {
                "attributeName": "Department",
                "sourceName": "Employees"
            },
            "type": "accountAttribute"
        },
        "table": {
            "Services": "OU=Services,OU=Users,DC=example,DC=com",
            "Human Resources": "OU=HR,OU=Users,DC=example,DC=com",
            "Information Technology": "OU=IT,OU=Users,DC=example,DC=com",
            "Engineering": "OU=Engineering,OU=Users,DC=example,DC=com",
            "default": "OU=Default,OU=Users,DC=example,DC=com"
        }
    },
    "id": "Calculate AD OU",
    "type": "lookup"
}

 

 

 

Example Before Provisioning Rule

The following example represents how to use these suggestions in a single Before Provisioning rule to handle account moves. This rule handles:

  • Rehire use case

  • Move use case, in case of a department change

  • Termination use case

Note: This Rule does NOT account for uniqueness checks when moving the account. It assumes the CN is unique across the domain as recommended above.

 

 

 

import sailpoint.object.Identity;
import sailpoint.object.ProvisioningPlan;
import sailpoint.object.ProvisioningPlan.AccountRequest;
import sailpoint.object.ProvisioningPlan.AttributeRequest;
​
List accountRequests = plan.getAccountRequests();
​
if (accountRequests != null) {
    for (AccountRequest accountRequest: accountRequests) {
        AccountRequest.Operation op = accountRequest.getOperation();
        if(op == null) continue;
        String nativeIdentity = accountRequest.getNativeIdentity();
        Identity identity = plan.getIdentity();
        String currentLCS = null;
        String activeOU = null;
        String disabledOU = null;
        if(identity != null){
            currentLCS = identity.getAttribute("cloudLifecycleState");
            activeOU = identity.getAttribute("activeParentOu");
            disabledOU = identity.getAttribute("disabledParentOu");
        }
        
        boolean departmentChanged = false;
        if(op.equals(AccountRequest.Operation.Modify)){
            List dAttrReqs = accountRequest.getAttributeRequests("department");
            if(dAttrReqs != null && !dAttrReqs.isEmpty()){
                departmentChanged = true;
            }
        }
        String newOU = null;
        /*
            Get a new OU only if we are in 
                Rehire Use Case (Enable, user LCS is active and user was in the disabled OU)
                Mover Use Case (Modify and user LCS is active)
                Termination Use Case (Disable and user LCS is inactive)
        */
        if ("active".equals(currentLCS) && op.equals(AccountRequest.Operation.Enable)
            && disabledOU != null && activeOU != null && nativeIdentity.endsWith(disabledOU)){
            //Rehire Use Case
            newOU = activeOU;
        }
        else if ("active".equals(currentLCS) && departmentChanged && activeOU != null){
            //Mover Use Case
            newOU = activeOU;
        }
        else if("inactive".equals(currentLCS) && op.equals(AccountRequest.Operation.Disable)){
            //Termination Use Case
            newOU = disabledOU;
        }
        if(newOU != null && !nativeIdentity.endsWith(newOU)){
            //Account not currently in the proper OU. Put them there
            accountRequest.add(new AttributeRequest("AC_NewParent", ProvisioningPlan.Operation.Set, newOU));
        }
    }
}

 

 

 

Frequently Asked Questions

  • Can we handle account moves outside of IdentityNow?

    • Yes. Account moves can be handled outside of IdentityNow. However a full Aggregation must be run before any provisioning is processed through IdentityNow. Otherwise IdentityNow will think that the account is in one place and while it is really in another. This is true for account moves both from IdentityNow and outside of IdentityNow.

  • Can we use the attribute generator transform on an identity attribute to synchronize distinguishedName?

    • It is not recommended to use attribute generators in identity attributes. First, it would be a big performance hit. Second, due to the multi-threaded nature of IdentityNow's architecture, the uniqueness check at the identity attribute level is not guaranteed to return a unique value. Additionally, attribute generators use a source context that identity attributes do not have.

Labels (1)
Comments

Is there a reason for why we can't change the Account ID to another identifier, such as 'objectguid'? I believe this would resolve a lot of the complexities with handling account moves and will allow for delta aggregations.

@bostelmannper the July 2021 release notes:

The default native identifier for Active Directory applications has changed back to
distinguishedName. All new Active Directory applications created will have
distinguishedName as the native identifier. The use of objectGUID as the native
identifier introduced in previous patches introduced some usability and functional
limitations that will be corrected in a future release. The current recommended best
practice is to continue to use distinguishedName as the native identifier for Active
Directory applications. 

Hi, 

 

We have a strange situation where we need to enable account and move it to a different location. That we can handle based on the above in before provisioning rule but its not enabling the account as a password is needed to be set on the account before enabling. 

 

Is there a way to set a password on the account and then enable it sequentially i.e. modify the account to set the password and then call the enable operation on the account?

Many thanks for any prompt ideas. 

 

Regards,

Priyank

 

"The default native identifier for Active Directory applications has changed back to distinguishedName. All new Active Directory applications created will have distinguishedName as the native identifier. The use of objectGUID as the native identifier introduced in previous patches introduced some usability and functional limitations that will be corrected in a future release."

 

This is ridiculous.  Novell/NetIQ IDM used GUIDs for (their version of) nativeIdentity >15yrs ago.  Using DN, then requiring an agg (and not even a targeted/single-user agg, it has to be a full aggregation) is the most short-sighted thing I've ever seen for a Gartner "Magic Quadrant" product.  I was so excited to hear at Navigate '22 that this was being addressed... now I'm heartbroken.

 

Maybe I can try modifying the 'move' rule to modify the nativeIdentity value on the app link... but shouldn't have to.

Would this still be the best practice after the 8-14-23 update??

 

Connectivity (CB-DIR 6.1 ) - Active Directory

CONETN-4261

The Active Directory connector now instantly returns the Resource Object to IdentityNow on any OU changes done by the AC_New Parent, which can be further utilized to any rule to work with the updated Resource Object data values.

@mdeavers I second this.  Currently refactoring rehires for a customer and we need some clarity on the current best practice

Version history
Revision #:
11 of 11
Last update:
‎Oct 05, 2023 09:58 AM
Updated by: