Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Performs entitlement review and access certification campaigns using SailPoint IdentityIQ including manager certifications, targeted entitlement reviews, role-based access validation, SOD violation remediation, and automated revocation workflows. Activates for requests involving access reviews, entitlement certifications, SailPoint IIQ governance, or periodic user access recertification.
.claude/skills/performing-entitlement-review-with-sailpoint-iiq/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-15 | ✗→✓ | ▲ Improved | — | — |
| case-12 | ✗→✓ | ▲ Improved | — | — |
| case-02 | ✗→✓ | ▲ Improved | — | — |
| case-09 | ✗→✓ | ▲ Improved | — | — |
| case-18 | ✗→✓ | ▲ Improved | — | — |
Do not use for real-time access control decisions; IdentityIQ certifications are periodic review processes designed for governance and compliance validation.
Plan the certification scope and reviewer assignments:
java// SailPoint IdentityIQ BeanShell - Campaign Configuration import sailpoint.object.*; import sailpoint.api.*; import java.util.*; // Define campaign schedule for quarterly manager certifications CertificationSchedule schedule = new CertificationSchedule(); schedule.setName("Q1-2026-Manager-Access-Review"); schedule.setDescription("Quarterly manager certification for all active employees"); schedule.setType(Certification.Type.Manager); // Configure campaign scope CertificationDefinition certDef = new CertificationDefinition(); certDef.setName("Q1 Manager Certification"); certDef.setOwner(context.getObjectByName(Identity.class, "cert-admin")); // Set certification options certDef.setCertifierSelectionType(CertificationDefinition.CertifierSelectionType.Manager); certDef.setIncludeEntitlements(true); certDef.setIncludeRoles(true); certDef.setIncludeAccounts(true); certDef.setIncludeAdditionalEntitlements(true); // Exclude service accounts from manager reviews Filter exclusionFilter = Filter.ne("type", "service"); certDef.setExclusionFilter(exclusionFilter); // Configure notification settings certDef.setNotificationEnabled(true); certDef.setReminderFrequency(7); // days certDef.setEscalationEnabled(true); certDef.setEscalationDays(14); certDef.setEscalationRecipient("security-governance-team"); // Set active period certDef.setActivePeriodDays(30); certDef.setAutoCloseEnabled(true); certDef.setDefaultRevoke(true); // Revoke if not reviewed context.saveObject(certDef); context.commitTransaction();
Set up focused reviews for high-risk applications and privileged entitlements:
java// Targeted certification for privileged access review import sailpoint.object.*; import sailpoint.api.*; CertificationDefinition targetedCert = new CertificationDefinition(); targetedCert.setName("Privileged Access Targeted Review"); targetedCert.setType(Certification.Type.ApplicationOwner); // Scope to specific high-risk applications List applicationNames = new ArrayList(); applicationNames.add("Active Directory"); applicationNames.add("AWS IAM"); applicationNames.add("Oracle EBS"); applicationNames.add("SAP GRC"); applicationNames.add("CyberArk Vault"); targetedCert.setApplicationNames(applicationNames); // Filter for privileged entitlements only String entitlementFilter = "entitlement.classification == \"Privileged\" " + "|| entitlement.riskScore > 800 " + "|| entitlement.name.contains(\"Admin\") " + "|| entitlement.name.contains(\"Root\") " + "|| entitlement.name.contains(\"DBA\")"; targetedCert.setEntitlementFilter(entitlementFilter); // Assign application owners as certifiers targetedCert.setCertifierSelectionType( CertificationDefinition.CertifierSelectionType.ApplicationOwner ); // Configure approval workflow targetedCert.setApprovalRequired(true); targetedCert.setSignOffRequired(true); targetedCert.setReasonRequired(true); // Enable SOD policy check during certification targetedCert.setCheckSodPolicies(true); targetedCert.setSodPolicyAction(CertificationDefinition.SodPolicyAction.Flag); context.saveObject(targetedCert); context.commitTransaction();
Define Separation of Duties policies that flag violations during reviews:
java// Create SOD policy for financial system access conflicts import sailpoint.object.*; import sailpoint.object.Policy; Policy sodPolicy = new Policy(); sodPolicy.setName("Financial SOD - AP/AR Conflict"); sodPolicy.setType(Policy.TYPE_SOD); sodPolicy.setDescription("Prevents users from having both Accounts Payable " + "and Accounts Receivable access simultaneously"); sodPolicy.setViolationOwner( context.getObjectByName(Identity.class, "compliance-team") ); // Define conflicting entitlements SODConstraint constraint = new SODConstraint(); constraint.setName("AP-AR Separation"); // Left side: Accounts Payable entitlements PolicyConstraint leftSide = new PolicyConstraint(); leftSide.setApplication("SAP ERP"); leftSide.addEntitlement("SAP_AP_PROCESSOR"); leftSide.addEntitlement("SAP_AP_APPROVER"); leftSide.addEntitlement("SAP_AP_ADMIN"); constraint.setLeftConstraint(leftSide); // Right side: Accounts Receivable entitlements PolicyConstraint rightSide = new PolicyConstraint(); rightSide.setApplication("SAP ERP"); rightSide.addEntitlement("SAP_AR_PROCESSOR"); rightSide.addEntitlement("SAP_AR_APPROVER"); rightSide.addEntitlement("SAP_AR_ADMIN"); constraint.setRightConstraint(rightSide); // Set violation severity and remediation constraint.setViolationSeverity("High"); constraint.setCompensatingControl("Dual approval required for transactions > $10,000"); sodPolicy.addConstraint(constraint); context.saveObject(sodPolicy); context.commitTransaction();
Automate access removal when certifiers revoke entitlements:
java// Configure automatic provisioning for revoked entitlements import sailpoint.object.*; import sailpoint.api.*; // Create remediation workflow Workflow remediationWorkflow = new Workflow(); remediationWorkflow.setName("Certification Revocation Workflow"); remediationWorkflow.setType(Workflow.Type.CertificationRemediation); // Step 1: Create provisioning plan for revocation Step createPlan = new Step(); createPlan.setName("Create Revocation Plan"); createPlan.setScript( "import sailpoint.object.ProvisioningPlan;\n" + "import sailpoint.object.ProvisioningPlan.AccountRequest;\n" + "import sailpoint.object.ProvisioningPlan.AttributeRequest;\n\n" + "ProvisioningPlan plan = new ProvisioningPlan();\n" + "plan.setIdentity(identity);\n" + "AccountRequest acctReq = new AccountRequest();\n" + "acctReq.setApplication(applicationName);\n" + "acctReq.setOperation(AccountRequest.Operation.Modify);\n" + "AttributeRequest attrReq = new AttributeRequest();\n" + "attrReq.setName(entitlementAttribute);\n" + "attrReq.setValue(entitlementValue);\n" + "attrReq.setOperation(ProvisioningPlan.Operation.Remove);\n" + "acctReq.add(attrReq);\n" + "plan.add(acctReq);\n" + "return plan;" ); // Step 2: Execute provisioning with retry logic Step executeProvisioning = new Step(); executeProvisioning.setName("Execute Revocation"); executeProvisioning.setScript( "import sailpoint.api.Provisioner;\n" + "Provisioner provisioner = new Provisioner(context);\n" + "provisioner.setNoTriggers(false);\n" + "ProvisioningResult result = provisioner.execute(plan);\n" + "if (result.isCommitted()) {\n" + " auditEvent(\"Entitlement revoked successfully\", identity, plan);\n" + "} else {\n" + " openWorkItem(\"Manual revocation required\", identity, plan);\n" + "}" ); // Step 3: Send notification to user and manager Step notification = new Step(); notification.setName("Send Revocation Notification"); notification.setScript( "import sailpoint.tools.EmailTemplate;\n" + "EmailTemplate template = context.getObjectByName(\n" + " EmailTemplate.class, \"Access Revocation Notification\");\n" + "Map args = new HashMap();\n" + "args.put(\"identityName\", identity.getDisplayName());\n" + "args.put(\"applicationName\", applicationName);\n" + "args.put(\"entitlementName\", entitlementValue);\n" + "args.put(\"certifierName\", certifier.getDisplayName());\n" + "args.put(\"revocationReason\", decisionReason);\n" + "context.sendEmailNotification(template, args);" ); context.saveObject(remediationWorkflow); context.commitTransaction();
Track certification completion and generate compliance evidence:
java// Campaign monitoring and reporting script import sailpoint.object.*; import sailpoint.api.*; import java.util.*; // Get all active certification campaigns QueryOptions qo = new QueryOptions(); qo.addFilter(Filter.eq("phase", Certification.Phase.Active)); Iterator certIterator = context.search(Certification.class, qo); while (certIterator.hasNext()) { Certification cert = certIterator.next(); System.out.println("Campaign: " + cert.getName()); System.out.println(" Type: " + cert.getType()); System.out.println(" Phase: " + cert.getPhase()); System.out.println(" Due Date: " + cert.getExpiration()); // Get completion statistics CertificationStats stats = cert.getStatistics(); int totalItems = stats.getTotalEntities(); int completedItems = stats.getCompletedEntities(); int pendingItems = totalItems - completedItems; double completionPct = (completedItems * 100.0) / totalItems; System.out.println(" Total Items: " + totalItems); System.out.println(" Completed: " + completedItems + " (" + String.format("%.1f", completionPct) + "%)"); System.out.println(" Pending: " + pendingItems); // Decision breakdown int approved = stats.getApprovedCount(); int revoked = stats.getRevokedCount(); int mitigated = stats.getMitigatedCount(); int delegated = stats.getDelegatedCount(); System.out.println(" Decisions:"); System.out.println(" Approved: " + approved); System.out.println(" Revoked: " + revoked); System.out.println(" Mitigated: " + mitigated); System.out.println(" Delegated: " + delegated); // Identify overdue certifiers List certifiers = cert.getCertifiers(); for (Object certObj : certifiers) { CertificationEntity entity = (CertificationEntity) certObj; if (!entity.isCompleted() && cert.isOverdue()) { System.out.println(" [OVERDUE] Certifier: " + entity.getCertifier().getDisplayName()); } } System.out.println(); }
Export certification results for auditor review:
java// Generate audit report for completed certifications import sailpoint.object.*; import sailpoint.api.*; import sailpoint.tools.Util; // Query completed certifications for the audit period QueryOptions qo = new QueryOptions(); qo.addFilter(Filter.eq("phase", Certification.Phase.End)); qo.addFilter(Filter.ge("signed", Util.stringToDate("2026-01-01"))); qo.addFilter(Filter.le("signed", Util.stringToDate("2026-03-31"))); List results = context.getObjects(Certification.class, qo); StringBuilder auditReport = new StringBuilder(); auditReport.append("ACCESS CERTIFICATION AUDIT REPORT\n"); auditReport.append("Period: Q1 2026\n"); auditReport.append("Generated: " + new Date() + "\n"); auditReport.append("=".repeat(50) + "\n\n"); int totalCampaigns = 0; int totalDecisions = 0; int totalRevocations = 0; for (Certification cert : results) { totalCampaigns++; CertificationStats stats = cert.getStatistics(); auditReport.append("Campaign: " + cert.getName() + "\n"); auditReport.append(" Certifier: " + cert.getCertifiers().size() + " reviewers\n"); auditReport.append(" Items Reviewed: " + stats.getTotalEntities() + "\n"); auditReport.append(" Approved: " + stats.getApprovedCount() + "\n"); auditReport.append(" Revoked: " + stats.getRevokedCount() + "\n"); auditReport.append(" Completed: " + cert.getSigned() + "\n"); auditReport.append(" Sign-off: " + (cert.isSignedOff() ? "YES" : "NO") + "\n\n"); totalDecisions += stats.getTotalEntities(); totalRevocations += stats.getRevokedCount(); } auditReport.append("SUMMARY\n"); auditReport.append("Total Campaigns: " + totalCampaigns + "\n"); auditReport.append("Total Decisions: " + totalDecisions + "\n"); auditReport.append("Total Revocations: " + totalRevocations + "\n"); auditReport.append("Revocation Rate: " + String.format("%.1f%%", (totalRevocations * 100.0) / totalDecisions)); System.out.println(auditReport.toString());
| Term | Definition | |------|------------| | Certification Campaign | An organized review process where designated certifiers validate whether users should retain their current access entitlements across one or more applications | | Access Review | Individual review unit within a campaign where a certifier examines and makes approve/revoke decisions on specific user entitlements | | Entitlement | A specific permission, group membership, role, or access right granted to an identity on a target application | | Certifier | The reviewer responsible for making access decisions, typically a manager, application owner, or data owner | | Revocation | Decision to remove an entitlement from a user, triggering a provisioning request to the target application for access removal | | SOD Violation | Separation of Duties conflict where a user holds entitlements from two or more conflicting access groups that create a segregation risk | | Remediation | Automated or manual process of removing revoked access from target systems following certification decisions |
Context: A publicly traded company must demonstrate quarterly access reviews for all financial applications per SOX Section 404. The previous manual review process took 6 weeks and produced inconsistent results.
Approach:
Pitfalls:
ACCESS CERTIFICATION CAMPAIGN REPORT
=======================================
Campaign: Q1-2026 Manager Access Review
Type: Manager Certification
Period: 2026-01-15 to 2026-02-14
Status: COMPLETED
COVERAGE
Identities Reviewed: 2,847
Applications In Scope: 34
Total Entitlements: 18,392
DECISION SUMMARY
Approved: 16,841 (91.6%)
Revoked: 1,203 (6.5%)
Mitigated: 198 (1.1%)
Delegated: 150 (0.8%)
REVOCATION STATUS
Provisioned: 1,089 / 1,203 (90.5%)
Pending: 87
Failed: 27 (manual work items created)
SOD VIOLATIONS
Flagged: 43
Remediated: 31
Compensating Controls: 12
CERTIFIER COMPLIANCE
On-Time Completion: 89.3%
Required Escalation: 14 certifiers
Average Review Time: 3.2 minutes per item
SIGN-OFF
Campaign Signed: 2026-02-14 by compliance-admin
Audit Evidence: Exported to /reports/Q1-2026-cert-evidence.pdf| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-17 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-04 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-15 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-12 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-02 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-09 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-18 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-07 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-06 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-10 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-01 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-03 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-11 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-05 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-19 | pass→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-20 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-14 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-16 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-08 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-13 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-21 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-22 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 21 counted toward the lift figure. The other 1 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +41 percentage points is the difference between those two pass rates over the 21 comparable cases.
The per-case answers from this run were removed by the retention sweep, so the case table below shows the verdicts without the text either arm produced. The counts above were recorded at the time and are unaffected. Answers are now kept for 180 days.
Other measured skills in the registry, with their headline benchmark lift.