Managing SailPoint IdentityNow Applications via API with PowerShell

The SailPoint IdentityNow Request Center comes pre-populated with 130 Applications (as shown below) that by default are visible to users in the Dashboard and can be requested via the Request Center. Whilst this is great the majority are not often applicable and you need to configure each individual application to remove visibility and requestablity. You could of course ask your IdentityNow Support representative to do this for you, or you could manage it yourself. Lets go with option B and I’ll show you how.

Application List.PNG

To disable visibility of an Application, and to also remove it from being requested through the Request Center there are two options that need to be toggled off. Enabled For Users, and Visible in the Request Center. 

Application Settings 1.PNG

Say you want to remove all from being visible and requestable. You will need to open each app, toggle the slider and the radio button and select save. That’s a minimum of 4 mouse clicks and some mouse scrolling x 130, or do it via the IdentityNow API in < 60 seconds. Option B please.

Retrieving Applications

The URI to return all IdentityNow Applications is

https://$($orgName).api.identitynow.com/cc/api/app/list

Before you can call that URI you will need to be authenticated to IdentityNow. Follow this post and make sure you have the headers in the WebSession configured with the Bearer Access Token.

Then using PowerShell you can return all Applications with;

$appList = Invoke-RestMethod -Uri $appListURI -Method Get -WebSession $IDN

If you want to find a single app, find it by name using Select-Object | Where-Object

$myApp = $appList | Select-Object | Where-Object {$_.name -eq "New York Times"}

The Application PowerShell Object for the New York Times looks like;

id : 24184
appId : 11
serviceId : 32896
serviceAppId : 24184
name : New York Times
description : American daily newspaper
appCenterEnabled : False
provisionRequestEnabled : False
controlType : PERSONAL
mobile : True
privateApp : False
scriptName : C:1-new-york-times
status : ACTIVE
icon : https://files.accessiq.sailpoint.com/modules/builds/static-assets/perpetual/identitynow/icons/2.0/n
ytimes/
health : @{status=HEALTHY; lastChanged=1539766560496; since=0; healthy=True}
enableSso : True
ssoMethod : PASSWORD
hasLinks : True
hasAutomations : True
primaryLink : https://myaccount.nytimes.com/auth/login
primaryMobileLink : https://myaccount.nytimes.com/mobile/login/smart/index.html?EXIT_URI=://mobile.nytimes.com/loginRet
urnthUK?url=/?redir_esc=
stepUpAuthData :
stepUpAuthType : NONE
usageAnalytics : False
usageCertRequired : False
usageCertText :
launchpadEnabled : False
passwordManaged : False
owner :
dateCreated : 1522393052000
lastUpdated : 1539766536000
defaultAccessProfile :
service : New York Times
selectedSsoMethod : PASSWORD
supportedSsoMethods : 2
authenticationCookie : []
directoryPassword_supported : false
none_supported : true
passwordReplay_supported : true
proxy_supported : false
saml_supported : false
wsfed_supported : false
accountServiceId : -1
launcherCount : 0
accountServiceName :
accountServiceExternalId :
accountServiceMatchAllAccounts : True
externalId :
passwordServiceId : -1

Removing Applications from User Visibility

Let’s remove all Applications from user visibility (and the Dashboard). The process is simply to retrieve all Applications, then update each one to toggle off the options for visibility. The following script does just that.

After updating each app the Request Center is empty. Much quicker than hundreds of mouse clicks.

Request Center Empty.PNG

Summary

With the ability to retrieve Applications and update them via the API repetitive configuration becomes super quick.

Managing SailPoint IdentityNow Roles via API and PowerShell

Managing SailPoint IdentityNow Role Groups typically involves leveraging the SailPoint IdentityNow Portal for the creation and on-going management. That’s because the API for Roles is not published or documented.

What happens then if you have many to create, update/manage? How does the IdentityNow Portal use the non-published undocumented API’s to create and manage them? I’ve worked it out and am documenting it here in the interim until the API’s get versioned and published.

Note: There is a chance that the Roles API may change, 
so use at your own risk. 

Roles API Authentication

First up the Roles API URI looks like this.

https://OrgName.api.identitynow.com/cc/api/role

The /cc/ part is a good indication that the API isn’t documented, but also that the Authentication mechanism to interact with it is using a JWT Bearer Token. I covered how to obtain a JWT Bearer Token specifically for interacting with these API’s in this post here. I’m not going to cover that here so read that post to get up to speed with that process.

Associated with managing the criteria of Roles we will also need to reference IdentityNow Sources. We can do that via a non-published API too.

https://OrgName.api.identitynow.com/cc/api/source

Listing all IdentityNow Roles

Similar to Governance Groups that I detailed in this post Roles can be returned on an individual basis (if you know the ID of the Role which you won’t). So the simplest way is to query and return them all (no, the Search (BETA) doesn’t support Roles either). The API to list all roles is:

https://OrgName.api.identitynow.com/cc/api/role/list

Doing this then via PowerShell to return all roles looks like this:

Roles = Invoke-RestMethod -Uri "https://OrgName.api.identitynow.com/cc/api/role/list" -WebSession $IDN
and finding Roles you are interested in can be done using Where-Object
$Roles.items | Select-Object | Where-Object {$_.displayName -like "Kloud*"}

SailPoint Roles.PNG

Creating Roles

The example script below shows the generation of information for a Role Object. Specifically;

  • name
  • displayname
  • description
  • disabled (whether the Role is enabled or disabled)
  • owner (the IdentityNow NAME attribute value of the owner of the Role)

Executing this creates the Role.

Role Created.PNG

Looking in the Portal we can then see the Role.

Role Created in Portal.PNG

Managing Role Criteria

The Role Criteria will obviously depend on what your criteria is. Is it based on Standard Group Rules, a List of Identities or Custom? I’ll cover a List of Identities and Group based criteria.

Adding a List of Identities to a Role

This isn’t too dis-similar to Governance Roles. We search for the list of users we want to add to the Role and add them to a collection. The key difference is that we use Name instead of ID. We then specify the type of Criteria (Identity_List) and the ID of the Group to update.

Executing the Script

The example script below switches the Headers for Basic Auth to use the v2 endpoint to search and locate the users to add to the Role. It then switches the Headers over to JWT Bearer Auth, generates the body for the request to update the Role Group and updates the Role Group.

Executing the script looks as per below and runs through successfully.

Adding IdentityList Members to Role Group.PNG

Checking the Role Group in the IdentityNow Portal

Identity List Updated - Portal.PNG

Adding a Members Based on Criteria to a Role

Adding users to a Role based on Criteria is similar to above except rather than searching for Identities we are adding the criteria for a role.

The criteria can be based on an Identity Attribute an Account Attribute or an Entitlement. I’ll show using an Identity Attribute and an Account Attribute.

Account Attribute based Criteria

Account criteria is based on attributes available in the Schema of a Source. In order to reference the Source we need the ID of the Source. This is available via the non-published Source API cc/api/source

The example script below shows getting all Sources and finding the one you want to base your Role Criteria off (based on name). You can of course mix criteria across many sources, but I’m showing you doing it from one. Running the following script will return your Sources. You require the ID of the Source you want to leverage attributes from to base your criteria off. The attribute that contains this used further along in these examples is $RoleSource 

Now that we have the Source ID for the Source that contains the attribute that we want to base our Role Criteria on, we need to build the criteria. Let’s start with a simple one and Single Criteria.

Here is an example JSON document with a Single Criteria that contains the variables for the Role that we just created (Role ID), the Source ID for the Source with the attribute we are using for the criteria and the value we want to match (RoleCriteriaValue). The Attribute from my Source that I’m using is Supplier. Update for the attribute you’re using on your Source.

"{`"id`":`"$($newRole.id)`",`"accessProfileIds`":[],`"selector`":{`"type`":`"COMPLEX_CRITERIA`",`"entitlementIds`":[],`"aliasList`":[],`"valueMap`":[],`"complexRoleCriterion`":{`"operation`":`"OR`",`"children`":[{`"operation`":`"EQUALS`",`"key`":{`"type`":`"ACCOUNT`",`"property`":`"attribute.Supplier`",`"sourceId`":`"$($RoleSource)`"},`"value`":`"$($RoleCriteriaValue)`"}]}}}"
After converting the JSON object to a PowerShell Object using ConvertFrom-JSON it looks like this:
Single Role Criteria.PNG

Having it as a PowerShell Object also makes it easy to modify. If you wanted to change the criteria to match against, the Operator and/or the operation then just change the value. e.g. the following will change the value to match from “Kloud Solutions Pty Ltd” to “Darren J Robinson

$RoleCriteria.selector.complexRoleCriterion.children.value = "Darren J Robinson"

Convert back to JSON for Post via the webrequest to the API. That and updating the Role with the criteria thereby is;

Update Single Criteria.PNG

In the Portal we can see that the Criteria has been added.

Update Single Criteria - Portal.PNG

And you will notice I have a Role Refresh call after the update to update the Role Membership as it is now based on Criteria. If you are updating/adding criteria to numerous roles only call the Refresh at the end.

Role Refresh.PNG

Adding Multiple Criterion

Multiple criterion is just more information to pass to the update. The format can be a little confusing so here is a template for three criteria showing the three Operators (Equals, Contains and Not_Equals).

$RoleCriteria = "{`"id`":`"$($newRole.id)`",`"accessProfileIds`":[],`"selector`":{`"type`":`"COMPLEX_CRITERIA`",`"entitlementIds`":[],`"aliasList`":[],`"valueMap`":[],`"complexRoleCriterion`":{`"operation`":`"OR`",`"children`":[{`"operation`":`"AND`",`"children`":[{`"operation`":`"EQUALS`",`"key`":{`"type`":`"ACCOUNT`",`"property`":`"attribute.Supplier`",`"sourceId`":`"$($RoleSource)`"},`"value`":`"$($RoleCriteriaValue)`"},{`"operation`":`"NOT_EQUALS`",`"key`":{`"type`":`"ACCOUNT`",`"property`":`"attribute.country`",`"sourceId`":`"$($RoleSource)`"},`"value`":`"New Zealand`"},{`"operation`":`"CONTAINS`",`"key`":{`"type`":`"ACCOUNT`",`"property`":`"attribute.email`",`"sourceId`":`"$($RoleSource)`"},`"value`":`".com.au`"}]}]}}}"

When converted to a PowerShell Object and displayed it looks like this;

3 Account Criteria Options.PNG

Identity Attribute based Criteria

The last example is Identity Attribute Criteria. This is simpler than the Account Attribute Criteria as we just need to reference the Identity Attribute and don’t need to reference a Source. A single criteria for isEmployee  = True looks like this;

{`"operation`":`"EQUALS`",`"key`":{`"type`":`"IDENTITY`",`"property`":`"attribute.isemployee`"},`"value`":`"true`"}

As a second Criteria Group though in the Portal it looks like this;

2nd Criteria Group.PNG

and for the JSON object (RAW without variablizing) looks like this;

"{`"id`":`"2c918086663fbbd0016612345678909876`",`"accessProfileIds`":[],`"selector`":{`"type`":`"COMPLEX_CRITERIA`",`"entitlementIds`":[],`"aliasList`":[],`"valueMap`":[],`"complexRoleCriterion`":{`"operation`":`"OR`",`"children`":[{`"operation`":`"AND`",`"children`":[{`"operation`":`"EQUALS`",`"key`":{`"type`":`"ACCOUNT`",`"property`":`"attribute.Supplier`",`"sourceId`":`"2c91808365f742620165f9ba0e831bf8`"},`"value`":`"Kloud Solutions Pty Ltd`"},{`"operation`":`"NOT_EQUALS`",`"key`":{`"type`":`"ACCOUNT`",`"property`":`"attribute.country`",`"sourceId`":`"2c91808365f742620165f9ba0e831bf8`"},`"value`":`"New Zealand`"},{`"operation`":`"CONTAINS`",`"key`":{`"type`":`"ACCOUNT`",`"property`":`"attribute.email`",`"sourceId`":`"2c91808365f742620165f9ba0e831bf8`"},`"value`":`".com.au`"}]},{`"operation`":`"EQUALS`",`"key`":{`"type`":`"IDENTITY`",`"property`":`"attribute.isemployee`"},`"value`":`"true`"}]}}}"

Summary

Using the cc/api/role APIs we can Create Role Groups, Update Roles Groups to contain Criteria and Refresh Role Groups to have the membership calculated. With the base functionality detailed we can now use this to create and manage our Role Groups through automation. Happy Days.

Managing SailPoint IdentityNow Governance Groups via the API with PowerShell

In this post I detail the management of SailPoint IdentityNow Governance Groups using the IdentityNow v2 API as the functions associated with Governance Groups is not currently detailed in the v2 API Documentation here (9 Oct 2018).

In order to interact with the v2 API you will need to use Basic Authentication which I detail in this post here. The common authentication/authorization piece from that post is also shown below.

Retrieving Governance Groups

Now that you’re authorized to IdentityNow using Basic Authentication we can look to retrieve Governance Groups. This can be achieved by calling the /v2/workgroups API.

https://OrgName.api.identitynow.com/v2/workgroups?&org=ORGName

Using PowerShell all Governance Groups can be returned by making the following API call.

$GovGroups = Invoke-RestMethod -Method Get -Uri "$($baseURI)/v2/workgroups?&org=$($orgName)" -Headers @{Authorization = "Basic $($encodedAuth)"}

To retrieve an individual group you need to know the ID of the Group. You can then retrieve it directly using the v2/workgroups API  e.g.

https://OrgName.api.identitynow.com/v2/workgroups/6289788a-c73c-426b-9170-12340aaa6789
Doing that via PowerShell looks like this:
Invoke-RestMethod -uri "https://OrgName.api.identitynow.com/v2/workgroups/6289788a-c73c-426b-9170-12340aaa6789" -Method Get -Headers @{Authorization = "Basic $($encodedAuth)"}

It would be nice to search Governance Groups using the new Search (BETA) feature. But currently the only Groups that are returned via it are Entitlement Groups.

Searching for Governance Groups

As mentioned above the new Search Beta only returns Entitlement Groups. Retrieving Governance Groups via the Governance Group ID is fine, if you know it (which you won’t).  So here is my workaround for this. Retrieve all Governance Groups as detailed above using PowerShell and then use the power of PowerShell (Where-Object) to search and find the group you want.

$GovGroups = Invoke-RestMethod -Method Get -Uri "$($baseURI)/v2/workgroups?&org=$($orgName)" -Headers @{Authorization = "Basic $($encodedAuth)"}
$myGovGroup = $GovGroups | Select-Object | Where-Object {$_.description -like "Kloud*"}

The above looks through each of the Governance Groups to find the ones that contain the word Kloud in the Description field. 53 Groups returned and 2 meet the criteria.

Search Governance Groups.PNG

Creating IdentityNow Governance Groups

To create a Governance Group you will/should provide:

  • IdentityNow Governance Group
    • name (e.g Vendor XX)
    • description (e.g Vendo)
    • owner
      • displayName (e.g Vendor Admin)
      • emailaddress (e.g vendor_admin@vendor.com.au)
      • id (eg 2c918084624f8b59016275c123456789)
      • name (e.g Vendor_Admin)

My approach is;

  • Use the Search API to search and find the user account that will be the Owner for the Governance Group
  • Create the Governance Group assigning the Owner

Here is an example of creating a single Governance Group implementing the approach above.

Executing the script successfully creates the group.

Create Governance Group.PNG

Looking at the Group in the Portal I can see that it has been created with the correct owner.

Governance Group Created

Now if you are like me and you have numerous Governance Groups to create you can of course have a list of Governance Groups to be created and loop through creating each one. Brilliant.

Managing Members of Governance Groups

Updating a group for membership is a simple case of sending through a collection of members to add/remove. This isn’t a replace operation but an addition. So if you want to add a single member, just send through the details to add that member and they will be added to the Governance Group. Likewise for removal.

Process overview;

  • taking a group that was just created we use the ID of that group to then update the membership
  • searching IdentityNow we find the members to add
  • generate the collection to add
  • update the group

Here is a sample wscript the performs that process.

And looking at the Governance Group in the IdentityNow Portal we can see the membership has been updated. Obtaining the Group (using the search method above) also allows for easy removal of all/any members.

Members Added to Governance Group.PNG

Summary

Using the v2/workgroups IdentityNow API we can create and manage Governance Groups. This is extremely powerful when you have many to create and manage.

Leveraging v1, v2 and non-Published SailPoint IdentityNow API’s with PowerShell

This post supersedes my previous posts on leveraging the IdentityNow API’s in relation to API Authentication/Authorization;

Using this Compass document as my guide (which takes a bit of finding) I’ve automated the process of being able to use PowerShell to leverage the non versioned/published API’s. The method I show below is also valid for the documented and versioned API’s.

I show how I generate the necessary credentials required for:

  • IdentityNow Basic Authentication
  • IdentityNow Cookie Authentication
  • IdentityNow JWT oAuth Bearer Authentication

I also show working calls using Basic and JWT oAuth Authentication. The CCSessionID is extracted for use in Cookie Authentication for completeness, but everything can be accomplished using Basic and JWT oAuth Authentication. This document on SailPoint Compass provides more details on each.

Script Overview

Using PowerShell I;

  • authenticate to the IdentityNow Portal
  • elevate via authentication to the Admin section of the IdentityNow Portal
  • obtain the CCSESSIONID Cookie and the CSRF Token
  • provide the ability to add into the Web Session Header IdentityNow Basic or JWT oAuth Authentication credentials

That then allows access to the non-published API’s that are leveraged via the IdentityNow Portal and published API’s.

Obtaining the CSRF Token, JWT Access Token and Session Cookie Programatically with PowerShell

Update the Strong Authentication Methods for IdentityNow Admins

As we need to programatically authenticate to the Portal itself to get the necessary information required for API authorization, we need a mechanism that supports that. The only one that does easily is password. So you will need to enable that.

  • NOTE: chances are you’re using programmatic access to configure/ingest data or configuration as part of service enablement. Once that is done, REMOVE “re-entering password” as a Strong Authentication Method.

In the IdentityNow Portal go to Admin => Identities => Identity Profiles => IdentityNow Admins =>Enable By re-entering their password

Admin Centre Strong Auth Options.PNG

Using a Chrome Browser head to the IdentityNow Login screen for your Tenant. e.g. https://TENANT.identitynow.com. Press F12 for Developer Tools and then enter the Username and Password for an Admin account. Press the Record button (highlighted below, if it isn’t already red) to start recording and then press the Sign In button.

Portal Login Window

When the browser has logged you in, select the Network tab and then right-click on the ‘login’ entry in the trace. Select Copy and then Copy as PowerShell which will copy the webrequest that you just performed to login. Paste this into the script below on Line 25.

WebRequest Login

Next in the browser select Admin and then any of the Admin menu items. e.g. Dashboard => Overview. Select Enter password and check Remember my preference then Continue.

Record the Strong Auth Screen.PNG

The next screen will give you the prompt to supply your password again. Enter the password and then clear the traces from the Developer Tools pane and then make sure Record is enabled, then press Authenticate.

Record Password 2nd Screen.PNG

Select the strongAuthn trace from the Network tab, right-click and select Copy and then Copy as PowerShell. Paste this into the script below on Line 43. Don’t forget to edit it for the CSRF Token variable.  

Strong Auth Capture.PNG

The Script

Update the script below for your environment by:

  • Line 3 with your IdentityNow Organisation name
  • Line 9 with your IdentityNow API Client ID
  • Line 11 with your IdentityNow API Client Secret
  • Line 16 with your Admin login name for the IdentityNow Portal
  • Line 25 with the first PowerShell Webrequest you copied above
  • Line 43 update with the second PowerShell Webrequest you copied above. Make sure to go back and add in the variable for the CSRF Token as shown below. $($orgName) is optional.
    • example $admPortalAuthN = Invoke-WebRequest -Uri $adminStrongAuthURI -Method “POST” -Headers @{“Origin” = “https://$($orgName).identitynow.com”; “Accept-Encoding” = “gzip, deflate, br”; “X-CSRF-Token” = $($csrf); “Accept-Language” = “en-US,en;q=0.9”; “User-Agent” = “Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36”; “Accept” = “*/*”; “Referer” = “https://$($orgname).identitynow.com/ui/admin”; “X-Requested-With” = “XMLHttpRequest”} -ContentType “application/x-www-form-urlencoded; charset=UTF-8” -Body “password=f2dbeb5a897abeeecafc9deee5612345678903456789bdedf7d42” -WebSession $IDN

Output from the Script

The screenshot below shows successfully making API calls to IdentityNow across the v1, v2 and the non versioned API’s after generating the necessary Authentication credentials.

Note that after calling the v1 and non versioned API’s I change the Headers to remove the Bearer Authorization Token and replace it with the Basic Authorization Token so that the v2 API’s can be called.

Examples Output.PNG

Optional: Obtaining the CSRF Token Manually

If you do want to obtain the CSRF Token manually then using a web browser.

  • Login to IdentityNow Portal main Dashboard with an Admin account
    • A direct URI looks like this;
https://TENANT.identitynow.com/login/login?goto=https%3A%2F%2FTENANT.identitynow.com%2Fui%2Fd%2Fdashboard
  • Head to the Admin Dashboard and you will be prompted for Strong Authentication
https://TENANT.identitynow.com/ui/admin#admin:dashboard:overview
    • At this point though you will also be able to retrieve the CSRF Token

Using the Chrome Developer Tools (e.g. pressing F12 in Chrome) select Console, then at the prompt type SLPT.CSRFToken You will then see your CSRF Token for that session.

CSRFToken via Browser.PNG

Summary

With the ability to programatically generate the necessary Authorization tokens for IdentityNow we can interact with the documented API’s along with the API’s that are being leveraged by the IdentityNow Admin Portal itself.

Integrating with SailPoint IdentityNow Private (v1) API’s using PowerShell

How to generate the ‘Password Hash’ to leverage the IdentityNow Private API’s

Recently I’ve posted about integrating with the SailPoint IdentityNow API’s. Specifically;

So why another post on a very similar subject? Well, not all IdentityNow API’s are exposed on the v2 API Endpoints that were leveraged in the previous posts. The v1 (Private API List) is detailed on SailPoint Compass here and contains a number of functions that are extremely useful. And here is where it gets interesting. The authentication methods between v1 and v2 are not the same. There is a document that gives you most of what you need also on SailPoint Compass here that describes IdentityNow’s oAuth methods.

But here is the kicker. In order to use the older v1 API endpoints you need to generate a hash for the user associated with oAuth2.0 authentication which is in addition to the Client ID and Client Secret. The only method that I’m aware of (and believe me I lost time and effort searching) that SailPoint provide to generate the hash is to use the File Upload Utility which is available on Compass here. And that method only came to my attention after posting to the IdentityNow Community.

Now let’s say you run into the problem I did with the version of Java (yes it is a Java Utility) I had installed (v1.7);

java version "1.7.0_71"
Java(TM) SE Runtime Environment (build 1.7.0_71-b14)
Java HotSpot(TM) 64-Bit Server VM (build 24.71-b01, mixed mode)

Wrong Version of Java.PNG

I didn’t have a need for Java, in fact I was surprised it was even installed on my laptop. Seems it was from an installation of Virtual Box some time ago. I didn’t want to go and get another version etc etc. But I did spin up a VM and get the Java App to run and generate the hashed password. A hashed password for IdentityNow v1 API integration looks like this;

160a028019a1ce58c679f2216a7f707fa666a674772b4742cef7b08eab99de7b

Looking at that I guessed SHA256, but there was something else going on (check the case).

The Premise and Intent

I’ve generated the password hash, why not just move on? What I was looking to achieve was the ability for a number of services to interact with IdentityNow via v1 Private API’s. As part of those processes and for management of that privileged access, it needs to be automated. Running a Java app to generate the hashed password for each identity and on each password change wasn’t an option.

The Solution

What I ended up doing, as there was no accessible documentation around how the hashed password is generated for v1 API integration still makes me feel a bit dirty and guilty that I had to do it. Maybe I shouldn’t even be documenting it? But we are licensed for this service and integration with it is still limited to what functions are available via the API and identity you are authenticating with.

I decompiled the Java App, peeked inside and looked to see how the hash was being generated. Then mimicked the process in PowerShell.

Direct Integration with IdentityNow Private (v1) API’s

Direct integration is essentially like any other API. What you need is;

  • Client ID and Client Secret (enabled via the Admin => Global => Security Settings => API Management)
  • Admin Account and Password (account name and password of an account granted Admin permissions in IdentityNow)
    • this is passed in the WebRequest Header as Digest AuthN (Base64 Encoded)
  • Token End Point to get a Token
    • “https://orgname.identitynow.com/api/oauth/token?grant_type=password&username=AdminUser&password=HashedAdminPassword”

The process is;

  1. Generate the Request to the Token Endpoint
  2. Submit the request and obtain a token
  3. Execute subsquent requests with the Bearer Token received in Step 2
  4. Renew token before it expires if continuing to make requests longer than the token life (default 60 mins)

That all looks simple right. Except for that bit about ‘hashed password’.

The Special Sauce

You’ve made it this far, so you’re probably looking to do this. Here it is. The inputs are the IdentityNow Login Name for an Admin account and the plaintext password for that account.

In order to simplify generating the hash you will need to install the PowerShell Community Extensions (PSCX) Module which is in the PowerShell Gallery here. This provides the super handy Get-Hash cmdlet that I use extensively.

You should be on PowerShell 5.1 or later so the following will install it for you (from an elevated PowerShell console);

install-module -name pscx

Generate passwordhash Script

Update lines 2 and 3 for the Admin Identity you are generating the hash for. Line 8 and 9 are the lines that generate the hash and prepare it for use in requesting a token.

Calling IdentityNow Private API’s with PowerShell

Here is an example of using PowerShell to generate the hashed Password, obtain a token then call the API to return the list of Profiles in IdentityNow.

  • Update the obvious lines for your instance (Lines 2, 4, 8, 10, 11)
  • Update Line 25 if you want to call a different v1 API

Summary

Hopefully I’ve saved others the couple of hours of messing around to workout how to programatically generate the needed password hash to allow automated integration with the SailPoint IdentityNow v1 Private API’s.

Lifecycle Management of Identities in SailPoint IdentityNow via API and PowerShell

Introduction

If you’ve been following along I’ve been posting about leveraging the SailPoint IdentityNow API for;

Now that I’ve covered Searching and Authoring all that is left is lifecycle management. And that’s what I’ll cover in this post. Updating and Deleting Entities via the API.

Updating SailPoint IdentityNow Entities

If you have not read the first post in this series, start there as ‘updating’ builds on top of Search/Reporting. It also covers enabling the API.

My quick start guide to updating IdentityNow Entities starts with searching to find the Entities (probably Users) you want to update. In my example below I’m searching for all objects on a Source. Then I iterate through the results and update them. I’m updating the Country attribute.

When updating an entity (e.g User) you need to perform a PATCH webrequest specifying the underlying ID (objectID) of the object. The URI format looks like;

https://orgName.api.identitynow.com/v2/accounts/2c91808365bd1f010165caf761625bcd?org=orgName

Example Script

Here is an example script. As per the previous two posts, change all the lines for your tenant and your API details.

  • Line 16 is the query for objects to update
  • Lines 39-41 is the attribute to update

Updating Manager

For manager, the attribute is a reference on the IdentityNow Source to the Manager. On my “External Entities” Source I locate the object representing the Manager and obtain their accountId (which in my case is firstname.lastname) and set that as the ManagerID. I then find the users that I want to update for this manager and update them as we did in the previous example, but with a reference to accountId of the Manager for the Manager attribute.

NOTE: When querying IdentityNow via the API the syntax is very important. Especially when also incorporating variables. If I have a variable $manager with a displayName value, that would normally contain a space. So we need to capture the whole string. Here is an example of doing that. So in order to query for $manager = “Rick Sanchez” in PowerShell that would be:

$queryManager = "attributes.displayName:"+'"'+"$($manager)"+'"'

which will give us attributes.displayName:”Rick Sanchez” which will return in my case the single object for Rich Sanchez not a list of references to Rick Sanchez.

Deleting SailPoint IdentityNow Entities

Deleting is very similar to Updating. Again the easiest method is to search and obtain the object(s) to be deleted and then delete via a DELETE webrequest specifying the underlying ID (objectID) of the object to be deleted. The URI looks like;

https://orgName.api.identitynow.com/v2/accounts/2c91808565bd1f110165cb628d1a702f?org=orgName

Example Script

Here is an example script. It searches IdentityNow based on object naming (see line 14), then finds the Source that the object is connected to that we wish to delete. In this example the Source is the one I created in the last post “External Entities”. Update for the name of your Source (line 25).

Summary

Using the API we can Search for Identities, Author and Update them.

Authoring Identities in SailPoint IdentityNow via the API and PowerShell

Introduction

A key aspect of any Identity Management project is having an Authoritative Source for Identity. Typically this is a Human Resources system. But what about identity types that aren’t in the authoritative source? External Vendors, contingent contractors and identities that are used by End User Computing systems such as Privileged Accounts, Service Accounts, Training Accounts.

Now some Identity Management Solutions allow you to Author identity through their Portals, and provide a nice GUI to create a user/training/service account. SailPoint IdentityNow however doesn’t have that functionality. However it does have an API and I’ll show you in the post how you can use it to Author identity into IdentityNow via the API.

Overview

So, now you’re thinking great, I can author Identity into IdentityNow via the API. But, am I supposed to get managers to interface with an API to kick off a workflow to create identities? Um, no. I don’t think we want to be giving them API access into our Identity Management solution.

The concept is this. An Identity Request WebApp would collect the necessary information for the identities to be authored and facilitate the creation of them in IdentityNow via the API. SailPoint kindly provide a sample project that does just that. It is available on Github here. Through looking at this project and the IdentityNow API I worked out how to author identity via the API using PowerShell. There were a few gotchas I had to work through so I’m providing a working example for you to base a solution around.

Getting Started

There are a couple of things to note.

  • Obviously you’ll need API access
  • You’ll want to create a Source that is of the Flat File type (Generic or Delimited File)
    • We can’t create accounts against Directly Connected Sources
  • There are a few attributes that are mandatory for the creation
    • At a minimum I supply id, name, givenName, familyName, displayName and e-mail
    • At an absolute bare minimum you need the following. Otherwise you will end up with an account in IdentityNow that will show as “Identity Exception”
      • id, name, givenName, familyName, e-mail*

* see note below on e-mail/email attribute format based on Source type

Creating a Flat File Source to be used for Identity Authoring

In the IdentityNow Portal under Admin => Connections => Sources select New.

Create New Source.PNG

I’m using Generic as the Source Type. Give it a name and description. Select Continue

New Generic Source.PNG

Assign an Owner for the Source and check the Accounts checkbox. Select Save.

New Source Properties.PNG

At the end of the URL of the now Saved new Source get and record the SourceID. This will be required so that when we create users via the API, they will be created against this Source.

SourceID.PNG

If we look at the Accounts on this Source we see there are obviously none.

Accounts.PNG

We’d better create some. But first you need to complete the configuration for this Source. Go and create an Identity Profile for this Source, and configure your Identity Mappings as per your requirements. This is the same as you would for any other IdentityNow Source.

Authoring Identities in IdentityNow with PowerShell

The following script is the bare minimum to use PowerShell to create an account in IdentityNow. Change;

  • line 2 for your Client ID
  • line 4 for your Client Secret
  • line 8 for your Tenant Org Name
  • line 12 for your Source ID
  • the body of the request for the account to be created (lines 16-21)

NOTE: By default on the Generic Source the email attribute is ’email’. By default on the Delimited Source the email attribute is ‘e-mail’. If your identities after executing the script and a correlation are showing as ‘Identity Exception’ then it’s probably because of this field being incorrect for the Source type. If in doubt check the Account Schema on the Source.

Execute the script and refresh the Accounts page. You’ll see we now have an account for Rick.

Rick Sanchez.PNG

Expanding Rick’s account we can see the full details.

Rick Full Details.PNG

Testing it out for a Bulk Creation

A few weeks ago I wrote this post about generating user data from public datasets. I’m going to take that and generate 50 accounts. I’ve added additional attributes to the Account Schema (for suburb, state, postcode, street). Here is a script combining the two.

Running the script creates our 50 users in conjunction to the couple I already had present.

Bulk Accounts Created.PNG

Summary

Using the IdentityNow API we can quickly leverage it to author identity into SailPoint IdentityNow. That’s the easy bit sorted. Now to come up with a pretty UI and a UX that passes the End-User usability tests. I’ll leave that with you.

 

Reporting on SailPoint IdentityNow Identities using the 'Search' (Beta) API and PowerShell

Introduction

SailPoint recently made available in BETA their new Search functionality. There’s some great documentation around using the Search functions through the IdentityNow Portal on Compass^. Specifically;

^ Compass Access Required
Each of those articles are great, but they are centered around performing the search via the Portal.  For some of my needs, I need to do it via the API and that’s what I’ll cover in this post.
*NOTE: Search is currently in BETA. There is a chance some functionality may change. SailPoint advise to not use this functionality in Production whilst it is in Beta.  

Enabling API Access

Under Admin => Global => Security Settings => API Management select New and give the API Account a Description.
New API Client.PNG
Client ID and Client Secret
ClientID & Secret.PNG
In the script to access the API we will take the Client ID and Client Secret and encode them for Basic Authentication to the IdentityNow Search API. To do that in PowerShell use the following example replacing ClientID and ClientSecret with yours.

$clientID = 'abcd1234567'
$clientSecret = 'abcd12345sdkslslfjahd'
$Bytes = [System.Text.Encoding]::utf8.GetBytes("$($clientID):$($clientSecret)")
$encodedAuth =[Convert]::ToBase64String($Bytes)

Searching

With API access now enabled we can start building some queries. There are two methods I’ve found. Using query strings on the URL and using JSON payloads as an HTTP Post. I’ll give examples of both.

PowerShell Setup

Here is the base of all my scripts for using PowerShell to access the IdentityNow Search.
Change;

  • line 3 for your Client ID
  • line 5 for your Client Secret
  • line 10 for your IdentityNow Tenant Organisation name (by default the host portion of the URL e.g https://orgname.identitynow.com )

Searching via URL Query String

First we will start with searching by having the query string in the URL.

Single attribute search via URL

$query = 'firstname EQ Darren'
$Accounts = Invoke-RestMethod -Method Get -Uri "$($URI)limit=$($searchLimit)&query=$($query)" -Headers @{Authorization = "Basic $($encodedAuth)" }

Single Attribute URL Search.PNG

Multiple attribute search via URL

Multiple criteria queries need to be constructed carefully. The query below just looks wrong, yet if you place the quotes where you think they should go, you don’t get the expected results. The following works.

$query = 'attributes.firstname"="Darren" AND attributes.lastname"="Robinson"'

and it works whether you Encode the URL or not

$queryEncoded = [System.Web.HttpUtility]::UrlEncode($query)
$Accounts = Invoke-RestMethod -Method Get -Uri "$($URI)limit=$($searchLimit)&query=$($queryEncoded)" -Headers @{Authorization = "Basic $($encodedAuth)"

Multiple Attribute Query Search.PNG
Here is another searching based on identities having a connection to a source containing the word ‘Directory’ AND having less the 5 accounts

$URI = "https://$($org).api.identitynow.com/v2/search/identities?"
$query = '@access(source.name:*Directory*) AND entitlementCount:<5'
$Accounts = Invoke-RestMethod -Method Get -Uri "$($URI)limit=$($searchLimit)&query=$($query)" -Headers @{Authorization = "Basic $($encodedAuth)" }

Multiple Attribute Query Search2.PNG

Searching via HTTP Post and JSON Body

Now we will perform similar searches, but with the search strings in the body of the HTTP Request.

Single attribute search via POST and JSON Based Body Query

$body = @{"match"=@{"attributes.firstname"="Darren"}}
$body = $body | convertto-json
$Accounts = Invoke-RestMethod -Method POST -Uri "$($URI)limit=$($searchLimit)" -Headers @{Authorization = "Basic $($encodedAuth)" } -ContentType 'application/json' -Body $body
Single Attribute JSON Search.PNG

Multiple attribute search via POST and JSON Based Body Query

If you want to have multiple criteria and submit it via a POST request, this is how I got it working. For each part I construct it and convert it to JSON and build up the body with each search element.

$body1 = @{"match"=@{"attributes.firstname"="Darren"}}
$body2 = @{"match"=@{"attributes.lastname"="Robinson"}}
$body = $body1 | ConvertTo-Json
$body += $body2 | ConvertTo-Json
$Accounts = Invoke-RestMethod -Method POST -Uri "$($URI)limit=$($searchLimit)" -Headers @{Authorization = "Basic $($encodedAuth)" } -ContentType 'application/json' -Body $body
Multiple Attribute JSON Search.PNG

Getting Full Identity Objects based off Search

Lastly now that we’ve been able to build queries via two different methods and we have the results we’re looking for, lets output some relevant information about them. We will iterate through each of the returned results and output some specifics about their sources and entitlements. Same as above, update for your ClientID, ClientSecret, Orgname and search criteria.

Extended Information.PNG

Summary

Once you’ve enabled API access and understood the query format it is super easy to get access to the identity data in your IdentityNow tenant.
My recommendation is to use the IdentityNow Search function in the Portal to refine your searches for what you are looking to return programmatically and then use the API to get the data for whatever purpose it is.

Reporting on SailPoint IdentityNow Identities using the ‘Search’ (Beta) API and PowerShell

Introduction

SailPoint recently made available in BETA their new Search functionality. There’s some great documentation around using the Search functions through the IdentityNow Portal on Compass^. Specifically;

^ Compass Access Required

Each of those articles are great, but they are centered around performing the search via the Portal.  For some of my needs, I need to do it via the API and that’s what I’ll cover in this post.

*NOTE: Search is currently in BETA. There is a chance some functionality may change. SailPoint advise to not use this functionality in Production whilst it is in Beta.  

Enabling API Access

Under Admin => Global => Security Settings => API Management select New and give the API Account a Description.

New API Client.PNG

Client ID and Client Secret

ClientID & Secret.PNG

In the script to access the API we will take the Client ID and Client Secret and encode them for Basic Authentication to the IdentityNow Search API. To do that in PowerShell use the following example replacing ClientID and ClientSecret with yours.

$clientID = 'abcd1234567'
$clientSecret = 'abcd12345sdkslslfjahd'
$Bytes = [System.Text.Encoding]::utf8.GetBytes("$($clientID):$($clientSecret)")
$encodedAuth =[Convert]::ToBase64String($Bytes)

Searching

With API access now enabled we can start building some queries. There are two methods I’ve found. Using query strings on the URL and using JSON payloads as an HTTP Post. I’ll give examples of both.

PowerShell Setup

Here is the base of all my scripts for using PowerShell to access the IdentityNow Search.

Change;

  • line 3 for your Client ID
  • line 5 for your Client Secret
  • line 10 for your IdentityNow Tenant Organisation name (by default the host portion of the URL e.g https://orgname.identitynow.com )

Searching via URL Query String

First we will start with searching by having the query string in the URL.

Single attribute search via URL

$query = 'firstname EQ Darren'
$Accounts = Invoke-RestMethod -Method Get -Uri "$($URI)limit=$($searchLimit)&query=$($query)" -Headers @{Authorization = "Basic $($encodedAuth)" }

Single Attribute URL Search.PNG

Multiple attribute search via URL

Multiple criteria queries need to be constructed carefully. The query below just looks wrong, yet if you place the quotes where you think they should go, you don’t get the expected results. The following works.

$query = 'attributes.firstname"="Darren" AND attributes.lastname"="Robinson"'

and it works whether you Encode the URL or not

$queryEncoded = [System.Web.HttpUtility]::UrlEncode($query)
$Accounts = Invoke-RestMethod -Method Get -Uri "$($URI)limit=$($searchLimit)&query=$($queryEncoded)" -Headers @{Authorization = "Basic $($encodedAuth)" 

Multiple Attribute Query Search.PNG

Here is another searching based on identities having a connection to a source containing the word ‘Directory’ AND having less the 5 accounts

$URI = "https://$($org).api.identitynow.com/v2/search/identities?"
$query = '@access(source.name:*Directory*) AND entitlementCount:<5'
$Accounts = Invoke-RestMethod -Method Get -Uri "$($URI)limit=$($searchLimit)&query=$($query)" -Headers @{Authorization = "Basic $($encodedAuth)" }

Multiple Attribute Query Search2.PNG

Searching via HTTP Post and JSON Body

Now we will perform similar searches, but with the search strings in the body of the HTTP Request.

Single attribute search via POST and JSON Based Body Query

$body = @{"match"=@{"attributes.firstname"="Darren"}}
$body = $body | convertto-json 
$Accounts = Invoke-RestMethod -Method POST -Uri "$($URI)limit=$($searchLimit)" -Headers @{Authorization = "Basic $($encodedAuth)" } -ContentType 'application/json' -Body $body
Single Attribute JSON Search.PNG

Multiple attribute search via POST and JSON Based Body Query

If you want to have multiple criteria and submit it via a POST request, this is how I got it working. For each part I construct it and convert it to JSON and build up the body with each search element.

$body1 = @{"match"=@{"attributes.firstname"="Darren"}}
$body2 = @{"match"=@{"attributes.lastname"="Robinson"}}
$body = $body1 | ConvertTo-Json
$body += $body2 | ConvertTo-Json
$Accounts = Invoke-RestMethod -Method POST -Uri "$($URI)limit=$($searchLimit)" -Headers @{Authorization = "Basic $($encodedAuth)" } -ContentType 'application/json' -Body $body
Multiple Attribute JSON Search.PNG

Getting Full Identity Objects based off Search

Lastly now that we’ve been able to build queries via two different methods and we have the results we’re looking for, lets output some relevant information about them. We will iterate through each of the returned results and output some specifics about their sources and entitlements. Same as above, update for your ClientID, ClientSecret, Orgname and search criteria.

Extended Information.PNG

Summary

Once you’ve enabled API access and understood the query format it is super easy to get access to the identity data in your IdentityNow tenant.

My recommendation is to use the IdentityNow Search function in the Portal to refine your searches for what you are looking to return programmatically and then use the API to get the data for whatever purpose it is.

Deploying a SailPoint IdentityNow Virtual Appliance in Azure

Introduction

The CentOS image that SailPoint provide for the IdentityNow Virtual Appliance that performs integration between ‘Sources’ and IdentityNow is VMWare based. I don’t have any VMWare Infrastructure to run it on and really didn’t want to run up any VMWare environments for this component. All my other infrastructure is in Azure. I’d love to run my VA(s) in Azure too.
In discussions with SailPoint I understand it is simply a case that they haven’t certified their CentOS image on Azure. So I figured I’d convert the VM, get it into Azure and see if it works from my Sandpit environment. This blog post details how I got it working.
Disclaimer: If you use this for more than a Sandpit/Test environment let your SailPoint CSM know. This isn’t an approved process or a support configuration. That said it works for me.

Overview

This is the high-level process I threw together that worked for me.

  1. Obtain the CentOS Image from the IdentityNow Virtual Appliance Setup
  2. Convert the VMWare VMDK image to Hyper-V VHD format using VirtualBox vboxmanage (free)
  3. From the Azure MarketPlace create a Seed VM based on CentOS (with new Resource Group, Storage Account, Virtual Network etc)
  4. Upload the VHD to the Azure Storage Account (associated with VM from Step 3) using Azure Storage Explorer
  5. Create a new VM based off the VM from Step 3 to use the disk from Step 4 as the Operating System disk
  6. Log in and configure the Virtual Appliance

Convert VMWare VM to Hyper-V.png

Prerequisites

  1. Virtual Box (for the disk image converter). You could probably do it with other tools but I’ve used this before and it just works.
  2. Enough hard disk space for the VA image and the converted image. The base image is ~2.8Gb and when converted to a fixed disk image it becomes ~128Gb (which can compress to ~3Gb for initial upload).
  3. Azure Storage Explorer. We’ll need this to upload the converted virtual disk to Azure.

SailPoint Virtual Appliance CentOS VMWare Image

To download the CentOS VMWare Image login to the Admin section of your IdentityNow Tenant.  Under Admin => Connections => Virtual Appliances create a New Cluster. Select that Cluster then Virtual Appliances => New 
Download the Appliance Package 
Create New VA.PNG

Converting the CentOS VMWare Virtual Disk to a Fixed Hyper-V Virtual Disk

I already had Virtual Box installed on my computer. I had to give the full path to VBoxManage (as shown below) and called it with the switches to convert the image;
vboxmanage clonehd –format VHD –variant Fixed
The –variant Fixed switch takes the dynamic image and converts it to Fixed as this is a requirement in Azure.
ConvertVADisk 1.PNG
The image conversion started and completed in under ten minutes.
Converted Fixed.PNG

Creating an Azure CentOS VM

In the Azure Portal I created a New Resource and chose CoreOS.
NewCoreOS 1
I gave it a name, chose HDD as the disk type and gave it a Username and Password.
NewCoreOS 2
I chose sizing in line with the recommendations for a Virtual Appliance.
NewCoreOS 3
And kept everything else simple (for my sandpit environment).
NewCoreOS 4
After the VM had deployed I had a Resource Group with the necessary Virtual Network, Storage Account etc.
Resource Group.PNG

Upload the Converted Disk to Azure Storage

I created a vhd container (in the Storage Group associated with the VM I just created) to hold the new VHD. Using Azure Storage Explorer I then uploaded the converted image. Select Page Blob for the blob type.
Upload VHD
You’ll want to have a decent internet connection to do this. I converted the SailPoint image on an Azure VM (to which I added a 256Gb data disk too). I then uploaded the new 128Gb VHD disk image from within Azure to the target Resource Group in about 75 minutes.
Upload VHD 2
Below I show the SailPoint Virtual Appliance CentOS OS converted disk image uploaded to Azure Storage Account Blob Storage.
Upload VHD 3.PNG

Generate SAS Token / Get Blob URI

We won’t used a SAS Token, but this just gives easy access to the Storage Blob URL. Right click on the VHD Blob and select Generate Shared Access Signature. Select Create.
Right Click - Get Shared Access Signature
Copy the URL. We’ll need parts of this for the script to create a new CentOS VM with our VA Disk Image.
Get VHD and BLOB Details

Create the new VM for our Virtual Appliance

Update the script below for:

  • The Resource Group you created the Seed VM in (line 2)
  • The Seed VM Name (line 4)
  • The Seed VM Subnet Name (line 6)

Each of those are easily obtained from the Seed VM Summary as highlighted below.

  •  update the Disk Blob details in Live 8 and 10 as copied earlier

After stepping through the script to create the new VM, and happy with the new name etc, I executed the New-AzureRMVM command.
Create New VM
And the VM was created in a couple of minutes.
Create VM Initiated

Accessing the new VM

Getting the IP address from the new VM Summary I SSH’d into it.
VM Started
And logged in with the default credentials from SailPoint. (Windows Subsystem for Linux is awesome).
SSH In to VA

Next Steps

  1. Change the password on your Virtual Appliance (passwrd)
  2. Create a DNS Name, update the configuration as per SailPoint VA Configuration tasks
  3. Create the VA and Test the Connection from the IdentityNow Portal
  4. Delete your original SeedVM as it is no longer required
  5. Add an NSG to the new VM
  6. Create another VM in a different location for High Availability and configure it in IdentityNow

Below shows my Azure based Virtual Appliance connected and all setup.
Cluster Up and Running.PNG

Summary

Whilst not officially supported it is possible to convert the SailPoint Virtual Appliance VMWare based image to an Azure compatible Hyper-V image and assign it as the Operating System disk on an Azure Linux (CoreOS) Virtual Machine. If you need to do something similar I hope my approach gives you some ideas.
If you then need to create another Virtual Appliance in Azure you have a Data Disk you can assign to a VM and upload to wherever it needs to be for creation of another Virtual Appliance VM.

Follow ...+

Kloud Blog - Follow