contexa-iam

Authorization Architecture

XACML-based authorization architecture for URL and method-level policy evaluation, AI-powered security expressions, and runtime policy management through the current OSS admin flows.

Overview

Traditional Spring Security authorization uses static annotations like @PreAuthorize("hasRole('ADMIN')") that are hardcoded at compile time. When business requirements change —such as restricting admin access to business hours or requiring MFA for sensitive operations —you must modify source code and redeploy.

Contexa's authorization architecture solves this by externalizing authorization policies into the database. Policies are managed through the admin console, with Policy Center serving as the primary OSS authoring surface, and are applied at runtime without code changes. The engine follows the XACML standard architecture with five components that separate policy enforcement, decision-making, administration, information gathering, and retrieval into distinct, testable concerns.

For details on how these components are wired into the Spring Security filter chain, see Identity DSL.

Static vs Dynamic Authorization

AspectStatic (Spring Security default)Dynamic (Contexa)
Policy definitionAnnotations in source codeDatabase-stored policies via Admin UI
Policy changesRequires code change + redeployRuntime hot-reload, zero downtime
Enforcement scopePer-method or per-URL (compile time)URL-level + method-level (runtime)
Context awarenessAuthentication + authorities onlyUser, resource, environment, behavioral metrics, AI threat scores
AI integrationNot available#ai.isAllowed(), #ai.needsChallenge() in SpEL
Audit trailManual implementation requiredCentralAuditFacade integration for policy-service events and denied URL authorization results
CoexistenceBoth can work together: .requestMatchers().permitAll() for static rules, .anyRequest().access(customDynamicAuthorizationManager) for dynamic

Key Capabilities

  • Runtime policy changes —Add, modify, or revoke access rules without redeployment via Policy Center or server-side policy APIs
  • Two enforcement layers —URL-level via Dynamic Authorization and method-level via @Protectable
  • Rich context evaluation —Policies can reference behavioral metrics, time-of-day, device info, and AI threat scores collected by the PIP
  • AI-powered security expressions —Use #ai.isAllowed(), #ai.needsChallenge(), and other AI expressions directly in SpEL policy conditions
  • End-to-end resource managementResource Scanner discovers endpoints, ManagedResourceRepository stores synchronized resources, and Policy Center drives the current OSS permission-definition and policy-authoring flow
  • SpEL-native —Uses Spring Expression Language instead of XML, keeping the familiar Spring Security programming model
Related pages:

Architecture Overview

Contexa implements the XACML reference architecture with SpEL (Spring Expression Language) as the policy expression language. Instead of XML-based XACML policies, Contexa uses a relational data model where policies, rules, conditions, and targets are stored as JPA entities with SpEL expressions for evaluation.

Text
Incoming Request
PEP (Enforcement)
CustomDynamicAuthorizationManager
Policy Components
PIP
Attribute Info
PDP
Policy Decision
PRP
Policy Retrieval
Decision: ALLOW / DENY
PEP Enforce

PEP —Policy Enforcement Point

The PEP intercepts authorization requests and delegates decisions to the PDP. Contexa provides two PEP implementations for URL-level and method-level enforcement.

CustomDynamicAuthorizationManager

Implements AuthorizationManager<RequestAuthorizationContext> for URL-based policy enforcement. On application context refresh, it loads all URL policies from the PRP and builds a list of RequestMatcherEntry mappings.

Java
public class CustomDynamicAuthorizationManager
        implements AuthorizationManager<RequestAuthorizationContext> {

    private final PolicyRetrievalPoint policyRetrievalPoint;
    private final ExpressionAuthorizationManagerResolver managerResolver;
    private final ContextHandler contextHandler;
    private final ZeroTrustEventPublisher zeroTrustEventPublisher;
    private final AuthorizationMetrics metricsCollector;

    // Initializes on ContextRefreshedEvent
    @EventListener
    public void onApplicationEvent(ContextRefreshedEvent event) {
        initialize();
    }

    @Override
    public AuthorizationDecision check(
            Supplier<Authentication> authenticationSupplier,
            RequestAuthorizationContext context) { ... }

    // Hot-reload: clears PRP cache and re-initializes mappings
    public synchronized void reload() { ... }
}

Policy-to-Expression Conversion

The getExpressionFromPolicy() method converts a Policy entity into a SpEL expression string:

  • No conditions with ALLOW effect —permitAll
  • No conditions with DENY effect —denyAll
  • Single condition —uses the expression directly
  • Multiple simple authority conditions —hasAnyAuthority('A','B')
  • Multiple mixed conditions —joined with or
  • DENY effect —wraps the expression in !()
  • hasPermission() calls are stripped from URL policies since they are only relevant for method-level evaluation

ExpressionAuthorizationManagerResolver

Resolves SpEL expression strings into AuthorizationManager instances by delegating to a chain of ExpressionEvaluator implementations.

Java
public class ExpressionAuthorizationManagerResolver {

    private final List<ExpressionEvaluator> evaluators;
    private final SecurityExpressionHandler<RequestAuthorizationContext>
            customWebSecurityExpressionHandler;

    public AuthorizationManager<RequestAuthorizationContext> resolve(
            String expression) {
        // Iterates evaluators; WebSpelExpressionEvaluator creates
        // WebExpressionAuthorizationManager with custom handler
    }
}

PDP —Policy Decision Point

The PDP evaluates authorization requests against policies and returns decisions. In Contexa, runtime URL and method evaluation happens through SpEL expression handling; PolicyExpressionConverter prepares runtime URL expressions, while PolicyTranslator serves human-readable translation and entitlement rendering.

PolicyTranslator

Translates Policy entities to human-readable strings and EntitlementDto objects by walking the SpEL AST (Abstract Syntax Tree). It supports pluggable SpelFunctionTranslator instances for custom SpEL method translations.

Java
public class PolicyTranslator {

    private final RoleRepository roleRepository;
    private final GroupRepository groupRepository;
    private final PermissionRepository permissionRepository;
    private final List<SpelFunctionTranslator> translators;

    // Policy -> Human readable string
    public String translatePolicyToString(Policy policy) { ... }

    // Policy -> Entitlement DTOs with subject/action/condition analysis
    public Stream<EntitlementDto> translate(Policy policy, String resourceName) { ... }

    // Policy -> ExpressionNode tree for programmatic analysis
    public ExpressionNode parsePolicy(Policy policy) { ... }

    // Single condition -> ExpressionNode
    public ExpressionNode parseCondition(PolicyCondition condition) { ... }
}

SpEL AST Node Translation

SpEL NodeTranslation
OpAnd(left and right)
OpOr(left or right)
OperatorNotNOT (expr)
OpEQleft equals right
MethodReferenceDelegated to matching SpelFunctionTranslator
Identifier("permitAll")All access permitted
Identifier("denyAll")All access denied

PAP —Policy Administration Point

The PAP manages the lifecycle of authorization policies. See the Policy Management page for detailed API documentation of all PAP services.

ServiceResponsibility
PolicyService Manages policy CRUD operations and synchronizes policies when role-permission assignments change.
PolicyBuilderService Provides template lookup, visual-model conversion, and conflict detection for policy authoring services. The current OSS UI exposes authoring primarily through Policy Center rather than a standalone builder template.
PolicySynchronizationService Automatically regenerates and updates policies when a RolePermissionsChangedEvent is published.
PolicyEnrichmentService Enriches policies with human-readable descriptions by delegating to the PolicyTranslator.
BusinessPolicyService Translates business-level rules into technical policy representations that the PDP can evaluate.

PIP —Policy Information Point

The PIP collects attributes needed for policy evaluation. It provides contextual data about subjects, resources, actions, and the environment to the PDP.

AttributeInformationPoint

Java
public interface AttributeInformationPoint {
    Map<String, Object> getAttributes(AuthorizationContext context);
}

DatabaseAttributePIP

The primary PIP implementation that enriches the authorization context from database sources. It collects five categories of attributes:

CategoryAttributes Collected
Basic User userId, userEmail, userGroups, groupCount, mfaEnabled, createdAt
Behavior Metrics requestsInLastHour, requestsInLastDay, uniqueResourcesAccessed, typicalAccessHours, accessVelocity
Resource Patterns resourceTotalAccess, resourceUniqueUsers, resourceSensitivityLevel, resourceRecentFailures
Time/Environment currentHour, currentDayOfWeek, isBusinessHours, isWeekend, remoteAddress
Security Profile userSecurityScore, hasRecentFailures, highAccessVelocity, unusualAccessTime, riskIndicatorCount

AuthorizationContext

Java
public record AuthorizationContext(
    Authentication subject,
    Users subjectEntity,
    ResourceDetails resource,
    String action,
    EnvironmentDetails environment,
    Map<String, Object> attributes
) {}

ContextHandler

Creates AuthorizationContext instances for both URL and method-level authorization:

Java
public interface ContextHandler {
    AuthorizationContext create(Authentication authentication,
                               HttpServletRequest request);
    AuthorizationContext create(Authentication authentication,
                               MethodInvocation invocation);
}

PRP —Policy Retrieval Point

The PRP retrieves policies from the underlying data store. Contexa caches policies through ContexaCacheService to minimize database queries during high-throughput authorization.

Java
public interface PolicyRetrievalPoint {
    List<Policy> findUrlPolicies();
    void clearUrlPoliciesCache();
    List<Policy> findMethodPolicies(String methodIdentifier);
    void clearMethodPoliciesCache();
}

DatabasePolicyRetrievalPoint

The default implementation that retrieves policies from the database via PolicyRepository with caching through ContexaCacheService.

Cache KeyDescription
policies:url:allAll active URL policies
policies:method:{identifier}Method-specific policies by method identifier

AI-generated policies are only included when their approvalStatus is APPROVED and isActive is true. Unapproved AI policies are filtered out during the initialization phase in the PEP.

Complete Authorization Flow

Text
1. Request arrives at Spring Security filter chain
2. PEP (CustomDynamicAuthorizationManager) receives RequestAuthorizationContext
3. ContextHandler creates AuthorizationContext with subject, resource, action
4. PEP matches request URL against cached RequestMatcherEntry list
5. Matched entry's AuthorizationManager evaluates the SpEL expression
   - The expression was derived from Policy -> Rules -> Conditions
   - hasRole(), hasAuthority(), hasAnyAuthority() etc.
6. PDP (SpEL evaluator) returns AuthorizationDecision(granted/denied)
7. PEP enforces the decision
   - If granted: request proceeds to the controller
   - If denied: 403 Forbidden response
8. Denied URL authorization results and policy-service events are recorded through CentralAuditFacade-backed audit flows

AI-Powered Security Expressions

Contexa extends the standard Spring Security SpEL environment with AI-driven expressions. These are available in both URL-level and method-level policy conditions through the #ai variable, backed by AbstractAISecurityExpressionRoot.

AI Expression Reference

All AI expressions query the Zero Trust action available for the current request. In OSS, method-level evaluation checks the current request attribute first, then a short-lived local Caffeine cache, and then the shared ZeroTrustActionRepository lookup.

ExpressionReturn TypeDescription
#ai.isAllowed()booleanReturns true if the AI Zero Trust action is ALLOW
#ai.isBlocked()booleanReturns true if the AI Zero Trust action is BLOCK
#ai.needsChallenge()booleanReturns true if the AI recommends a step-up authentication challenge
#ai.needsEscalation()booleanReturns true if the AI recommends escalation to a human reviewer
#ai.isPendingAnalysis()booleanReturns true if the AI analysis has not yet completed
#ai.hasAction('ACTION')booleanReturns true if the Zero Trust action matches the given string
#ai.hasActionIn('A','B')booleanReturns true if the Zero Trust action is one of the given values
#ai.hasActionOrDefault('DEFAULT','A','B')booleanLike hasActionIn, but uses the default action when no analysis result exists

Usage in SpEL Policy Conditions

SpEL
// Require both role and AI approval
hasRole('ADMIN') and #ai.isAllowed()

// Allow if user has role OR AI allows it
hasRole('MANAGER') or #ai.isAllowed()

// Block if AI detects threat, regardless of role
hasRole('USER') and !#ai.isBlocked()

// Flexible action matching with fallback
hasRole('USER') and #ai.hasActionOrDefault('ALLOW', 'ALLOW', 'CHALLENGE')

URL-Level Expressions

CustomWebSecurityExpressionRoot adds HTTP-specific expressions available in URL policy conditions:

ExpressionDescription
hasIpAddress('192.168.1.0/24')Checks if the request originates from the specified IP address or CIDR range
getHttpMethod()Returns the HTTP method of the request (GET, POST, PUT, DELETE, etc.)

Method-Level Expressions

CustomMethodSecurityExpressionRoot adds method-specific expressions with local caching:

  • hasPermission(target, permission) —Evaluates permission through the CompositePermissionEvaluator, including ownership verification when ownerField is set
  • hasPermission(targetId, targetType, permission) —ID-based permission evaluation with the same ownership support
  • Local cache —Method-level Zero Trust action results are cached locally using Caffeine with a 5-second TTL and 10,000-entry maximum before falling back to the shared repository lookup
Expression hierarchy:
  • AbstractAISecurityExpressionRoot —provides AI expressions (#ai.*) to both URL and method contexts
  • CustomWebSecurityExpressionRoot —adds hasIpAddress() for URL policies
  • CustomMethodSecurityExpressionRoot —adds hasPermission() with ownership verification for method policies

Quick Start

Get dynamic authorization running in four steps:

1. Configure Spring Security

Inject CustomDynamicAuthorizationManager and add it to your security filter chain:

Java
@Configuration
public class SecurityConfig {

    @Autowired
    private CustomDynamicAuthorizationManager dynamicAuthManager;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(auth -> auth
            // Static rules evaluated first
            .requestMatchers("/", "/home", "/css/**", "/js/**").permitAll()
            .requestMatchers("/login", "/register").permitAll()
            // All other requests use dynamic authorization
            .anyRequest().access(dynamicAuthManager)
        );
        return http.build();
    }
}

2. Create Your First Policy

Open the Admin Console and navigate to Policy Center. Use the Create surface to set a URL target (e.g., /admin/**) with an ALLOW effect and condition hasRole('ADMIN').

3. Protect a Method

Java
@Service
public class OrderService {

    @PreAuthorize("hasRole('ROLE_USER')")
    public Order getOrder(Long orderId) {
        return orderRepository.findById(orderId).orElseThrow();
    }
}

4. Verify

Access the protected URL or method. Policy-service events and denied URL authorization results are visible through the admin audit and monitoring surfaces. To change the policy, update it in Policy Center or related admin policy flows —the hot-reload path applies the new runtime mappings without rebuilding the application.

Next steps:

Getting Started with the Admin Console

The Contexa admin console provides a visual interface for managing the entire authorization lifecycle. Access it at /admin/dashboard after enabling the admin module.

Core Authorization Workflows

The admin console offers three main workflows for building and managing authorization policies:

  1. Policy Center resource review —Discover and define protected resources through the current integrated OSS workflow. Policy Center works with the managed-resource registry built by the scanners and lets operators review, define, exclude, and connect resources to policies.
  2. Policy authoring flows —Create authorization policies through Policy Center and related legacy controller routes. Define targets, conditions, and effects without writing raw XML. Assisted draft generation can propose conditions, but administrators still review the stored SpEL rule.
  3. Security Monitor —Monitor policy enforcement in real-time. Review audit logs to verify that authorization decisions match expectations and use the dashboard for security visibility.

For the complete admin console reference, see the Admin Console documentation. For a step-by-step walkthrough covering resource discovery through policy testing, see the End-to-End Workflow guide.