Complete Guide to Built-in ConditionMatchers in CoSec

CoSec provides 16 built-in ConditionMatchers ranging from path matching and role-based access control to rate limiting and expression evaluation, all implementing the ConditionMatcherFactory interface and auto-registered via ConditionMatcherFactoryProvider.

The ahoo-wang/cosec repository ships with a comprehensive set of built-in ConditionMatchers that enable developers to express complex authorization policies without writing custom Kotlin or Java code. Each matcher is instantiated through a factory pattern and automatically discovered by the Spring Boot starter, allowing immediate use in JSON or YAML policy definitions.

Logical Combinators and Context Matchers

These matchers handle boolean logic and security context validation, forming the foundation for role-based and multi-tenant access control policies.

AllConditionMatcher

Type: all

The AllConditionMatcher (implemented in AllConditionMatcherFactory.kt) returns true for every request. Use this as a catch-all or default policy condition.

{
  "type": "all"
}

BoolConditionMatcher

Type: bool

The BoolConditionMatcher (implemented in BoolConditionMatcherFactory.kt) provides logical composition via and and or arrays, allowing nested conditions without custom code.

{
  "type": "bool",
  "and": [
    { "type": "authenticated" },
    { "type": "path", "path": "/api/**" }
  ]
}

AuthenticatedConditionMatcher

Type: authenticated

Located in AuthenticatedConditionMatcherFactory.kt, this matcher verifies that the current SecurityContext contains an authenticated principal.

{
  "type": "authenticated"
}

InTenantConditionMatcher

Type: inTenant

Implemented in InTenantConditionMatcherFactory.kt, this matcher checks if the current tenant ID exists within a configured list.

{
  "type": "inTenant",
  "tenants": ["tenant-a", "tenant-b"]
}

InRoleConditionMatcher

Type: inRole

The InRoleConditionMatcher (source: InRoleConditionMatcherFactory.kt) validates that the authenticated principal possesses at least one role from the supplied array.

{
  "type": "inRole",
  "roles": ["ADMIN", "OPERATOR"]
}

HTTP Request Part Matchers

These matchers operate on specific attributes of the HTTP request, such as the URI path or header values.

PathConditionMatcher

Type: path

Defined in PathConditionMatcherFactory.kt, this matcher supports Ant-style patterns (e.g., /admin/**) and regular expressions against the request URI.

{
  "type": "path",
  "path": "/admin/**"
}

StartsWithConditionMatcher

Type: startsWith

Located in StartsWithConditionMatcherFactory.kt, this checks whether a string part (path, header, etc.) begins with a configured value. Supports case-insensitive matching via a boolean flag.

{
  "type": "startsWith",
  "part": "path",
  "value": "/api/v1",
  "ignoreCase": true
}

EndsWithConditionMatcher

Type: endsWith

Implemented in EndsWithConditionMatcherFactory.kt, this matcher verifies suffix matches on request parts.

{
  "type": "endsWith",
  "part": "uri",
  "value": ".json"
}

ContainsConditionMatcher

Type: contains

The ContainsConditionMatcher (source: ContainsConditionMatcherFactory.kt) checks for substring presence within a request attribute.

{
  "type": "contains",
  "part": "userAgent",
  "value": "Mobile"
}

EqConditionMatcher

Type: eq

Located in EqConditionMatcherFactory.kt, this performs strict equality checks with optional case insensitivity.

{
  "type": "eq",
  "part": "method",
  "value": "GET",
  "ignoreCase": false
}

InConditionMatcher

Type: in

Implemented in InConditionMatcherFactory.kt, this matcher checks if a string part exists within a supplied set of values.

{
  "type": "in",
  "part": "header:X-Client-Type",
  "values": ["web", "mobile", "api"]
}

RegularConditionMatcher

Type: regex

The RegularConditionMatcher (source: RegularConditionMatcherFactory.kt) applies Java regular expressions to request parts for complex pattern matching.

{
  "type": "regex",
  "part": "path",
  "pattern": "^/api/v[0-9]+/.*$"
}

Expression Evaluation Matchers

For scenarios requiring dynamic evaluation beyond static pattern matching, CoSec integrates two expression languages.

SpELConditionMatcher

Type: spel

The SpELConditionMatcher (implemented in SpelConditionMatcherFactory.kt) evaluates Spring Expression Language expressions against the request context and security attributes.

{
  "type": "spel",
  "expression": "#request.headers['X-Api-Key'] == 'secret'"
}

OGNLConditionMatcher

Type: ognl

Located in OgnlConditionMatcherFactory.kt, this matcher uses OGNL (Object-Graph Navigation Language) for expression-based matching in non-Spring environments or legacy integrations.

{
  "type": "ognl",
  "expression": "request.method == 'POST'"
}

Rate Limiting and Throttling Matchers

These matchers enforce traffic control policies at the policy level, independent of external gateway configurations.

RateLimiterConditionMatcher

Type: rateLimiter

Implemented in RateLimiterConditionMatcherFactory.kt, this matcher restricts requests per time window based on a configurable key extractor (e.g., client IP).

{
  "type": "rateLimiter",
  "key": "clientIp",
  "limit": 100,
  "duration": "1m"
}

GroupedRateLimiterConditionMatcher

Type: groupedRateLimiter

The GroupedRateLimiterConditionMatcher (source: GroupedRateLimiterConditionMatcherFactory.kt) extends rate limiting to support distinct limits per group (tenant, user, or custom attribute).

{
  "type": "groupedRateLimiter",
  "groupKey": "tenantId",
  "limit": 1000,
  "duration": "1h"
}

How Built-in Matchers Are Registered and Executed

Understanding the lifecycle of ConditionMatchers ensures proper debugging and extension.

Factory Registration

Upon Spring context startup, MatcherFactoryRegister (located in cosec-spring-boot-starter/src/main/kotlin/me/ahoo/cosec/spring/boot/starter/policy/MatcherFactoryRegister.kt) scans for all beans implementing ConditionMatcherFactory. It registers each discovered factory with the ConditionMatcherFactoryProvider singleton using the factory's type constant as the lookup key.

Policy Deserialization

When parsing policy JSON or YAML, JsonConditionMatcherSerializer (in cosec-core/src/main/kotlin/me/ahoo/cosec/serialization/JsonConditionMatcherSerializer.kt) extracts the type field, retrieves the corresponding factory via ConditionMatcherFactoryProvider.getRequired(type), and invokes the factory's create method to instantiate the matcher.

Runtime Evaluation

At request time, the AuthorizationGatewayFilter (or servlet filter) calls ConditionMatcher.match(request, securityContext). The concrete implementation—whether PathConditionMatcher, InRoleConditionMatcher, or SpelConditionMatcher—executes its specific logic against the request attributes and returns a boolean result.

Practical Policy Configuration Examples

Complex Boolean Logic

Combine multiple matchers using the bool type to enforce multi-factor authorization:

{
  "policyId": "secure-admin-api",
  "condition": {
    "type": "bool",
    "and": [
      { "type": "authenticated" },
      {
        "type": "bool",
        "or": [
          { "type": "inRole", "roles": ["ADMIN"] },
          { "type": "inRole", "roles": ["SUPERUSER"] }
        ]
      },
      { "type": "path", "path": "/admin/api/**" }
    ]
  },
  "action": {
    "type": "allow"
  }
}

Multi-Tenant Rate Limiting

Apply per-tenant request throttling using the grouped rate limiter:

{
  "policyId": "tenant-throttle",
  "condition": {
    "type": "groupedRateLimiter",
    "groupKey": "tenantId",
    "limit": 500,
    "duration": "5m"
  },
  "action": {
    "type": "allow"
  }
}

SpEL-Based Dynamic Checks

Use Spring expressions for header validation without custom code:

{
  "policyId": "api-key-check",
  "condition": {
    "type": "spel",
    "expression": "#request.headers['X-API-Version'] matches '2\\\\.0'"
  },
  "action": {
    "type": "allow"
  }
}

Summary

  • CoSec includes 16 built-in ConditionMatchers covering logical operations, context validation, string pattern matching, expression evaluation, and rate limiting.
  • Each matcher follows the Factory pattern, implementing ConditionMatcherFactory and registering automatically via ConditionMatcherFactoryProvider.
  • Source files are organized by function: context matchers reside in policy/condition/context/, part matchers in policy/condition/part/, and limiters in policy/condition/limiter/.
  • Policy definitions use the type field to reference factories, with configuration parameters specific to each matcher implementation.
  • Extension is straightforward: implement ConditionMatcherFactory as a Spring bean to add custom matchers alongside built-ins.

Frequently Asked Questions

How do I create a custom ConditionMatcher in CoSec?

Implement the ConditionMatcherFactory interface and define a unique type constant. Register your implementation as a Spring bean (e.g., using @Component). The MatcherFactoryRegister will automatically discover and register it with ConditionMatcherFactoryProvider, making it available in policy JSON using your custom type.

What is the difference between the bool and all matchers?

The all matcher (type: all) is a constant matcher that always returns true, useful for default allow/deny policies. The bool matcher (type: bool) is a logical combinator that evaluates nested and or or arrays of other matchers, enabling complex boolean logic without writing code.

When should I use SpEL versus OGNL expression matchers?

Use SpEL (type: spel) when running CoSec within a Spring ecosystem, as it provides tight integration with Spring's bean context and security expressions. Use OGNL (type: ognl) for lightweight deployments or non-Spring environments where you need expression evaluation without Spring dependencies.

How does groupedRateLimiter differ from the standard rateLimiter?

The standard rateLimiter (type: rateLimiter) applies a single global limit based on a key (like client IP). The groupedRateLimiter (type: groupedRateLimiter) maintains separate rate-limit counters per distinct group value (like tenant ID or user ID), allowing you to enforce "100 requests per minute per user" rather than "100 requests per minute total."

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 →