contexa-iam

Resource Scanner

Automatic resource discovery that scans @Protectable methods and MVC endpoints at application startup, registering them as ManagedResource entities for policy assignment.

Overview

Contexa provides two complementary resource scanners that detect different types of protectable resources in the application:

  • MethodResourceScanner —Discovers non-controller methods annotated with @Protectable
  • MvcResourceScanner —Discovers Spring MVC controller endpoints via RequestMappingHandlerMapping

Both scanners implement the ResourceScanner interface and produce ManagedResource entities with an initial status of NEEDS_DEFINITION.

End-to-End Pipeline

Resource scanning is the first stage of a four-step resource management pipeline: Scan —Define —Policy —Dynamic Authorization. At application startup, ResourceScanner implementations discover all @RequestMapping endpoints and @Protectable methods, storing them as ManagedResource entities in the database. The AI engine then generates human-readable friendly names for discovered resources in batch.

The scanners synchronize discovered resources into ManagedResourceRepository. In the current OSS operator flow, review, permission definition, and policy creation are centered in the integrated Policy Center resources/create experience. The legacy /admin/workbench/resources controller path still exists in server code and continues to expose the underlying define, exclude, restore, and management endpoints.

Resource Scanning Pipeline
Application Start WorkbenchInitializer triggers resource scanning
MethodResourceScanner.scan() Scan beans in io.contexa.contexaiam -- Skip @Controller / @RestController -- Find public methods with @Protectable -- Register as ManagedResource (METHOD)
MvcResourceScanner.scan() Get RequestMappingHandlerMapping -- Iterate handler methods -- Extract URL patterns and HTTP methods -- Register as ManagedResource (URL)
ManagedResource Entities status: NEEDS_DEFINITION
Admin Assigns Permission status: PERMISSION_CREATED
Policy Connected status: POLICY_CONNECTED

ResourceScanner Interface

Java
public interface ResourceScanner {
    List<ManagedResource> scan();
}

MethodResourceScanner

Scans all Spring beans in the io.contexa.contexaiam package for public methods annotated with @Protectable. Controller classes are explicitly excluded since they are handled by MvcResourceScanner.

Scan Logic

  1. Iterate all bean definitions in the ApplicationContext
  2. Resolve the target class (unwrapping AOP proxies via AopUtils.getTargetClass())
  3. Skip classes outside the io.contexa.contexaiam package
  4. Skip classes annotated with @Controller or @RestController
  5. For each public method with @Protectable, create a ManagedResource

Resource Identifier Format

Method resources use a fully qualified method signature as the identifier:

Text
io.contexa.contexaiam.service.AccountService.updateAccount(Long,AccountDto)

ManagedResource Fields (METHOD type)

FieldValue Source
resourceIdentifierFully qualified method signature with parameter types
resourceTypeMETHOD
serviceOwnerSimple class name of the declaring class
parameterTypesJSON array of fully qualified parameter type names
returnTypeFully qualified return type name
sourceCodeLocationDerived from class name: io/contexa/.../ClassName.java
statusNEEDS_DEFINITION

MvcResourceScanner

Scans Spring MVC @Controller and @RestController classes for URL-mapped endpoints using RequestMappingHandlerMapping.

Scan Logic

  1. Retrieve the requestMappingHandlerMapping bean
  2. Iterate all registered handler methods
  3. Skip classes outside the io.contexa.contexaiam package
  4. Skip classes not annotated with @Controller or @RestController
  5. Extract URL patterns from PathPatternsRequestCondition
  6. Extract HTTP method (defaulting to ANY)
  7. Generate API docs URL using IamAdminProperties.restDocsPath

ManagedResource Fields (URL type)

FieldValue Source
resourceIdentifierURL pattern string (e.g., /admin/users/{id})
resourceTypeURL
httpMethodGET, POST, PUT, DELETE, PATCH, or ANY
friendlyNameHandler method name
descriptionURL: [HTTP_METHOD] /path/pattern
serviceOwnerSimple class name of the controller
apiDocsUrl{restDocsPath}#{controller}_{method}
statusNEEDS_DEFINITION

ManagedResource Entity

Java
@Entity
@Table(name = "MANAGED_RESOURCE")
public class ManagedResource {
    private Long id;
    private String resourceIdentifier;    // URL pattern or method signature
    private ResourceType resourceType;    // URL or METHOD
    private HttpMethod httpMethod;        // GET, POST, PUT, DELETE, PATCH, ANY
    private String friendlyName;
    private String description;
    private String serviceOwner;
    private String parameterTypes;        // JSON array (METHOD only)
    private String returnType;            // Fully qualified type (METHOD only)
    private String apiDocsUrl;            // Link to API documentation
    private String sourceCodeLocation;    // Source file path (METHOD only)
    private String availableContextVariables;
    private Status status;                // NEEDS_DEFINITION, PERMISSION_CREATED,
                                          // POLICY_CONNECTED, EXCLUDED
    private Permission permission;        // OneToOne mapping
    private LocalDateTime createdAt;
    private LocalDateTime updatedAt;

    public enum ResourceType { URL, METHOD }
    public enum HttpMethod { GET, POST, PUT, DELETE, PATCH, ANY }
    public enum Status {
        NEEDS_DEFINITION,
        PERMISSION_CREATED,
        POLICY_CONNECTED,
        EXCLUDED
    }
}

Resource Lifecycle

StatusDescription
NEEDS_DEFINITIONDiscovered by scanner; no permission assigned yet
PERMISSION_CREATEDA Permission entity has been linked to this resource
POLICY_CONNECTEDA policy references this resource through its targets
EXCLUDEDExplicitly excluded from authorization (e.g., public endpoints)

ManagedResource Lifecycle

Status Transitions

ManagedResource Status Transitions
NEEDS_DEFINITION Resource discovered by scanner, not yet configured
PERMISSION_CREATED defineResourceAsPermission() called
POLICY_CONNECTED Policy created and linked
EXCLUDED Resource excluded from active management (public endpoints, static assets)
StatusDescriptionTransition Trigger
NEEDS_DEFINITIONResource discovered by scanner, not yet configuredInitial scan
PERMISSION_CREATEDdefineResourceAsPermission() called, Permission entity createdAdmin action in the Policy Center resources flow or legacy workbench route
POLICY_CONNECTEDPolicy created and linked to this resourcePolicy Center / legacy policy screens
EXCLUDEDResource excluded from authorization managementExclude flow updates the managed resource status

ManagedResource Entity Fields

FieldTypeDescription
resourceIdentifierStringUnique ID (URL pattern + method, or qualified method signature)
resourceTypeResourceTypeURL or METHOD
friendlyNameStringAI-suggested human-readable name, or a fallback name when AI suggestions are unavailable
statusManagedResource.StatusNEEDS_DEFINITION, PERMISSION_CREATED, POLICY_CONNECTED, EXCLUDED

Resource Workbench

The legacy /admin/workbench/resources route is still implemented in server code. In the current OSS UI bundle, day-to-day review and policy authoring are centered in Policy Center, which uses the same managed-resource registry and related admin endpoints.

Discovering Resources

  • View all scanned resources with status-based filtering
  • Refresh scan results on demand
  • Search and filter by resource type, status, or name

Defining Resources as Permissions

Click "Define as Permission" on a NEEDS_DEFINITION resource to:

  1. Create a corresponding Permission entity
  2. Update the resource status to PERMISSION_CREATED
  3. Make the resource available for policy creation

Two Paths from Workbench

After defining a resource as a permission, two policy creation options are available:

PathActionUse Case
Quick GrantPolicy Center quick-create flow with selected roles, permissions, or stored SpEL shortcutsSimple role-to-permission assignment
Advanced PolicyPolicy Center manual / AI-assisted create flow with resource contextComplex conditions, AI expressions, multi-rule policies

End-to-End Workflow

End-to-End Resource Management Pipeline
Step 1: SCAN
MvcResourceScanner + MethodResourceScanner ManagedResource (NEEDS_DEFINITION)
Step 2: DEFINE
Policy Center Resources Flow Integrated review/define flow backed by managed-resource endpoints (PERMISSION_CREATED)
Step 3: POLICY
Policy Center / authoring flow /admin/policy-center?tab=create -- from-resource-aware policy creation (POLICY_CONNECTED)
Step 4: ENFORCE
CustomDynamicAuthorizationManager reload() -- .anyRequest().access(dynamic)

Step 1: Scan

Automatic at application startup via WorkbenchInitializer. MvcResourceScanner scans all @Controller and @RestController classes. MethodResourceScanner scans all @Protectable methods. Friendly names and descriptions are then filled from AI suggestions when available, with fallback values used if AI suggestions are unavailable.

Step 2: Review & Define

Review NEEDS_DEFINITION resources through the current Policy Center integrated resources area or the legacy workbench-backed endpoints. Define relevant resources as permissions, and exclude resources that do not need authorization (static assets, public endpoints).

Step 3: Create Policy

From the current Policy Center resources flow, or the legacy /admin/policy-builder/from-resource route, continue into policy authoring with the selected resource context. Compatible condition templates are filtered for the chosen resource, and the same managed-resource lifecycle stays in sync as the policy is created.

Step 4: Dynamic Authorization

When the policy is saved, reloadAuthorizationSystem() triggers CustomDynamicAuthorizationManager.reload(). The policy takes effect immediately. With .anyRequest().access(customDynamicAuthorizationManager) in your security configuration, no static authorization rules are needed.

Resource Workbench: Operations Guide

The managed-resource lifecycle is still backed by the legacy /admin/workbench/resources controller, but the current OSS UI centers operators in Policy Center. This section describes the shared operational workflows behind both surfaces.

Filtering Resources

The current resource review flow provides multiple filtering options to find resources quickly, whether operators use the integrated Policy Center surface or the legacy workbench-backed endpoints:

FilterOptionsUse Case
By StatusNEEDS_DEFINITION, PERMISSION_CREATED, POLICY_CONNECTED, EXCLUDEDFind resources at a specific lifecycle stage
By Service OwnerController or service class nameFilter resources belonging to a specific module
By KeywordFree text searchSearch by resource identifier, friendly name, or description
By Resource TypeURL or METHODFilter by endpoint type vs. method-level resource

Defining a Resource

When you define a resource, the following happens in sequence:

  1. Click "Define as Permission" on a NEEDS_DEFINITION resource
  2. Enter a friendly name for the permission (or accept the AI-suggested name)
  3. A Permission entity is automatically created and linked to the resource
  4. The resource status changes to PERMISSION_CREATED
  5. The resource is now ready for policy assignment

Policy Setup from Workbench

After defining a resource, a modal appears offering two policy creation paths:

Quick Grant (Wizard)

Use the Policy Center quick-create flow to open a simplified grant path with the selected resource context.

  • Pre-selects the resource permission
  • Choose target roles and confirm
  • Creates a simple ALLOW policy
VS

Advanced (Manual / builder-compatible flow)

Use the Policy Center manual create flow to open the full policy authoring experience with the selected resource context. The legacy builder controller path still exists in server code, but the current OSS template bundle centers this flow in Policy Center.

  • Target is pre-filled (from-resource mode)
  • Full condition template selection
  • Supports complex rules and AI conditions

Excluding and Restoring Resources

Resources that do not require authorization (public endpoints, static assets, health checks) can be excluded:

  • Excluding: Click "Exclude" on a NEEDS_DEFINITION resource. The status changes to EXCLUDED, and the resource is removed from authorization management.
  • Restoring: Excluded resources can be restored by clicking "Restore". The status reverts to NEEDS_DEFINITION, and the resource re-enters the management lifecycle.

When to exclude: Public API endpoints, static asset paths, health check endpoints (/actuator/health), documentation paths.

When to restore: Previously public endpoints that now require authorization, or resources excluded by mistake.

Status Transition Diagram

Resource Workbench Status Flow
NEEDS_DEFINITION Discovered by scanner at startup
PERMISSION_CREATED "Define as Permission" clicked -- Permission entity linked
POLICY_CONNECTED Policy created via Policy Center quick or manual flow -- Resource fully managed
EXCLUDED "Exclude" clicked -- Not managed -- Can be restored

AI Auto-Naming

When resources are discovered by the scanner, their technical identifiers (URL patterns or method signatures) are not user-friendly. The AI auto-naming system generates human-readable names and descriptions automatically.

How It Works

ResourceRegistryServiceImpl calls the AI ResourceNaming service after scanning is complete. The AI analyzes each technical identifier and generates:

  • Friendly name: A concise, business-oriented name (e.g., "Update User Profile" for PUT /api/users/{id})
  • Description: A longer explanation of what the resource does

Batch Processing

To optimize AI API usage, auto-naming processes resources in batches of 10 items per batch. This approach:

  • Reduces the number of AI API calls
  • Provides contextual awareness across related resources in the same batch
  • Handles failures gracefully by retrying individual batches

Name Generation Strategy

AI Auto-Naming Pipeline
Technical Identifiers URL patterns + method signatures
AI ResourceNaming Batch of 10 items analyzed
Friendly Names Business-readable names + descriptions
Technical IdentifierAI-Generated Friendly Name
GET /api/usersList All Users
PUT /api/users/{id}Update User Profile
DELETE /admin/roles/{id}Delete Role
AccountService.updateAccount(Long,AccountDto)Update Account Details