Disable Account in Source triggers Modify but needs to go through Disable

I am currently working on a JDBC provisioning rule along with provisioning policies where the “Disable Account” action on an individual account in the Source needs to disable it. Due to having an UPDATE provisioning policy active for Role changes, disabling is using that instead of its own DISABLE provisioning policy, thus sending fields through that are unwanted. This is causing the “Disable Account” action to use the Modify operation in my rule instead of the Disable operation.

Base database columns: userId, role, active, modifiedDate, currentDate.
Where active = 0 is disabled, active = 1 is enabled.

Two situations should disable the account:

  1. When a role is removed from the account (logic in my provisioning rule).
  2. When the “Disable Account” action is selected on the connector source.

Two situations should enable the account:

  1. When a role is added to the currently disabled account.
  2. When the “Enable Account” action is selected on the connector source.

Disable provisioning policy

{
    "name": "Disable Account",
    "description": null,
    "usageType": "DISABLE",
    "fields": [
        {
            "name": "userId",
            "transform": {
                "type": "identityAttribute",
                "attributes": {
                    "name": "identificationNumber"
                }
            },
            "attributes": {},
            "isRequired": false,
            "type": "string",
            "isMultiValued": false
        }
    ]
}

Update provisioning policy

{
    "name": "Update Account",
    "description": null,
    "usageType": "UPDATE",
    "fields": [
        {
            "name": "userId",
            "transform": {
                "type": "identityAttribute",
                "attributes": {
                    "name": "identificationNumber"
                }
            },
            "attributes": {},
            "isRequired": false,
            "type": "string",
            "isMultiValued": false
        },
        {
            "name": "active",
            "transform": {
                "type": "static",
                "attributes": {
                    "value": true
                }
            },
            "attributes": {},
            "isRequired": false,
            "type": "boolean",
            "isMultiValued": false
        }
    ]
}

Due to the inclusion of the “active” field in the UPDATE provisioning policy, the “Disable Account” action goes through UPDATE instead of DISABLE, which causes it to also send “true” through, thus leaving the account to remain enabled. However, while getting rid of the UPDATE provisioning policy resolves that issue since “Disable Account” would actually use the DISABLE provisioning policy, my logic in my provisioning rule where adding a role should re-enable an account does not fully function since the “active” field is not sent through. The role updates, but the “active” status does not. Keeping the UPDATE provisioning policy but removing the hardcoded active field attribute also fails, since SailPoint does not see the addition of the previously held role as a delta, and thus no provisioning plan is generated to provision the change to the active status.

Sanitized code snippet of the Modify operation.

          } else if (AccountRequest.Operation.Modify.equals(account.getOperation())) {

            try {
              log.error("=====PROVISIONING : EXECUTING MODIFY OPERATION=====");

              Integer nativeIdentity = Integer.parseInt(account.getNativeIdentity());
              // Check for current DB roleId
              log.error("=====PROVISIONING : CHECKING CURRENT ROLE=====");
              statement = connection.prepareStatement("SELECT role FROM app.user WHERE userId = ?");
              statement.setInt(1, nativeIdentity);
              ResultSet checkResults = statement.executeQuery();

              // Check SELECT query results
              String currentRoleId = "";
              while(checkResults.next()) {
                currentRole = checkResults.getString(1); // getting column index 1
                log.error("=====PROVISIONING : CURRENT ROLE: " + currentRole);
              }

              statement = connection.prepareStatement("UPDATE app.user SET role = ?, active = ?, modifiedDate = CURRENT_TIMESTAMP WHERE userId = ?");
              statement.setInt(3, nativeIdentity);

              activeStatusStmt = connection.prepareStatement("UPDATE app.user SET active = ?, modifiedDate = CURRENT_TIMESTAMP WHERE userId = ?");
              activeStatusStmt.setInt(2, nativeIdentity);


              if (account != null) {
                AttributeRequest roleAttrReq = account.getAttributeRequest("role");
                AttributeRequest activeAttrReq = account.getAttributeRequest("active");
                log.error("=====PROVISIONING : ROLE ATTRIBUTE REQUEST VALUE: " + (roleAttrReq != null ? roleAttrReq.getValue() : "NULL") + " =====");
                log.error("=====PROVISIONING : ACTIVE ATTRIBUTE REQUEST VALUE: " + (activeAttrReq != null ? activeAttrReq.getValue() : "NULL") + " =====");
                
                if (roleAttrReq != null && ProvisioningPlan.Operation.Remove.equals(roleAttrReq.getOperation())) {
                  log.error("=====PROVISIONING : MODIFY OPERATION IS REMOVE=====");
                  statement.setString(1, roleAttrReq.getValue());
                  statement.setBoolean(2, false);
                  statement.executeUpdate();              
                } else if (roleAttrReq != null && !currentRole.equals(roleAttrReq.getValue()) && activeAttrReq != null && (activeAttrReq.getValue() == true)) {
                  log.error("=====PROVISIONING : MODIFY OPERATION IS ADD WITH DIFFERENT ROLE ASSIGNMENT=====");
                  statement.setString(1, roleAttrReq.getValue());
                  statement.setBoolean(2, true);
                  statement.executeUpdate();
/* =================================================================================================================================
  PROBLEM AREA
    1. Disable is still sending Attribute Request values (active status) so SailPoint detects a delta.
        - With use of UPDATE provisioning policy
            - Disable ends up also using it to send the active attribute values
        - Removal of the active field from the update provisioning policy resolves disable
            - successful trigger of DISABLE operator because active value is not sent
            - BUT results in role assignments to NOT trigger enablement of account for the same reason
    2. Delta is only detected with test identities (active status value is sent through) 
        - Users already in the database do not and will successfully trigger the DISABLE operator
    3. Fallback disable conditional within MODIFY overlaps with Modify operation is add with last held role assignment */
                } else if (activeAttrReq != null && (activeAttrReq.getValue() == false)) { // activeAttrReq.getValue() is actually = true...but this overlaps with the below condition
                  log.error("=====PROVISIONING : FALLBACK HANDLING OF DISABLE OPERATION=====");
                  activeStatusStmt.setBoolean(1, false);
                  activeStatusStmt.executeUpdate();
                } else if (activeAttrReq != null && (activeAttrReq.getValue() == true)) {
                  // for reactivating user with same role assignment as last held
                  log.error("=====PROVISIONING : MODIFY OPERATION IS ADD WITH LAST HELD ROLE ASSIGNMENT=====");
                  activeStatusStmt.setBoolean(1, activeAttrReq.getValue());
                  activeStatusStmt.executeUpdate();
/* ================================================================================================================================= */
                } else {
                  // for adding initial entitlement upon create
                  log.error("=====PROVISIONING : MODIFY OPERATION IS ADD FOR NEW ROLE ASSIGNMENT=====");
                  statement.setString(1, roleAttrReq.getValue());
                  statement.setBoolean(2, true);
                  statement.executeUpdate();
                }
                result.setStatus(ProvisioningResult.STATUS_COMMITTED);
              }

What is the best method to resolve this? Ideally, I do not want the “Disable Account” action to go through Modify, aka, do not want to even have that fallback handling of disable within Modify.

Hi @mliu8 !

Have you considered using workflows to help with this (assuming you have it in your tenant? It might help simplify things a bit. Basically use something like a provisioning completed trigger with the intended source, entitlement, and operation to trigger an account enable/disable action (Manage Accounts) when needed? This way if accounts are added to or removed from an entitlement/role, the workflow will enable/disable them. We just did something similar for an OOTB SaaS connector, and it worked well.

Please let me know if this helps!

  • Zach