SailPoint IIQ: BuildMap Rule – Told You So :-)

Okay, here’s an article I wasn’t planning on posting, but based on some feedback I received privately via email, I thought I would throw this one example out there. Sometimes the simplest and unlikeliest of examples can tell you a whole lot about the plumbing of a product such as SailPoint IdentityIQ. Concerning my most recent post on SailPoint IIQ Build Map rules, this next exercise I think will fit the bill of being quite revealing even though simple and extremely unlikely to mirror real world.

I Told You So 🙂

In my last post, I indicated that Build Map rules (as well as other rule hooks in SailPoint IdentityIQ) do not care what you are doing inside them, in general. In the case of the Build Map rule, I stated that SailPoint IdentityIQ does not do a single thing to validate your code. It does not validate it against your application schema; it’s trusting you 100% to wire your build map rule to your schema in the right way — 100%. The only thing SailPoint IdentityIQ does do is map fields from your build map into a resource object (later in aggregation processing) that matches the schema, which is a short way of saying…

(1) If you don’t provide a field from your return map that matches the application schema, that field in the schema will be blank (or null), and…

(2) If you provide a field from your return map that does NOT match the application schema, that field in the build map will be dropped.

That’s it. The rest is up to you and here’s a very small example that in my mind pretty much demonstrates everything about how Build Map rules work.

Setting This Up

Let’s set this up. Try this in your development sandbox. First, create a plain text file that has nothing in it but one number per line — lines numbered from say 1 to 25. Nothing else. This is easy to setup on the Linux command line. (For you Windows peeps, I’m sorry to say it may be just as easy to jump into NotePad and bang out 25 lines by hand! 🙁 :-))

$ perl -e 'for (1..25) { print "$_\n" }' > dummy25.txt

Now create a delimited file application in SailPoint IdentityIQ called “Dummy Application” that reads in this text file:


Application Name: Dummy Application
Application Type: DelimitedFile
Application Type: /path/to/dummy25.txt
Delimiter: “,” (but could be any character — it won’t matter for this example)
File has column header on the first line: Leave unchecked (we don’t need it)
Columns: “number” (or any other single word — again, it’s not going to matter, trust me)
Filter Empty: checked


Now create a build map rule for this application. Call it “Build Map – Dummy Application” or whatever suits you. Here’s the code:

int number = new Integer( record.get( 0 ) );
HashMap map = new HashMap();
// For "employeeId", pick an employee Id that you know correlates
// to an identity in your sandbox.
map.put( "employeeId", "000055102C" );
map.put( "fullName", "Chris Olive" );
map.put( "account", "colive" + number );
map.put( "company", "Qubera Solutions" );
map.put( "dne", "Doesn't exist in schema, so this field will go to the bit bucket!" );
return map;

Now create the application schema as follows:

Now, drop into connectorDebug in IIQ console and look at your output. It should tell you a lot:

$ iiq console -j
> connectorDebug "Dummy Application" iterate
<ResourceObject displayName="colive1" identity="colive1" objectType="account">
  <Attributes>
    <Map>
      <entry key="account" value="colive1"/>
      <entry key="company" value="Qubera Solutions"/>
      <entry key="employeeId" value="000055102C"/>
      <entry key="fullName" value="Chris Olive"/>
    </Map>
  </Attributes>
</ResourceObject>

<ResourceObject displayName="colive2" identity="colive2" objectType="account">
  <Attributes>
    <Map>
      <entry key="account" value="colive2"/>
      <entry key="company" value="Qubera Solutions"/>
      <entry key="employeeId" value="000055102C"/>
      <entry key="fullName" value="Chris Olive"/>
    </Map>
  </Attributes>
</ResourceObject>

<ResourceObject displayName="colive3" identity="colive3" objectType="account">
  <Attributes>
    <Map>
      <entry key="account" value="colive3"/>
      <entry key="company" value="Qubera Solutions"/>
      <entry key="employeeId" value="000055102C"/>
      <entry key="fullName" value="Chris Olive"/>
    </Map>
  </Attributes>
</ResourceObject>
   :
   :
   :
<ResourceObject displayName="colive25" identity="colive25" objectType="account">
  <Attributes>
    <Map>
      <entry key="account" value="colive25"/>
      <entry key="company" value="Qubera Solutions"/>
      <entry key="employeeId" value="000055102C"/>
      <entry key="fullName" value="Chris Olive"/>
    </Map>
  </Attributes>
</ResourceObject>

ConnectorDebug Analysis

Where are the dne field contents from the build map rule? In the bit bucket, like we said. It wasn’t in your application schema, so it’s dropped. The rest of the magic should be apparent. We read in a file of nothing but numbers. This essentially caused SailPoint IdentityIQ to simply iterate by the number of records we read. The record contents have essentially nothing stored in them, and yet from “nothing” we “created” field values that are meaningful using rule logic.

From this exercise, do you see why we didn’t care what delimiter we used? The application definition requires you to have one, however, so we had to put something. You could put “Z” there and it wouldn’t matter. (Go ahead… try it!) And do you see why not even the column name was consequential? (Go ahead… Go back into your application definition, change your column name from “number” to “foo” and run connectorDebug "Dummy Application" iterate again. It doesn’t matter. :-))

The reason it doesn’t matter is this example was so simple, we didn’t even need the DelimitedFileConnector.defaultBuildMap(cols,record) call we usually see in DelimitedFile build map rules. We know the number in the file is the first (and only) column in the input record. So we can use a record.get(0) method call on the record Java List object SailPoint IdentityIQ provides, and just get the first value in that List for the number. So in this case, we don’t even need the usual defaultBuildMap() method call on the DelimitedFileConnector class.

Conclusion

This is probably the last I’ll blog on the BuildMap rule simply because I’ve got a growing list of other technical articles to post that I know some of you are interested in, and quite frankly, as I said, this simple but unlikely example I think shows it all, so I couldn’t resist posting it.

Go ahead, if you want, and if you’ve made the adjustments to your employeeId field in the build map rule to use an employeeId that correlates to an identity in your system… add an employeeId to employeeId correlation rule (you can do this from the GUI and if you have the Financial Application defined from SailPoint Implementor Training, you can just re-use the same correlation), and correlate this wacky example. You should see these 25 dummy accounts correlate to your lucky identity:

View Identity Chris Olive

And if you needed a run-away, rogue user with multiple identities in your sandbox to test your “too many application accounts” policy for certifications… you now have that as well. 🙂

Cheers from the Twin Cities!

Chris Olive

Chris Olive is a seasoned and passionate cybersecurity strategist, evangelist, consultant, trusted advisor, and hands-on technologist with over two decades of cybersecurity consulting experience in the US/UK governments, the Fortune 500, and large international companies all over the world. Chris has primary expertise in Identity Access Management and Identity Governance & Administration along with professional experience and expertise in Ethic Hacking & Penetration Testing, Secure Development, and Data Security & Encryption. Chris is a frequent writer, speaker, and evangelist on a range of cybersecurity topics. Chris is currently a Senior National Security Advisor & Architect for CDW -- a worldwide leader and innovator in solutioning, architecting, and delivering secure information technology solutions on-prem, in the cloud, multi-cloud, hybrid, or co-hosted leveraging the world's largest, best, and most trusted brands.

View all posts by Chris Olive →