Roles and Privileges
This document describes how authorization is managed in the tSM (Telco Service Management) application — specifically how roles, composite roles, and privileges work together to define what each user can do within the system.
The goal of this model is to provide a predictable, auditable, and flexible access control mechanism that scales from simple standalone setups to complex enterprise environments integrated with IAM systems.
Overview
In tSM, user permissions are determined by combining:
- Privileges – the smallest atomic access rights (e.g.,
Um.User.Edit) - Roles – groups of privileges that define allowed or denied operations
- Composite Roles – roles that include other roles
- Global Role Priority – defines which role dominates in case of conflict (via
globalPriorityfield) - canRestrictParent – defines whether a sub-role can remove privileges from its parent
1. Privileges
A Privilege represents the most granular unit of access control — a single action or right granted within the system.
Examples:
| Privilege Code | Description |
|---|---|
Um.User.View | View user records |
Um.User.Edit | Edit user details |
Inv.Service.Delete | Delete or deactivate a service |
Inv.Service.Approve | Approve a service change |
Cm.Config.View | View configuration data |
Privileges are usually grouped by functional module and entity:
Um.User.*– User ManagementInv.Service.*– Inventory and Service ManagementCm.Config.*– Configuration Management
2. Roles
A Role represents a named collection of privileges.
Each role defines what a user can do, and may either grant or remove certain privileges using prefix notation.
2.1 Privilege Prefixes
+Privilege→ grants permission–Privilege→ revokes permission
Example role definition:
+Um.User.View
+Um.User.Edit
-Um.User.Delete
This role allows the user to view and edit users, but not delete them.
Prefix definitions may also apply to entire namespaces:
+Um.Usergrants all user-related privileges.-Um.User.Commentsremoves all privileges related to comments.
3. Global Role Priority
When a user is assigned multiple roles, tSM resolves privilege conflicts using role priority (stored in the globalPriority field).
Each role has a numeric globalPriority (default = 0).
If multiple roles define conflicting privileges for the same action:
- The role with the higher priority wins.
- If two roles have the same priority, the negative (
–) privilege takes precedence (for safety).
Example 1 — Priority Conflict Resolution
| Role | Privilege | Prefix | Global Priority |
|---|---|---|---|
| Admin | +Inv.Service.Edit | + | 100 |
| Reader | -Inv.Service.Edit | - | 10 |
Result: the privilege Inv.Service.Edit remains allowed, since the Admin role has higher global priority (100 > 10).
Example 2 — Priority with Prefix Wildcards
| Role | Privilege Pattern | Prefix | Global Priority |
|---|---|---|---|
| Admin | +Inv.Service | + | 100 |
| LimitedUser | -Inv.Service.Delete | - | 50 |
Result:
Inv.Service.View→ ✅ allowed (from Admin, no conflict)Inv.Service.Edit→ ✅ allowed (from Admin, no conflict)Inv.Service.Delete→ ✅ allowed (Admin priority 100 overrides LimitedUser priority 50)
4. Composite Roles
A Composite Role is a role that includes one or more other roles.
This allows for modular and hierarchical role definitions — for example:
Admin
├── Operator
└── Reader
Composite roles simplify maintenance by enabling reuse of base roles and consistent propagation of privilege changes.
4.1 Restriction Behavior (canRestrictParent)
Each composite relationship defines whether the included (child) role can restrict privileges of the parent role via the canRestrictParent field.
| Parameter | Type | Description |
|---|---|---|
canRestrictParent | Boolean | If true, the included role's negative privileges (–) can override parent privileges. Default: false. |
- If
canRestrictParent = false, the child role can only add privileges (its–entries are ignored). - If
canRestrictParent = true, the child role can add and remove privileges.
4.2 Example 1 — Non-restricting Role
Admin
├── Reader (canRestrictParent = false)
| Role | Privilege | Prefix |
|---|---|---|
| Admin | +Inv.Service | + |
| Reader | -Inv.Service.Edit | - |
Result:
Inv.Service.Edit remains granted, since Reader cannot restrict Admin privileges (canRestrictParent = false).
4.3 Example 2 — Restricting Role
Auditor
├── Compliance (canRestrictParent = true)
| Role | Privilege | Prefix |
|---|---|---|
| Auditor | +Inv.Service.View | + |
| Compliance | -Inv.Service.Delete | - |
Result:
Inv.Service.Delete is revoked, since Compliance can restrict its parent (canRestrictParent = true).
5. Merge Algorithm
tSM calculates a user's effective privileges through a deterministic two-phase merge process:
Phase 1: Compose Each Role (within role hierarchy)
For each assigned role:
- Collect privileges from the role itself.
- Recursively include all child roles from composite relationships.
- Apply
canRestrictParentlogic:- If
canRestrictParent = false: ignore negative (–) privileges from the child role - If
canRestrictParent = true: apply both positive and negative privileges from the child role
- If
- Result: a flattened privilege set for this role with all composite relationships resolved.
Phase 2: Merge Across Roles (using global priority)
- Collect all composed roles assigned to the user.
- Sort by
globalPriority(highest first). - Apply privileges in priority order:
- Start with the highest priority role's privileges
- For each subsequent role, only apply privileges that haven't been decided yet
- If a privilege conflict occurs, the higher priority wins
- Tie-breaking: If two roles have equal
globalPriority, negative (–) overrides positive (+) for safety. - Generate audit trace indicating the origin of each privilege.
Example
Given user assigned roles:
- Admin (simple role, priority 100)
- ServiceManager (composite role, priority 50)
Role definitions:
Admin (globalPriority = 100):
+Inv.Service # Grants all service privileges
ServiceManager (globalPriority = 50):
+Inv.Service.View
+Inv.Service.Edit
Includes: RestrictivePolicy (canRestrictParent = true)
RestrictivePolicy (child of ServiceManager):
-Inv.Service.Delete # Removes delete permission
-Inv.Service.Approve # Removes approve permission
Step 1: Compose Each Role (within role hierarchy)
| Role | Direct Privileges | Includes | canRestrictParent | Composed Result |
|---|---|---|---|---|
| Admin | +Inv.Service | — | — | +Inv.Service (grants all: View, Edit, Delete, Approve) |
| ServiceManager | +Inv.Service.View+Inv.Service.Edit | RestrictivePolicy | true | +Inv.Service.View+Inv.Service.Edit-Inv.Service.Delete (restriction applied)-Inv.Service.Approve (restriction applied) |
Explanation of Step 1:
- Admin: Simple role, no composition. Result: grants entire
Inv.Servicenamespace. - ServiceManager: Composite role that includes
RestrictivePolicywithcanRestrictParent = true- Starts with:
+View,+Edit - RestrictivePolicy adds:
-Delete,-Approve - Because
canRestrictParent = true, the negative privileges are applied - Composed result: View ✅, Edit ✅, Delete ❌, Approve ❌
- Starts with:
Step 2: Merge Across Roles (using global priority)
Now we merge the two composed roles based on globalPriority:
| Priority | Role | Privilege | Decision | Reason |
|---|---|---|---|---|
| 100 | Admin | Inv.Service.View | ✅ Allow | Highest priority grants it |
| 100 | Admin | Inv.Service.Edit | ✅ Allow | Highest priority grants it |
| 100 | Admin | Inv.Service.Delete | ✅ Allow | Highest priority grants it |
| 100 | Admin | Inv.Service.Approve | ✅ Allow | Highest priority grants it |
| 50 | ServiceManager | All privileges | — | Ignored (lower priority) |
Effective permissions:
Inv.Service.View→ ✅ allowed (Admin priority 100)Inv.Service.Edit→ ✅ allowed (Admin priority 100)Inv.Service.Delete→ ✅ allowed (Admin priority 100 wins over ServiceManager's restriction)Inv.Service.Approve→ ✅ allowed (Admin priority 100 wins over ServiceManager's restriction)
Alternative Scenario: If user has only ServiceManager role (without Admin):
| Priority | Role | Privilege | Decision |
|---|---|---|---|
| 50 | ServiceManager | Inv.Service.View | ✅ Allow |
| 50 | ServiceManager | Inv.Service.Edit | ✅ Allow |
| 50 | ServiceManager | Inv.Service.Delete | ❌ Deny |
| 50 | ServiceManager | Inv.Service.Approve | ❌ Deny |
Effective permissions:
Inv.Service.View→ ✅ allowedInv.Service.Edit→ ✅ allowedInv.Service.Delete→ ❌ denied (RestrictivePolicy restriction viacanRestrictParent = true)Inv.Service.Approve→ ❌ denied (RestrictivePolicy restriction viacanRestrictParent = true)
Key insight:
- Phase 1 (Composition):
canRestrictParent = trueallows child roles to restrict parent's privileges within a single composed role.- Phase 2 (Merge):
globalPrioritydetermines which role wins across different roles - higher priority always overrides lower priority, regardless of restrictions in the lower-priority composed role.
6. Data Model Overview
| Entity | Description |
|---|---|
| roles | Defines role metadata, including globalPriority and composedRoles (list of included child roles). |
| role_privileges | Links roles to privileges with prefixes + or –. |
| user_roles | Associates users with roles. |
| privileges | Stores all available privilege codes and descriptions. |
Domain Model
6.1 Reference - Entity Attributes
Role (attributes)
| Field | Type | Required | Read-only | Description / Notes |
|---|---|---|---|---|
id | UUID | – | – | Unique identifier (not intended for end-user display). |
code | String | Yes | – | Unique ASCII code (no spaces). Used in APIs & configurations. Min 1, max 255 characters. |
name | String | Yes | – | Display name shown to users. Min 1, max 255 characters. |
description | String | – | – | Tooltip/long description. |
validityFrom | Date | – | – | Begin of the validity of the role. |
validityTo | Date | – | – | End of the validity of the role. |
valid | Boolean | – | Yes | True/False depending on whether we are within validity interval. Computed, not stored. |
localizationData | Object | – | – | Translations for attributes (e.g., name, description). |
dataTags | List | – | – | Labels/tags for search and reporting. |
ldapMemberOf | String | – | – | If role is in LDAP, the location in LDAP directory. |
config | Map | – | – | Additional configuration. |
auditInfo | Object | – | – | Standard audit fields (created by/at, updated by/at). |
globalPriority | Integer | – | – | Global priority for conflict resolution. Default: 0. Higher values take precedence. |
composedRoles | List<ComposedRole> | – | – | List of child roles included in this composite role. Each entry specifies childRoleId, childRoleCode, and canRestrictParent. |
Privilege (attributes)
| Field | Type | Required | Read-only | Description / Notes |
|---|---|---|---|---|
id | UUID | – | – | Unique identifier (not intended for end-user display). |
code | String | Yes | – | Unique ASCII code (no spaces). Used in APIs & configurations. Min 1, max 255 characters. |
name | String | Yes | – | Display name shown to users. Min 1, max 255 characters. |
description | String | – | – | Tooltip/long description. |
validityFrom | Date | – | – | Begin of the validity of the privilege. |
validityTo | Date | – | – | End of the validity of the privilege. |
valid | Boolean | – | Yes | True/False depending on whether we are within validity interval. Computed, not stored. |
localizationData | Object | – | – | Translations for attributes (e.g., name, description). |
dataTags | List | – | – | Labels/tags for search and reporting. |
config | Map | – | – | Additional general configuration of the Privilege entity. |
auditInfo | Object | – | – | Standard audit fields (created by/at, updated by/at). |
privType | Enum | – | – | Type of privilege: SYSTEM or USER. Default: SYSTEM. |
PrivType Enum:
SYSTEM— system-defined privilegeUSER— user-defined privilege
ComposedRole (nested object)
Part of: Role.composedRoles list
Purpose: Defines a child role included in a composite role and its composition rules.
| Field | Type | Required | Description |
|---|---|---|---|
childRole | String | – | Code of the child role |
canRestrictParent | Boolean | – | If true, child role's negative privileges can override parent's positive privileges. Default: false. |
Example API representation:
{
"id": "parent-role-uuid",
"code": "ServiceManager",
"name": "Service Manager",
"globalPriority": 50,
"composedRoles": [
{
"childRole": "RestrictivePolicy",
"canRestrictParent": true
},
{
"childRole": "BaseOperator",
"canRestrictParent": false
}
]
}
Role Privilege (attributes)
Links roles to privileges with grant/deny prefixes.
| Field | Type | Required | Description |
|---|---|---|---|
id | UUID | – | Unique identifier of the role-privilege relationship. |
roleId | UUID | Yes | ID of the role. |
privilegeCode | String | Yes | Code of the privilege (can be a specific privilege or a namespace prefix). |
prefix | String | Yes | + (grant) or - (deny). |
auditInfo | Object | – | Standard audit fields. |
User Role (attributes)
Associates users with roles.
| Field | Type | Required | Description |
|---|---|---|---|
id | UUID | – | Unique identifier of the user-role assignment. |
userId | UUID | Yes | ID of the user. |
roleId | UUID | Yes | ID of the assigned role. |
auditInfo | Object | – | Standard audit fields. |
7. Auditing and Debugging
Every effective privilege can be traced to its source. tSM records which role granted or removed each permission and how conflicts were resolved.
Example audit log entry:
Privilege: Inv.Service.Edit
Effective: ALLOW
Source: +Inv.Service (from role Admin, priority 100)
Conflicted with: -Inv.Service.Edit (from role Reader, priority 10, ignored)
This ensures transparent decision tracking for compliance and debugging.
8. Best Practices
| Recommendation | Description |
|---|---|
| Use higher priorities for broader or administrative roles. | Example: Admin = 100, Manager = 50, Reader = 10. |
Keep canRestrictParent = false for most composites. | Ensures inherited roles only expand capabilities. |
Use canRestrictParent = true for compliance or security roles. | Allows limiting sensitive actions. |
| Avoid deep nesting of roles. | Simplifies privilege resolution. |
| Regularly review effective privileges. | Changes in composite hierarchies can propagate widely. |
9. Summary
| Concept | Description |
|---|---|
| Privilege | Smallest atomic access right (e.g., Um.User.Edit). |
| Role | A collection of privileges with + and – prefixes. |
| Global Priority | Determines which role wins when conflicts occur. |
| Composite Role | Role that includes other roles. |
| canRestrictParent | Defines whether a child role can override the parent's rights. |
The result is a clear, modular, and auditable authorization system that supports both simple deployments and enterprise IAM integration.