This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 010bcd575ebd CAMEL-23525: Add optional JWT issuer and audience claim
validation (#23389)
010bcd575ebd is described below
commit 010bcd575ebd9d7a39780b22e7e3f3fb0129c372
Author: Vishal Nagaraj <[email protected]>
AuthorDate: Thu May 21 11:16:34 2026 +0530
CAMEL-23525: Add optional JWT issuer and audience claim validation (#23389)
The embedded HTTP server in camel-platform-http-main previously
configured Vert.x JWTAuth with keystore parameters only. Tokens were
verified for signature and the default exp/nbf claims, but the
RFC 7519 registered claims iss (issuer) and aud (audience) were not
validated.
Add optional jwtIssuer and jwtAudience properties to both
HttpServerConfigurationProperties (camel.server.*) and
HttpManagementServerConfigurationProperties (camel.management.*).
When either is set, attach a JWTOptions configured with the
corresponding values to the JWTAuthOptions passed to JWTAuth.create.
Behaviour is unchanged when both are unset.
jwtAudience accepts a comma-separated list; a token is accepted if
its aud claim matches any configured value.
---
.../main/camel-main-configuration-metadata.json | 4 +
.../src/main/docs/platform-http-main.adoc | 24 +++
.../JWTAuthenticationConfigurer.java | 70 +++++++--
...erAudienceAuthenticationMainHttpServerTest.java | 164 +++++++++++++++++++++
.../resources/jwt-issuer-audience-auth.properties | 25 ++++
...entServerConfigurationPropertiesConfigurer.java | 14 ++
...ttpServerConfigurationPropertiesConfigurer.java | 14 ++
.../camel-main-configuration-metadata.json | 4 +
core/camel-main/src/main/docs/main.adoc | 8 +-
...ttpManagementServerConfigurationProperties.java | 44 ++++++
.../main/HttpServerConfigurationProperties.java | 44 ++++++
.../ROOT/pages/camel-4x-upgrade-guide-4_21.adoc | 12 ++
12 files changed, 411 insertions(+), 16 deletions(-)
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
index 225c7f367946..9d1f25dc6189 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/main/camel-main-configuration-metadata.json
@@ -215,6 +215,8 @@
{ "name": "camel.management.infoPath", "required": false, "description":
"The path endpoint used to expose the info status", "sourceType":
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type":
"string", "javaType": "java.lang.String", "defaultValue": "\/observe\/info",
"secret": false },
{ "name": "camel.management.jolokiaEnabled", "required": false,
"description": "Whether to enable jolokia. If enabled then you can access
jolokia api on context-path: \/observe\/jolokia", "sourceType":
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type":
"boolean", "javaType": "boolean", "defaultValue": false, "secret": false },
{ "name": "camel.management.jolokiaPath", "required": false,
"description": "The path endpoint used to expose the jolokia data.",
"sourceType":
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type":
"string", "javaType": "java.lang.String", "defaultValue": "\/observe\/jolokia",
"secret": false },
+ { "name": "camel.management.jwtAudience", "required": false,
"description": "Expected JWT audience (aud claim) for token validation.
Multiple values can be separated by comma. When set, tokens whose audience does
not contain any of the configured values are rejected.", "sourceType":
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type":
"string", "javaType": "java.lang.String", "secret": false },
+ { "name": "camel.management.jwtIssuer", "required": false, "description":
"Expected JWT issuer (iss claim) for token validation. When set, tokens whose
issuer does not match are rejected.", "sourceType":
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type":
"string", "javaType": "java.lang.String", "secret": false },
{ "name": "camel.management.jwtKeystorePassword", "required": false,
"description": "Password from the keystore used for JWT tokens validation.",
"sourceType":
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type":
"string", "javaType": "java.lang.String", "secret": true, "security": "secret"
},
{ "name": "camel.management.jwtKeystorePath", "required": false,
"description": "Path to the keystore file used for JWT tokens validation.",
"sourceType":
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type":
"string", "javaType": "java.lang.String", "secret": false },
{ "name": "camel.management.jwtKeystoreType", "required": false,
"description": "Type of the keystore used for JWT tokens validation (jks,
pkcs12, etc.).", "sourceType":
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type":
"string", "javaType": "java.lang.String", "secret": false },
@@ -332,6 +334,8 @@
{ "name": "camel.server.fileUploadDirectory", "required": false,
"description": "Directory to temporary store file uploads while Camel routes
the incoming request. If no directory has been explicit configured, then a
temporary directory is created in the java.io.tmpdir directory.", "sourceType":
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string",
"javaType": "java.lang.String", "secret": false },
{ "name": "camel.server.fileUploadEnabled", "required": false,
"description": "Whether to enable file uploads being supported (such as POST
multipart\/form-data) and stored into a temporary directory.", "sourceType":
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "boolean",
"javaType": "boolean", "defaultValue": true, "secret": false },
{ "name": "camel.server.host", "required": false, "description": "Hostname
to use for binding embedded HTTP server", "sourceType":
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string",
"javaType": "java.lang.String", "defaultValue": "0.0.0.0", "secret": false },
+ { "name": "camel.server.jwtAudience", "required": false, "description":
"Expected JWT audience (aud claim) for token validation. Multiple values can be
separated by comma. When set, tokens whose audience does not contain any of the
configured values are rejected.", "sourceType":
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string",
"javaType": "java.lang.String", "secret": false },
+ { "name": "camel.server.jwtIssuer", "required": false, "description":
"Expected JWT issuer (iss claim) for token validation. When set, tokens whose
issuer does not match are rejected.", "sourceType":
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string",
"javaType": "java.lang.String", "secret": false },
{ "name": "camel.server.jwtKeystorePassword", "required": false,
"description": "Password from the keystore used for JWT tokens validation.",
"sourceType": "org.apache.camel.main.HttpServerConfigurationProperties",
"type": "string", "javaType": "java.lang.String", "secret": true, "security":
"secret" },
{ "name": "camel.server.jwtKeystorePath", "required": false,
"description": "Path to the keystore file used for JWT tokens validation.",
"sourceType": "org.apache.camel.main.HttpServerConfigurationProperties",
"type": "string", "javaType": "java.lang.String", "secret": false },
{ "name": "camel.server.jwtKeystoreType", "required": false,
"description": "Type of the keystore used for JWT tokens validation (jks,
pkcs12, etc.).", "sourceType":
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string",
"javaType": "java.lang.String", "secret": false },
diff --git
a/components/camel-platform-http-main/src/main/docs/platform-http-main.adoc
b/components/camel-platform-http-main/src/main/docs/platform-http-main.adoc
index 2992696a0b34..141c11e4da03 100644
--- a/components/camel-platform-http-main/src/main/docs/platform-http-main.adoc
+++ b/components/camel-platform-http-main/src/main/docs/platform-http-main.adoc
@@ -42,6 +42,30 @@ These features are as follows:
You configure these features in the `application.properties` file using the
`camel.server.xxx` and `camel.management.xxx` options.
+== JWT authentication
+
+The embedded HTTP server can validate JWT bearer tokens on incoming requests.
+Token signatures are verified against a keystore, and the `exp` and `nbf`
claims
+are checked by default. Set `jwtIssuer` and/or `jwtAudience` to also validate
+the `iss` and `aud` claims.
+
+[source,properties]
+----
+camel.server.enabled=true
+camel.server.authenticationEnabled=true
+camel.server.authenticationPath=/*
+
+camel.server.jwtKeystoreType=jks
+camel.server.jwtKeystorePath=keystore.jks
+camel.server.jwtKeystorePassword=changeme
+
+camel.server.jwtIssuer=https://issuer.example.com
+camel.server.jwtAudience=api,internal-api
+----
+
+`jwtAudience` accepts a comma-separated list of values. A token is accepted if
+its `aud` claim contains any of the configured values.
+
== See More
- xref:platform-http-vertx.adoc[Platform HTTP Vert.x]
diff --git
a/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/authentication/JWTAuthenticationConfigurer.java
b/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/authentication/JWTAuthenticationConfigurer.java
index 03380ba21611..9b51b4befbe3 100644
---
a/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/authentication/JWTAuthenticationConfigurer.java
+++
b/components/camel-platform-http-main/src/main/java/org/apache/camel/component/platform/http/main/authentication/JWTAuthenticationConfigurer.java
@@ -17,6 +17,7 @@
package org.apache.camel.component.platform.http.main.authentication;
import io.vertx.core.json.JsonObject;
+import io.vertx.ext.auth.JWTOptions;
import io.vertx.ext.auth.authentication.AuthenticationProvider;
import io.vertx.ext.auth.jwt.JWTAuth;
import io.vertx.ext.auth.jwt.JWTAuthOptions;
@@ -27,6 +28,7 @@ import
org.apache.camel.component.platform.http.vertx.auth.AuthenticationConfig.
import
org.apache.camel.component.platform.http.vertx.auth.AuthenticationConfig.AuthenticationHandlerFactory;
import org.apache.camel.main.HttpManagementServerConfigurationProperties;
import org.apache.camel.main.HttpServerConfigurationProperties;
+import org.apache.camel.util.ObjectHelper;
public class JWTAuthenticationConfigurer implements
MainAuthenticationConfigurer {
@@ -48,13 +50,20 @@ public class JWTAuthenticationConfigurer implements
MainAuthenticationConfigurer
return JWTAuthHandler.create(authProvider, realm);
}
});
- entry.setAuthenticationProviderFactory(vertx -> JWTAuth.create(
- vertx,
- new JWTAuthOptions(
- new JsonObject().put("keyStore", new JsonObject()
- .put("type", properties.getJwtKeystoreType())
- .put("path", properties.getJwtKeystorePath())
- .put("password",
properties.getJwtKeystorePassword())))));
+
+ entry.setAuthenticationProviderFactory(vertx -> {
+ JWTAuthOptions jwtAuthOptions = new JWTAuthOptions(
+ new JsonObject().put("keyStore", new JsonObject()
+ .put("type", properties.getJwtKeystoreType())
+ .put("path", properties.getJwtKeystorePath())
+ .put("password",
properties.getJwtKeystorePassword())));
+
+ JWTOptions jwtOptions =
buildJwtOptions(properties.getJwtAudience(), properties.getJwtIssuer());
+ if (jwtOptions != null) {
+ jwtAuthOptions.setJWTOptions(jwtOptions);
+ }
+ return JWTAuth.create(vertx, jwtAuthOptions);
+ });
authenticationConfig.getEntries().add(entry);
authenticationConfig.setEnabled(true);
@@ -78,15 +87,48 @@ public class JWTAuthenticationConfigurer implements
MainAuthenticationConfigurer
return JWTAuthHandler.create(authProvider, realm);
}
});
- entry.setAuthenticationProviderFactory(vertx -> JWTAuth.create(
- vertx,
- new JWTAuthOptions(
- new JsonObject().put("keyStore", new JsonObject()
- .put("type", properties.getJwtKeystoreType())
- .put("path", properties.getJwtKeystorePath())
- .put("password",
properties.getJwtKeystorePassword())))));
+
+ entry.setAuthenticationProviderFactory(vertx -> {
+ JWTAuthOptions jwtAuthOptions = new JWTAuthOptions(
+ new JsonObject().put("keyStore", new JsonObject()
+ .put("type", properties.getJwtKeystoreType())
+ .put("path", properties.getJwtKeystorePath())
+ .put("password",
properties.getJwtKeystorePassword())));
+
+ JWTOptions jwtOptions =
buildJwtOptions(properties.getJwtAudience(), properties.getJwtIssuer());
+ if (jwtOptions != null) {
+ jwtAuthOptions.setJWTOptions(jwtOptions);
+ }
+ return JWTAuth.create(vertx, jwtAuthOptions);
+ });
authenticationConfig.getEntries().add(entry);
authenticationConfig.setEnabled(true);
}
+
+ private static JWTOptions buildJwtOptions(String audience, String issuer) {
+
+ boolean isAudienceEmpty = ObjectHelper.isEmpty(audience);
+ boolean isIssuerEmpty = ObjectHelper.isEmpty(issuer);
+
+ if (isAudienceEmpty && isIssuerEmpty) {
+ return null;
+ }
+
+ JWTOptions options = new JWTOptions();
+
+ if (!isAudienceEmpty) {
+ for (String a : audience.split(",")) {
+ if (ObjectHelper.isNotEmpty(a)) {
+ options.addAudience(a.trim());
+ }
+ }
+ }
+
+ if (!isIssuerEmpty) {
+ options.setIssuer(issuer);
+ }
+
+ return options;
+ }
}
diff --git
a/components/camel-platform-http-main/src/test/java/org/apache/camel/component/platform/http/main/authentication/JWTIssuerAudienceAuthenticationMainHttpServerTest.java
b/components/camel-platform-http-main/src/test/java/org/apache/camel/component/platform/http/main/authentication/JWTIssuerAudienceAuthenticationMainHttpServerTest.java
new file mode 100644
index 000000000000..251cb3cc6158
--- /dev/null
+++
b/components/camel-platform-http-main/src/test/java/org/apache/camel/component/platform/http/main/authentication/JWTIssuerAudienceAuthenticationMainHttpServerTest.java
@@ -0,0 +1,164 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.platform.http.main.authentication;
+
+import io.vertx.core.Vertx;
+import io.vertx.core.json.JsonObject;
+import io.vertx.ext.auth.JWTOptions;
+import io.vertx.ext.auth.jwt.JWTAuth;
+import io.vertx.ext.auth.jwt.JWTAuthOptions;
+import org.apache.camel.CamelContext;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.main.Main;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import static io.restassured.RestAssured.given;
+import static org.hamcrest.Matchers.equalTo;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+public class JWTIssuerAudienceAuthenticationMainHttpServerTest {
+
+ private static final String EXPECTED_ISSUER =
"https://issuer.camel.example";
+ private static final String EXPECTED_AUDIENCE = "camel-api";
+ private static final String SECOND_EXPECTED_AUDIENCE = "camel-internal";
+
+ private static Main main;
+ private static JWTAuth jwtAuth;
+
+ @BeforeAll
+ static void init() {
+ main = new Main();
+
main.setPropertyPlaceholderLocations("jwt-issuer-audience-auth.properties");
+ main.configure().addRoutesBuilder(new PlatformHttpRouteBuilder());
+ main.enableTrace();
+ main.start();
+
+ jwtAuth = JWTAuth.create(Vertx.vertx(), new JWTAuthOptions(
+ new JsonObject().put("keyStore", new JsonObject()
+ .put("type", "jks")
+ .put("path", "test-camel-main-auth-jwt.jks")
+ .put("password", "changeme"))));
+ }
+
+ @AfterAll
+ static void tearDown() {
+ main.stop();
+ }
+
+ @Test
+ void testNoAuthHeaderReturns401() {
+ CamelContext camelContext = main.getCamelContext();
+ assertNotNull(camelContext);
+
+ given()
+ .when()
+ .get("/main-http-test")
+ .then()
+ .statusCode(401)
+ .body(equalTo("Unauthorized"));
+ }
+
+ @Test
+ void testMatchingIssuerAndAudienceReturns200() {
+ String token = mintToken(new JWTOptions()
+ .setIssuer(EXPECTED_ISSUER)
+ .addAudience(EXPECTED_AUDIENCE));
+
+ given()
+ .header("Authorization", "Bearer " + token)
+ .when()
+ .get("/main-http-test")
+ .then()
+ .statusCode(200)
+ .body(equalTo("main-http-auth-jwt-test-response"));
+ }
+
+ @Test
+ void testMatchingIssuerAndSecondAudienceReturns200() {
+ String token = mintToken(new JWTOptions()
+ .setIssuer(EXPECTED_ISSUER)
+ .addAudience(SECOND_EXPECTED_AUDIENCE));
+
+ given()
+ .header("Authorization", "Bearer " + token)
+ .when()
+ .get("/main-http-test")
+ .then()
+ .statusCode(200)
+ .body(equalTo("main-http-auth-jwt-test-response"));
+ }
+
+ @Test
+ void testWrongIssuerReturns401() {
+ String token = mintToken(new JWTOptions()
+ .setIssuer("https://attacker.example")
+ .addAudience(EXPECTED_AUDIENCE));
+
+ given()
+ .header("Authorization", "Bearer " + token)
+ .when()
+ .get("/main-http-test")
+ .then()
+ .statusCode(401)
+ .body(equalTo("Unauthorized"));
+ }
+
+ @Test
+ void testWrongAudienceReturns401() {
+ String token = mintToken(new JWTOptions()
+ .setIssuer(EXPECTED_ISSUER)
+ .addAudience("not-in-list"));
+
+ given()
+ .header("Authorization", "Bearer " + token)
+ .when()
+ .get("/main-http-test")
+ .then()
+ .statusCode(401)
+ .body(equalTo("Unauthorized"));
+ }
+
+ @Test
+ void testMissingAudienceReturns401() {
+ String token = mintToken(new JWTOptions()
+ .setIssuer(EXPECTED_ISSUER));
+
+ given()
+ .header("Authorization", "Bearer " + token)
+ .when()
+ .get("/main-http-test")
+ .then()
+ .statusCode(401)
+ .body(equalTo("Unauthorized"));
+ }
+
+ private static String mintToken(JWTOptions jwtOptions) {
+ return jwtAuth.generateToken(new JsonObject().put("admin", "camel"),
jwtOptions);
+ }
+
+ private static class PlatformHttpRouteBuilder extends RouteBuilder {
+
+ @Override
+ public void configure() throws Exception {
+ from("platform-http:/main-http-test")
+ .log("Received request with headers: ${headers}\nWith
body: ${body}")
+ .setBody(simple("main-http-auth-jwt-test-response"));
+ }
+ }
+}
diff --git
a/components/camel-platform-http-main/src/test/resources/jwt-issuer-audience-auth.properties
b/components/camel-platform-http-main/src/test/resources/jwt-issuer-audience-auth.properties
new file mode 100644
index 000000000000..a35c59260378
--- /dev/null
+++
b/components/camel-platform-http-main/src/test/resources/jwt-issuer-audience-auth.properties
@@ -0,0 +1,25 @@
+## ---------------------------------------------------------------------------
+## Licensed to the Apache Software Foundation (ASF) under one or more
+## contributor license agreements. See the NOTICE file distributed with
+## this work for additional information regarding copyright ownership.
+## The ASF licenses this file to You under the Apache License, Version 2.0
+## (the "License"); you may not use this file except in compliance with
+## the License. You may obtain a copy of the License at
+##
+## http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an "AS IS" BASIS,
+## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+## See the License for the specific language governing permissions and
+## limitations under the License.
+## ---------------------------------------------------------------------------
+camel.server.enabled=true
+
+camel.server.authenticationEnabled=true
+camel.server.authenticationPath=/*
+camel.server.jwtKeystoreType=jks
+camel.server.jwtKeystorePath=test-camel-main-auth-jwt.jks
+camel.server.jwtKeystorePassword=changeme
+camel.server.jwtIssuer=https://issuer.camel.example
+camel.server.jwtAudience=camel-api,camel-internal
diff --git
a/core/camel-main/src/generated/java/org/apache/camel/main/HttpManagementServerConfigurationPropertiesConfigurer.java
b/core/camel-main/src/generated/java/org/apache/camel/main/HttpManagementServerConfigurationPropertiesConfigurer.java
index ad55f4821f9f..6e0e3eb74b8f 100644
---
a/core/camel-main/src/generated/java/org/apache/camel/main/HttpManagementServerConfigurationPropertiesConfigurer.java
+++
b/core/camel-main/src/generated/java/org/apache/camel/main/HttpManagementServerConfigurationPropertiesConfigurer.java
@@ -36,6 +36,8 @@ public class
HttpManagementServerConfigurationPropertiesConfigurer extends org.a
map.put("InfoPath", java.lang.String.class);
map.put("JolokiaEnabled", boolean.class);
map.put("JolokiaPath", java.lang.String.class);
+ map.put("JwtAudience", java.lang.String.class);
+ map.put("JwtIssuer", java.lang.String.class);
map.put("JwtKeystorePassword", java.lang.String.class);
map.put("JwtKeystorePath", java.lang.String.class);
map.put("JwtKeystoreType", java.lang.String.class);
@@ -79,6 +81,10 @@ public class
HttpManagementServerConfigurationPropertiesConfigurer extends org.a
case "jolokiaEnabled": target.setJolokiaEnabled(property(camelContext,
boolean.class, value)); return true;
case "jolokiapath":
case "jolokiaPath": target.setJolokiaPath(property(camelContext,
java.lang.String.class, value)); return true;
+ case "jwtaudience":
+ case "jwtAudience": target.setJwtAudience(property(camelContext,
java.lang.String.class, value)); return true;
+ case "jwtissuer":
+ case "jwtIssuer": target.setJwtIssuer(property(camelContext,
java.lang.String.class, value)); return true;
case "jwtkeystorepassword":
case "jwtKeystorePassword":
target.setJwtKeystorePassword(property(camelContext, java.lang.String.class,
value)); return true;
case "jwtkeystorepath":
@@ -135,6 +141,10 @@ public class
HttpManagementServerConfigurationPropertiesConfigurer extends org.a
case "jolokiaEnabled": return boolean.class;
case "jolokiapath":
case "jolokiaPath": return java.lang.String.class;
+ case "jwtaudience":
+ case "jwtAudience": return java.lang.String.class;
+ case "jwtissuer":
+ case "jwtIssuer": return java.lang.String.class;
case "jwtkeystorepassword":
case "jwtKeystorePassword": return java.lang.String.class;
case "jwtkeystorepath":
@@ -187,6 +197,10 @@ public class
HttpManagementServerConfigurationPropertiesConfigurer extends org.a
case "jolokiaEnabled": return target.isJolokiaEnabled();
case "jolokiapath":
case "jolokiaPath": return target.getJolokiaPath();
+ case "jwtaudience":
+ case "jwtAudience": return target.getJwtAudience();
+ case "jwtissuer":
+ case "jwtIssuer": return target.getJwtIssuer();
case "jwtkeystorepassword":
case "jwtKeystorePassword": return target.getJwtKeystorePassword();
case "jwtkeystorepath":
diff --git
a/core/camel-main/src/generated/java/org/apache/camel/main/HttpServerConfigurationPropertiesConfigurer.java
b/core/camel-main/src/generated/java/org/apache/camel/main/HttpServerConfigurationPropertiesConfigurer.java
index c4bbf04ce2df..cec5e0d0cf15 100644
---
a/core/camel-main/src/generated/java/org/apache/camel/main/HttpServerConfigurationPropertiesConfigurer.java
+++
b/core/camel-main/src/generated/java/org/apache/camel/main/HttpServerConfigurationPropertiesConfigurer.java
@@ -30,6 +30,8 @@ public class HttpServerConfigurationPropertiesConfigurer
extends org.apache.came
map.put("FileUploadDirectory", java.lang.String.class);
map.put("FileUploadEnabled", boolean.class);
map.put("Host", java.lang.String.class);
+ map.put("JwtAudience", java.lang.String.class);
+ map.put("JwtIssuer", java.lang.String.class);
map.put("JwtKeystorePassword", java.lang.String.class);
map.put("JwtKeystorePath", java.lang.String.class);
map.put("JwtKeystoreType", java.lang.String.class);
@@ -61,6 +63,10 @@ public class HttpServerConfigurationPropertiesConfigurer
extends org.apache.came
case "fileuploadenabled":
case "fileUploadEnabled":
target.setFileUploadEnabled(property(camelContext, boolean.class, value));
return true;
case "host": target.setHost(property(camelContext,
java.lang.String.class, value)); return true;
+ case "jwtaudience":
+ case "jwtAudience": target.setJwtAudience(property(camelContext,
java.lang.String.class, value)); return true;
+ case "jwtissuer":
+ case "jwtIssuer": target.setJwtIssuer(property(camelContext,
java.lang.String.class, value)); return true;
case "jwtkeystorepassword":
case "jwtKeystorePassword":
target.setJwtKeystorePassword(property(camelContext, java.lang.String.class,
value)); return true;
case "jwtkeystorepath":
@@ -105,6 +111,10 @@ public class HttpServerConfigurationPropertiesConfigurer
extends org.apache.came
case "fileuploadenabled":
case "fileUploadEnabled": return boolean.class;
case "host": return java.lang.String.class;
+ case "jwtaudience":
+ case "jwtAudience": return java.lang.String.class;
+ case "jwtissuer":
+ case "jwtIssuer": return java.lang.String.class;
case "jwtkeystorepassword":
case "jwtKeystorePassword": return java.lang.String.class;
case "jwtkeystorepath":
@@ -145,6 +155,10 @@ public class HttpServerConfigurationPropertiesConfigurer
extends org.apache.came
case "fileuploadenabled":
case "fileUploadEnabled": return target.isFileUploadEnabled();
case "host": return target.getHost();
+ case "jwtaudience":
+ case "jwtAudience": return target.getJwtAudience();
+ case "jwtissuer":
+ case "jwtIssuer": return target.getJwtIssuer();
case "jwtkeystorepassword":
case "jwtKeystorePassword": return target.getJwtKeystorePassword();
case "jwtkeystorepath":
diff --git
a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
index 225c7f367946..9d1f25dc6189 100644
---
a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
+++
b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json
@@ -215,6 +215,8 @@
{ "name": "camel.management.infoPath", "required": false, "description":
"The path endpoint used to expose the info status", "sourceType":
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type":
"string", "javaType": "java.lang.String", "defaultValue": "\/observe\/info",
"secret": false },
{ "name": "camel.management.jolokiaEnabled", "required": false,
"description": "Whether to enable jolokia. If enabled then you can access
jolokia api on context-path: \/observe\/jolokia", "sourceType":
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type":
"boolean", "javaType": "boolean", "defaultValue": false, "secret": false },
{ "name": "camel.management.jolokiaPath", "required": false,
"description": "The path endpoint used to expose the jolokia data.",
"sourceType":
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type":
"string", "javaType": "java.lang.String", "defaultValue": "\/observe\/jolokia",
"secret": false },
+ { "name": "camel.management.jwtAudience", "required": false,
"description": "Expected JWT audience (aud claim) for token validation.
Multiple values can be separated by comma. When set, tokens whose audience does
not contain any of the configured values are rejected.", "sourceType":
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type":
"string", "javaType": "java.lang.String", "secret": false },
+ { "name": "camel.management.jwtIssuer", "required": false, "description":
"Expected JWT issuer (iss claim) for token validation. When set, tokens whose
issuer does not match are rejected.", "sourceType":
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type":
"string", "javaType": "java.lang.String", "secret": false },
{ "name": "camel.management.jwtKeystorePassword", "required": false,
"description": "Password from the keystore used for JWT tokens validation.",
"sourceType":
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type":
"string", "javaType": "java.lang.String", "secret": true, "security": "secret"
},
{ "name": "camel.management.jwtKeystorePath", "required": false,
"description": "Path to the keystore file used for JWT tokens validation.",
"sourceType":
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type":
"string", "javaType": "java.lang.String", "secret": false },
{ "name": "camel.management.jwtKeystoreType", "required": false,
"description": "Type of the keystore used for JWT tokens validation (jks,
pkcs12, etc.).", "sourceType":
"org.apache.camel.main.HttpManagementServerConfigurationProperties", "type":
"string", "javaType": "java.lang.String", "secret": false },
@@ -332,6 +334,8 @@
{ "name": "camel.server.fileUploadDirectory", "required": false,
"description": "Directory to temporary store file uploads while Camel routes
the incoming request. If no directory has been explicit configured, then a
temporary directory is created in the java.io.tmpdir directory.", "sourceType":
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string",
"javaType": "java.lang.String", "secret": false },
{ "name": "camel.server.fileUploadEnabled", "required": false,
"description": "Whether to enable file uploads being supported (such as POST
multipart\/form-data) and stored into a temporary directory.", "sourceType":
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "boolean",
"javaType": "boolean", "defaultValue": true, "secret": false },
{ "name": "camel.server.host", "required": false, "description": "Hostname
to use for binding embedded HTTP server", "sourceType":
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string",
"javaType": "java.lang.String", "defaultValue": "0.0.0.0", "secret": false },
+ { "name": "camel.server.jwtAudience", "required": false, "description":
"Expected JWT audience (aud claim) for token validation. Multiple values can be
separated by comma. When set, tokens whose audience does not contain any of the
configured values are rejected.", "sourceType":
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string",
"javaType": "java.lang.String", "secret": false },
+ { "name": "camel.server.jwtIssuer", "required": false, "description":
"Expected JWT issuer (iss claim) for token validation. When set, tokens whose
issuer does not match are rejected.", "sourceType":
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string",
"javaType": "java.lang.String", "secret": false },
{ "name": "camel.server.jwtKeystorePassword", "required": false,
"description": "Password from the keystore used for JWT tokens validation.",
"sourceType": "org.apache.camel.main.HttpServerConfigurationProperties",
"type": "string", "javaType": "java.lang.String", "secret": true, "security":
"secret" },
{ "name": "camel.server.jwtKeystorePath", "required": false,
"description": "Path to the keystore file used for JWT tokens validation.",
"sourceType": "org.apache.camel.main.HttpServerConfigurationProperties",
"type": "string", "javaType": "java.lang.String", "secret": false },
{ "name": "camel.server.jwtKeystoreType", "required": false,
"description": "Type of the keystore used for JWT tokens validation (jks,
pkcs12, etc.).", "sourceType":
"org.apache.camel.main.HttpServerConfigurationProperties", "type": "string",
"javaType": "java.lang.String", "secret": false },
diff --git a/core/camel-main/src/main/docs/main.adoc
b/core/camel-main/src/main/docs/main.adoc
index ac293f180104..b61505434e8a 100644
--- a/core/camel-main/src/main/docs/main.adoc
+++ b/core/camel-main/src/main/docs/main.adoc
@@ -196,7 +196,7 @@ The camel.routecontroller supports 12 options, which are
listed below.
=== Camel Embedded HTTP Server (only for standalone; not Spring Boot or
Quarkus) configurations
-The camel.server supports 18 options, which are listed below.
+The camel.server supports 20 options, which are listed below.
[width="100%",cols="2,5,^1,2",options="header"]
|===
@@ -209,6 +209,8 @@ The camel.server supports 18 options, which are listed
below.
| *camel.server.fileUploadDirectory* | Directory to temporary store file
uploads while Camel routes the incoming request. If no directory has been
explicit configured, then a temporary directory is created in the
java.io.tmpdir directory. | | String
| *camel.server.fileUploadEnabled* | Whether to enable file uploads being
supported (such as POST multipart/form-data) and stored into a temporary
directory. | true | boolean
| *camel.server.host* | Hostname to use for binding embedded HTTP server |
0.0.0.0 | String
+| *camel.server.jwtAudience* | Expected JWT audience (aud claim) for token
validation. Multiple values can be separated by comma. When set, tokens whose
audience does not contain any of the configured values are rejected. | | String
+| *camel.server.jwtIssuer* | Expected JWT issuer (iss claim) for token
validation. When set, tokens whose issuer does not match are rejected. | |
String
| *camel.server.jwtKeystorePassword* | Password from the keystore used for JWT
tokens validation. | | String
| *camel.server.jwtKeystorePath* | Path to the keystore file used for JWT
tokens validation. | | String
| *camel.server.jwtKeystoreType* | Type of the keystore used for JWT tokens
validation (jks, pkcs12, etc.). | | String
@@ -223,7 +225,7 @@ The camel.server supports 18 options, which are listed
below.
=== Camel Embedded HTTP management Server (only for standalone; not Spring
Boot or Quarkus) configurations
-The camel.management supports 24 options, which are listed below.
+The camel.management supports 26 options, which are listed below.
[width="100%",cols="2,5,^1,2",options="header"]
|===
@@ -242,6 +244,8 @@ The camel.management supports 24 options, which are listed
below.
| *camel.management.infoPath* | The path endpoint used to expose the info
status | /observe/info | String
| *camel.management.jolokiaEnabled* | Whether to enable jolokia. If enabled
then you can access jolokia api on context-path: /observe/jolokia | false |
boolean
| *camel.management.jolokiaPath* | The path endpoint used to expose the
jolokia data. | /observe/jolokia | String
+| *camel.management.jwtAudience* | Expected JWT audience (aud claim) for token
validation. Multiple values can be separated by comma. When set, tokens whose
audience does not contain any of the configured values are rejected. | | String
+| *camel.management.jwtIssuer* | Expected JWT issuer (iss claim) for token
validation. When set, tokens whose issuer does not match are rejected. | |
String
| *camel.management.jwtKeystorePassword* | Password from the keystore used for
JWT tokens validation. | | String
| *camel.management.jwtKeystorePath* | Path to the keystore file used for JWT
tokens validation. | | String
| *camel.management.jwtKeystoreType* | Type of the keystore used for JWT
tokens validation (jks, pkcs12, etc.). | | String
diff --git
a/core/camel-main/src/main/java/org/apache/camel/main/HttpManagementServerConfigurationProperties.java
b/core/camel-main/src/main/java/org/apache/camel/main/HttpManagementServerConfigurationProperties.java
index 9329f7584144..0f8891a94766 100644
---
a/core/camel-main/src/main/java/org/apache/camel/main/HttpManagementServerConfigurationProperties.java
+++
b/core/camel-main/src/main/java/org/apache/camel/main/HttpManagementServerConfigurationProperties.java
@@ -73,6 +73,10 @@ public class HttpManagementServerConfigurationProperties
implements BootstrapClo
private String jwtKeystorePath;
@Metadata(label = "security", security = "secret")
private String jwtKeystorePassword;
+ @Metadata(label = "security")
+ private String jwtIssuer;
+ @Metadata(label = "security")
+ private String jwtAudience;
public
HttpManagementServerConfigurationProperties(MainConfigurationProperties parent)
{
this.parent = parent;
@@ -362,6 +366,29 @@ public class HttpManagementServerConfigurationProperties
implements BootstrapClo
this.jwtKeystorePassword = jwtKeystorePassword;
}
+ public String getJwtIssuer() {
+ return jwtIssuer;
+ }
+
+ /**
+ * Expected JWT issuer (iss claim) for token validation. When set, tokens
whose issuer does not match are rejected.
+ */
+ public void setJwtIssuer(String jwtIssuer) {
+ this.jwtIssuer = jwtIssuer;
+ }
+
+ public String getJwtAudience() {
+ return jwtAudience;
+ }
+
+ /**
+ * Expected JWT audience (aud claim) for token validation. Multiple values
can be separated by comma. When set,
+ * tokens whose audience does not contain any of the configured values are
rejected.
+ */
+ public void setJwtAudience(String jwtAudience) {
+ this.jwtAudience = jwtAudience;
+ }
+
/**
* Whether embedded HTTP management server is enabled. By default, the
server is not enabled.
*/
@@ -542,6 +569,23 @@ public class HttpManagementServerConfigurationProperties
implements BootstrapClo
return this;
}
+ /**
+ * Expected JWT issuer (iss claim) for token validation. When set, tokens
whose issuer does not match are rejected.
+ */
+ public HttpManagementServerConfigurationProperties withJwtIssuer(String
jwtIssuer) {
+ this.jwtIssuer = jwtIssuer;
+ return this;
+ }
+
+ /**
+ * Expected JWT audience (aud claim) for token validation. Multiple values
can be separated by comma. When set,
+ * tokens whose audience does not contain any of the configured values are
rejected.
+ */
+ public HttpManagementServerConfigurationProperties withJwtAudience(String
jwtAudience) {
+ this.jwtAudience = jwtAudience;
+ return this;
+ }
+
/**
* The path endpoint used to expose the info status
*/
diff --git
a/core/camel-main/src/main/java/org/apache/camel/main/HttpServerConfigurationProperties.java
b/core/camel-main/src/main/java/org/apache/camel/main/HttpServerConfigurationProperties.java
index fc025a584c28..d51cf5e9a36a 100644
---
a/core/camel-main/src/main/java/org/apache/camel/main/HttpServerConfigurationProperties.java
+++
b/core/camel-main/src/main/java/org/apache/camel/main/HttpServerConfigurationProperties.java
@@ -64,6 +64,10 @@ public class HttpServerConfigurationProperties implements
BootstrapCloseable {
private String jwtKeystorePath;
@Metadata(label = "security", security = "secret")
private String jwtKeystorePassword;
+ @Metadata(label = "security")
+ private String jwtIssuer;
+ @Metadata(label = "security")
+ private String jwtAudience;
public HttpServerConfigurationProperties(MainConfigurationProperties
parent) {
this.parent = parent;
@@ -283,6 +287,29 @@ public class HttpServerConfigurationProperties implements
BootstrapCloseable {
this.jwtKeystorePassword = jwtKeystorePassword;
}
+ public String getJwtIssuer() {
+ return jwtIssuer;
+ }
+
+ /**
+ * Expected JWT issuer (iss claim) for token validation. When set, tokens
whose issuer does not match are rejected.
+ */
+ public void setJwtIssuer(String jwtIssuer) {
+ this.jwtIssuer = jwtIssuer;
+ }
+
+ public String getJwtAudience() {
+ return jwtAudience;
+ }
+
+ /**
+ * Expected JWT audience (aud claim) for token validation. Multiple values
can be separated by comma. When set,
+ * tokens whose audience does not contain any of the configured values are
rejected.
+ */
+ public void setJwtAudience(String jwtAudience) {
+ this.jwtAudience = jwtAudience;
+ }
+
/**
* Whether embedded HTTP server is enabled. By default, the server is not
enabled.
*/
@@ -434,4 +461,21 @@ public class HttpServerConfigurationProperties implements
BootstrapCloseable {
return this;
}
+ /**
+ * Expected JWT issuer (iss claim) for token validation. When set, tokens
whose issuer does not match are rejected.
+ */
+ public HttpServerConfigurationProperties withJwtIssuer(String jwtIssuer) {
+ this.jwtIssuer = jwtIssuer;
+ return this;
+ }
+
+ /**
+ * Expected JWT audience (aud claim) for token validation. Multiple values
can be separated by comma. When set,
+ * tokens whose audience does not contain any of the configured values are
rejected.
+ */
+ public HttpServerConfigurationProperties withJwtAudience(String
jwtAudience) {
+ this.jwtAudience = jwtAudience;
+ return this;
+ }
+
}
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 506dc1371e00..a2845e96d083 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
@@ -651,6 +651,18 @@ The page titles are likewise disambiguated (`JSON Jackson
2` / `JSON Jackson 3`,
variants now appear in the dataformats navigation. Update any external `xref:`
links that point
at the old filenames; routes referencing the dataformats by `name` are
unaffected.
+=== camel-platform-http-main
+
+Two new optional configuration properties are available on both
`camel.server.*` and `camel.management.*`
+for the embedded HTTP server:
+
+* `jwtIssuer` — when set, validates the `iss` (issuer) claim of incoming JWT
tokens.
+* `jwtAudience` — comma-separated list of accepted audience values; when set,
validates the `aud` (audience)
+ claim. A token is accepted if its `aud` claim matches any configured value.
+
+Both default to unset. When both are unset, JWT validation behaviour is
unchanged (signature plus the
+default `exp` / `nbf` checks).
+
=== Deprecation of camel-ironmq
The component camel-ironmq is deprecated. The official library used has been
unmaintained since 2017