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)