Segregation of Duties (SoD) policies

Segregation of Duties (SoD) is a security and compliance control that prevents any single user from holding a combination of access rights that could enable fraud, error, or abuse of privilege. In OpenIAM, SoD policies define which entitlements (roles, groups, resources, or organizations) are considered conflicting, detect users who violate those policies, and provide tooling to remediate or formally exempt violations.

The SoD feature is typically used for:

  • Preventing a user from holding both "Create Payment" and "Approve Payment" roles simultaneously.
  • Flagging users who belong to conflicting business units.
  • Ensuring compliance with SOX, SOC 2, ISO 27001, or internal audit requirements.

Core concepts

Policy

A SoD policy is the top-level object defining a conflict. Key attributes are as follows.

FieldTypeDescription
nameStringHuman-readable policy name
descriptionString (max 1024 chars)Explanation of the conflict
activeBooleanWhether the policy is enforced
severitySOFT / HARDImpact level of a violation (see §5)
policyThresholdIntegerMinimum number of violated segments before a policy-level violation is triggered
exceptionsAllowedBooleanWhether exemptions may be granted for this policy
managerCanHandleSpvBooleanWhether the user's manager may handle violations
managerGroupIdStringID of the group responsible for managing violations
riskId / riskNameStringRisk classification category
segments Set\<SodPolicySegment\>One or more conflict segments (see policy segments below)
mitigatingControlsSet\<SodMitigatingControl\>Controls that mitigate the policy risk (see mitigating controls below)

Policy segments

A segment defines the specific set of conflicting entitlements within a policy. A policy can have multiple segments; the policyThreshold controls how many segments must be violated before the policy is considered violated overall.

Each segment contains:

FieldDescription
name / descriptionSegment identification
activeWhether this segment is actively evaluated
thresholdMinimum conflicting entitlements within the segment to trigger violation
managerGroupIdSegment-level manager group (overrides policy-level if set)
rolesRoles that are in conflict within this segment
groupsGroups that are in conflict within this segment
resourcesResources that are in conflict within this segment
organizationsOrganizations that are in conflict within this segment

Example: A segment named "Payment Controls" might contain both the "Payment Creator" role and the "Payment Approver" role. Any user holding both would trigger a violation of this segment.

Mitigating controls

A mitigating control is a compensating measure that reduces the risk of an SoD violation without removing the conflicting access. Mitigating controls are documented in the system for audit purposes and linked to policies.

FieldDescription
name / descriptionControl identification
activeWhether the control is active
ownerType / ownerIdUser or group that owns the control
managerType / managerIdUser or group that manages the control
reviewFrequencyMONTHLY, QUARTERLY, SEMI_ANNUALLY, or ANNUALLY
effectiveDate / expirationDateValidity period of the control

More on mitigating controls can be found in this document.


Configuration

Creating a policy

REST endpoint: POST /rest/api/sod-policy/save

A new policy is created with a name, description, severity, and at least one segment. The request body (SodPolicyBean) supports:

  • Setting the policy active or inactive.
  • Linking mitigating controls by ID.
  • Defining one or more segments, each with sets of conflicting role/group/resource/organization IDs.

On successful save, the system:

  1. Persists the policy and its segments to the database (SOD_POLICY, SOD_POLICY_SEGMENT and related junction tables).
  2. Refreshes the Redis policy cache.
  3. Triggers a background job to re-evaluate all users against the updated policy.

Audit actions generated are CREATE_SOD_POLICY or UPDATE_SOD_POLICY

Searching policies

REST endpoint: GET /rest/api/sod-policy/search

Supported filters:

ParameterDescription
nameSubstring match on policy name
resourceIdsPolicies referencing these resources
groupIdsPolicies referencing these groups
roleIdsPolicies referencing these roles
organizationIdsPolicies referencing these organizations
from / sizePagination
sortBy / orderByColumn and direction for sorting

Deleting a policy

REST endpoint: DELETE /rest/api/sod-policy/{id}

Removes the policy and its segments. Existing exemptions and historical violation records are retained for audit purposes.

Audit action generated is DELETE_SOD_POLICY.


Violation detection

How violations are detected

Violation detection evaluates each user's full entitlement set against all active SoD policies and segments. There are two types of violations:

TypeDescription
DirectThe user holds the conflicting entitlement explicitly and directly
IndirectThe user has effective access to a conflicting entitlement via inheritance (e.g., through a parent group or role hierarchy)

Detection algorithm (per user, per policy):

  1. Retrieve the user's complete entitlement set from the AuthorizationManager.
  2. For each active segment in the policy: a. Apply any existing exemptions — exclude exempted entitlements from evaluation. b. Compare the user's entitlements against the segment's conflicting sets (roles, groups, resources, organizations). c. Classify each match as direct or indirect. d. If the number of matched entitlements meets or exceeds the segment threshold, record a segment violation.
  3. If the number of violated segments meets or exceeds the policy policyThreshold, record a policy violation.

Violation data is stored in ElasticSearch for fast querying.

Triggering detection

REST endpoint: POST /rest/api/sod-policy-violation/impacted-users/detect

This triggers a system-wide re-evaluation of all users against all policies. Detection is also triggered automatically when:

  • A policy is saved or updated.
  • A user's entitlements change via provisioning.

Querying violations

EndpointDescription
GET /rest/api/sod-policy-violation/impacted-users/searchList all users with at least one policy violation
GET /rest/api/sod-policy-violation/{userId}Summary of all violated policies for a specific user
GET /rest/api/sod-policy-violation/{userId}/{sodPolicyId}Detailed entitlements violating a specific policy for a user

The detailed response includes the specific conflicting entitlements (direct and indirect), the segment that defines the conflict, and whether each violation has been resolved.


Severity levels

Severity determines what happens at the moment a provisioning operation (user create or update) would result in a SoD conflict. The check runs inside UserMgr.validateAgainstSodPolicy(), which is called during every user save unless the request explicitly sets skipSodPolicyCheck=true.

Hard violation

A HARD violation blocks the provisioning operation entirely.

What happens step by step:

  1. The system evaluates the user's incoming entitlement set against all active SoD policies (via AuthManager.isConflict()).
  2. A HARD conflict is found.
  3. Audit log entry is written with action HARD_SOD_POLICY_VIOLATION_DETECTION, including the full violation details serialized as JSON.
  4. A SodPolicyServiceException (ResponseCode.SOD_POLICY_VIOLATION) is thrown — the user save rolls back and the entitlement change is rejected.
  5. The policy's managerGroupId members are notified via the SOD_VIOLATION_HARD notification type, every time the violation is detected (including repeat occurrences, not just the first time).

The calling code receives the exception, and the end user or API consumer gets an error response. The conflicting entitlement is never persisted.

Soft violation

A SOFT violation allows the provisioning operation to proceed but records and notifies about the conflict.

What happens step by step:

  1. The system evaluates the user's incoming entitlement set against all active SoD policies.
  2. A SOFT conflict is found.
  3. Audit log entry is written with action SOFT_SOD_POLICY_VIOLATION_DETECTION.
  4. The user is saved to the database normally — the entitlement change is applied.
  5. For existing users: if this is a new (previously unknown) violation, the violation is recorded in Elasticsearch (UserViolatedSodPolicyDoc) and the manager group is notified via SOD_VIOLATION_SOFT. For repeat known violations, no additional notification is sent.
  6. For new users (no existing ID): the violation is noted in the audit log but no Elasticsearch doc is written and no notification is sent at detection time (the doc is maintained after save via maintainViolatedSodUserDoc).
  7. After the save completes, maintainViolatedSodUserDoc reconciles the violation tracking document — stale violations (no longer present) are removed from Elasticsearch and the manager group receives a SOD_VIOLATION_RESOLVED notification.

Violation resolution notification

When a user's entitlements are updated and a previously recorded SOFT violation no longer applies (e.g., one of the conflicting entitlements was removed), the system:

  1. Detects that the violation is no longer present during the next save.
  2. Sends a SOD_VIOLATION_RESOLVED notification to the manager group.
  3. Deletes the violation entry from the ElasticSearch document.

To distinguish between SOFT and HARD violation better, please use the table below.

BehaviorSOFTHARD
Provisioning blockedNo — save proceedsYes — save is rejected
Exception thrownNoSodPolicyServiceException
Audit actionSOFT_SOD_POLICY_VIOLATION_DETECTIONHARD_SOD_POLICY_VIOLATION_DETECTION
Manager group notificationOn first (new) violation onlyEvery time the violation is detected
Notification typeSOD_VIOLATION_SOFTSOD_VIOLATION_HARD
Elasticsearch trackingYes — recorded in UserViolatedSodPolicyDocNo (save never completes)
Resolution notificationYes — SOD_VIOLATION_RESOLVED when clearedN/A
Can be skippedProvisionUser.skipSodPolicyCheck=true skips both SOFT and HARD checksSame flag

Remediation

When a user is found to violate a policy, administrators have two options:

  1. Remove conflicting access REST endpoint: POST /rest/api/sod-policy-violation/handle-violations (with isDelete=true) Removes the specified conflicting entitlements from the user via the provisioning service. This is the standard remediation path.
  2. Grant an exemption REST endpoint: POST /rest/api/sod-policy-violation/handle-violations (with isDelete=false) Creates a formal exemption that allows the user to retain the conflicting entitlements. Requirements and behavior:
    • The policy must have exceptionsAllowed=true.
    • A comment/reason must be provided.
    • The exemption records: user ID, policy ID, entitlement type (ROLE, GROUP, RESOURCE, ORGANIZATION), entitlement ID, timestamp, and the ID of the user who granted the exemption.
    • Exempted entitlements are excluded from future violation evaluations for that user. Exemptions can be queried per user via the service to support auditing.

Audit action generated: Logged with user ID, policy ID, entitlement details, and a comment.

Integration with Access Certification

SoD violations are surfaced inside Access Certification reviews. When a manager reviews a user's access during a certification campaign:

  • Each access review item is checked against active SoD policies. \
  • Violations are displayed as AccessReviewItemSodViolation records attached to the review item.
  • Each violation includes: policy name, severity, risk classification, conflicting entitlement details, segment information, and whether it is a direct or indirect violation. - The manager can certify (retain) or revoke access, with SoD context visible for informed decision-making. - Resolved violations are tracked via the resolved flag on the violation record.

Reporting

SoD feature allows reporting on the violations and other activity with the feature involved. The reports are located and can be configured via org.openiam.sod.reports.directory property. The SoD report service generates CSV exports of violations. Reports can be filtered by:

  • Specific policy IDs.
  • Severity level.
  • Risk ID Each row in the report includes: user identity information, entitlement details, violated SoD policies, and associated mitigating controls. The report service uses LRU caching internally to minimize database load for frequently accessed user and entitlement data.

Data model

SodPolicy (SOD_POLICY)
├── segments: SodPolicySegment (SOD_POLICY_SEGMENT) [1..N]
│ ├── roles → SOD_SEGMENT_ROLERoleEntity
│ ├── groups → SOD_SEGMENT_GRPGroupEntity
│ ├── resources → SOD_SEGMENT_RESResourceEntity
│ └── organizations → SOD_SEGMENT_ORGOrganizationEntity
└── mitigatingControls → SOD_POLICY_MCSodMitigatingControl (SOD_MITIGATING_CONTROL)
SodExemption
└── references: user, sodPolicy, entitlementType, entitlementId

Boolean flags (active, exceptionsAllowed, managerCanHandleSpv) are stored as Y/N in the database via YesNoConverter.


Caching architecture

  • All SoD policies are cached in Redis (SodPolicyCacheList) for fast access during entitlement evaluations.
  • The cache is refreshed automatically whenever a policy is created or updated.
  • Cache refresh is propagated via RabbitMQ (SodPolicyMQListener) to all service nodes.

Enumerations Reference

EnumValues
SodSeveritySOFT, HARD
SodViolationModeDIRECT, INDIRECT
SodMitigatingControlAssigneeTypeUSER, GROUP
SodMitigatingControlReviewFrequencyANNUALLY, SEMI_ANNUALLY, QUARTERLY, MONTHLY
UserEntitlementTypeROLE, GROUP, RESOURCE, ORGANIZATION