oscerd commented on code in PR #27332:
URL: https://github.com/apache/camel/pull/27332#discussion_r4177661116


##########
components/camel-ai/camel-ai-tool/src/main/java/org/apache/camel/component/ai/tool/AiToolConsumer.java:
##########
@@ -54,6 +58,55 @@ protected void doStart() throws Exception {
         register();
     }
 
+    /**
+     * Wraps the tool route's processor with the configured {@link 
AuthorizationPolicy}, if any, so the call is
+     * authorized before the route runs. The policy is applied via {@code 
beforeWrap} then {@code wrap} (as the
+     * {@code .policy()} DSL does through {@code PolicyReifier}); the wrapped 
processor is started and stopped with this
+     * consumer. Because {@code getProcessor()} is the route's <em>outer</em> 
processor, the guard runs in front of the
+     * route (before its unit of work, tracing and error handling): a denied 
call is logged and returned to the model as

Review Comment:
   Deliberate — the guard wraps the route's outer processor (so a deny produces 
no span/metric and `onException` can't see it), and I've corrected the docs to 
say exactly that: the `applyAuthorizationPolicy` javadoc and the "Authorizing 
tool calls" adoc now say the guard runs *in front of* the route (logged at 
`WARN`, relayed as `AuthorizationDenied`, no route span), and I fixed the PR 
description's "inside the route / visible to tracing" line. Running the check 
truly inside the route — so a deny emits a span/metric/event and fires 
`onException` — needs model-level policy injection (a `PolicyDefinition` on the 
route) rather than a processor wrap, which is a larger change; I'll open a 
follow-up for that observability. For now the deny is fail-closed, typed, and 
relayed to the model, which is the security behaviour the issue needs.
   
   _Claude Code on behalf of oscerd_
   



##########
components/camel-ai/camel-ai-tool/src/main/docs/ai-tool-component.adoc:
##########
@@ -353,6 +353,74 @@ YAML::
 ----
 ====
 
+== Authorizing tool calls
+
+A tool call is a security boundary: an AI model decides, from its own output, 
which `ai-tool` route to invoke. Set
+an `authorizationPolicy` — a reference to an 
`org.apache.camel.spi.AuthorizationPolicy` bean — to authorize every
+call before the route runs. Set it on the *component* to guard every tool 
route by construction, or on a single
+endpoint to override.
+
+[tabs]
+====
+Java::
++
+[source,java]
+----
+// one policy guarding every ai-tool route
+AiToolComponent ai = context.getComponent("ai-tool", AiToolComponent.class);
+ai.getConfiguration().setAuthorizationPolicy(myAuthorizationPolicy);
+
+from("ai-tool:transferFunds?tags=banking&description=Transfer funds")
+    .to("bean:ledger");
+
+// ...or override on a single endpoint
+from("ai-tool:transferFunds?tags=banking&description=Transfer 
funds&authorizationPolicy=#myAuthorizationPolicy")
+    .to("bean:ledger");
+----
+
+YAML::
++
+[source,yaml]
+----
+- route:
+    from:
+      uri: ai-tool:transferFunds
+      parameters:
+        tags: banking
+        description: "Transfer funds"
+        authorizationPolicy: "#myAuthorizationPolicy"
+      steps:
+        - to: bean:ledger
+----
+====
+
+The guard runs in front of the route: it wraps the route's outer processor, so 
it executes before the route's unit
+of work, tracing and error handling. A denied call 
(`CamelAuthorizationException`) is returned to the model as a
+short refusal it can relay — not as a tool result and not as a stack trace — 
regardless of the tool-execution error
+strategy; the denial is logged at `WARN`, but it does not produce a route span 
or metric.
+
+The policy authorizes on *trustworthy* input only:
+
+* the *tool name* comes from the route (the tool's id), never from model 
output;
+* the *caller identity* comes from an exchange *property* (or a validated 
token) set before the agent ran — for
+  example by `camel-spiffe` or `camel-keycloak`. Authorize on properties or 
validated tokens only, *never* on
+  message headers: on a tool route the headers carry the model-controlled tool 
arguments (and, on the
+  `langchain4j-agent` path, the caller's inbound HTTP headers), so a policy 
such as OPA with the default

Review Comment:
   Agreed — #27332 and #27264 (CAMEL-24832) both touch this section and 
`AiToolExecutor` / the adapters. #27264 gives the tool route a detached copy 
and propagates the caller context for openai and spring-ai; this PR's adoc 
already carries an "until CAMEL-24832" bullet for exactly that. Whichever 
merges first, I'll rebase the second onto it and reconcile this section — the 
overlap is additive (the context-propagation text from #27264 plus the 
authorization text here). I won't let them drift.
   
   _Claude Code on behalf of oscerd_
   



-- 
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