Andrea Cosentino created CAMEL-24754:
----------------------------------------

             Summary: camel-opa - a verdict claimed by an inbound message 
survives a failed evaluation
                 Key: CAMEL-24754
                 URL: https://issues.apache.org/jira/browse/CAMEL-24754
             Project: Camel
          Issue Type: Bug
            Reporter: Andrea Cosentino
            Assignee: Andrea Cosentino


h2. Problem

{{camel-opa}} writes its verdict to {{CamelOpaDecisionAllow}} (plus 
{{CamelOpaDecision}} and {{CamelOpaPolicyPath}}) at the *end* of an evaluation:

{code:java}
boolean allowed = isAllowed(decision);
setDecisionHeaders(exchange, decision, allowed);
{code}

That overwrites anything the message arrived with, so on the allow and deny 
paths a verdict claimed by an inbound message is correctly replaced. 
{{buildInput}} likewise excludes the three decision headers case-insensitively, 
so a claimed verdict never reaches OPA or its decision log.

The failure paths never get there. When the policy cannot be evaluated at all - 
the OPA server is unreachable, the decision is undefined, the input cannot be 
serialized - {{evaluate}} throws {{OpaPolicyEvaluationException}} without 
touching the headers, and whatever the message carried survives:

{code:java}
throw new OpaPolicyEvaluationException("Failed to evaluate policy " + 
policyPath, exchange, e);
{code}

The same applies to {{OpaSecurityPolicy}}, which throws 
{{CamelAuthorizationException}} through the same shared {{evaluate}}.

h2. Why it matters

The exchange carries the exception, so a route that lets it propagate is 
unaffected. A route that *handles* it is not: {{doTry/doCatch}}, or 
{{onException(...).handled(true)}} / {{.continued(true)}}, resumes routing with 
the message still carrying the sender's own {{CamelOpaDecisionAllow=true}}. A 
downstream step reading that header sees "allowed" attributed to a policy that 
never produced it - and the component's own documentation presents the header 
as the way a route acts on the verdict, with a filter or a choice.

A route author setting the header is trusted and out of scope. The reachable 
case is a consumer in front of the route that maps untrusted input into the 
header map without a strict, case-insensitive {{Camel*}} 
{{HeaderFilterStrategy}} - the header-injection class the security model puts 
explicitly in scope, and the reason a security component should not depend on 
the consumer having got it right.

h2. Fix

Clear the three decision headers on entry to {{evaluate}} rather than relying 
on overwriting them at the end, so every exit - allowed, denied, or a failure 
the route goes on to handle - leaves only what this component decided.

h2. Scope

{{main}} only. {{camel-opa}} is new and unreleased in 4.23.0, so no released 
behaviour changes and no advisory is warranted.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to