Permission Types
The MATIH Platform uses a string-based permission model with three dimensions: resource, action, and scope. Permissions are evaluated by the RbacService and PermissionEvaluator classes, which support wildcards, composite policies, and resource-level ownership checks. This page documents all permission types, the naming convention, and how they are evaluated.
Permission Format
Every permission in MATIH follows the resource:action format:
resource:action| Component | Description | Examples |
|---|---|---|
| Resource | The type of entity being accessed | data, queries, pipelines, reports, users, settings |
| Action | The operation being performed | read, write, execute, delete |
Wildcard Permissions
The system supports three forms of wildcard:
| Pattern | Meaning | Example |
|---|---|---|
* | Full wildcard -- grants all permissions on all resources | Assigned to super_admin |
resource:* | Resource wildcard -- grants all actions on a specific resource | data:* grants read, write, delete on data |
*:action | Action wildcard -- grants a specific action on all resources | *:read grants read access to everything |
Wildcard Resolution
The hasResourcePermission method checks all three levels:
// From RbacService.java
public boolean hasResourcePermission(String userId, String resource, String action) {
String permission = resource + ":" + action;
String wildcardResource = resource + ":*";
String wildcardAction = "*:" + action;
return hasAnyPermission(userId, permission, wildcardResource, wildcardAction);
}The check evaluates in this order:
- Exact match:
data:read - Resource wildcard:
data:* - Action wildcard:
*:read - Global wildcard:
*
Standard Resource Types
The platform defines the following standard resource types:
| Resource | Description | Available Actions |
|---|---|---|
data | Data sources and datasets | read, write, delete |
queries | SQL queries and saved queries | read, write, execute, delete |
pipelines | Data pipelines and jobs | read, write, execute, delete |
reports | Dashboards and reports | read, write, delete, share |
users | User accounts and profiles | read, write, delete |
settings | Tenant and service configuration | read, write |
audit | Audit logs and compliance records | read |
data_quality | Data quality rules and results | read, write, execute |
models | ML models and experiments | read, write, deploy, delete |
agents | AI agents and workflows | read, write, execute, deploy, delete |
connectors | Data source connectors | read, write, test, delete |
schedules | Job schedules and triggers | read, write, delete |
Standard Action Types
| Action | Description | HTTP Method Mapping |
|---|---|---|
read | View or list resources | GET |
write | Create or update resources | POST, PUT, PATCH |
delete | Remove resources | DELETE |
execute | Run or trigger resources (queries, pipelines, agents) | POST (to execution endpoint) |
deploy | Deploy to production (models, agents) | POST (to deployment endpoint) |
share | Share resources with other users or tenants | POST (to sharing endpoint) |
test | Test connections or configurations | POST (to test endpoint) |
Resource-Level Policies
The PermissionEvaluator supports resource-level policies that go beyond simple role-based checks. These policies can inspect the actual resource instance to make authorization decisions.
ResourcePolicy Interface
// From PermissionEvaluator.java
public interface ResourcePolicy {
boolean evaluate(String userId, String action, Object resource);
}Ownership Policy
The most common resource-level policy is ownership, which restricts write and delete operations to the resource owner:
// From PermissionEvaluator.java
public static class OwnershipPolicy<T> implements ResourcePolicy {
private final Function<T, String> ownerExtractor;
private final Set<String> ownerOnlyActions;
public OwnershipPolicy(Function<T, String> ownerExtractor) {
this(ownerExtractor, Set.of("update", "delete"));
}
@Override
@SuppressWarnings("unchecked")
public boolean evaluate(String userId, String action, Object resource) {
if (resource == null) {
return true; // No instance to check
}
// Only enforce ownership for specific actions
if (!ownerOnlyActions.contains(action)) {
return true;
}
try {
String ownerId = ownerExtractor.apply((T) resource);
return userId.equals(ownerId);
} catch (ClassCastException e) {
return false;
}
}
}Registering Ownership Policies
// Register an ownership policy for dashboards
evaluator.registerOwnershipPolicy("reports",
(Dashboard dashboard) -> dashboard.getCreatedBy()
);
// Register an ownership policy for saved queries
evaluator.registerOwnershipPolicy("queries",
(SavedQuery query) -> query.getOwnerId()
);Composite Policies
Multiple policies can be composed using AllOfPolicy (all must pass) or AnyOfPolicy (any must pass):
// All policies must pass
ResourcePolicy strictPolicy = new PermissionEvaluator.AllOfPolicy(
new OwnershipPolicy<>(Dashboard::getCreatedBy),
(userId, action, resource) -> !((Dashboard) resource).isLocked()
);
// Any policy can pass
ResourcePolicy flexiblePolicy = new PermissionEvaluator.AnyOfPolicy(
new OwnershipPolicy<>(Dashboard::getCreatedBy),
(userId, action, resource) -> ((Dashboard) resource).isSharedWith(userId)
);Tenant-Aware Permission Checks
The PermissionEvaluator automatically enforces tenant isolation when a resource implements the TenantAware interface:
// From PermissionEvaluator.java
public interface TenantAware {
String getTenantId();
}When evaluating permissions with a SecurityContext, the evaluator checks that the resource belongs to the same tenant as the requesting user:
public <T> boolean evaluate(SecurityContext context, String resource,
String action, T resourceInstance) {
// ...
// Tenant isolation check
if (context.tenantId() != null && resourceInstance instanceof TenantAware tenantAware) {
if (!context.tenantId().equals(tenantAware.getTenantId())) {
return false; // Tenant isolation violation
}
}
return evaluate(context.userId(), resource, action, resourceInstance);
}This ensures that even if a user has the correct role-based permissions, they cannot access resources belonging to another tenant.
SecurityContext
The SecurityContext record carries the complete authorization context for a request:
// From PermissionEvaluator.java
public record SecurityContext(
String userId,
String tenantId,
Set<String> roles,
Map<String, Object> attributes
) {
public static SecurityContext of(String userId, String tenantId) {
return new SecurityContext(userId, tenantId, Set.of(), Map.of());
}
public static SecurityContext of(String userId, String tenantId, Set<String> roles) {
return new SecurityContext(userId, tenantId, roles, Map.of());
}
public Optional<Object> getAttribute(String key) {
return Optional.ofNullable(attributes.get(key));
}
}The attributes map can carry arbitrary context data for attribute-based access control (ABAC), such as:
| Attribute | Type | Description |
|---|---|---|
ip_address | String | Client IP for geo-restriction |
mfa_verified | Boolean | Whether MFA was completed |
session_id | String | Session identifier for session-scoped policies |
data_classification | String | Data classification level for data-level policies |
Permission Requirement Builders
The PermissionEvaluator provides a fluent API for creating reusable permission requirements as Predicate<SecurityContext>:
// Require a specific permission
Predicate<SecurityContext> canRead = evaluator.requirePermission("data:read");
// Require any of several permissions
Predicate<SecurityContext> canManage = evaluator.requireAnyPermission(
"data:write", "data:delete"
);
// Require all permissions
Predicate<SecurityContext> canFullyManage = evaluator.requireAllPermissions(
"data:read", "data:write", "data:delete"
);
// Require a specific role
Predicate<SecurityContext> isAdmin = evaluator.requireRole("tenant_admin");
// Require any role
Predicate<SecurityContext> isPrivileged = evaluator.requireAnyRole(
"tenant_admin", "super_admin"
);These predicates can be composed using standard Java functional interfaces:
// Must be admin AND have MFA verified
Predicate<SecurityContext> secureAdmin = isAdmin
.and(ctx -> ctx.getAttribute("mfa_verified")
.map(v -> Boolean.TRUE.equals(v))
.orElse(false));Related Pages
- RBAC Model -- Overview of the RBAC system
- Role Hierarchy -- Built-in roles, custom roles, inheritance
- OPA Policies -- OPA integration for policy-as-code