You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by zr...@apache.org on 2018/08/22 10:55:36 UTC

[camel] 02/02: CAMEL-12728: much better TLS/SSL configuration ...

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

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

commit 93cda6ebc3416f0d24359da882ce7bb99dc087d4
Author: Zoran Regvart <zr...@apache.org>
AuthorDate: Wed Aug 22 12:11:51 2018 +0200

    CAMEL-12728: much better TLS/SSL configuration ...
    
    ...in `camel-rest-swagger`
    
    Setting up TLS/SSL settings in `camel-rest-swagger` was limited to the
    delegate component being configured and present in the context. This
    adds support for setting TLS/SSL configuration via Camel's standard
    `SSLContextParameters` and `useGlobalSslContextParameters` flag used in
    many components that deal with TLS/SSL.
    
    In addition to that, this adds a new parameter considered in the
    `RestProducerFactory` SPI: now parameters that need to be applied to the
    delegate component can be specified in the `component` key of the
    parameter Map. Those properties will be only considered if the component
    is not already present in the Camel context. That is, if the
    `CamelContext::getEndpoint` would have the side effect of creating the
    delegate component and adding it to the Camel context. Now that
    component can be customized with properties from the `component`
    parameters Map.
---
 .../apache/camel/component/rest/RestEndpoint.java  |   8 +-
 .../camel/spi/RestProducerFactoryHelper.java       |  84 ++++++++++
 .../camel/component/http4/HttpComponent.java       |   7 +
 .../camel/component/jetty/JettyHttpComponent.java  |   6 +
 .../component/netty4/http/NettyHttpComponent.java  |  10 ++
 .../src/main/docs/rest-swagger-component.adoc      |   4 +-
 .../rest/swagger/RestSwaggerComponent.java         |  30 +++-
 .../rest/swagger/RestSwaggerEndpoint.java          |  30 +++-
 .../camel/component/rest/swagger/HttpsTest.java    | 176 +++++++++++++++++++++
 .../rest/swagger/Jetty94ServerFactory.java         |  75 +++++++++
 .../rest/swagger/RestSwaggerDelegateHttpsTest.java |  41 +++++
 .../rest/swagger/RestSwaggerGlobalHttpsTest.java   |  33 ++++
 .../src/test/resources/localhost.p12               | Bin 0 -> 2428 bytes
 .../camel/component/restlet/RestletComponent.java  |   6 +
 .../component/undertow/UndertowComponent.java      |   6 +
 .../RestSwaggerComponentConfiguration.java         |  27 ++++
 16 files changed, 536 insertions(+), 7 deletions(-)

diff --git a/camel-core/src/main/java/org/apache/camel/component/rest/RestEndpoint.java b/camel-core/src/main/java/org/apache/camel/component/rest/RestEndpoint.java
index 70c6e85..bbbf937 100644
--- a/camel-core/src/main/java/org/apache/camel/component/rest/RestEndpoint.java
+++ b/camel-core/src/main/java/org/apache/camel/component/rest/RestEndpoint.java
@@ -41,6 +41,8 @@ import org.apache.camel.util.ObjectHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static org.apache.camel.spi.RestProducerFactoryHelper.setupComponent;
+
 /**
  * The rest component is used for either hosting REST services (consumer) or calling external REST services (producer).
  */
@@ -301,7 +303,7 @@ public class RestEndpoint extends DefaultEndpoint {
             if (comp instanceof RestProducerFactory) {
                 factory = (RestProducerFactory) comp;
             } else {
-                comp = getCamelContext().getComponent(getComponentName());
+                comp = setupComponent(getComponentName(), getCamelContext(), (Map<String, Object>) parameters.get("component"));
                 if (comp instanceof RestProducerFactory) {
                     factory = (RestProducerFactory) comp;
                 }
@@ -320,7 +322,7 @@ public class RestEndpoint extends DefaultEndpoint {
         // try all components
         if (factory == null) {
             for (String name : getCamelContext().getComponentNames()) {
-                Component comp = getCamelContext().getComponent(name);
+                Component comp = setupComponent(getComponentName(), getCamelContext(), (Map<String, Object>) parameters.get("component"));
                 if (comp instanceof RestProducerFactory) {
                     factory = (RestProducerFactory) comp;
                     cname = name;
@@ -345,7 +347,7 @@ public class RestEndpoint extends DefaultEndpoint {
             RestProducerFactory found = null;
             String foundName = null;
             for (String name : DEFAULT_REST_PRODUCER_COMPONENTS) {
-                Object comp = getCamelContext().getComponent(name, true);
+                Object comp = setupComponent(getComponentName(), getCamelContext(), (Map<String, Object>) parameters.get("component"));
                 if (comp instanceof RestProducerFactory) {
                     if (found == null) {
                         found = (RestProducerFactory) comp;
diff --git a/camel-core/src/main/java/org/apache/camel/spi/RestProducerFactoryHelper.java b/camel-core/src/main/java/org/apache/camel/spi/RestProducerFactoryHelper.java
new file mode 100644
index 0000000..400d687
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/spi/RestProducerFactoryHelper.java
@@ -0,0 +1,84 @@
+/**
+ * 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.spi;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Component;
+import org.apache.camel.util.IntrospectionSupport;
+import org.apache.camel.util.ServiceHelper;
+import org.apache.camel.util.StringHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Helper for creating configured {@link Component}s used by the
+ * {@link RestProducerFactory} contract.
+ * 
+ * When {@link RestProducerFactory} contract is used it could instantiate, start
+ * and register the underlying component. During this process we have no way of
+ * configuring component properties, most notably the SSL properties.
+ */
+public final class RestProducerFactoryHelper {
+
+    private static final Logger LOG = LoggerFactory.getLogger(RestProducerFactoryHelper.class);
+
+    private RestProducerFactoryHelper() {
+        // helper class
+    }
+
+    public static void setupComponentFor(final String url, final CamelContext camelContext,
+        final Map<String, Object> componentProperties) throws Exception {
+        final String scheme = StringHelper.before(url, ":");
+
+        setupComponent(scheme, camelContext, componentProperties);
+    }
+
+    public static Component setupComponent(final String componentName, final CamelContext camelContext,
+        final Map<String, Object> componentProperties) throws Exception {
+        if (componentProperties == null || componentProperties.isEmpty()) {
+            return camelContext.getComponent(componentName);
+        }
+
+        final Component existing = camelContext.getComponent(componentName, false, false);
+        if (existing != null) {
+            if (!componentProperties.isEmpty()) {
+                LOG.warn(
+                    "Found existing `{}` component already present in the Camel context. Not setting component"
+                        + " properties on the existing component. You can either prevent the component creation or"
+                        + " set the given properties on the component. Component properties given: {}",
+                    componentName, componentProperties);
+            }
+
+            return existing;
+        }
+
+        // component was not added to the context we can configure it
+        final Component newlyCreated = camelContext.getComponent(componentName, true, false);
+        // need to make a copy of the component properties as
+        // IntrospectionSupport::setProperties will remove any that are set and
+        // we might be called multiple times
+        final Map<String, Object> copyOfComponentProperties = new HashMap<>(componentProperties);
+        IntrospectionSupport.setProperties(camelContext, camelContext.getTypeConverter(), newlyCreated,
+            copyOfComponentProperties);
+        ServiceHelper.startService(newlyCreated);
+
+        return newlyCreated;
+    }
+}
diff --git a/components/camel-http4/src/main/java/org/apache/camel/component/http4/HttpComponent.java b/components/camel-http4/src/main/java/org/apache/camel/component/http4/HttpComponent.java
index 7444681..a4e243c 100644
--- a/components/camel-http4/src/main/java/org/apache/camel/component/http4/HttpComponent.java
+++ b/components/camel-http4/src/main/java/org/apache/camel/component/http4/HttpComponent.java
@@ -42,6 +42,7 @@ import org.apache.camel.spi.HeaderFilterStrategy;
 import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.RestConfiguration;
 import org.apache.camel.spi.RestProducerFactory;
+import org.apache.camel.spi.RestProducerFactoryHelper;
 import org.apache.camel.util.FileUtil;
 import org.apache.camel.util.IntrospectionSupport;
 import org.apache.camel.util.ObjectHelper;
@@ -453,6 +454,12 @@ public class HttpComponent extends HttpCommonComponent implements RestProducerFa
         if (!query.isEmpty()) {
             url = url + "?" + query;
         }
+
+        // there are cases where we might end up here without component being created beforehand
+        // we need to abide by the component properties specified in the parameters when creating
+        // the component, one such case is when we switch from "http4" to "https4" component name
+        RestProducerFactoryHelper.setupComponentFor(url, camelContext, (Map<String, Object>) parameters.get("component"));
+
         HttpEndpoint endpoint = camelContext.getEndpoint(url, HttpEndpoint.class);
         if (parameters != null && !parameters.isEmpty()) {
             setProperties(camelContext, endpoint, parameters);
diff --git a/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/JettyHttpComponent.java b/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/JettyHttpComponent.java
index d20b1332..47018f2 100644
--- a/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/JettyHttpComponent.java
+++ b/components/camel-jetty-common/src/main/java/org/apache/camel/component/jetty/JettyHttpComponent.java
@@ -60,6 +60,7 @@ import org.apache.camel.spi.RestApiConsumerFactory;
 import org.apache.camel.spi.RestConfiguration;
 import org.apache.camel.spi.RestConsumerFactory;
 import org.apache.camel.spi.RestProducerFactory;
+import org.apache.camel.spi.RestProducerFactoryHelper;
 import org.apache.camel.util.FileUtil;
 import org.apache.camel.util.HostUtils;
 import org.apache.camel.util.IntrospectionSupport;
@@ -1274,6 +1275,11 @@ public abstract class JettyHttpComponent extends HttpCommonComponent implements
             url = url + "?" + query;
         }
 
+        // there are cases where we might end up here without component being created beforehand
+        // we need to abide by the component properties specified in the parameters when creating
+        // the component
+        RestProducerFactoryHelper.setupComponentFor(url, camelContext, (Map<String, Object>) parameters.get("component"));
+
         JettyHttpEndpoint endpoint = camelContext.getEndpoint(url, JettyHttpEndpoint.class);
         if (parameters != null && !parameters.isEmpty()) {
             setProperties(camelContext, endpoint, parameters);
diff --git a/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/NettyHttpComponent.java b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/NettyHttpComponent.java
index bcac251..aa076d8 100644
--- a/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/NettyHttpComponent.java
+++ b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/NettyHttpComponent.java
@@ -38,6 +38,7 @@ import org.apache.camel.spi.RestApiConsumerFactory;
 import org.apache.camel.spi.RestConfiguration;
 import org.apache.camel.spi.RestConsumerFactory;
 import org.apache.camel.spi.RestProducerFactory;
+import org.apache.camel.spi.RestProducerFactoryHelper;
 import org.apache.camel.util.FileUtil;
 import org.apache.camel.util.HostUtils;
 import org.apache.camel.util.IntrospectionSupport;
@@ -445,12 +446,21 @@ public class NettyHttpComponent extends NettyComponent implements HeaderFilterSt
             }
         }
 
+        if (host.startsWith("https:")) {
+            map.put("ssl", true);
+        }
+
         // get the endpoint
         String query = URISupport.createQueryString(map);
         if (!query.isEmpty()) {
             url = url + "?" + query;
         }
 
+        // there are cases where we might end up here without component being created beforehand
+        // we need to abide by the component properties specified in the parameters when creating
+        // the component
+        RestProducerFactoryHelper.setupComponentFor(url, camelContext, (Map<String, Object>) parameters.get("component"));
+
         NettyHttpEndpoint endpoint = camelContext.getEndpoint(url, NettyHttpEndpoint.class);
         if (parameters != null && !parameters.isEmpty()) {
             setProperties(camelContext, endpoint, parameters);
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 75e736b..b5a04e8 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
@@ -84,7 +84,7 @@ in path such as `/api/{version}/users/{id}`.
 ### Options
 
 // component options: START
-The REST Swagger component supports 7 options, which are listed below.
+The REST Swagger component supports 9 options, which are listed below.
 
 
 
@@ -97,6 +97,8 @@ The REST Swagger component supports 7 options, which are listed below.
 | *host* (producer) | Scheme hostname and port to direct the HTTP requests to in the form of https://hostname:port. Can be configured at the endpoint, component or in the correspoding REST configuration in the Camel Context. If you give this component a name (e.g. petstore) that REST configuration is consulted first, rest-swagger next, and global configuration last. If set overrides any value found in the Swagger specification, RestConfiguration. Can be overriden in endpoint configuratio [...]
 | *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. Can be overriden in endpoint configuration. |  | String
 | *specificationUri* (producer) | Path to the Swagger specification file. The scheme, host base path are taken from this specification, but these can be overriden with properties on the component or endpoint level. If not given the component tries to load swagger.json resource. Note that the host defined on the component and endpoint of this Component should contain the scheme, hostname and optionally the port in the URI syntax (i.e. https://api.example.com:8080). Can be overriden in end [...]
+| *sslContextParameters* (security) | Customize TLS parameters used by the component. If not set defaults to the TLS parameters set in the Camel context |  | SSLContextParameters
+| *useGlobalSslContext Parameters* (security) | Enable usage of global SSL context parameters. | false | boolean
 | *resolveProperty Placeholders* (advanced) | Whether the component should resolve property placeholders on itself when starting. Only properties which are of String type can use property placeholders. | true | boolean
 |===
 // component options: END
diff --git a/components/camel-rest-swagger/src/main/java/org/apache/camel/component/rest/swagger/RestSwaggerComponent.java b/components/camel-rest-swagger/src/main/java/org/apache/camel/component/rest/swagger/RestSwaggerComponent.java
index 9442fd2..89a5e1e 100644
--- a/components/camel-rest-swagger/src/main/java/org/apache/camel/component/rest/swagger/RestSwaggerComponent.java
+++ b/components/camel-rest-swagger/src/main/java/org/apache/camel/component/rest/swagger/RestSwaggerComponent.java
@@ -21,9 +21,11 @@ import java.util.Map;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.Endpoint;
+import org.apache.camel.SSLContextParametersAware;
 import org.apache.camel.impl.DefaultComponent;
 import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.RestProducerFactory;
+import org.apache.camel.util.jsse.SSLContextParameters;
 
 import static org.apache.camel.component.rest.swagger.RestSwaggerHelper.isHostParam;
 import static org.apache.camel.component.rest.swagger.RestSwaggerHelper.isMediaRange;
@@ -74,7 +76,7 @@ import static org.apache.camel.util.StringHelper.notEmpty;
  * from(...).to("petstore:getPetById")
  * </pre>
  */
-public final class RestSwaggerComponent extends DefaultComponent {
+public final class RestSwaggerComponent extends DefaultComponent implements SSLContextParametersAware {
     public static final String DEFAULT_BASE_PATH = "/";
 
     static final URI DEFAULT_SPECIFICATION_URI = URI.create(RestSwaggerComponent.DEFAULT_SPECIFICATION_URI_STR);
@@ -123,6 +125,14 @@ public final class RestSwaggerComponent extends DefaultComponent {
         + " configuration.", defaultValue = DEFAULT_SPECIFICATION_URI_STR, label = "producer", required = "false")
     private URI specificationUri;
 
+    @Metadata(description = "Customize TLS parameters used by the component. If not set defaults to the TLS parameters"
+        + " set in the Camel context ", label = "security", required = "false")
+    private SSLContextParameters sslContextParameters;
+
+    @Metadata(description = "Enable usage of global SSL context parameters.", label = "security",
+        defaultValue = "false")
+    private boolean useGlobalSslContextParameters;
+
     public RestSwaggerComponent() {
     }
 
@@ -154,6 +164,15 @@ public final class RestSwaggerComponent extends DefaultComponent {
         return specificationUri;
     }
 
+    public SSLContextParameters getSslContextParameters() {
+        return sslContextParameters;
+    }
+
+    @Override
+    public boolean isUseGlobalSslContextParameters() {
+        return useGlobalSslContextParameters;
+    }
+
     public void setBasePath(final String basePath) {
         this.basePath = notEmpty(basePath, "basePath");
     }
@@ -178,6 +197,15 @@ public final class RestSwaggerComponent extends DefaultComponent {
         this.specificationUri = notNull(specificationUri, "specificationUri");
     }
 
+    public void setSslContextParameters(final SSLContextParameters sslContextParameters) {
+        this.sslContextParameters = sslContextParameters;
+    }
+
+    @Override
+    public void setUseGlobalSslContextParameters(final boolean useGlobalSslContextParameters) {
+        this.useGlobalSslContextParameters = useGlobalSslContextParameters;
+    }
+
     @Override
     protected Endpoint createEndpoint(final String uri, final String remaining, final Map<String, Object> parameters)
         throws Exception {
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 20b3df0..93ff96e 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
@@ -59,6 +59,8 @@ import org.apache.camel.util.ObjectHelper;
 import org.apache.camel.util.ResourceHelper;
 import org.apache.camel.util.StringHelper;
 import org.apache.camel.util.UnsafeUriCharactersEncoder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import static org.apache.camel.component.rest.swagger.RestSwaggerHelper.isHostParam;
 import static org.apache.camel.component.rest.swagger.RestSwaggerHelper.isMediaRange;
@@ -75,6 +77,8 @@ import static org.apache.camel.util.StringHelper.notEmpty;
     syntax = "rest-swagger:specificationUri#operationId", label = "rest,swagger,http", producerOnly = true)
 public final class RestSwaggerEndpoint extends DefaultEndpoint {
 
+    private static final Logger LOG = LoggerFactory.getLogger(RestSwaggerEndpoint.class);
+
     /**
      * Remaining parameters specified in the Endpoint URI.
      */
@@ -329,10 +333,12 @@ public final class RestSwaggerEndpoint extends DefaultEndpoint {
             parameters.put("host", host);
         }
 
+        final RestSwaggerComponent component = component();
+
         // what we consume is what the API defined by Swagger specification
         // produces
         final String determinedConsumes = determineOption(swagger.getProduces(), operation.getProduces(),
-            component().getConsumes(), consumes);
+            component.getConsumes(), consumes);
 
         if (isNotEmpty(determinedConsumes)) {
             parameters.put("consumes", determinedConsumes);
@@ -341,7 +347,7 @@ public final class RestSwaggerEndpoint extends DefaultEndpoint {
         // what we produce is what the API defined by Swagger specification
         // consumes
         final String determinedProducers = determineOption(swagger.getConsumes(), operation.getConsumes(),
-            component().getProduces(), produces);
+            component.getProduces(), produces);
 
         if (isNotEmpty(determinedProducers)) {
             parameters.put("produces", determinedProducers);
@@ -353,6 +359,26 @@ public final class RestSwaggerEndpoint extends DefaultEndpoint {
             parameters.put("queryParameters", queryParameters);
         }
 
+        // pass properties that might be applied if the delegate component is created, i.e. if it's not
+        // present in the Camel Context already
+        final Map<String, Object> componentParameters = new HashMap<>();
+
+        if (component.isUseGlobalSslContextParameters()) {
+            // by default it's false
+            componentParameters.put("useGlobalSslContextParameters", component.isUseGlobalSslContextParameters());
+        }
+        if (component.getSslContextParameters() != null) {
+            componentParameters.put("sslContextParameters", component.getSslContextParameters());
+        }
+
+        if (!componentParameters.isEmpty()) {
+            final Map<Object, Object> nestedParameters = new HashMap<>();
+            nestedParameters.put("component", componentParameters);
+
+            // we're trying to set RestEndpoint.parameters['component']
+            parameters.put("parameters", nestedParameters);
+        }
+
         return parameters;
     }
 
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
new file mode 100644
index 0000000..6bf472d
--- /dev/null
+++ b/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/HttpsTest.java
@@ -0,0 +1,176 @@
+/**
+ * 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.rest.swagger;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URISyntaxException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.security.KeyStore;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Marshaller;
+
+import com.github.tomakehurst.wiremock.common.HttpsSettings;
+import com.github.tomakehurst.wiremock.junit.WireMockRule;
+import com.google.common.io.Resources;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.rest.RestEndpoint;
+import org.apache.camel.converter.jaxb.JaxbDataFormat;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.apache.camel.util.jsse.CipherSuitesParameters;
+import org.apache.camel.util.jsse.SSLContextParameters;
+import org.apache.camel.util.jsse.TrustManagersParameters;
+import org.eclipse.jetty.util.resource.Resource;
+import org.eclipse.jetty.util.security.CertificateUtils;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
+import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
+import static com.github.tomakehurst.wiremock.client.WireMock.get;
+import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
+import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
+
+@RunWith(Parameterized.class)
+public abstract class HttpsTest extends CamelTestSupport {
+
+    @ClassRule
+    public static WireMockRule petstore = new WireMockRule(
+        wireMockConfig().httpServerFactory(new Jetty94ServerFactory()).containerThreads(13).dynamicPort()
+            .dynamicHttpsPort().keystorePath(Resources.getResource("localhost.p12").toString()).keystoreType("PKCS12")
+            .keystorePassword("password"));
+
+    static final Object NO_BODY = null;
+
+    @Parameter
+    public String componentName;
+
+    @Before
+    public void resetWireMock() {
+        petstore.resetRequests();
+    }
+
+    @Test
+    public void shouldBeConfiguredForHttps() throws Exception {
+        final Pet pet = template.requestBodyAndHeader("direct:getPetById", 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();
+
+        final RestSwaggerComponent component = new RestSwaggerComponent();
+        component.setComponentName(componentName);
+        component.setHost("https://localhost:" + petstore.httpsPort());
+
+        camelContext.addComponent("petStore", component);
+
+        return camelContext;
+    }
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                final JAXBContext jaxbContext = JAXBContext.newInstance(Pet.class, Pets.class);
+
+                final JaxbDataFormat jaxb = new JaxbDataFormat(jaxbContext);
+
+                jaxb.setJaxbProviderProperties(Collections.singletonMap(Marshaller.JAXB_FORMATTED_OUTPUT, false));
+
+                from("direct:getPetById").to("petStore:getPetById").unmarshal(jaxb);
+            }
+        };
+    }
+
+    @Parameters(name = "component = {0}")
+    public static Iterable<String> knownProducers() {
+        final List<String> producers = new ArrayList<>(Arrays.asList(RestEndpoint.DEFAULT_REST_PRODUCER_COMPONENTS));
+
+        // we cannot support SSL in the `http` component as it needs to be
+        // configured via static helper method and this influences all users of
+        // the commons-httpclient (all endpoints, component instances)
+        producers.remove("http");
+
+        // `http4` component transforms the endpoint uri from `http4://` to
+        // `https4://` we need to accommodate for that otherwise we'll end up
+        // configuring the wrong component's properties in
+        // RestSwaggerDelegateHttpsTest
+        producers.replaceAll(c -> "http4".equals(c) ? "https4" : c);
+
+        return producers;
+    }
+
+    @BeforeClass
+    public static void setupStubs() throws IOException, URISyntaxException {
+        petstore.stubFor(get(urlEqualTo("/swagger.json")).willReturn(aResponse().withBody(
+            Files.readAllBytes(Paths.get(RestSwaggerGlobalHttpsTest.class.getResource("/swagger.json").toURI())))));
+
+        petstore.stubFor(
+            get(urlEqualTo("/v2/pet/14")).willReturn(aResponse().withStatus(HttpURLConnection.HTTP_OK).withBody(
+                "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><Pet><id>14</id><name>Olafur Eliason Arnalds</name></Pet>")));
+    }
+
+    static SSLContextParameters createHttpsParameters(final CamelContext camelContext) throws Exception {
+        final TrustManagersParameters trustManagerParameters = new TrustManagersParameters();
+        trustManagerParameters.setCamelContext(camelContext);
+        final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("PKIX");
+        final HttpsSettings httpsSettings = petstore.getOptions().httpsSettings();
+        final KeyStore trustStore = CertificateUtils.getKeyStore(Resource.newResource(httpsSettings.keyStorePath()),
+            httpsSettings.keyStoreType(), null, httpsSettings.keyStorePassword());
+        trustManagerFactory.init(trustStore);
+        final TrustManager trustManager = trustManagerFactory.getTrustManagers()[0];
+        trustManagerParameters.setTrustManager(trustManager);
+
+        final SSLContextParameters sslContextParameters = new SSLContextParameters();
+        sslContextParameters.setCamelContext(camelContext);
+        sslContextParameters.setTrustManagers(trustManagerParameters);
+        final CipherSuitesParameters cipherSuites = new CipherSuitesParameters();
+        cipherSuites.setCipherSuite(Collections.singletonList("TLS_RSA_WITH_AES_128_CBC_SHA256"));
+        sslContextParameters.setCipherSuites(cipherSuites);
+        sslContextParameters.setSecureSocketProtocol("TLSv1.2");
+        return sslContextParameters;
+    }
+
+}
diff --git a/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/Jetty94ServerFactory.java b/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/Jetty94ServerFactory.java
new file mode 100644
index 0000000..3791706
--- /dev/null
+++ b/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/Jetty94ServerFactory.java
@@ -0,0 +1,75 @@
+/**
+ * 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.rest.swagger;
+
+import com.github.tomakehurst.wiremock.common.HttpsSettings;
+import com.github.tomakehurst.wiremock.common.JettySettings;
+import com.github.tomakehurst.wiremock.core.Options;
+import com.github.tomakehurst.wiremock.http.AdminRequestHandler;
+import com.github.tomakehurst.wiremock.http.HttpServer;
+import com.github.tomakehurst.wiremock.http.StubRequestHandler;
+import com.github.tomakehurst.wiremock.jetty9.JettyHttpServer;
+import com.github.tomakehurst.wiremock.jetty9.JettyHttpServerFactory;
+
+import org.eclipse.jetty.io.NetworkTrafficListener;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.eclipse.jetty.server.SecureRequestCustomizer;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.SslConnectionFactory;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+
+/**
+ * Wiremock 2.18.0 ships with Jetty 9.2, Camel (currently) uses 9.4 and the
+ * {@link org.eclipse.jetty.util.ssl.SslContextFactory} removed
+ * {@code selectCipherSuites} method.
+ */
+public final class Jetty94ServerFactory extends JettyHttpServerFactory {
+    @Override
+    public HttpServer buildHttpServer(final Options options, final AdminRequestHandler adminRequestHandler,
+        final StubRequestHandler stubRequestHandler) {
+
+        return new JettyHttpServer(options, adminRequestHandler, stubRequestHandler) {
+            @Override
+            protected ServerConnector createHttpsConnector(final String bindAddress, final HttpsSettings httpsSettings,
+                final JettySettings jettySettings, final NetworkTrafficListener listener) {
+                final SslContextFactory sslContextFactory = new SslContextFactory();
+
+                sslContextFactory.setKeyStorePath(httpsSettings.keyStorePath());
+                sslContextFactory.setKeyManagerPassword(httpsSettings.keyStorePassword());
+                sslContextFactory.setKeyStorePassword(httpsSettings.keyStorePassword());
+                sslContextFactory.setKeyStoreType(httpsSettings.keyStoreType());
+                if (httpsSettings.hasTrustStore()) {
+                    sslContextFactory.setTrustStorePath(httpsSettings.trustStorePath());
+                    sslContextFactory.setTrustStorePassword(httpsSettings.trustStorePassword());
+                    sslContextFactory.setTrustStoreType(httpsSettings.trustStoreType());
+                }
+                sslContextFactory.setNeedClientAuth(httpsSettings.needClientAuth());
+                sslContextFactory.setIncludeCipherSuites("TLS_RSA_WITH_AES_128_CBC_SHA256");
+                sslContextFactory.setProtocol("TLSv1.2");
+
+                final HttpConfiguration httpConfig = createHttpConfig(jettySettings);
+                httpConfig.addCustomizer(new SecureRequestCustomizer());
+
+                final int port = httpsSettings.port();
+
+                return createServerConnector(bindAddress, jettySettings, port, listener,
+                    new SslConnectionFactory(sslContextFactory, "http/1.1"), new HttpConnectionFactory(httpConfig));
+            }
+        };
+    }
+}
diff --git a/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/RestSwaggerDelegateHttpsTest.java b/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/RestSwaggerDelegateHttpsTest.java
new file mode 100644
index 0000000..f106177
--- /dev/null
+++ b/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/RestSwaggerDelegateHttpsTest.java
@@ -0,0 +1,41 @@
+/**
+ * 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.rest.swagger;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Component;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.util.IntrospectionSupport;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class RestSwaggerDelegateHttpsTest extends HttpsTest {
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        final CamelContext camelContext = super.createCamelContext();
+
+        final Component delegate = ((DefaultCamelContext) camelContext).getComponentResolver()
+            .resolveComponent(componentName, camelContext);
+        IntrospectionSupport.setProperty(delegate, "sslContextParameters", createHttpsParameters(camelContext));
+        camelContext.addComponent(componentName, delegate);
+
+        return camelContext;
+    }
+
+}
diff --git a/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/RestSwaggerGlobalHttpsTest.java b/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/RestSwaggerGlobalHttpsTest.java
new file mode 100644
index 0000000..b49da74
--- /dev/null
+++ b/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/RestSwaggerGlobalHttpsTest.java
@@ -0,0 +1,33 @@
+/**
+ * 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.rest.swagger;
+
+import org.apache.camel.CamelContext;
+
+public class RestSwaggerGlobalHttpsTest extends HttpsTest {
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        CamelContext camelContext = super.createCamelContext();
+        camelContext.setSSLContextParameters(createHttpsParameters(camelContext));
+
+        RestSwaggerComponent component = camelContext.getComponent("petStore", RestSwaggerComponent.class);
+        component.setUseGlobalSslContextParameters(true);
+
+        return camelContext;
+    }
+}
diff --git a/components/camel-rest-swagger/src/test/resources/localhost.p12 b/components/camel-rest-swagger/src/test/resources/localhost.p12
new file mode 100644
index 0000000..ebcd4c1
Binary files /dev/null and b/components/camel-rest-swagger/src/test/resources/localhost.p12 differ
diff --git a/components/camel-restlet/src/main/java/org/apache/camel/component/restlet/RestletComponent.java b/components/camel-restlet/src/main/java/org/apache/camel/component/restlet/RestletComponent.java
index 15752f9..2609871 100644
--- a/components/camel-restlet/src/main/java/org/apache/camel/component/restlet/RestletComponent.java
+++ b/components/camel-restlet/src/main/java/org/apache/camel/component/restlet/RestletComponent.java
@@ -40,6 +40,7 @@ import org.apache.camel.spi.RestApiConsumerFactory;
 import org.apache.camel.spi.RestConfiguration;
 import org.apache.camel.spi.RestConsumerFactory;
 import org.apache.camel.spi.RestProducerFactory;
+import org.apache.camel.spi.RestProducerFactoryHelper;
 import org.apache.camel.util.FileUtil;
 import org.apache.camel.util.HostUtils;
 import org.apache.camel.util.ObjectHelper;
@@ -863,6 +864,11 @@ public class RestletComponent extends DefaultComponent implements RestConsumerFa
             url += "?restletMethod=" + restletMethod;
         }
 
+        // there are cases where we might end up here without component being created beforehand
+        // we need to abide by the component properties specified in the parameters when creating
+        // the component
+        RestProducerFactoryHelper.setupComponentFor(url, camelContext, (Map<String, Object>) parameters.get("component"));
+
         RestletEndpoint endpoint = camelContext.getEndpoint(url, RestletEndpoint.class);
         if (parameters != null && !parameters.isEmpty()) {
             setProperties(camelContext, endpoint, parameters);
diff --git a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowComponent.java b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowComponent.java
index f2d42ce..62014cd 100644
--- a/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowComponent.java
+++ b/components/camel-undertow/src/main/java/org/apache/camel/component/undertow/UndertowComponent.java
@@ -42,6 +42,7 @@ import org.apache.camel.spi.RestApiConsumerFactory;
 import org.apache.camel.spi.RestConfiguration;
 import org.apache.camel.spi.RestConsumerFactory;
 import org.apache.camel.spi.RestProducerFactory;
+import org.apache.camel.spi.RestProducerFactoryHelper;
 import org.apache.camel.util.FileUtil;
 import org.apache.camel.util.HostUtils;
 import org.apache.camel.util.IntrospectionSupport;
@@ -296,6 +297,11 @@ public class UndertowComponent extends DefaultComponent implements RestConsumerF
             url = url + "?" + query;
         }
 
+        // there are cases where we might end up here without component being created beforehand
+        // we need to abide by the component properties specified in the parameters when creating
+        // the component
+        RestProducerFactoryHelper.setupComponentFor(url, camelContext, (Map<String, Object>) parameters.get("component"));
+
         UndertowEndpoint endpoint = camelContext.getEndpoint(url, UndertowEndpoint.class);
         if (parameters != null && !parameters.isEmpty()) {
             setProperties(camelContext, endpoint, parameters);
diff --git a/platforms/spring-boot/components-starter/camel-rest-swagger-starter/src/main/java/org/apache/camel/component/rest/swagger/springboot/RestSwaggerComponentConfiguration.java b/platforms/spring-boot/components-starter/camel-rest-swagger-starter/src/main/java/org/apache/camel/component/rest/swagger/springboot/RestSwaggerComponentConfiguration.java
index c24681a..08fe84d 100644
--- a/platforms/spring-boot/components-starter/camel-rest-swagger-starter/src/main/java/org/apache/camel/component/rest/swagger/springboot/RestSwaggerComponentConfiguration.java
+++ b/platforms/spring-boot/components-starter/camel-rest-swagger-starter/src/main/java/org/apache/camel/component/rest/swagger/springboot/RestSwaggerComponentConfiguration.java
@@ -87,6 +87,16 @@ public class RestSwaggerComponentConfiguration
      */
     private URI specificationUri;
     /**
+     * Customize TLS parameters used by the component. If not set defaults to
+     * the TLS parameters set in the Camel context. The option is a
+     * org.apache.camel.util.jsse.SSLContextParameters type.
+     */
+    private String sslContextParameters;
+    /**
+     * Enable usage of global SSL context parameters.
+     */
+    private Boolean useGlobalSslContextParameters = false;
+    /**
      * Whether the component should resolve property placeholders on itself when
      * starting. Only properties which are of String type can use property
      * placeholders.
@@ -141,6 +151,23 @@ public class RestSwaggerComponentConfiguration
         this.specificationUri = specificationUri;
     }
 
+    public String getSslContextParameters() {
+        return sslContextParameters;
+    }
+
+    public void setSslContextParameters(String sslContextParameters) {
+        this.sslContextParameters = sslContextParameters;
+    }
+
+    public Boolean getUseGlobalSslContextParameters() {
+        return useGlobalSslContextParameters;
+    }
+
+    public void setUseGlobalSslContextParameters(
+            Boolean useGlobalSslContextParameters) {
+        this.useGlobalSslContextParameters = useGlobalSslContextParameters;
+    }
+
     public Boolean getResolvePropertyPlaceholders() {
         return resolvePropertyPlaceholders;
     }