oscerd opened a new pull request, #26165:
URL: https://github.com/apache/camel/pull/26165

   ## What
   
   Adds `camel-opa`, a new component that evaluates [Open Policy 
Agent](https://www.openpolicyagent.org/) (Rego) policies against an Exchange 
and records the allow/deny decision on it.
   
   `camel-spiffe` (CAMEL-23305 / CAMEL-24571) gave Camel a way to establish 
*who* a caller is. Nothing answered *whether that caller is allowed*, so 
authorization logic ends up hand-coded in `.process()` / `.bean()` blocks — 
scattered across routes and impossible to change without redeploying the 
integration. `camel-shiro` and `camel-keycloak` each ship an 
`AuthorizationPolicy`, but both are bound to one identity provider and to 
coarse role/permission checks; neither supports externalised, attribute-based 
policy.
   
   ## Two usage modes
   
   **Producer** — `opa:<policyPath>` evaluates the policy and sets 
`CamelOpaDecisionAllow` (Boolean) plus `CamelOpaDecision` (the raw decision 
document), leaving the body untouched, so the route decides with a filter:
   
   ```java
   from("platform-http:/orders")
       .to("opa:authz/orders/allow")
       .filter(header(OpaConstants.DECISION_ALLOW).isEqualTo(true))
           .to("direct:handleOrder");
   ```
   
   **Security policy** — `OpaSecurityPolicy implements AuthorizationPolicy`, so 
it wraps a route segment and a deny throws `CamelAuthorizationException`:
   
   ```java
   from("platform-http:/orders")
       .policy(opaPolicy)
           .to("direct:handleOrder");
   ```
   
   ## Design decisions worth a look
   
   - **Fails closed.** Any failure to reach a verdict — OPA unreachable, 
timeout, error, or a failure building/serializing the input document — throws: 
`OpaPolicyEvaluationException` from the producer, `CamelAuthorizationException` 
from the security policy. It never proceeds as allowed. `failOpen=true` 
reverses this and is marked `security = "insecure:dev"`.
   - **A deny is distinct from a failure.** A policy that ran and said no is a 
decision; an unreachable PDP is not. The exception cause lets a route tell them 
apart.
   - **The policy path is not header-overridable.** Taken from the endpoint 
only, so an inbound message cannot select which policy judges it.
   - **Decision headers are written on every evaluation**, and are never sent 
back to OPA in the input document — so a verdict claimed by an inbound message 
neither survives into the route nor is shown to the policy.
   - **The body is not sent by default** (`includeBody=false`); 
`includeHeaders` narrows the header set. Bodies can be large or streaming and 
most decisions need only headers.
   - **Only a JSON boolean counts as an allow** — as the whole document, or as 
the `allowKey` entry of an object. Anything else is a deny, with the raw 
document kept on the exchange so the route can inspect deny reasons or 
obligations.
   - **`OpaSecurityProcessor` extends `DelegateAsyncProcessor`**, following the 
`Policy` SPI's advice, so the wrapped route segment keeps the asynchronous 
routing engine. (`camel-shiro` and `camel-keycloak` both use the synchronous 
`DelegateProcessor`, which its own javadoc warns against; new code shouldn't 
repeat that.)
   
   ## Dependency
   
   `com.styra:opa:2.1.1` — the official OPA Java SDK 
([styrainc/opa-java](https://github.com/styrainc/opa-java)), Apache-2.0 and on 
Maven Central. It wraps OPA's REST Data API, which is the standard OPA sidecar 
deployment model. Its stray runtime-scoped `junit-jupiter-engine` is excluded.
   
   In-process Rego evaluation via WASM (`com.styra.opa:opa-java-wasm`) is 
deliberately out of scope for this first increment — that artifact is still at 
0.0.6.
   
   ## Testing
   
   25 unit tests across producer behaviour, input-document shaping and the 
security policy, covering the fail-closed paths, the non-boolean decision 
shapes and the header-overwrite guarantees. Full reactor build green; 
`camel-catalog` tests green.
   
   `main` only — new component, nothing to backport. No upgrade-guide entry: 
the guide is for migration, and this adds nothing existing users must migrate.
   
   _Claude Code on behalf of @oscerd_
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to