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 361c2daeaa3 CAMEL-22276: camel-http OAuth2.0 body authentication
(#18757)
361c2daeaa3 is described below
commit 361c2daeaa3129fbc3ca4de7551e5d2bf5d3a92f
Author: Billy <[email protected]>
AuthorDate: Tue Jul 29 15:11:00 2025 +0200
CAMEL-22276: camel-http OAuth2.0 body authentication (#18757)
* CAMEL-22276: camel-http - add new option for OAuth2 body authentication
* CAMEL-22276: camel-http - add http oauth2 tests for new body
authentication
* CAMEL-22276: camel-http run mvn clean install for formatting
---
.../apache/camel/http/common/HttpConfiguration.java | 14 ++++++++++++++
.../apache/camel/component/http/HttpComponent.java | 9 +++++++--
.../camel/component/http/OAuth2ClientConfigurer.java | 15 +++++++++++----
.../component/http/HttpOAuth2AuthenticationTest.java | 16 ++++++++++++++++
.../http/handler/OAuth2TokenRequestHandler.java | 20 ++++++++++++++++++--
5 files changed, 66 insertions(+), 8 deletions(-)
diff --git
a/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpConfiguration.java
b/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpConfiguration.java
index 43838911014..e12a60b74ba 100644
---
a/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpConfiguration.java
+++
b/components/camel-http-common/src/main/java/org/apache/camel/http/common/HttpConfiguration.java
@@ -56,6 +56,9 @@ public class HttpConfiguration implements Serializable {
+
"If you set this parameter to too small value, you
can get 4xx http errors because camel will think that the received token is
still valid, while in reality the token is expired for the Authentication
server.")
private long oauth2CachedTokensExpirationMarginSeconds = 5L;
+ @UriParam(label = "producer,security", defaultValue = "false",
+ description = "Whether to use OAuth2 body authentication.")
+ private boolean oauth2BodyAuthentication;
@Metadata(label = "producer,security", description = "Authentication
domain to use with NTLM")
@Deprecated
private String authDomain;
@@ -346,4 +349,15 @@ public class HttpConfiguration implements Serializable {
public void setOauth2ResourceIndicator(final String
oauth2ResourceIndicator) {
this.oauth2ResourceIndicator = oauth2ResourceIndicator;
}
+
+ public boolean isOauth2BodyAuthentication() {
+ return oauth2BodyAuthentication;
+ }
+
+ /**
+ * Whether to use OAuth2 body authentication.
+ */
+ public void setOauth2BodyAuthentication(boolean oauth2BodyAuthentication) {
+ this.oauth2BodyAuthentication = oauth2BodyAuthentication;
+ }
}
diff --git
a/components/camel-http/src/main/java/org/apache/camel/component/http/HttpComponent.java
b/components/camel-http/src/main/java/org/apache/camel/component/http/HttpComponent.java
index d7e67b64d6a..02b8998f11a 100644
---
a/components/camel-http/src/main/java/org/apache/camel/component/http/HttpComponent.java
+++
b/components/camel-http/src/main/java/org/apache/camel/component/http/HttpComponent.java
@@ -257,7 +257,11 @@ public class HttpComponent extends HttpCommonComponent
implements RestProducerFa
"oauth2CachedTokensExpirationMarginSeconds",
long.class,
configDefaults.getOauth2CachedTokensExpirationMarginSeconds());
-
+ boolean useBodyAuthentication = getParameter(
+ parameters,
+ "oauth2BodyAuthentication",
+ boolean.class,
+ configDefaults.isOauth2BodyAuthentication());
if (clientId != null && clientSecret != null && tokenEndpoint != null)
{
return CompositeHttpConfigurer.combineConfigurers(configurer,
new OAuth2ClientConfigurer(
@@ -268,7 +272,8 @@ public class HttpComponent extends HttpCommonComponent
implements RestProducerFa
scope,
cacheTokens,
cachedTokensDefaultExpirySeconds,
- cachedTokensExpirationMarginSeconds));
+ cachedTokensExpirationMarginSeconds,
+ useBodyAuthentication));
}
return configurer;
}
diff --git
a/components/camel-http/src/main/java/org/apache/camel/component/http/OAuth2ClientConfigurer.java
b/components/camel-http/src/main/java/org/apache/camel/component/http/OAuth2ClientConfigurer.java
index 10270d080ff..e82a6b2c8dd 100644
---
a/components/camel-http/src/main/java/org/apache/camel/component/http/OAuth2ClientConfigurer.java
+++
b/components/camel-http/src/main/java/org/apache/camel/component/http/OAuth2ClientConfigurer.java
@@ -52,12 +52,14 @@ public class OAuth2ClientConfigurer extends ServiceSupport
implements HttpClient
private final Long cachedTokensDefaultExpirySeconds;
private final Long cachedTokensExpirationMarginSeconds;
private final static ConcurrentMap<OAuth2URIAndCredentials, TokenCache>
tokenCache = new ConcurrentHashMap<>();
+ private final boolean useBodyAuthentication;
private final String resourceIndicator;
private HttpClient httpClient;
public OAuth2ClientConfigurer(String clientId, String clientSecret, String
tokenEndpoint, String resourceIndicator,
String scope, boolean cacheTokens,
- long cachedTokensDefaultExpirySeconds, long
cachedTokensExpirationMarginSeconds) {
+ long cachedTokensDefaultExpirySeconds, long
cachedTokensExpirationMarginSeconds,
+ boolean useBodyAuthentication) {
this.clientId = clientId;
this.clientSecret = clientSecret;
this.tokenEndpoint = tokenEndpoint;
@@ -66,6 +68,7 @@ public class OAuth2ClientConfigurer extends ServiceSupport
implements HttpClient
this.cacheTokens = cacheTokens;
this.cachedTokensDefaultExpirySeconds =
cachedTokensDefaultExpirySeconds;
this.cachedTokensExpirationMarginSeconds =
cachedTokensExpirationMarginSeconds;
+ this.useBodyAuthentication = useBodyAuthentication;
}
@Override
@@ -106,9 +109,13 @@ public class OAuth2ClientConfigurer extends ServiceSupport
implements HttpClient
}
final HttpPost httpPost = new HttpPost(tokenEndpoint);
-
- httpPost.addHeader(HttpHeaders.AUTHORIZATION,
- HttpCredentialsHelper.generateBasicAuthHeader(clientId,
clientSecret));
+ if (useBodyAuthentication) {
+ bodyStr += "&client_id=" + clientId;
+ bodyStr += "&client_secret=" + clientSecret;
+ } else {
+ httpPost.addHeader(HttpHeaders.AUTHORIZATION,
+ HttpCredentialsHelper.generateBasicAuthHeader(clientId,
clientSecret));
+ }
if (null != resourceIndicator) {
bodyStr = String.join(bodyStr, "&resource=" + resourceIndicator);
}
diff --git
a/components/camel-http/src/test/java/org/apache/camel/component/http/HttpOAuth2AuthenticationTest.java
b/components/camel-http/src/test/java/org/apache/camel/component/http/HttpOAuth2AuthenticationTest.java
index 223b53457b1..fb29678eed2 100644
---
a/components/camel-http/src/test/java/org/apache/camel/component/http/HttpOAuth2AuthenticationTest.java
+++
b/components/camel-http/src/test/java/org/apache/camel/component/http/HttpOAuth2AuthenticationTest.java
@@ -98,6 +98,22 @@ public class HttpOAuth2AuthenticationTest extends
BaseHttpTest {
}
+ @Test
+ public void bodyAuthenticationIsPresent() {
+ String tokenEndpoint = "http://localhost:" +
localServer.getLocalPort() + "/token";
+
+ Exchange exchange
+ = template.request("http://localhost:" +
localServer.getLocalPort() + "/post?httpMethod=POST&oauth2ClientId="
+ + clientId + "&oauth2ClientSecret=" +
clientSecret + "&oauth2TokenEndpoint=" + tokenEndpoint
+ +
+ "&oauth2BodyAuthentication=true",
+ exchange1 -> {
+ });
+
+ assertExchange(exchange);
+
+ }
+
protected void assertHeaders(Map<String, Object> headers) {
assertEquals(HttpStatus.SC_OK,
headers.get(Exchange.HTTP_RESPONSE_CODE));
}
diff --git
a/components/camel-http/src/test/java/org/apache/camel/component/http/handler/OAuth2TokenRequestHandler.java
b/components/camel-http/src/test/java/org/apache/camel/component/http/handler/OAuth2TokenRequestHandler.java
index cb649223f79..6d2ae6b606b 100644
---
a/components/camel-http/src/test/java/org/apache/camel/component/http/handler/OAuth2TokenRequestHandler.java
+++
b/components/camel-http/src/test/java/org/apache/camel/component/http/handler/OAuth2TokenRequestHandler.java
@@ -28,6 +28,7 @@ import org.apache.hc.core5.http.ClassicHttpResponse;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.HttpException;
import org.apache.hc.core5.http.HttpHeaders;
+import org.apache.hc.core5.http.ProtocolException;
import org.apache.hc.core5.http.io.HttpRequestHandler;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.io.entity.StringEntity;
@@ -54,8 +55,12 @@ public class OAuth2TokenRequestHandler implements
HttpRequestHandler {
.filter(pair -> pair.getName().equals("grant_type") &&
pair.getValue().equals("client_credentials"))
.findAny().orElseThrow(() -> new HttpException("Invalid or
missing grant_type"));
- if (request.getHeader(HttpHeaders.AUTHORIZATION) == null ||
!request.getHeader(HttpHeaders.AUTHORIZATION).getValue()
-
.equals(HttpCredentialsHelper.generateBasicAuthHeader(clientId, clientSecret)))
+ Map<String, String> bodyCredentials = new HashMap<>();
+ WWWFormCodec.parse(requestBody, StandardCharsets.UTF_8).stream()
+ .filter(pair -> pair.getName().equals("client_id") ||
pair.getName().equals("client_secret"))
+ .forEach(pair -> bodyCredentials.put(pair.getName(),
pair.getValue()));
+
+ if (!hasValidHeaderAuthentication(request) &&
!hasValidBodyAuthentication(bodyCredentials))
throw new HttpException("Invalid credentials");
Map<String, String> responseEntity = new HashMap<>();
@@ -64,4 +69,15 @@ public class OAuth2TokenRequestHandler implements
HttpRequestHandler {
response.setEntity(new StringEntity(Jsoner.serialize(responseEntity),
ContentType.APPLICATION_JSON));
}
+ private boolean hasValidHeaderAuthentication(ClassicHttpRequest request)
throws ProtocolException {
+ return request.containsHeader(HttpHeaders.AUTHORIZATION) &&
request.getHeader(HttpHeaders.AUTHORIZATION).getValue()
+
.equals(HttpCredentialsHelper.generateBasicAuthHeader(clientId, clientSecret));
+ }
+
+ private boolean hasValidBodyAuthentication(Map<String, String>
credentials) {
+ if (null == credentials || credentials.isEmpty())
+ return false;
+ return clientId.equals(credentials.get("client_id")) &&
clientSecret.equals(credentials.get("client_secret"));
+ }
+
}