ConditionMatchers in CoSec: How Policy-Based Access Control Works

ConditionMatchers in CoSec are lightweight, pluggable components that inspect incoming requests and security contexts, returning true or false to determine whether access-control policies are satisfied.

ConditionMatchers form the evaluative backbone of the ahoo-wang/cosec authorization framework, enabling declarative security rules through JSON or YAML policy definitions. These components implement a standardized interface that allows the policy engine to compose granular checks—ranging from authentication status to request attributes—into complex authorization decisions without modifying core engine code.

What Are ConditionMatchers?

A ConditionMatcher is a contract that extends RequestMatcher and defines the runtime evaluation logic for policy conditions. Every matcher implements the interface located at cosec-api/src/main/kotlin/me/ahoo/cosec/api/policy/ConditionMatcher.kt:

interface ConditionMatcher : RequestMatcher

When CoSec evaluates an access-control policy, it invokes the match(request) method on the appropriate ConditionMatcher. The method returns true if the request satisfies the specific rule (such as matching a path pattern or possessing a required role), otherwise false. This boolean result drives the subsequent authorization decision, determining whether to allow or deny the request.

Core Architecture Components

The ConditionMatcher ecosystem relies on three primary abstractions that separate policy definition from runtime execution.

The ConditionMatcher Interface

The base contract ConditionMatcher extends RequestMatcher and serves as the runtime evaluation point for all condition logic. Located in cosec-api/src/main/kotlin/me/ahoo/cosec/api/policy/ConditionMatcher.kt, this interface ensures that every matcher, whether built-in or custom, adheres to a consistent method signature for request inspection.

ConditionMatcherFactory

Each matcher type requires a corresponding ConditionMatcherFactory that knows how to construct the matcher from a configuration object. Defined in cosec-core/src/main/kotlin/me/ahoo/cosec/policy/condition/ConditionMatcherFactory.kt, factories parse the JSON/YAML policy fragments and instantiate the concrete matcher with the appropriate parameters (such as regex patterns, role names, or comparison values).

ConditionMatcherFactoryProvider

The ConditionMatcherFactoryProvider acts as the central registry, mapping the type string from policy definitions to the corresponding factory implementation. This provider is implemented in cosec-core/src/main/kotlin/me/ahoo/cosec/policy/condition/ConditionMatcherFactoryProvider.kt and maintains a lookup table that enables runtime discovery of matcher implementations.

MatcherFactoryRegister

Factory registration occurs automatically through Spring's bean scanning mechanism. The MatcherFactoryRegister.kt file in cosec-spring-boot-starter/src/main/kotlin/me/ahoo/cosec/spring/boot/starter/policy/ handles this auto-discovery:

// MatcherFactoryRegister.kt
applicationContext.getBeansOfType(ConditionMatcherFactory::class.java)
                  .values.forEach { ConditionMatcherFactoryProvider.register(it) }

This registration process ensures that all ConditionMatcherFactory beans present in the application context are available to the policy engine at runtime.

Built-in ConditionMatcher Types

CoSec provides a comprehensive library of built-in matchers located under me.ahoo.cosec.policy.condition in the cosec-core module. These cover common authorization scenarios:

  • Bool – Logical composition (and, or, not) of other matchers via BoolConditionMatcherFactory
  • All – Matches any request, serving as a default "allow" condition via AllConditionMatcherFactory
  • Eq / In / StartsWith / EndsWith / Contains / Regex – Value comparisons on request attributes (headers, query parameters) via factories such as EqConditionMatcherFactory and InConditionMatcherFactory
  • Path – Ant-style path matching for request URIs via PathConditionMatcherFactory
  • Authenticated – Verifies the request has an authenticated principal via AuthenticatedConditionMatcherFactory
  • InTenant / InRole – Checks tenant membership or role assignment via InTenantConditionMatcherFactory and InRoleConditionMatcherFactory
  • SpEL / OGNL – Evaluates Spring Expression Language or OGNL scripts against the request context via SpelConditionMatcherFactory and OgnlConditionMatcherFactory
  • RateLimiter / GroupedRateLimiter – Applies token bucket or fixed-window rate limits via RateLimiterConditionMatcherFactory and GroupedRateLimiterConditionMatcherFactory

All concrete implementations reside in cosec-core/src/main/kotlin/me/ahoo/cosec/policy/condition.

Runtime Evaluation Flow

When a request arrives, CoSec processes the ConditionMatcher through the following pipeline:

  1. Policy parsing – The policy engine reads the condition block from the JSON/YAML policy definition, extracting the type field and configuration parameters.

  2. Factory resolution – The engine queries ConditionMatcherFactoryProvider to locate the registered factory matching the specified type.

  3. Matcher instantiation – The factory creates the concrete ConditionMatcher instance, injecting the configuration (such as regex patterns or role lists).

  4. Evaluation – CoSec invokes match(request) on the matcher. For composite matchers like bool, this recursively evaluates child matchers.

Consider this policy example that demonstrates composition:

{
  "id": "read-profile",
  "action": { "type": "allow" },
  "condition": {
    "type": "bool",
    "and": [
      { "type": "authenticated" },
      { "type": "inRole", "roles": ["USER", "ADMIN"] },
      { "type": "eq", "key": "request.method", "value": "GET" },
      { "type": "path", "pattern": "/api/profile/**" }
    ]
  }
}

In this example, BoolConditionMatcherFactory creates a BoolConditionMatcher that ensures all child conditions succeed: the user must be authenticated, possess the USER or ADMIN role, send a GET request, and access a path under /api/profile/.

Extending ConditionMatchers

Developers can implement custom authorization logic by creating new ConditionMatchers without modifying the CoSec core engine. Follow this four-step process:

  1. Implement the ConditionMatcher interface – Create a class that implements ConditionMatcher and overrides the match(request) method with your custom evaluation logic.

  2. Create a factory – Implement ConditionMatcherFactory with a unique type string identifier. The factory's create(configuration) method should instantiate your matcher with the provided configuration map.

  3. Register as a Spring bean – Annotate your factory with @Component or define it as a bean in your Spring configuration. The MatcherFactoryRegister will automatically detect it during application startup, or you can manually register it via ConditionMatcherFactoryProvider.register().

  4. Reference in policy – Use your custom type identifier in policy JSON/YAML definitions:

{
  "condition": {
    "type": "customIpAllowlist",
    "allowedIps": ["192.168.1.0/24"]
  }
}

This plugin architecture supports specialized requirements such as IP allow-listing, time-of-day restrictions, or custom header validation.

Summary

  • ConditionMatchers implement the ConditionMatcher : RequestMatcher interface in cosec-api/src/main/kotlin/me/ahoo/cosec/api/policy/ConditionMatcher.kt to evaluate request attributes and security contexts.
  • ConditionMatcherFactory implementations construct matchers from policy configurations, while ConditionMatcherFactoryProvider maintains the runtime registry of available factories.
  • Built-in matchers in cosec-core/src/main/kotlin/me/ahoo/cosec/policy/condition cover authentication, path matching, role verification, rate limiting, and logical composition via the Bool matcher.
  • MatcherFactoryRegister in the Spring Boot starter automatically discovers and registers factories via Spring's application context.
  • Custom matchers integrate seamlessly by implementing the interface, providing a factory, and registering as a Spring bean, enabling domain-specific authorization logic without engine modifications.

Frequently Asked Questions

How do ConditionMatchers differ from ActionMatchers in CoSec?

ConditionMatchers evaluate the context and attributes of a request (such as headers, authentication status, or path patterns) to determine if a policy applies, whereas ActionMatchers typically evaluate the action being performed (such as HTTP method or resource operation). ConditionMatchers focus on when a policy should be evaluated, while ActionMatchers focus on what is being accessed. Both implement similar factory patterns but serve different phases of the authorization decision.

Can I combine multiple conditions in a single CoSec policy?

Yes, CoSec supports complex condition composition through the Bool matcher type. The BoolConditionMatcher (created by BoolConditionMatcherFactory) accepts and, or, and not arrays containing child matchers. This allows you to construct sophisticated rules requiring multiple attributes to match simultaneously, alternative conditions to satisfy, or specific conditions to be excluded, all within a single policy condition block.

Where does CoSec store the JSON schema for condition definitions?

CoSec provides a formal JSON Schema that describes valid condition structures in schema/condition.schema.json at the repository root. This schema defines the required fields, valid matcher types, and configuration parameters for all built-in ConditionMatchers, enabling IDE autocompletion and validation for policy files during development.

What is the performance impact of using SpEL or OGNL ConditionMatchers?

SpEL (Spring Expression Language) and OGNL (Object-Graph Navigation Language) matchers offer maximum flexibility for complex logic but incur higher evaluation overhead compared to simple matchers like eq or path. According to the source implementation in SpelConditionMatcherFactory and OgnlConditionMatcherFactory, these matchers parse and evaluate expressions at runtime against the security context. For high-throughput applications, prefer compiled matchers (such as PathConditionMatcher or InRoleConditionMatcher) for critical paths, reserving script-based matchers for administrative or low-frequency endpoints.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →