This is an automated email from the ASF dual-hosted git repository.

luigidemasi pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 2ec45e1f23c19ec695b3fd15240971a90f9d1c5b
Author: Luigi De Masi <[email protected]>
AuthorDate: Thu Jun 11 17:01:16 2026 +0200

    CAMEL-23723: Make oauthProfile a first-class rest-openapi endpoint option
    
    Declares oauthProfile as a @UriParam on RestOpenApiEndpoint and injects it
    explicitly into the parameters passed to the consumer delegate factory,
    instead of relying on lenient pass-through. Reverts the lenientProperties
    annotation addition; runtime leniency via isLenientProperties() is 
unchanged.
    
    Co-authored-by: Claude Opus 4.6 <[email protected]>
---
 .../camel/catalog/components/rest-openapi.json      |  5 +++--
 .../rest/openapi/RestOpenApiEndpointConfigurer.java |  6 ++++++
 .../rest/openapi/RestOpenApiEndpointUriFactory.java |  5 +++--
 .../camel/component/rest/openapi/rest-openapi.json  |  5 +++--
 .../src/main/docs/rest-openapi-component.adoc       |  4 ++--
 .../component/rest/openapi/RestOpenApiEndpoint.java | 21 +++++++++++++++++++--
 .../rest/openapi/RestOpenApiEndpointV3Test.java     |  3 +++
 .../ROOT/pages/camel-4x-upgrade-guide-4_21.adoc     |  8 ++++----
 .../modules/ROOT/pages/rest-dsl-openapi.adoc        |  6 +++---
 .../dsl/RestOpenApiEndpointBuilderFactory.java      | 17 +++++++++++++++++
 10 files changed, 63 insertions(+), 17 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/rest-openapi.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/rest-openapi.json
index 95d974acb41a..40b618315912 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/rest-openapi.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/rest-openapi.json
@@ -19,7 +19,7 @@
     "api": false,
     "consumerOnly": false,
     "producerOnly": false,
-    "lenientProperties": true,
+    "lenientProperties": false,
     "browsable": false,
     "remote": true
   },
@@ -64,6 +64,7 @@
     "produces": { "index": 15, "kind": "parameter", "displayName": "Produces", 
"group": "producer", "label": "producer", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": false, "description": "What payload type this component is producing. 
For example application\/json according to the RFC7231. This equates to the 
value of Content-Type HTTP header. If set overrides any value present in the 
OpenApi specification. Overr [...]
     "requestValidationEnabled": { "index": 16, "kind": "parameter", 
"displayName": "Request Validation Enabled", "group": "producer", "label": 
"producer", "required": false, "type": "boolean", "javaType": "boolean", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": 
false, "description": "Enable validation of requests against the configured 
OpenAPI specification" },
     "componentName": { "index": 17, "kind": "parameter", "displayName": 
"Component Name", "group": "producer (advanced)", "label": "producer,advanced", 
"required": false, "type": "string", "javaType": "java.lang.String", 
"deprecated": false, "autowired": false, "secret": false, "description": "Name 
of the Camel component that will perform the requests. The component must be 
present in Camel registry and it must implement RestProducerFactory service 
provider interface. If not set CLASSPAT [...]
-    "lazyStartProducer": { "index": 18, "kind": "parameter", "displayName": 
"Lazy Start Producer", "group": "producer (advanced)", "label": 
"producer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Whether the producer should be started 
lazy (on the first message). By starting lazy you can use this to allow 
CamelContext and routes to startup in situations where a produ [...]
+    "lazyStartProducer": { "index": 18, "kind": "parameter", "displayName": 
"Lazy Start Producer", "group": "producer (advanced)", "label": 
"producer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Whether the producer should be started 
lazy (on the first message). By starting lazy you can use this to allow 
CamelContext and routes to startup in situations where a produ [...]
+    "oauthProfile": { "index": 19, "kind": "parameter", "displayName": "OAuth 
Profile", "group": "security", "label": "consumer,security", "required": false, 
"type": "string", "javaType": "java.lang.String", "deprecated": false, 
"autowired": false, "secret": false, "description": "OAuth profile name passed 
to the HTTP consumer delegate for validating incoming Authorization: Bearer 
tokens. The selected consumer component must support the oauthProfile option; 
delegates that ignore unknown  [...]
   }
 }
diff --git 
a/components/camel-rest-openapi/src/generated/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpointConfigurer.java
 
b/components/camel-rest-openapi/src/generated/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpointConfigurer.java
index 5fa644a83f82..27c86cc5c395 100644
--- 
a/components/camel-rest-openapi/src/generated/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpointConfigurer.java
+++ 
b/components/camel-rest-openapi/src/generated/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpointConfigurer.java
@@ -49,6 +49,8 @@ public class RestOpenApiEndpointConfigurer extends 
PropertyConfigurerSupport imp
         case "missingOperation": 
target.setMissingOperation(property(camelContext, java.lang.String.class, 
value)); return true;
         case "mockincludepattern":
         case "mockIncludePattern": 
target.setMockIncludePattern(property(camelContext, java.lang.String.class, 
value)); return true;
+        case "oauthprofile":
+        case "oauthProfile": target.setOauthProfile(property(camelContext, 
java.lang.String.class, value)); return true;
         case "produces": target.setProduces(property(camelContext, 
java.lang.String.class, value)); return true;
         case "requestvalidationenabled":
         case "requestValidationEnabled": 
target.setRequestValidationEnabled(property(camelContext, boolean.class, 
value)); return true;
@@ -87,6 +89,8 @@ public class RestOpenApiEndpointConfigurer extends 
PropertyConfigurerSupport imp
         case "missingOperation": return java.lang.String.class;
         case "mockincludepattern":
         case "mockIncludePattern": return java.lang.String.class;
+        case "oauthprofile":
+        case "oauthProfile": return java.lang.String.class;
         case "produces": return java.lang.String.class;
         case "requestvalidationenabled":
         case "requestValidationEnabled": return boolean.class;
@@ -126,6 +130,8 @@ public class RestOpenApiEndpointConfigurer extends 
PropertyConfigurerSupport imp
         case "missingOperation": return target.getMissingOperation();
         case "mockincludepattern":
         case "mockIncludePattern": return target.getMockIncludePattern();
+        case "oauthprofile":
+        case "oauthProfile": return target.getOauthProfile();
         case "produces": return target.getProduces();
         case "requestvalidationenabled":
         case "requestValidationEnabled": return 
target.isRequestValidationEnabled();
diff --git 
a/components/camel-rest-openapi/src/generated/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpointUriFactory.java
 
b/components/camel-rest-openapi/src/generated/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpointUriFactory.java
index b168baf6feef..f2285b934b61 100644
--- 
a/components/camel-rest-openapi/src/generated/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpointUriFactory.java
+++ 
b/components/camel-rest-openapi/src/generated/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpointUriFactory.java
@@ -24,7 +24,7 @@ public class RestOpenApiEndpointUriFactory extends 
org.apache.camel.support.comp
     private static final Set<String> ENDPOINT_IDENTITY_PROPERTY_NAMES;
     private static final Map<String, String> MULTI_VALUE_PREFIXES;
     static {
-        Set<String> props = new HashSet<>(19);
+        Set<String> props = new HashSet<>(20);
         props.add("apiContextPath");
         props.add("basePath");
         props.add("bridgeErrorHandler");
@@ -39,6 +39,7 @@ public class RestOpenApiEndpointUriFactory extends 
org.apache.camel.support.comp
         props.add("lazyStartProducer");
         props.add("missingOperation");
         props.add("mockIncludePattern");
+        props.add("oauthProfile");
         props.add("operationId");
         props.add("produces");
         props.add("requestValidationEnabled");
@@ -90,7 +91,7 @@ public class RestOpenApiEndpointUriFactory extends 
org.apache.camel.support.comp
 
     @Override
     public boolean isLenientProperties() {
-        return true;
+        return false;
     }
 }
 
diff --git 
a/components/camel-rest-openapi/src/generated/resources/META-INF/org/apache/camel/component/rest/openapi/rest-openapi.json
 
b/components/camel-rest-openapi/src/generated/resources/META-INF/org/apache/camel/component/rest/openapi/rest-openapi.json
index 95d974acb41a..40b618315912 100644
--- 
a/components/camel-rest-openapi/src/generated/resources/META-INF/org/apache/camel/component/rest/openapi/rest-openapi.json
+++ 
b/components/camel-rest-openapi/src/generated/resources/META-INF/org/apache/camel/component/rest/openapi/rest-openapi.json
@@ -19,7 +19,7 @@
     "api": false,
     "consumerOnly": false,
     "producerOnly": false,
-    "lenientProperties": true,
+    "lenientProperties": false,
     "browsable": false,
     "remote": true
   },
@@ -64,6 +64,7 @@
     "produces": { "index": 15, "kind": "parameter", "displayName": "Produces", 
"group": "producer", "label": "producer", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": false, "description": "What payload type this component is producing. 
For example application\/json according to the RFC7231. This equates to the 
value of Content-Type HTTP header. If set overrides any value present in the 
OpenApi specification. Overr [...]
     "requestValidationEnabled": { "index": 16, "kind": "parameter", 
"displayName": "Request Validation Enabled", "group": "producer", "label": 
"producer", "required": false, "type": "boolean", "javaType": "boolean", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": 
false, "description": "Enable validation of requests against the configured 
OpenAPI specification" },
     "componentName": { "index": 17, "kind": "parameter", "displayName": 
"Component Name", "group": "producer (advanced)", "label": "producer,advanced", 
"required": false, "type": "string", "javaType": "java.lang.String", 
"deprecated": false, "autowired": false, "secret": false, "description": "Name 
of the Camel component that will perform the requests. The component must be 
present in Camel registry and it must implement RestProducerFactory service 
provider interface. If not set CLASSPAT [...]
-    "lazyStartProducer": { "index": 18, "kind": "parameter", "displayName": 
"Lazy Start Producer", "group": "producer (advanced)", "label": 
"producer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Whether the producer should be started 
lazy (on the first message). By starting lazy you can use this to allow 
CamelContext and routes to startup in situations where a produ [...]
+    "lazyStartProducer": { "index": 18, "kind": "parameter", "displayName": 
"Lazy Start Producer", "group": "producer (advanced)", "label": 
"producer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Whether the producer should be started 
lazy (on the first message). By starting lazy you can use this to allow 
CamelContext and routes to startup in situations where a produ [...]
+    "oauthProfile": { "index": 19, "kind": "parameter", "displayName": "OAuth 
Profile", "group": "security", "label": "consumer,security", "required": false, 
"type": "string", "javaType": "java.lang.String", "deprecated": false, 
"autowired": false, "secret": false, "description": "OAuth profile name passed 
to the HTTP consumer delegate for validating incoming Authorization: Bearer 
tokens. The selected consumer component must support the oauthProfile option; 
delegates that ignore unknown  [...]
   }
 }
diff --git 
a/components/camel-rest-openapi/src/main/docs/rest-openapi-component.adoc 
b/components/camel-rest-openapi/src/main/docs/rest-openapi-component.adoc
index 27eee299b6bc..2988682af8e0 100644
--- a/components/camel-rest-openapi/src/main/docs/rest-openapi-component.adoc
+++ b/components/camel-rest-openapi/src/main/docs/rest-openapi-component.adoc
@@ -138,8 +138,8 @@ xref:components:others:oauth.adoc[camel-oauth] or from the 
runtime integration.
 OpenAPI `securitySchemes` and operation security requirements are not 
converted into `oauthProfile`
 configuration; select the OAuth profile explicitly with the REST endpoint 
property or direct endpoint
 URI option.
-Because `rest-openapi` endpoint URIs are lenient, pass-through options are 
accepted by
-`rest-openapi` and forwarded to the selected delegate. If the delegate ignores 
an unknown option,
+The `oauthProfile` option is a first-class `rest-openapi` endpoint option that 
is forwarded to the
+selected delegate, which is responsible for enforcing it. If the delegate 
ignores the option,
 the endpoint can start without the expected protection, so verify that the 
selected consumer
 component supports `oauthProfile`.
 
diff --git 
a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpoint.java
 
b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpoint.java
index 7b36960a6443..039826116e64 100644
--- 
a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpoint.java
+++ 
b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpoint.java
@@ -90,8 +90,7 @@ import static org.apache.camel.util.StringHelper.before;
  * To call and expose REST services using OpenAPI specification as contract.
  */
 @UriEndpoint(firstVersion = "3.1.0", scheme = "rest-openapi", title = "REST 
OpenApi",
-             syntax = "rest-openapi:specificationUri#operationId", category = 
{ Category.REST, Category.API },
-             lenientProperties = true)
+             syntax = "rest-openapi:specificationUri#operationId", category = 
{ Category.REST, Category.API })
 public final class RestOpenApiEndpoint extends DefaultEndpoint {
 
     private static final Logger LOG = 
LoggerFactory.getLogger(RestOpenApiEndpoint.class);
@@ -177,6 +176,12 @@ public final class RestOpenApiEndpoint extends 
DefaultEndpoint {
     private String mockIncludePattern;
     @UriParam(label = "consumer", description = "Sets the context-path to use 
for servicing the OpenAPI specification")
     private String apiContextPath;
+    @UriParam(label = "consumer,security", displayName = "OAuth Profile",
+              description = "OAuth profile name passed to the HTTP consumer 
delegate for validating incoming"
+                            + " Authorization: Bearer tokens. The selected 
consumer component must support the"
+                            + " oauthProfile option; delegates that ignore 
unknown options will start without"
+                            + " endpoint protection.")
+    private String oauthProfile;
 
     public RestOpenApiEndpoint() {
         // help tooling instantiate endpoint
@@ -324,6 +329,10 @@ public final class RestOpenApiEndpoint extends 
DefaultEndpoint {
         if (factory != null) {
             RestConfiguration config = 
CamelContextHelper.getRestConfiguration(getCamelContext(), cname);
             Map<String, Object> copy = new HashMap<>(parameters); // defensive 
copy of the parameters
+            // pass oauthProfile to the delegate consumer, which is 
responsible for enforcing it
+            if (isNotEmpty(oauthProfile)) {
+                copy.put("oauthProfile", oauthProfile);
+            }
             // avoid duplicate context-path
             if (basePath.equals(config.getContextPath())) {
                 basePath = "";
@@ -504,6 +513,14 @@ public final class RestOpenApiEndpoint extends 
DefaultEndpoint {
         this.apiContextPath = apiContextPath;
     }
 
+    public String getOauthProfile() {
+        return oauthProfile;
+    }
+
+    public void setOauthProfile(String oauthProfile) {
+        this.oauthProfile = oauthProfile;
+    }
+
     public String getBindingPackageScan() {
         return bindingPackageScan;
     }
diff --git 
a/components/camel-rest-openapi/src/test/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpointV3Test.java
 
b/components/camel-rest-openapi/src/test/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpointV3Test.java
index 1f58e9853109..c15f84e5c6b5 100644
--- 
a/components/camel-rest-openapi/src/test/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpointV3Test.java
+++ 
b/components/camel-rest-openapi/src/test/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpointV3Test.java
@@ -115,6 +115,9 @@ public class RestOpenApiEndpointV3Test {
             endpoint.createConsumer(exchange -> {
             });
 
+            // oauthProfile is a first-class endpoint option bound to the 
endpoint and injected into
+            // the parameters passed to the delegate consumer factory
+            assertThat(endpoint.getOauthProfile()).isEqualTo("myprofile");
             assertThat(delegate.parameters).containsEntry("oauthProfile", 
"myprofile");
         } finally {
             camelContext.stop();
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_21.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_21.adoc
index 7ae5f745a352..fe9c4f4d676c 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_21.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_21.adoc
@@ -876,10 +876,10 @@ Rest DSL and contract-first OpenAPI routes pass the 
option to the selected HTTP
 Direct contract-first OpenAPI consumer routes can also pass the option on the 
endpoint URI, for example
 
`rest-openapi:petstore-v3.json?consumerComponentName=platform-http&oauthProfile=myprofile`.
 OpenAPI `securitySchemes` are not converted into `oauthProfile` automatically.
-Because `rest-openapi` endpoint URIs are lenient, pass-through options such as 
`oauthProfile` are
-accepted by the selected consumer delegate but may not appear as first-class 
`rest-openapi` options in
-component metadata or tooling. Verify that the selected delegate supports the 
pass-through option;
-delegates that ignore unknown options can otherwise start without the expected 
endpoint protection.
+The `oauthProfile` option is a first-class `rest-openapi` endpoint option that 
is forwarded to the
+selected consumer delegate, which is responsible for enforcing it. Verify that 
the selected delegate
+supports `oauthProfile`; delegates that ignore the option can otherwise start 
without the expected
+endpoint protection.
 For netty-http consumers, `oauthProfile` requires `usingExecutorService=true` 
and `sync=true`, which
 are the defaults, so blocking validation does not run on a Netty event-loop 
thread and rejection
 responses can be returned to the client. Routes that combine `oauthProfile`
diff --git a/docs/user-manual/modules/ROOT/pages/rest-dsl-openapi.adoc 
b/docs/user-manual/modules/ROOT/pages/rest-dsl-openapi.adoc
index 573a0d310d3f..ff6ed3055fba 100644
--- a/docs/user-manual/modules/ROOT/pages/rest-dsl-openapi.adoc
+++ b/docs/user-manual/modules/ROOT/pages/rest-dsl-openapi.adoc
@@ -65,9 +65,9 @@ support it. Direct `rest-openapi` consumer endpoint URIs can 
also pass the optio
 for example 
`rest-openapi:petstore-v3.json?consumerComponentName=platform-http&oauthProfile=myprofile`.
 Consumer endpoint URIs identify the OpenAPI specification and do not include 
an `#operationId`
 fragment.
-Because `rest-openapi` endpoint URIs are lenient, delegate options may be 
accepted by
-`rest-openapi` even when the selected delegate ignores them. Verify that the 
selected consumer
-component supports `oauthProfile`.
+The `oauthProfile` option is forwarded to the selected delegate, which is 
responsible for
+enforcing it. Verify that the selected consumer component supports 
`oauthProfile`; a delegate
+that ignores the option starts without the expected protection.
 
 == Contract first
 
diff --git 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/RestOpenApiEndpointBuilderFactory.java
 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/RestOpenApiEndpointBuilderFactory.java
index bf2adee3f17a..0322ea108e4c 100644
--- 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/RestOpenApiEndpointBuilderFactory.java
+++ 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/RestOpenApiEndpointBuilderFactory.java
@@ -175,6 +175,23 @@ public interface RestOpenApiEndpointBuilderFactory {
             doSetProperty("missingOperation", missingOperation);
             return this;
         }
+        /**
+         * OAuth profile name passed to the HTTP consumer delegate for
+         * validating incoming Authorization: Bearer tokens. The selected
+         * consumer component must support the oauthProfile option; delegates
+         * that ignore unknown options will start without endpoint protection.
+         * 
+         * The option is a: <code>java.lang.String</code> type.
+         * 
+         * Group: security
+         * 
+         * @param oauthProfile the value to set
+         * @return the dsl builder
+         */
+        default RestOpenApiEndpointConsumerBuilder oauthProfile(String 
oauthProfile) {
+            doSetProperty("oauthProfile", oauthProfile);
+            return this;
+        }
     }
 
     /**

Reply via email to