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 0c2aa42 [CAMEL-13213] Cannot use rest-swagger component with swagger.json provided over HTTPS protocol (#3374) 0c2aa42 is described below commit 0c2aa42dcba4a1a02044622bdf474cb51c4e0629 Author: JiriOndrusek <jondr...@redhat.com> AuthorDate: Tue Dec 3 14:10:50 2019 +0100 [CAMEL-13213] Cannot use rest-swagger component with swagger.json provided over HTTPS protocol (#3374) --- components/camel-rest-swagger/pom.xml | 11 ++-- .../src/main/docs/rest-swagger-component.adoc | 3 +- .../rest/swagger/RestSwaggerEndpoint.java | 76 ++++++++++++++++++---- .../camel/component/rest/swagger/HttpsTest.java | 19 +++++- .../rest/swagger/RestSwaggerEndpointTest.java | 4 +- .../karaf/features/src/main/resources/features.xml | 1 + 6 files changed, 91 insertions(+), 23 deletions(-) diff --git a/components/camel-rest-swagger/pom.xml b/components/camel-rest-swagger/pom.xml index f9ea6f5..cd2f0a5 100644 --- a/components/camel-rest-swagger/pom.xml +++ b/components/camel-rest-swagger/pom.xml @@ -71,6 +71,11 @@ </exclusions> </dependency> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-http</artifactId> + </dependency> + <!-- test --> <dependency> <groupId>org.apache.camel</groupId> @@ -123,12 +128,6 @@ <dependency> <groupId>org.apache.camel</groupId> - <artifactId>camel-http</artifactId> - <scope>test</scope> - </dependency> - - <dependency> - <groupId>org.apache.camel</groupId> <artifactId>camel-netty-http</artifactId> <scope>test</scope> </dependency> diff --git a/components/camel-rest-swagger/src/main/docs/rest-swagger-component.adoc b/components/camel-rest-swagger/src/main/docs/rest-swagger-component.adoc index 844d9b6..fddde2a 100644 --- a/components/camel-rest-swagger/src/main/docs/rest-swagger-component.adoc +++ b/components/camel-rest-swagger/src/main/docs/rest-swagger-component.adoc @@ -126,7 +126,7 @@ with the following path and query parameters: |=== -=== Query Parameters (8 parameters): +=== Query Parameters (9 parameters): [width="100%",cols="2,5,^1,2",options="header"] @@ -140,6 +140,7 @@ with the following path and query parameters: | *produces* (producer) | 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 Swagger specification. Overrides all other configuration. | | String | *basicPropertyBinding* (advanced) | Whether the endpoint should use basic property binding (Camel 2.x) or the newer property binding with additional capabilities | false | boolean | *synchronous* (advanced) | Sets whether synchronous processing should be strictly used, or Camel is allowed to use asynchronous processing (if supported). | false | boolean +| *sslContextParameters* (security) | To configure security using SSLContextParameters. | | SSLContextParameters |=== // endpoint options: END // spring-boot-auto-configure options: START diff --git a/components/camel-rest-swagger/src/main/java/org/apache/camel/component/rest/swagger/RestSwaggerEndpoint.java b/components/camel-rest-swagger/src/main/java/org/apache/camel/component/rest/swagger/RestSwaggerEndpoint.java index 8245b28..5e94d11 100644 --- a/components/camel-rest-swagger/src/main/java/org/apache/camel/component/rest/swagger/RestSwaggerEndpoint.java +++ b/components/camel-rest-swagger/src/main/java/org/apache/camel/component/rest/swagger/RestSwaggerEndpoint.java @@ -51,6 +51,9 @@ import org.apache.camel.Endpoint; import org.apache.camel.ExchangePattern; import org.apache.camel.Processor; import org.apache.camel.Producer; +import org.apache.camel.component.http.HttpComponent; +import org.apache.camel.component.http.HttpEndpoint; +import org.apache.camel.component.http.HttpProducer; import org.apache.camel.spi.Metadata; import org.apache.camel.spi.RestConfiguration; import org.apache.camel.spi.UriEndpoint; @@ -58,9 +61,11 @@ import org.apache.camel.spi.UriParam; import org.apache.camel.spi.UriPath; import org.apache.camel.support.DefaultEndpoint; import org.apache.camel.support.ResourceHelper; +import org.apache.camel.support.jsse.SSLContextParameters; import org.apache.camel.util.ObjectHelper; import org.apache.camel.util.StringHelper; import org.apache.camel.util.UnsafeUriCharactersEncoder; +import org.apache.http.client.methods.HttpGet; import static java.util.Optional.ofNullable; import static org.apache.camel.component.rest.swagger.RestSwaggerHelper.isHostParam; @@ -123,6 +128,9 @@ public final class RestSwaggerEndpoint extends DefaultEndpoint { + " any value present in the Swagger specification. Overrides all other configuration.", label = "producer") private String produces; + @UriParam(label = "security", description = "To configure security using SSLContextParameters.") + private SSLContextParameters sslContextParameters; + @UriPath(description = "Path to the Swagger specification file. The scheme, host base path are taken from this" + " specification, but these can be overridden with properties on the component or endpoint level. If not" + " given the component tries to load `swagger.json` resource from the classpath. Note that the `host` defined on the" @@ -165,7 +173,8 @@ public final class RestSwaggerEndpoint extends DefaultEndpoint { @Override public Producer createProducer() throws Exception { final CamelContext camelContext = getCamelContext(); - final Swagger swagger = loadSpecificationFrom(camelContext, specificationUri); + + final Swagger swagger = loadSpecificationFrom(camelContext, specificationUri, resolveSslContextParameters()); final Map<String, Path> paths = swagger.getPaths(); @@ -200,6 +209,16 @@ public final class RestSwaggerEndpoint extends DefaultEndpoint { + "`. Operations defined in the specification are: " + supportedOperations); } + private SSLContextParameters resolveSslContextParameters() { + if (sslContextParameters != null) { + return sslContextParameters; + } + if (component().getSslContextParameters() != null) { + return component().getSslContextParameters(); + } + return component().retrieveGlobalSslContextParameters(); + } + public String getBasePath() { return basePath; } @@ -212,6 +231,10 @@ public final class RestSwaggerEndpoint extends DefaultEndpoint { return consumes; } + public SSLContextParameters getSslContextParameters() { + return sslContextParameters; + } + public String getHost() { return host; } @@ -245,6 +268,10 @@ public final class RestSwaggerEndpoint extends DefaultEndpoint { this.consumes = isMediaRange(consumes, "consumes"); } + public void setSslContextParameters(SSLContextParameters sslContextParameters) { + this.sslContextParameters = sslContextParameters; + } + public void setHost(final String host) { this.host = isHostParam(host); } @@ -592,31 +619,53 @@ public final class RestSwaggerEndpoint extends DefaultEndpoint { * @return the specification * @throws IOException */ - static Swagger loadSpecificationFrom(final CamelContext camelContext, final URI uri) throws IOException { + static Swagger loadSpecificationFrom(final CamelContext camelContext, final URI uri, SSLContextParameters sslContextParameters) throws IOException { final ObjectMapper mapper = Json.mapper(); final SwaggerParser swaggerParser = new SwaggerParser(); final String uriAsString = uri.toString(); - try (InputStream stream = ResourceHelper.resolveMandatoryResourceAsInputStream(camelContext, uriAsString)) { - final JsonNode node = mapper.readTree(stream); + if (sslContextParameters == null) { + try (InputStream stream = ResourceHelper.resolveMandatoryResourceAsInputStream(camelContext, uriAsString)) { + return parseInputStream(swaggerParser, mapper, stream); + } catch (final Exception e) { + return loadSpecificationFallback(swaggerParser, uriAsString, e); + } + } - return swaggerParser.read(node); + HttpComponent httpComponent = new HttpComponent(); + httpComponent.setSslContextParameters(sslContextParameters); + httpComponent.setCamelContext(camelContext); + try (HttpEndpoint e = (HttpEndpoint)httpComponent.createEndpoint(uriAsString); + HttpProducer p = (HttpProducer)e.createProducer(); + InputStream stream = p.getHttpClient().execute(new HttpGet(uri)).getEntity().getContent()) { + + return parseInputStream(swaggerParser, mapper, stream); } catch (final Exception e) { - // try Swaggers loader - final Swagger swagger = swaggerParser.read(uriAsString); + return loadSpecificationFallback(swaggerParser, uriAsString, e); + } + } - if (swagger != null) { - return swagger; - } + static Swagger loadSpecificationFallback(SwaggerParser swaggerParser, String uriAsString, Exception originalException) { + // try Swaggers loader + final Swagger swagger = swaggerParser.read(uriAsString); + + if (swagger != null) { + return swagger; + } - throw new IllegalArgumentException("The given Swagger specification could not be loaded from `" + uri + throw new IllegalArgumentException("The given Swagger specification could not be loaded from `" + uriAsString + "`. Tried loading using Camel's resource resolution and using Swagger's own resource resolution." + " Swagger tends to swallow exceptions while parsing, try specifying Java system property `debugParser`" + " (e.g. `-DdebugParser=true`), the exception that occurred when loading using Camel's resource" - + " loader follows", e); - } + + " loader follows", originalException); + } + + static Swagger parseInputStream(SwaggerParser swaggerParser, ObjectMapper mapper, InputStream stream) throws IOException { + final JsonNode node = mapper.readTree(stream); + + return swaggerParser.read(node); } static String pickBestScheme(final String specificationScheme, final List<Scheme> schemes) { @@ -651,4 +700,5 @@ public final class RestSwaggerEndpoint extends DefaultEndpoint { return expression.toString(); } + } diff --git a/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/HttpsTest.java b/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/HttpsTest.java index 4e53c40..33638a7 100644 --- a/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/HttpsTest.java +++ b/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/HttpsTest.java @@ -94,6 +94,20 @@ public abstract class HttpsTest extends CamelTestSupport { equalTo("application/xml, application/json"))); } + + @Test + public void swaggerJsonOverHttps() throws Exception { + final Pet pet = template.requestBodyAndHeader("direct:httpsJsonGetPetById", NO_BODY, "petId", 14, Pet.class); + + assertNotNull(pet); + + assertEquals(Integer.valueOf(14), pet.id); + assertEquals("Olafur Eliason Arnalds", pet.name); + + petstore.verify(getRequestedFor(urlEqualTo("/v2/pet/14")).withHeader("Accept", + equalTo("application/xml, application/json"))); + } + @Override protected CamelContext createCamelContext() throws Exception { final CamelContext camelContext = super.createCamelContext(); @@ -101,9 +115,10 @@ public abstract class HttpsTest extends CamelTestSupport { final RestSwaggerComponent component = new RestSwaggerComponent(); component.setComponentName(componentName); component.setHost("https://localhost:" + petstore.httpsPort()); + component.setUseGlobalSslContextParameters(true); camelContext.addComponent("petStore", component); - + camelContext.setSSLContextParameters(createHttpsParameters(camelContext)); return camelContext; } @@ -119,6 +134,8 @@ public abstract class HttpsTest extends CamelTestSupport { jaxb.setJaxbProviderProperties(Collections.singletonMap(Marshaller.JAXB_FORMATTED_OUTPUT, false)); from("direct:getPetById").to("petStore:getPetById").unmarshal(jaxb); + + from("direct:httpsJsonGetPetById").to("petStore:https://localhost:" + petstore.httpsPort() + "/swagger.json#getPetById").unmarshal(jaxb); } }; } diff --git a/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/RestSwaggerEndpointTest.java b/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/RestSwaggerEndpointTest.java index 8b4b432..42c3cd6 100644 --- a/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/RestSwaggerEndpointTest.java +++ b/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/RestSwaggerEndpointTest.java @@ -338,7 +338,7 @@ public class RestSwaggerEndpointTest { when(camelContext.getClassResolver()).thenReturn(new DefaultClassResolver()); assertThat( - RestSwaggerEndpoint.loadSpecificationFrom(camelContext, RestSwaggerComponent.DEFAULT_SPECIFICATION_URI)) + RestSwaggerEndpoint.loadSpecificationFrom(camelContext, RestSwaggerComponent.DEFAULT_SPECIFICATION_URI, null)) .isNotNull(); } @@ -363,7 +363,7 @@ public class RestSwaggerEndpointTest { final CamelContext camelContext = mock(CamelContext.class); when(camelContext.getClassResolver()).thenReturn(new DefaultClassResolver()); - RestSwaggerEndpoint.loadSpecificationFrom(camelContext, URI.create("non-existant.json")); + RestSwaggerEndpoint.loadSpecificationFrom(camelContext, URI.create("non-existant.json"), null); } @Test diff --git a/platforms/karaf/features/src/main/resources/features.xml b/platforms/karaf/features/src/main/resources/features.xml index 5b7d2ac..13cb2d4 100644 --- a/platforms/karaf/features/src/main/resources/features.xml +++ b/platforms/karaf/features/src/main/resources/features.xml @@ -2083,6 +2083,7 @@ </feature> --> <feature name='camel-rest-swagger' version='${project.version}' start-level='50'> <feature version='${project.version}'>camel-core</feature> + <feature version='${project.version}'>camel-http</feature> <bundle dependency='true'>mvn:org.yaml/snakeyaml/${snakeyaml-version}</bundle> <bundle dependency='true'>mvn:javax.validation/validation-api/${validation-1-api-version}</bundle> <bundle dependency='true'>mvn:com.fasterxml.jackson.core/jackson-core/${jackson2-version}</bundle>