This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/master by this push: new 376a610 CAMEL-12764: http componponents that use username:password in authority part of urls is now supported in toD EIPs 376a610 is described below commit 376a610918efd1b36bea0a18df0d696d7a1a708b Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Tue Mar 23 15:14:07 2021 +0100 CAMEL-12764: http componponents that use username:password in authority part of urls is now supported in toD EIPs --- .../camel/http/base/HttpSendDynamicAware.java | 23 ++++- .../http/HttpSendDynamicAwareBasicAuthTest.java | 106 +++++++++++++++++++++ .../http/handler/DrinkAuthValidationHandler.java | 39 ++++++++ 3 files changed, 163 insertions(+), 5 deletions(-) diff --git a/components/camel-http-base/src/main/java/org/apache/camel/http/base/HttpSendDynamicAware.java b/components/camel-http-base/src/main/java/org/apache/camel/http/base/HttpSendDynamicAware.java index 8247708..d2bd5e0 100644 --- a/components/camel-http-base/src/main/java/org/apache/camel/http/base/HttpSendDynamicAware.java +++ b/components/camel-http-base/src/main/java/org/apache/camel/http/base/HttpSendDynamicAware.java @@ -55,6 +55,7 @@ public class HttpSendDynamicAware extends SendDynamicAwareSupport { String[] hostAndPath = parseUri(entry); String host = hostAndPath[0]; String path = hostAndPath[1]; + String auth = hostAndPath[2]; if (path != null || !entry.getLenientProperties().isEmpty()) { // the context path can be dynamic or any lenient properties // and therefore build a new static uri without path or lenient options @@ -72,7 +73,13 @@ public class HttpSendDynamicAware extends SendDynamicAwareSupport { } // build static url with the known parameters - String url = getScheme() + ":" + host; + String url; + if (auth != null && auth.indexOf('@') != -1) { + // only use auth if there is a username:password@host + url = getScheme() + ":" + auth; + } else { + url = getScheme() + ":" + host; + } if (!params.isEmpty()) { url += "?" + URISupport.createQueryString(params, false); } @@ -110,6 +117,11 @@ public class HttpSendDynamicAware extends SendDynamicAwareSupport { return postProcessor; } + /** + * Parses the uri into an string array with 3 elements. + * + * 0 = host:port 1 = path 2 = authority + */ public String[] parseUri(DynamicAwareEntry entry) { String u = entry.getUri(); @@ -130,11 +142,12 @@ public class HttpSendDynamicAware extends SendDynamicAwareSupport { u = StringHelper.before(u, "?"); } - // favour using java.net.URI for parsing into host and context-path + // favour using java.net.URI for parsing into host, context-path and authority try { URI parse = new URI(u); String host = parse.getHost(); String path = parse.getPath(); + String authority = parse.getAuthority(); // if the path is just a trailing slash then skip it (eg it must be longer than just the slash itself) if (path != null && path.length() > 1) { int port = parse.getPort(); @@ -152,15 +165,15 @@ public class HttpSendDynamicAware extends SendDynamicAwareSupport { host = scheme + "://" + host; } } - return new String[] { host, path }; + return new String[] { host, path, authority }; } } catch (URISyntaxException e) { // ignore - return new String[] { u, null }; + return new String[] { u, null, null }; } // no context path - return new String[] { u, null }; + return new String[] { u, null, null }; } } diff --git a/components/camel-http/src/test/java/org/apache/camel/component/http/HttpSendDynamicAwareBasicAuthTest.java b/components/camel-http/src/test/java/org/apache/camel/component/http/HttpSendDynamicAwareBasicAuthTest.java new file mode 100644 index 0000000..3a23745 --- /dev/null +++ b/components/camel-http/src/test/java/org/apache/camel/component/http/HttpSendDynamicAwareBasicAuthTest.java @@ -0,0 +1,106 @@ +/* + * 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.http; + +import java.util.Properties; + +import org.apache.camel.CamelContext; +import org.apache.camel.RoutesBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.http.handler.DrinkAuthValidationHandler; +import org.apache.http.impl.bootstrap.HttpServer; +import org.apache.http.impl.bootstrap.ServerBootstrap; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.apache.camel.component.http.HttpMethods.GET; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class HttpSendDynamicAwareBasicAuthTest extends BaseHttpTest { + + private HttpServer localServer; + + @BeforeEach + @Override + public void setUp() throws Exception { + localServer = ServerBootstrap.bootstrap().setHttpProcessor(getBasicHttpProcessor()) + .setConnectionReuseStrategy(getConnectionReuseStrategy()).setResponseFactory(getHttpResponseFactory()) + .setExpectationVerifier(getHttpExpectationVerifier()).setSslContext(getSSLContext()) + .registerHandler("/moes", new DrinkAuthValidationHandler(GET.name(), null, null, "drink")) + .registerHandler("/joes", new DrinkAuthValidationHandler(GET.name(), null, null, "drink")).create(); + + localServer.start(); + + super.setUp(); + } + + @Override + protected CamelContext createCamelContext() throws Exception { + CamelContext context = super.createCamelContext(); + + Properties prop = new Properties(); + prop.put("myUsername", "scott"); + prop.put("myPassword", "tiger"); + context.getPropertiesComponent().setInitialProperties(prop); + + return context; + } + + @AfterEach + @Override + public void tearDown() throws Exception { + super.tearDown(); + + if (localServer != null) { + localServer.stop(); + } + } + + @Override + protected RoutesBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:moes") + .toD("http://{{myUsername}}:{{myPassword}}@localhost:" + localServer.getLocalPort() + + "/moes?authMethod=Basic&authenticationPreemptive=true&throwExceptionOnFailure=false&drink=${header.drink}"); + + from("direct:joes") + .toD("http://localhost:" + localServer.getLocalPort() + + "/joes?authMethod=Basic&authUsername={{myUsername}}&authPassword={{myPassword}}&authenticationPreemptive=true&throwExceptionOnFailure=false&drink=${header.drink}"); + } + }; + } + + @Test + public void testDynamicAware() throws Exception { + String out = fluentTemplate.to("direct:moes").withHeader("drink", "beer").request(String.class); + assertEquals("Drinking beer", out); + + out = fluentTemplate.to("direct:joes").withHeader("drink", "wine").request(String.class); + assertEquals("Drinking wine", out); + + // and there should be two http endpoint as they use different ways to configure username/password + long count = context.getEndpoints().stream().filter(e -> e instanceof HttpEndpoint).count(); + assertEquals(2, count); + + // we only have 2xdirect and 2xhttp + assertEquals(4, context.getEndpointMap().size()); + } + +} diff --git a/components/camel-http/src/test/java/org/apache/camel/component/http/handler/DrinkAuthValidationHandler.java b/components/camel-http/src/test/java/org/apache/camel/component/http/handler/DrinkAuthValidationHandler.java new file mode 100644 index 0000000..590ee5a --- /dev/null +++ b/components/camel-http/src/test/java/org/apache/camel/component/http/handler/DrinkAuthValidationHandler.java @@ -0,0 +1,39 @@ +/* + * 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.http.handler; + +import java.io.IOException; + +import org.apache.http.HttpException; +import org.apache.http.HttpRequest; +import org.apache.http.HttpResponse; +import org.apache.http.protocol.HttpContext; +import org.junit.jupiter.api.Assertions; + +public class DrinkAuthValidationHandler extends DrinkValidationHandler { + + public DrinkAuthValidationHandler(String expectedMethod, String expectedQuery, Object expectedContent, String header) { + super(expectedMethod, expectedQuery, expectedContent, header); + } + + @Override + public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException { + String auth = request.getFirstHeader("Authorization").getValue(); + Assertions.assertTrue(auth.startsWith("Basic")); + super.handle(request, response, context); + } +}