Status-Based RBAC in JMatrixPlatform: Lifecycle-Aware Access Control
JMatrixPlatform implements Role-Based Access Control (RBAC) by binding permissions to object statuses. Every object has a type and a lifecycle — a defined sequence of statuses that reflect its current state. When an object is created, its type and associated lifecycle are specified; the initial status defaults to the first in that lifecycle or is explicitly overridden in the createAction.
A single object type can support multiple lifecycles. For example:
| Object | Type | Lifecycle | Status | Available Next Statuses |
|--------|------|-----------|--------|--------------------------|
| Obj1 | Type1| LC1 | Stat1 | Stat1*, Stat2 |
| Obj2 | Type1| LC2 | Stat4 | Stat1–4* |
| Obj3 | Type1| LC3 | Stat2 | Stat1–3* |
Typical lifecycles include:
- Documentation: Draft → Published → Review → Archived → Issued
- Reference data: New → Active → Deprecated
Status transitions occur via promote (forward) or demote (backward), with full audit logging in the object_states table:
create table object_states (
object_id uuid not null,
policy_state varchar(100) not null,
user_id uuid not null,
state_start timestamp not null,
state_end timestamp
);
Audit logs enable process delay analysis: SELECT user_id FROM object_states WHERE policy_state = ? AND (state_end - state_start) >= ?.
Configuring Roles and Policies
Roles extend JRole:
@JModelPart
public final class ARLReferenceAdmin extends JRole {
public final static ARLReferenceAdmin ROLE = new ARLReferenceAdmin();
@Override
public Set<JRole> getParents() {
return Set.of(ARLRefDesigner.ROLE, ARLRefChangeManagementAdmin.ROLE, ARLRefApprover.ROLE);
}
@Override
public String getDescription() {
return "Reference Data Administrator";
}
}
Lifecycles extend JPolicy:
@JModelPart
public final class ALCReference extends JPolicy {
public final static ALCReference POLICY = new ALCReference();
@Override
public Set<JType> getTypes() {
return Set.of(ATPReference.TYPE);
}
@Override
public List<JState> getStates() {
return List.of(New.STATE, Active.STATE, Inactive.STATE);
}
public static final class New extends JPolicy.JState {
public static final New STATE = new New();
@Override
public Set<RoleAccess> getAccess() {
return Set.of(new RoleAccess(ARLReferenceAdmin.ROLE, AccessType.ALL));
}
}
public static final class Active extends JPolicy.JState {
public static final Active STATE = new Active();
@Override
public Set<RoleAccess> getAccess() {
return Set.of(
new RoleAccess(JPublic.ROLE, AccessType.READ),
new RoleAccess(ARLReferenceAdmin.ROLE, AccessType.PROMOTE, AccessType.DEMOTE));
}
}
public static final class Inactive extends JPolicy.JState {
public static final Inactive STATE = new Inactive();
@Override
public Set<RoleAccess> getAccess() {
return Set.of(
new RoleAccess(JPublic.ROLE, AccessType.READ),
new RoleAccess(ARLReferenceAdmin.ROLE, AccessType.DEMOTE));
}
}
}
AccessType values:
- ALL: Full control
- READ: View only
- CREATE: Create new instances
- MODIFY: Edit existing data
- DELETE: Remove objects
- RELEASE: Version management
- PROMOTE: Advance to next status
- DEMOTE: Revert to previous status
- CHECKIN: Upload files
- CHECKOUT: Download files
Object creation:
JDomainObject obj = new JDomainObject();
obj.create(ctx, ATPDocuments.TYPE, ALCDocument.POLICY);
The platform validates CREATE permission against the initial status. Status transitions use:
obj.promote(ctx); // forward
obj.demote(ctx); // backward
Database-Level Authorization Mechanisms
JWT roles integrate with Keycloak, and row-level filtering is applied directly in SQL queries — data never leaves the database without authorization.
Maximum Access
JSystemAdmin bypasses all checks for maximum throughput.
Status-Based Access
Example access matrix:
| Role | New | Active | Deprecated |
|-------------------|------------|-----------------------|--------------|
| ARLReferenceAdmin | ALL | READ, PROMOTE, DEMOTE | READ, DEMOTE |
| JPublic | #NOACCESS | READ | READ |
For JPublic: WHERE policy_state IN ('ALCReference.Active', 'ALCReference.Inactive').
For administrators: no status restrictions. Optimization note: ~100 statuses max per policy; temp-table-based filtering under consideration.
Property-Based Filtering
In development. Recursive relationship traversal for access checks is currently inefficient.
Key Takeaways
- Statuses are natively embedded into RBAC — enabling fine-grained, non-destructive access control.
- Full status audit trail in
object_statessupports process analytics and compliance reporting. - SQL-level filtering ensures sensitive data never leaves the database without explicit authorization.
- Every
promote/demoteaction is logged with user ID and timestamp. - Seamless Keycloak role synchronization into JWT tokens.
— Editorial Team
No comments yet.