Automatic Role Guarantor Transfer
@since 15.17.0
When a role guarantor stops being able to act as a guarantor (the identity is deleted or blocked, one of its contracts is deleted, deactivated or expires, or the guarantor loses the guarantee role assignment itself), the roles they guaranteed could be left without any active guarantor. This feature detects such situations and, before the destructive change is persisted, transfers the affected guarantees to a substitute (typically the original guarantor's manager / superior), so that every role keeps an active guarantor. Each new guarantor is then notified about the roles they became a guarantor of and why.
The transfer covers both kinds of role guarantee in IdStory:
- direct guarantee (
IdmRoleGuarantee) - an identity is set directly as a guarantor of a role; the guarantee carries an optional guarantee type (codelist `guarantee-type`), - guarantee role (
IdmRoleGuaranteeRole) - the guarantors of a role are all holders of a configured guarantee role; the guarantee type is a property of the owner role - guarantee role link.
Examples:
- A team lead who is the sole guarantor of several application roles leaves the company and their identity is deleted - the guarantees move to their manager.
- An external consultant's contract expires; they were the only holder of a guarantee role used by ten business roles - the guarantee role is reassigned to the manager reachable through that contract.
- A group synchronization removes the guarantee role from its last holder - the guarantee role is reassigned to the holder's manager.<note>The transfer is atomic with the operation that triggers it - it joins that operation's transaction. When the operation is rejected or fails (for example a contract controlled by contract slices cannot be deleted), the transfer is rolled back with it and the original guarantor is kept. Conversely, a failed transfer aborts the triggering operation instead of letting a role silently lose its guarantor.</note>
Key concepts
Last (active) guarantor of the given type
Anything happens only when the affected identity is the last active guarantor - if somebody else still guarantees the role, there is nothing to solve and nothing is changed (the inactive identity simply stops counting as an active guarantor). The "is there still someone else?" check considers only effective holders/guarantees:
- Direct guarantee - guarantee types are evaluated separately (a
nulltype is a type of its own): another guarantee counts only if it has the same type and its identity is valid (stateVALIDand not disabled). The substitute inherits the type of the guarantee it replaces, so the role keeps an active guarantor of each type. - Guarantee role - another holder counts only if all of the following hold: the role assignment is currently valid (
validFrom/validTill), it is held through a valid contract (stateisnulland the contract is valid byvalidFrom/validTill), and the holding identity is valid (stateVALIDand not disabled). The holding itself carries no type - the type lives on the owner role - guarantee role link, so the substitute inherits it automatically by holding the guarantee role.
Effectively active contract
A contract is considered effectively active when it has no special state (not EXCLUDED / DISABLED) and is valid now (validFrom /validTill). This is the same rule the exclusivity detection uses for "valid holder", and it drives the contract-level triggers.
Substitute
The identity (or identities) the guarantee is transferred to. Substitutes are resolved through a configurable system script (managers by default), with a robust fallback chain - see How a substitute is resolved.
Transfer marker (anti-loop)
The internal role requests created by the transfer are marked with the event property RoleGuaranteeTransferManager.PROPERTY_GUARANTEE_TRANSFER (`idm:role-guarantee-transfer`). The marker propagates to the role-assignment events of the request's concepts, so the assignment-loss triggers recognize and skip changes caused by the transfer itself - otherwise the transfer's own source-removal would recursively trigger another transfer.
When the transfer runs (scenario matrix)
The transfer always runs in the BEFORE phase of the triggering event (processor order CoreEvent.DEFAULT_ORDER - 100), so the live data needed to detect the last guarantor and to resolve managers still exists.
The following matrix describes the action taken in each situation when the affected user is the last active direct guarantor of some role or the last effective holder of a guarantee role. When another active guarantor / effective holder remains, nothing is transferred and nothing is changed. In every situation the substitute(s) are resolved by the configured script with its fallback chain (the fallback role holders and the admin identity as the last resort) - see How a substitute is resolved; which parameters the transfer passes to the resolution (and whose managers the bundled default script therefore returns) is described in System script:
| Event | Last direct guarantor of a role | Last holder of a guarantee role |
|---|---|---|
| The user is deleted | The guarantor is replaced by the resolved substitute(s). | The guarantee role is assigned to the resolved substitute(s). |
| The user is manually blocked | The resolved substitute(s) are added as a guarantor; the blocked user keeps its guarantee. | The guarantee role is assigned to the resolved substitute(s); the blocked user keeps its holding. |
| The user's active contract is deleted | When it was the user's last active contract (the user becomes inactive), the guarantor is replaced by the resolved substitute(s). | When the guarantee role was held on the deleted contract, it is assigned to the resolved substitute(s). |
The user's active contract expires (its validTill passes) | When it was the user's last active contract, the guarantor is replaced by the resolved substitute(s) (driven by the nightly tasks - see Natural contract expiry). | When the guarantee role was held on the expired contract, it is assigned to the resolved substitute(s). |
| The user's active contract validity is moved to the future (by an edit) | When it was the user's last active contract, the guarantor is replaced by the resolved substitute(s). | When the guarantee role was held on the changed contract, it is assigned to the resolved substitute(s); the original holding is removed. |
| The user's active contract validity is moved to the past (by an edit) | When it was the user's last active contract, the guarantor is replaced by the resolved substitute(s). | When the guarantee role was held on the changed contract, it is assigned to the resolved substitute(s); the original holding is removed. |
| The user's active contract is switched to "Excluded" | When it was the user's last active contract (the user becomes inactive), the resolved substitute(s) are added as a guarantor; the user keeps its guarantee. When another active contract remains, the user stays valid and nothing is changed. | When the guarantee role was held on the excluded contract, it is assigned to the resolved substitute(s); the user keeps its holding. |
| An active contract is set to "Excluded" outside the application (e.g. directly in the database) | The nightly HrContractExclusionProcess runs the transfer before its de-provisioning, with the same result as an exclusion by edit. | The same as an exclusion by edit - the substitute is assigned the guarantee role and the user keeps its holding. |
| The user's active contract is switched to "Disabled" | When it was the user's last active contract, the guarantor is replaced by the resolved substitute(s). | When the guarantee role was held on the changed contract, it is assigned to the resolved substitute(s); the original holding is removed. |
| The user is manually removed as a direct guarantor of a role | No reaction - a deliberate manual change is respected. | N/A |
| The guarantee role assignment validity is set to start in the future or end in the past (by an edit) | N/A | On saving a change that invalidates the assignment, the guarantee role is immediately assigned to the resolved substitute(s); the assignment itself is left with the validity the user has set. |
The guarantee role assignment expires (its validTill passes) | N/A | The date passing raises no event; the nightly Remove expired roles task removes the assignment and the removal triggers the transfer - the guarantee role is assigned to the resolved substitute(s). |
| The guarantee role is removed from the user | N/A | Every removal path (role request, bulk action, recertification, synchronization, automatic role recalculation, contract / identity delete cascades) ends in the assignment delete event: the guarantee role is assigned to the resolved substitute(s). The transfer's own requests are excluded (the anti-loop marker). |
| The role stops being a guarantee role (the owner role link is removed manually) | N/A | No reaction - a deliberate manual change is respected. |
| The guarantee role is deleted (manually from the GUI) | N/A | No reaction - the transfer is deliberately skipped for a role that is being deleted (the DELETED entity state guard); the guarantees disappear together with the role. |
| The guarantee role is deleted (e.g. by an import) | N/A | No reaction - the same guard as for the manual delete applies. |
The triggers are implemented by the following processors:
| Trigger | Event | Processor | Removes original holding? | Reason code |
|---|---|---|---|---|
| Identity is deleted | Identity DELETE | IdentityGuaranteeTransferDeleteProcessor | No - the delete cascade removes it | IDENTITY_DELETED |
| Identity is manually blocked | Identity UPDATE to DISABLED_MANUALLY | IdentityGuaranteeTransferDisableProcessor | No - the blocked identity keeps everything it guarantees | IDENTITY_DISABLED |
| Active contract is deleted | Contract DELETE | IdentityContractGuaranteeTransferDeleteProcessor | No - the delete cascade removes it | CONTRACT_DELETED |
Active contract is deactivated by an edit (validTill set to the past, validFrom set to the future, set DISABLED) | Contract UPDATE (active → inactive) | IdentityContractGuaranteeTransferDeactivateProcessor | Yes - the identity loses the contract's role assignments | CONTRACT_DEACTIVATED |
Active contract is set EXCLUDED by an edit | Contract UPDATE (active → excluded) | IdentityContractGuaranteeTransferDeactivateProcessor | No - exclusion keeps the role assignments, so the guarantees are kept too | CONTRACT_EXCLUDED |
Contract expires naturally (its validTill passes) | Contract EXPIRED | IdentityContractGuaranteeTransferExpiredProcessor | No - the expiration task removes it | CONTRACT_EXPIRED |
| Guarantee role assignment is removed (role request, bulk action, recertification, synchronization, automatic role recalculation, assignment expiration task, contract / identity delete cascades) | Role assignment DELETE | IdentityRoleGuaranteeTransferDeleteProcessor | No - the triggering removal deletes it | ASSIGNMENT_REMOVED |
| Guarantee role assignment loses validity by an edit (validFrom moved to the future, validTill to the past) | Role assignment UPDATE (valid → invalid) | IdentityRoleGuaranteeTransferDeactivateProcessor | No - the assignment stays with the validity the user has set | ASSIGNMENT_DEACTIVATED |
HrEndContractProcess (natural date-expiry) and HrContractExclusionProcess (a contract set EXCLUDED outside the application, e.g. directly in the database) - see Natural contract expiry and the implementation reference.
What exactly is transferred
Direct guarantees and guarantee roles are evaluated independently - each one is transferred on its own, so a role can get a substitute for one kind of guarantorship while the other one stays untouched. Both are, however, subject to the same two rules below.
A contract switched to Disabled or invalidated by date behaves the other way round - it takes the contract's role assignments away, so the replaced guarantees and guarantee role holdings are removed as well.
Direct guarantees
Only the guarantees that are actually replaced are touched. For every guarantee where the identity was the last active direct guarantee of the given role and type:
- the substitute(s) are added as a direct guarantee of the role with the inherited type (if they do not guarantee the role with that type yet), then
- the replaced guarantee of the original identity is removed.
A guarantee whose role keeps another active guarantee of the same type is left in place - there is nothing to replace, and the inactive identity does not count as an active guarantor anyway. This mirrors guarantee roles: an inactive holder also keeps a guarantee role that somebody else still holds. (When the identity is deleted, all its guarantees are removed by the identity delete itself, independently of the transfer.)
Guarantee roles
For every guarantee role exclusively held by the original identity (or held only through the affected contract or assignment):
- the guarantee role is assigned to the substitute(s) on the substitute's prime valid contract, via an internal role request executed immediately (without approval),
- by gaining the guarantee role, the substitute becomes a guarantor of all owner roles that use it - including the guarantee type defined on each owner role link,
- the original holding is removed when
removeSourceapplies (see the matrix above) - direct holdings only; sub-roles are removed together with their direct role.
Substitutes for a guarantee role are resolved per source contract (the contract through which the original identity held the guarantee role) and cached, so the DB-heavy resolution runs once per source contract rather than once per guarantee role.
Loss of the guarantee role assignment
Since the guarantors of a role can be all holders of a guarantee role, the role can lose its last guarantor also when the holding itself disappears - without the identity or contract becoming inactive. Two processors on the role-assignment events cover this:
- Removal (
IdentityRoleGuaranteeTransferDeleteProcessor) - every removal path in IdStory ends in the role-assignmentDELETEevent, so a single processor covers a role request (manual removal, bulk action, recertification), group synchronization, automatic role recalculation, the assignment expiration task (IdentityRoleExpirationTaskExecutor) and the cascades of contract / identity removal (including business-role sub-roles). The processor runs before the row is deleted, so the last-holding detection still sees it; the removed assignment itself is intentionally not checked for validity, so an already expired holding removed later by the expiration task is still detected as the last one. - Validity change (
IdentityRoleGuaranteeTransferDeactivateProcessor) - when an update moves the assignment validity to the past or to the future, the assignment stops being an effective holding. The assignment itself is left untouched - it stays with the validity the user has set (an assignment expired by date is removed later by the standard expiration task); only the substitute is assigned the guarantee role.
Substitutes are resolved through the contract of the lost assignment. The transfer is skipped when:
- the change was caused by the transfer itself (the transfer marker),
- another effective holder of the guarantee role remains (including the same identity holding it on another contract),
- the assigned role is being (force) deleted - the role is flagged with the
DELETEDentity state and transferring a guarantee of a role that is about to disappear makes no sense.
DELETE fires, the holding is no longer the last one and the transfer is a no-op. At the same time the assignment trigger acts as a safety net when the earlier transfer could not run.
How a substitute is resolved
Substitutes are resolved by a robust fallback chain (RoleGuaranteeTransferManager.resolveSubstitutes):
- Configured system script - run the script configured by
idm.sec.core.role.guarantee.transferScript(defaultroleGuaranteeTransferTargets), keep only the results that areIdmIdentityDtoand active (stateVALID, not disabled), and never the identity being removed. If this yields a non-empty list, those are the substitutes. - Fallback role holders - otherwise (empty result, wrong-typed result or a script failure), use the active holders of the fallback role configured by
idm.sec.core.role.guarantee.transferFallbackRole(the admin role when not configured). - Admin identity - if there are still none, fall back to the single
adminidentity.
If not even the admin identity is available, the affected roles are left without an active guarantor and an error is logged.
Natural contract expiry
Contracts that elapse by date (their validTill passes without any user action) are de-provisioned by the nightly scheduled tasks. To let the transfer react before the contract's role assignments are removed, these tasks publish the EXPIRED event for each genuinely date-expired contract (state is null) right before removing its roles. IdentityContractGuaranteeTransferExpiredProcessor reacts to that event.
Two tasks must cover this, because they reach de-provisioning differently and run at different times:
| Task | Default schedule | Role of the EXPIRED publish |
|---|---|---|
HrEndContractProcess (End of contract validity) | 00:50 | The primary task. With no workflow configured it calls IdentityContractEndProcessor directly (not via a contract event), so without this publish no guarantee-transfer processor would ever fire for a naturally expired contract. Publishes EXPIRED before processing - also before starting a configured workflow. |
IdentityContractExpirationTaskExecutor (Remove roles by expired identity contracts) | 01:00 | Secondary. Publishes EXPIRED before removing roles. As it runs after HrEndContractProcess, for contracts the HR task already handled it finds nothing left to transfer (idempotent no-op). |
EXPIRED publish is skipped on the very first run of each task (isFirstRun()), to avoid transferring guarantees for all historically expired contracts right after deployment. HrEndContractProcess only publishes for genuine date-expiry (state is null and validTill in the past); contracts invalid for another reason (future validity, disabled / excluded by state) are skipped - they were handled when their state changed. Publishing is wrapped in its own try/catch so a transfer failure can never block de-provisioning.
IdentityContractExpirationEventTriggerTaskExecutor also publishes EXPIRED. Running these tasks together is safe: the transfer is idempotent (a guarantee/holding already moved is detected and not duplicated), so a repeated EXPIRED for the same contract simply finds nothing left to do.
Traceability of the transfer requests
The internal role requests created by the transfer are self-describing, so anyone reviewing them later understands why the guarantee role was moved automatically:
- Description (user-visible on the role request detail) - a short English sentence with the reason code, different for the two operations: `Automatic role guarantor transfer - guarantee role assigned to a substitute (CONTRACT_DEACTIVATED).` and `Automatic role guarantor transfer - guarantee role removed from the original guarantor (CONTRACT_DEACTIVATED).`
- Log (visible in the admin mode of the request detail) - `Request was created by automatic role guarantee transfer.`
- Requested by -
AUTOMATICALLY, with the system implementer.
Notification
After a transfer, one consolidated e-mail per new guarantor is sent, listing every role they became a guarantor of and the reason.
| Item | Value |
|---|---|
| Topic | core:roleGuaranteeTransferred (CoreModuleDescriptor.TOPIC_ROLE_GUARANTEE_TRANSFERRED) |
| Template | roleGuaranteeTransferred (IdmCoreRoleGuaranteeTransferred.xml, system template, bilingual cs/en body) |
| Subject | `IdStory - stali jste se garantem rolí` |
| Default delivery | e-mail (IdmEmailLog), registered in CoreModuleDescriptor#getDefaultNotificationConfigurations |
| Level | INFO |
The body follows the standard IdStory e-mail layout: an impersonal greeting, the original guarantor referenced as first name last name (username), the affected roles listed by name, a human-readable reason sentence and a contact hint ("Pokud s přidělením garantství nesouhlasíte, kontaktujte prosím administrátory IdM. / If you disagree with the guarantorship assignment, please contact your IdM administrators.").
Template parameters:
| Parameter | Type | Description |
|---|---|---|
identity | IdmIdentityDto | the new guarantor (recipient) |
roles | List<IdmRoleDto> | roles the recipient became a guarantor of |
originalGuarantee | IdmIdentityDto | the original guarantor who is no longer active |
reason | String | one of IDENTITY_DELETED, IDENTITY_DISABLED, CONTRACT_DELETED, CONTRACT_DEACTIVATED, CONTRACT_EXCLUDED, CONTRACT_EXPIRED, ASSIGNMENT_REMOVED, ASSIGNMENT_DEACTIVATED |
Audit
Both guarantee entities implement AuditSearchable with the guaranteed role as the audit owner:
| Entity | Owner | Sub owner |
|---|---|---|
IdmRoleGuarantee | the guaranteed role | the guarantee identity |
IdmRoleGuaranteeRole | the guaranteed (owner) role | the guarantee role |
The role detail audit tab queries audit records by the related owner (relatedOwnerId = role identifier), so every create / update / delete of a role's guarantee - including the changes made by the automatic transfer - is visible directly on the role detail, tab Audit.
How to recognize an automatic guarantor transfer
When you need to find out why somebody is a guarantor of a role ("who made this person a guarantor?"), look for these traces:
- Role requests of the person (identity detail, tab Roles / role requests): the transfer requests carry the description `Automatic role guarantor transfer - guarantee role assigned to a substitute (<reason code>)`, are requested
AUTOMATICALLYand have the system implementer. - Notification log (Audit, Notifications): the new guarantor received an e-mail with the topic
core:roleGuaranteeTransferredlisting the roles and the reason. - Role detail, tab Audit: the creation of the new
IdmRoleGuarantee/ assignment changes are recorded with the role as the audit owner. - Server log: the transfer writes
INFOrecords (`Role […] direct guarantee of type […] transferred to substitute identity […]`, `Guarantee role […] assigned to substitute identity […]`).
Configuration
| Property | Default | Description |
|---|---|---|
idm.sec.core.role.guarantee.transferScript | roleGuaranteeTransferTargets | Code of the system script that resolves the substitutes (managers / superiors). |
idm.sec.core.role.guarantee.transferFallbackRole | (empty = admin role) | Role whose active holders are used as substitutes when the script yields none. The admin role is used when left empty. |
Both properties are exposed on the role configuration agenda (RoleConfiguration).
System script: roleGuaranteeTransferTargets
A SYSTEM-category Groovy script that resolves the managers / superiors to whom a guarantee should be transferred.
| Parameter | Type | Description |
|---|---|---|
identity | IdmIdentity | identity whose managers are resolved (required) |
contract | IdmIdentityContract | optional - when given, only manager(s) reachable through this contract are returned; otherwise all managers of the identity |
Returns List<IdmIdentityDto> (never null). It uses IdmIdentityFilter#setManagersFor (all managers) and, when a contract is given, IdmIdentityFilter#setManagersByContract (managers through that contract).
The transfer passes the parameters according to the trigger - with the default script this determines whose managers become the substitutes:
- identity-level events (the user is deleted / manually blocked) - for direct guarantees no contract is given, so the default script returns all managers of the user; for guarantee roles the contract through which the guarantee role was held is given (each of them, when it was held on several contracts), so only the manager(s) reachable through that contract are returned,
- contract-level events (contract delete / deactivation / expiry) - the affected contract is given, so the default script returns the manager(s) reachable through it,
- assignment-level events (loss of the guarantee role assignment) - the contract of the lost assignment is given.
import eu.bcvsolutions.idm.core.api.dto.filter.IdmIdentityFilter; if (identity == null) { return java.util.Collections.emptyList(); } IdmIdentityFilter filter = new IdmIdentityFilter(); filter.setManagersFor(identity.getId()); if (contract != null) { filter.setManagersByContract(contract.getId()); } return identityService.find(filter, null).getContent();
A custom script can be configured instead (e.g. to return a fixed support team). The contract given for an inactive contract still resolves managers, because DefaultManagersFilter enforces "valid contract managers" only when explicitly requested.
Transaction and ordering behaviour
- BEFORE phase, negative order (
DEFAULT_ORDER - 100) - guarantees, contracts and role assignments still exist, so the last guarantor can be detected and managers resolved. - Atomic with the triggering operation - the public methods of
RoleGuaranteeTransferManagerjoin the transaction of the operation that triggered them. An operation that is rejected or fails after the transfer ran (a validation such as a contract controlled by slices cannot be deleted, a constraint violation, an error while saving a contract during synchronization) rolls the transfer back as well, so the original guarantor is never silently replaced by a change that did not happen. The price is the opposite behaviour: a failed transfer aborts the triggering operation with an error instead of continuing without a guarantor. - Synchronous internal requests - the role requests the transfer creates are published with
PriorityType.IMMEDIATE, so they are executed inside the same transaction. This is what keeps the transfer atomic (an asynchronous request would run later in its own transaction and survive a rollback) and what makes the overlapping triggers of one operation see each other's result. - Idempotent across the triggers of one operation - one operation fires several triggers (deleting an identity also fires the contract and role-assignment events). The first trigger transfers; because its result is immediately visible, the exclusivity checks of the later triggers find the substitute as an effective holder / guarantee and do nothing, so neither the guarantee role nor the notification is duplicated. Assigning a guarantee / guarantee role that already exists is additionally detected and skipped.
- Anti-loop - the transfer's own role requests carry the transfer marker, so the assignment-loss triggers never react to them.
Implementation reference
Detection
| Type | Member | Purpose |
|---|---|---|
IdmRoleGuaranteeService | findExclusiveGuarantees(IdmIdentityDto) | Direct guarantees of the identity for which it is the last active guarantee of the given role and type (drives whether a substitute is added and with which type). Default method returns an empty list; implemented in DefaultIdmRoleGuaranteeService. |
IdmRoleGuaranteeService | find(filter.setGuarantee(id)) | All direct guarantees of the identity (used to remove it from all of them). |
IdmRoleGuaranteeRepository | findExclusiveGuarantees(UUID identityId) | JPQL (NOT EXISTS on other valid guarantees of the same type; null type is a type of its own) backing the above. |
IdmRoleGuaranteeRoleRepository | findExclusivelyHeldGuaranteeRoleIdsByIdentity(UUID, LocalDate) | Guarantee roles held only by the given identity (across any contract). |
IdmRoleGuaranteeRoleRepository | findExclusivelyHeldGuaranteeRoleIdsByContract(UUID, LocalDate) | Guarantee roles held only through the given contract. |
IdmRoleGuaranteeRoleRepository | findExclusivelyHeldGuaranteeRoleIdsByAssignment(UUID, UUID, LocalDate) | Guarantee role whose only effective holding is the given role assignment (the assignment itself is not filtered by validity). |
Transfer
| Component | Responsibility |
|---|---|
RoleGuaranteeTransferManager | Central service. transferForRemovedIdentity(…), transferForDeactivatedContract(…) and transferForRemovedAssignment(…) (all @Transactional, joining the triggering operation's transaction); direct guarantees replaced per role and type (substitute added with the inherited type, only the replaced guarantee removed); guarantee-role reassignment; substitute resolution + fallback chain; request description; new-guarantor notification; isContractEffectivelyActive(…); PROPERTY_GUARANTEE_TRANSFER anti-loop marker; guard for a role being (force) deleted. |
IdentityGuaranteeTransferDeleteProcessor | Identity DELETE. |
IdentityGuaranteeTransferDisableProcessor | Identity UPDATE into DISABLED_MANUALLY. |
IdentityContractGuaranteeTransferDeleteProcessor | Active contract DELETE. |
IdentityContractGuaranteeTransferDeactivateProcessor | Active contract UPDATE (active → inactive). |
IdentityContractGuaranteeTransferExpiredProcessor | Contract EXPIRED. |
IdentityRoleGuaranteeTransferDeleteProcessor | Role assignment DELETE (any removal path). |
IdentityRoleGuaranteeTransferDeactivateProcessor | Role assignment UPDATE (valid → invalid). |
HrEndContractProcess | Publishes EXPIRED for genuinely date-expired contracts (isFirstRun guard) before its standard de-provisioning / a configured workflow - the primary natural-expiry hook. |
HrContractExclusionProcess | For a contract excluded outside the application (state set to EXCLUDED directly, so no event fired), calls the transfer manager directly (removeSource = false, isFirstRun guard) before de-provisioning. |
IdentityContractExpirationTaskExecutor | Publishes EXPIRED (with isFirstRun guard) before removing roles of expired contracts. |
Configuration and resources
| Artifact | Location |
|---|---|
| Config properties | RoleConfiguration / DefaultRoleConfiguration |
| System script | eu/bcvsolutions/idm/scripts/roleGuaranteeTransferTargets.xml |
| Notification topic | CoreModule.TOPIC_ROLE_GUARANTEE_TRANSFERRED + CoreModuleDescriptor default config |
| E-mail template | eu/bcvsolutions/idm/templates/IdmCoreRoleGuaranteeTransferred.xml |
| Audit owners | IdmRoleGuarantee / IdmRoleGuaranteeRole implement AuditSearchable |
Tests
Integration tests (core-impl, JUnit 4 + TestHelper):
| Test class | Focus |
|---|---|
RoleGuaranteeExclusiveDetectionIntegrationTest | Detection queries / validity rules, incl. per-type exclusivity and the null-type bucket. |
RoleGuaranteeTransferManagerIntegrationTest | Transfer logic and substitute fallback chain, incl. type inheritance, removal of a non-last direct guarantee (without replacement) and the request description. |
RoleGuaranteeTransferNotificationIntegrationTest | New-guarantor notification (consolidation, role names, contact hint). |
RoleGuaranteeTransferIdentityEventIntegrationTest | Identity delete / block triggers. |
RoleGuaranteeTransferContractEventIntegrationTest | Contract delete / deactivate / expire triggers, incl. the expiration LRT and the HR end-contract / exclusion LRT paths. |
RoleGuaranteeTransferIdentityRoleEventIntegrationTest | Assignment-loss triggers (delete, validity change, assignment expiry LRT), anti-loop marker, deleted-role guard. |
RoleGuaranteeAuditIntegrationTest | Audit owner / sub owner of both guarantee entities, role detail audit reachability. |
RoleGuaranteeTransferConfigurationIntegrationTest | Config properties, script, template and notification configuration. |