diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTChannelInitializer.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTChannelInitializer.java index 8749a62e5..6500e2850 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTChannelInitializer.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTChannelInitializer.java @@ -22,7 +22,6 @@ import io.netty.handler.codec.http.HttpServerCodec; import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; import io.netty.handler.codec.mqtt.MqttDecoder; -import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslHandler; import io.netty.handler.timeout.IdleStateHandler; import io.streamnative.pulsar.handlers.mqtt.adapter.CombineAdapterHandler; @@ -30,13 +29,16 @@ import io.streamnative.pulsar.handlers.mqtt.adapter.MqttAdapterEncoder; import io.streamnative.pulsar.handlers.mqtt.codec.MqttWebSocketCodec; import io.streamnative.pulsar.handlers.mqtt.support.psk.PSKUtils; -import org.apache.pulsar.common.util.NettyServerSslContextBuilder; -import org.apache.pulsar.common.util.SslContextAutoRefreshBuilder; -import org.apache.pulsar.common.util.keystoretls.NettySSLContextAutoRefreshBuilder; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import lombok.extern.slf4j.Slf4j; +import org.apache.pulsar.common.util.PulsarSslConfiguration; +import org.apache.pulsar.common.util.PulsarSslFactory; /** * A channel initializer that initialize channels for MQTT protocol. */ +@Slf4j public class MQTTChannelInitializer extends ChannelInitializer { private final MQTTServerConfiguration mqttConfig; @@ -44,49 +46,32 @@ public class MQTTChannelInitializer extends ChannelInitializer { private final boolean enableTls; private final boolean enableTlsPsk; private final boolean enableWs; - private final boolean tlsEnabledWithKeyStore; + private PulsarSslFactory sslFactory; - private SslContextAutoRefreshBuilder sslCtxRefresher; - private NettySSLContextAutoRefreshBuilder nettySSLContextAutoRefreshBuilder; - - public MQTTChannelInitializer(MQTTService mqttService, boolean enableTls, boolean enableWs) { - this(mqttService, enableTls, false, enableWs); + public MQTTChannelInitializer(MQTTService mqttService, boolean enableTls, boolean enableWs, + ScheduledExecutorService sslContextRefresher) throws Exception { + this(mqttService, enableTls, false, enableWs, sslContextRefresher); } - public MQTTChannelInitializer(MQTTService mqttService, boolean enableTls, boolean enableTlsPsk, boolean enableWs) { + public MQTTChannelInitializer( + MQTTService mqttService, boolean enableTls, boolean enableTlsPsk, boolean enableWs, + ScheduledExecutorService sslContextRefresher) throws Exception { super(); this.mqttService = mqttService; this.mqttConfig = mqttService.getServerConfiguration(); this.enableTls = enableTls; this.enableTlsPsk = enableTlsPsk; this.enableWs = enableWs; - this.tlsEnabledWithKeyStore = mqttConfig.isMqttTlsEnabledWithKeyStore(); if (this.enableTls) { - if (tlsEnabledWithKeyStore) { - nettySSLContextAutoRefreshBuilder = new NettySSLContextAutoRefreshBuilder( - mqttConfig.getMqttTlsProvider(), - mqttConfig.getMqttTlsKeyStoreType(), - mqttConfig.getMqttTlsKeyStore(), - mqttConfig.getMqttTlsKeyStorePassword(), - mqttConfig.isMqttTlsAllowInsecureConnection(), - mqttConfig.getMqttTlsTrustStoreType(), - mqttConfig.getMqttTlsTrustStore(), - mqttConfig.getMqttTlsTrustStorePassword(), - mqttConfig.isMqttTlsRequireTrustedClientCertOnConnect(), - mqttConfig.getMqttTlsCiphers(), - mqttConfig.getMqttTlsProtocols(), - mqttConfig.getMqttTlsCertRefreshCheckDurationSec()); - } else { - sslCtxRefresher = new NettyServerSslContextBuilder( - null, - mqttConfig.isMqttTlsAllowInsecureConnection(), - mqttConfig.getMqttTlsTrustCertsFilePath(), - mqttConfig.getMqttTlsCertificateFilePath(), - mqttConfig.getMqttTlsKeyFilePath(), - mqttConfig.getMqttTlsCiphers(), - mqttConfig.getMqttTlsProtocols(), - mqttConfig.isMqttTlsRequireTrustedClientCertOnConnect(), - mqttConfig.getMqttTlsCertRefreshCheckDurationSec()); + PulsarSslConfiguration sslConfiguration = buildSslConfiguration(mqttConfig); + this.sslFactory = (PulsarSslFactory) Class.forName(mqttConfig.getSslFactoryPlugin()) + .getConstructor().newInstance(); + this.sslFactory.initialize(sslConfiguration); + this.sslFactory.createInternalSslContext(); + if (mqttConfig.getTlsCertRefreshCheckDurationSec() > 0) { + sslContextRefresher.scheduleWithFixedDelay(this::refreshSslContext, + mqttConfig.getTlsCertRefreshCheckDurationSec(), + mqttConfig.getTlsCertRefreshCheckDurationSec(), TimeUnit.SECONDS); } } } @@ -95,12 +80,7 @@ public MQTTChannelInitializer(MQTTService mqttService, boolean enableTls, boolea public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addFirst("idleStateHandler", new IdleStateHandler(0, 0, 120)); if (this.enableTls) { - if (this.tlsEnabledWithKeyStore) { - ch.pipeline().addLast(TLS_HANDLER, - new SslHandler(nettySSLContextAutoRefreshBuilder.get().createSSLEngine())); - } else { - ch.pipeline().addLast(TLS_HANDLER, sslCtxRefresher.get().newHandler(ch.alloc())); - } + ch.pipeline().addLast(TLS_HANDLER, new SslHandler(sslFactory.createServerSslEngine(ch.alloc()))); } else if (this.enableTlsPsk) { ch.pipeline().addLast(TLS_HANDLER, new SslHandler(PSKUtils.createServerEngine(ch, mqttService.getPskConfiguration()))); @@ -138,4 +118,36 @@ private void addWsHandler(ChannelPipeline pipeline) { true, mqttConfig.getWebSocketMaxFrameSize())); pipeline.addLast(Constants.HANDLER_MQTT_WEB_SOCKET_CODEC, new MqttWebSocketCodec()); } + + protected PulsarSslConfiguration buildSslConfiguration(MQTTServerConfiguration config) { + return PulsarSslConfiguration.builder() + .tlsProvider(config.getMqttTlsProvider()) + .tlsKeyStoreType(config.getMqttTlsKeyStoreType()) + .tlsKeyStorePath(config.getMqttTlsKeyStore()) + .tlsKeyStorePassword(config.getMqttTlsKeyStorePassword()) + .tlsTrustStoreType(config.getMqttTlsTrustStoreType()) + .tlsTrustStorePath(config.getMqttTlsTrustStore()) + .tlsTrustStorePassword(config.getMqttTlsTrustStorePassword()) + .tlsCiphers(config.getMqttTlsCiphers()) + .tlsProtocols(config.getMqttTlsProtocols()) + .tlsTrustCertsFilePath(config.getMqttTlsTrustCertsFilePath()) + .tlsCertificateFilePath(config.getMqttTlsCertificateFilePath()) + .tlsKeyFilePath(config.getMqttTlsKeyFilePath()) + .allowInsecureConnection(config.isMqttTlsAllowInsecureConnection()) + .requireTrustedClientCertOnConnect(config.isMqttTlsRequireTrustedClientCertOnConnect()) + .tlsEnabledWithKeystore(config.isMqttTlsEnabledWithKeyStore()) + .tlsCustomParams(config.getSslFactoryPluginParams()) + .authData(null) + .serverMode(true) + .build(); + } + + protected void refreshSslContext() { + try { + this.sslFactory.update(); + } catch (Exception e) { + log.error("Failed to refresh SSL context for mqtt channel.", e); + } + } + } diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTProtocolHandler.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTProtocolHandler.java index a98f9a3fd..39c51db50 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTProtocolHandler.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/MQTTProtocolHandler.java @@ -25,17 +25,21 @@ import com.google.common.collect.ImmutableMap; import io.netty.channel.ChannelInitializer; import io.netty.channel.socket.SocketChannel; +import io.netty.util.concurrent.DefaultThreadFactory; import io.streamnative.pulsar.handlers.mqtt.proxy.MQTTProxyConfiguration; import io.streamnative.pulsar.handlers.mqtt.proxy.MQTTProxyService; import io.streamnative.pulsar.handlers.mqtt.utils.ConfigurationUtils; import java.net.InetSocketAddress; import java.util.Map; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.apache.pulsar.broker.ServiceConfiguration; import org.apache.pulsar.broker.ServiceConfigurationUtils; import org.apache.pulsar.broker.protocol.ProtocolHandler; import org.apache.pulsar.broker.service.BrokerService; + /** * MQTT Protocol Handler load and run by Pulsar Service. */ @@ -56,6 +60,8 @@ public class MQTTProtocolHandler implements ProtocolHandler { @Getter private MQTTService mqttService; + private ScheduledExecutorService sslContextRefresher; + @Override public String protocolName() { return PROTOCOL_NAME; @@ -112,6 +118,9 @@ public Map> newChannelIniti checkArgument(mqttConfig.getMqttListeners() != null); checkArgument(brokerService != null); + this.sslContextRefresher = Executors.newSingleThreadScheduledExecutor( + new DefaultThreadFactory("mop-ssl-context-refresher")); + String listeners = mqttConfig.getMqttListeners(); String[] parts = listeners.split(LISTENER_DEL); try { @@ -122,27 +131,28 @@ public Map> newChannelIniti if (listener.startsWith(PLAINTEXT_PREFIX)) { builder.put( new InetSocketAddress(brokerService.pulsar().getBindAddress(), getListenerPort(listener)), - new MQTTChannelInitializer(mqttService, false, false)); + new MQTTChannelInitializer(mqttService, false, false, sslContextRefresher)); } else if (listener.startsWith(SSL_PREFIX)) { builder.put( new InetSocketAddress(brokerService.pulsar().getBindAddress(), getListenerPort(listener)), - new MQTTChannelInitializer(mqttService, true, false)); + new MQTTChannelInitializer(mqttService, true, false, sslContextRefresher)); } else if (listener.startsWith(SSL_PSK_PREFIX) && mqttConfig.isMqttTlsPskEnabled()) { builder.put( new InetSocketAddress(brokerService.pulsar().getBindAddress(), getListenerPort(listener)), - new MQTTChannelInitializer(mqttService, false, true, false)); + new MQTTChannelInitializer( + mqttService, false, true, false, sslContextRefresher)); } else if (listener.startsWith(WS_PLAINTEXT_PREFIX)) { builder.put( new InetSocketAddress(brokerService.pulsar().getBindAddress(), getListenerPort(listener)), - new MQTTChannelInitializer(mqttService, false, true)); + new MQTTChannelInitializer(mqttService, false, true, sslContextRefresher)); } else if (listener.startsWith(WS_SSL_PREFIX)) { builder.put( new InetSocketAddress(brokerService.pulsar().getBindAddress(), getListenerPort(listener)), - new MQTTChannelInitializer(mqttService, true, true)); + new MQTTChannelInitializer(mqttService, true, true, sslContextRefresher)); } else { log.error("MQTT listener {} not supported. supports {}, {} or {}", @@ -159,6 +169,9 @@ public Map> newChannelIniti @Override public void close() { + if (sslContextRefresher != null) { + sslContextRefresher.shutdownNow(); + } if (proxyService != null) { proxyService.close(); } diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyChannelInitializer.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyChannelInitializer.java index 8753d3bbb..73d3ad2c6 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyChannelInitializer.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyChannelInitializer.java @@ -17,21 +17,23 @@ import io.netty.channel.ChannelInitializer; import io.netty.channel.socket.SocketChannel; import io.netty.handler.codec.mqtt.MqttDecoder; -import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslHandler; import io.netty.handler.timeout.IdleStateHandler; import io.streamnative.pulsar.handlers.mqtt.adapter.CombineAdapterHandler; import io.streamnative.pulsar.handlers.mqtt.adapter.MqttAdapterDecoder; import io.streamnative.pulsar.handlers.mqtt.adapter.MqttAdapterEncoder; import io.streamnative.pulsar.handlers.mqtt.support.psk.PSKUtils; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import lombok.Getter; -import org.apache.pulsar.common.util.NettyServerSslContextBuilder; -import org.apache.pulsar.common.util.SslContextAutoRefreshBuilder; -import org.apache.pulsar.common.util.keystoretls.NettySSLContextAutoRefreshBuilder; +import lombok.extern.slf4j.Slf4j; +import org.apache.pulsar.common.util.PulsarSslConfiguration; +import org.apache.pulsar.common.util.PulsarSslFactory; /** * Proxy service channel initializer. */ +@Slf4j public class MQTTProxyChannelInitializer extends ChannelInitializer { private final MQTTProxyService proxyService; @@ -40,50 +42,37 @@ public class MQTTProxyChannelInitializer extends ChannelInitializer serverSslCtxRefresher; - private NettySSLContextAutoRefreshBuilder serverSSLContextAutoRefreshBuilder; + private PulsarSslFactory sslFactory; public MQTTProxyChannelInitializer(MQTTProxyService proxyService, MQTTProxyConfiguration proxyConfig, - boolean enableTls) { - this(proxyService, proxyConfig, enableTls, false); + boolean enableTls, + ScheduledExecutorService sslContextRefresher) throws MQTTProxyException { + this(proxyService, proxyConfig, enableTls, false, sslContextRefresher); } public MQTTProxyChannelInitializer(MQTTProxyService proxyService, MQTTProxyConfiguration proxyConfig, - boolean enableTls, boolean enableTlsPsk) { - this.proxyService = proxyService; - this.proxyConfig = proxyConfig; - this.enableTls = enableTls; - this.enableTlsPsk = enableTlsPsk; - this.tlsEnabledWithKeyStore = proxyConfig.isMqttTlsEnabledWithKeyStore(); - if (this.enableTls) { - if (tlsEnabledWithKeyStore) { - serverSSLContextAutoRefreshBuilder = new NettySSLContextAutoRefreshBuilder( - proxyConfig.getMqttTlsProvider(), - proxyConfig.getMqttTlsKeyStoreType(), - proxyConfig.getMqttTlsKeyStore(), - proxyConfig.getMqttTlsKeyStorePassword(), - proxyConfig.isMqttTlsAllowInsecureConnection(), - proxyConfig.getMqttTlsTrustStoreType(), - proxyConfig.getMqttTlsTrustStore(), - proxyConfig.getMqttTlsTrustStorePassword(), - proxyConfig.isMqttTlsRequireTrustedClientCertOnConnect(), - proxyConfig.getMqttTlsCiphers(), - proxyConfig.getMqttTlsProtocols(), - proxyConfig.getMqttTlsCertRefreshCheckDurationSec()); - } else { - serverSslCtxRefresher = new NettyServerSslContextBuilder( - null, - proxyConfig.isMqttTlsAllowInsecureConnection(), - proxyConfig.getMqttTlsTrustCertsFilePath(), - proxyConfig.getMqttTlsCertificateFilePath(), - proxyConfig.getMqttTlsKeyFilePath(), - proxyConfig.getMqttTlsCiphers(), - proxyConfig.getMqttTlsProtocols(), - proxyConfig.isMqttTlsRequireTrustedClientCertOnConnect(), - proxyConfig.getMqttTlsCertRefreshCheckDurationSec()); + boolean enableTls, boolean enableTlsPsk, + ScheduledExecutorService sslContextRefresher) throws MQTTProxyException { + try { + this.proxyService = proxyService; + this.proxyConfig = proxyConfig; + this.enableTls = enableTls; + this.enableTlsPsk = enableTlsPsk; + if (this.enableTls) { + PulsarSslConfiguration sslConfiguration = buildSslConfiguration(proxyConfig); + this.sslFactory = (PulsarSslFactory) Class.forName(proxyConfig.getSslFactoryPlugin()) + .getConstructor().newInstance(); + this.sslFactory.initialize(sslConfiguration); + this.sslFactory.createInternalSslContext(); + if (proxyConfig.getTlsCertRefreshCheckDurationSec() > 0) { + sslContextRefresher.scheduleWithFixedDelay(this::refreshSslContext, + proxyConfig.getTlsCertRefreshCheckDurationSec(), + proxyConfig.getTlsCertRefreshCheckDurationSec(), TimeUnit.SECONDS); + + } } + } catch (Exception e) { + throw new MQTTProxyException(e); } } @@ -91,15 +80,7 @@ public MQTTProxyChannelInitializer(MQTTProxyService proxyService, MQTTProxyConfi protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addFirst("idleStateHandler", new IdleStateHandler(30, 0, 0)); if (this.enableTls) { - if (serverSslCtxRefresher != null) { - SslContext sslContext = serverSslCtxRefresher.get(); - if (sslContext != null) { - ch.pipeline().addLast(TLS_HANDLER, sslContext.newHandler(ch.alloc())); - } - } else if (this.tlsEnabledWithKeyStore && serverSSLContextAutoRefreshBuilder != null) { - ch.pipeline().addLast(TLS_HANDLER, - new SslHandler(serverSSLContextAutoRefreshBuilder.get().createSSLEngine())); - } + ch.pipeline().addLast(TLS_HANDLER, new SslHandler(sslFactory.createServerSslEngine(ch.alloc()))); } else if (this.enableTlsPsk) { ch.pipeline().addLast(TLS_HANDLER, new SslHandler(PSKUtils.createServerEngine(ch, proxyService.getPskConfiguration()))); @@ -113,4 +94,35 @@ protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast("handler", new MQTTProxyInboundHandler(proxyService)); } + protected PulsarSslConfiguration buildSslConfiguration(MQTTProxyConfiguration config) { + return PulsarSslConfiguration.builder() + .tlsProvider(config.getMqttTlsProvider()) + .tlsKeyStoreType(config.getMqttTlsKeyStoreType()) + .tlsKeyStorePath(config.getMqttTlsKeyStore()) + .tlsKeyStorePassword(config.getMqttTlsKeyStorePassword()) + .tlsTrustStoreType(config.getMqttTlsTrustStoreType()) + .tlsTrustStorePath(config.getMqttTlsTrustStore()) + .tlsTrustStorePassword(config.getMqttTlsTrustStorePassword()) + .tlsCiphers(config.getMqttTlsCiphers()) + .tlsProtocols(config.getMqttTlsProtocols()) + .tlsTrustCertsFilePath(config.getMqttTlsTrustCertsFilePath()) + .tlsCertificateFilePath(config.getMqttTlsCertificateFilePath()) + .tlsKeyFilePath(config.getMqttTlsKeyFilePath()) + .allowInsecureConnection(config.isMqttTlsAllowInsecureConnection()) + .requireTrustedClientCertOnConnect(config.isMqttTlsRequireTrustedClientCertOnConnect()) + .tlsEnabledWithKeystore(config.isMqttTlsEnabledWithKeyStore()) + .tlsCustomParams(config.getSslFactoryPluginParams()) + .authData(null) + .serverMode(true) + .build(); + } + + protected void refreshSslContext() { + try { + this.sslFactory.update(); + } catch (Exception e) { + log.error("Failed to refresh SSL context for mqtt proxy channel.", e); + } + } + } diff --git a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyService.java b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyService.java index 1c8f9bef0..bc17954ab 100644 --- a/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyService.java +++ b/mqtt-impl/src/main/java/io/streamnative/pulsar/handlers/mqtt/proxy/MQTTProxyService.java @@ -30,6 +30,8 @@ import io.streamnative.pulsar.handlers.mqtt.support.systemtopic.SystemEventService; import io.streamnative.pulsar.handlers.mqtt.support.systemtopic.SystemTopicBasedSystemEventService; import java.io.Closeable; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.apache.pulsar.broker.PulsarService; @@ -68,6 +70,7 @@ public class MQTTProxyService implements Closeable { private DefaultThreadFactory acceptorThreadFactory = new DefaultThreadFactory("mqtt-redirect-acceptor"); private DefaultThreadFactory workerThreadFactory = new DefaultThreadFactory("mqtt-redirect-io"); + private ScheduledExecutorService sslContextRefresher; public MQTTProxyService(MQTTService mqttService, MQTTProxyConfiguration proxyConfig) { configValid(proxyConfig); @@ -89,6 +92,8 @@ public MQTTProxyService(MQTTService mqttService, MQTTProxyConfiguration proxyCon this.eventCenter = new PulsarEventCenterImpl(mqttService.getBrokerService(), proxyConfig.getEventCenterCallbackPoolThreadNum()); this.proxyAdapter = new MQTTProxyAdapter(this); + this.sslContextRefresher = Executors.newSingleThreadScheduledExecutor( + new DefaultThreadFactory("mop-proxy-ssl-context-refresher")); } private void configValid(MQTTProxyConfiguration proxyConfig) { @@ -102,7 +107,8 @@ public void start() throws MQTTProxyException { serverBootstrap.group(acceptorGroup, workerGroup); serverBootstrap.channel(EventLoopUtil.getServerSocketChannelClass(workerGroup)); EventLoopUtil.enableTriggeredMode(serverBootstrap); - serverBootstrap.childHandler(new MQTTProxyChannelInitializer(this, proxyConfig, false)); + serverBootstrap.childHandler(new MQTTProxyChannelInitializer( + this, proxyConfig, false, sslContextRefresher)); try { listenChannel = serverBootstrap.bind(proxyConfig.getMqttProxyPort()).sync().channel(); @@ -113,7 +119,8 @@ public void start() throws MQTTProxyException { if (proxyConfig.isMqttProxyTlsEnabled()) { ServerBootstrap tlsBootstrap = serverBootstrap.clone(); - tlsBootstrap.childHandler(new MQTTProxyChannelInitializer(this, proxyConfig, true)); + tlsBootstrap.childHandler(new MQTTProxyChannelInitializer( + this, proxyConfig, true, sslContextRefresher)); try { listenChannelTls = tlsBootstrap.bind(proxyConfig.getMqttProxyTlsPort()).sync().channel(); log.info("Started MQTT Proxy with TLS on {}", listenChannelTls.localAddress()); @@ -132,7 +139,8 @@ public void start() throws MQTTProxyException { this.eventService.addListener(pskConfiguration.getEventListener()); // Add channel initializer ServerBootstrap tlsPskBootstrap = serverBootstrap.clone(); - tlsPskBootstrap.childHandler(new MQTTProxyChannelInitializer(this, proxyConfig, false, true)); + tlsPskBootstrap.childHandler(new MQTTProxyChannelInitializer( + this, proxyConfig, false, true, sslContextRefresher)); try { listenChannelTlsPsk = tlsPskBootstrap.bind(proxyConfig.getMqttProxyTlsPskPort()).sync().channel(); log.info("Started MQTT Proxy with TLS-PSK on {}", listenChannelTlsPsk.localAddress()); @@ -164,5 +172,8 @@ public void close() { } this.proxyAdapter.shutdown(); this.connectionManager.close(); + if (sslContextRefresher != null) { + sslContextRefresher.shutdownNow(); + } } } diff --git a/pom.xml b/pom.xml index 7566b4657..fa3a580bd 100644 --- a/pom.xml +++ b/pom.xml @@ -49,7 +49,7 @@ 2.22.0 6.14.3 4.0.2 - 3.4.0-SNAPSHOT + 4.0.0-SNAPSHOT 4.1.94.Final 2.18.0 1.16 diff --git a/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/base/MQTTProtocolHandlerTestBase.java b/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/base/MQTTProtocolHandlerTestBase.java index 429285eb3..8816a58df 100644 --- a/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/base/MQTTProtocolHandlerTestBase.java +++ b/tests/src/test/java/io/streamnative/pulsar/handlers/mqtt/base/MQTTProtocolHandlerTestBase.java @@ -389,6 +389,7 @@ protected void startBroker(MQTTCommonConfiguration conf) throws Exception { mqttBrokerPort, mqttBrokerTlsPort, mqttBrokerTlsPskPort, mqttProxyPort, mqttProxyTlsPort, mqttProxyTlsPskPort); ConfigurationUtils.extractFieldToProperties(conf); + setTLSConf(conf); this.pulsarServiceList.add(doStartBroker(conf)); } @@ -526,4 +527,31 @@ public static String randomName(String prefix, int numChars) { return sb.toString(); } + private void setTLSConf(ServiceConfiguration conf) { + conf.setTlsTrustCertsFilePath(getResourcePath("tls/cacert.pem")); + conf.setTlsCertificateFilePath(getResourcePath("tls/server-cert.pem")); + conf.setTlsKeyFilePath(getResourcePath("tls/server-key.pem")); + conf.setBrokerClientTrustCertsFilePath(getResourcePath("tls/cacert.pem")); + conf.setBrokerClientCertificateFilePath(getResourcePath("tls/client-cert.pem")); + conf.setBrokerClientKeyFilePath(getResourcePath("tls/client-key.pem")); + conf.setBrokerClientTlsEnabled(true); + + conf.getProperties().setProperty("tlsTrustCertsFilePath", getResourcePath("tls/cacert.pem")); + conf.getProperties().setProperty("tlsCertificateFilePath", getResourcePath("tls/server-cert.pem")); + conf.getProperties().setProperty("tlsKeyFilePath", getResourcePath("tls/server-key.pem")); + conf.getProperties().setProperty("brokerClientTrustCertsFilePath", getResourcePath("tls/cacert.pem")); + conf.getProperties().setProperty("brokerClientCertificateFilePath", getResourcePath("tls/client-cert.pem")); + conf.getProperties().setProperty("brokerClientKeyFilePath", getResourcePath("tls/client-key.pem")); + conf.getProperties().setProperty("brokerClientTlsEnabled", "true"); + } + + private String getResourcePath(String path) { + // get resource directory path + URL resource = this.getClass().getClassLoader().getResource(path); + if (resource == null) { + throw new RuntimeException("Resource not found: " + path); + } + return resource.getPath(); + } + } diff --git a/tests/src/test/resources/tls/cacert.pem b/tests/src/test/resources/tls/cacert.pem new file mode 100644 index 000000000..127f56dd7 --- /dev/null +++ b/tests/src/test/resources/tls/cacert.pem @@ -0,0 +1,77 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 77:4f:f6:cf:99:ca:77:e8:a7:6e:1e:fd:e2:cf:ac:a9:da:68:d2:42 + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN = CARoot + Validity + Not Before: May 30 13:38:24 2022 GMT + Not After : May 27 13:38:24 2032 GMT + Subject: CN = CARoot + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:b8:5e:c2:60:ed:c4:ee:3c:5b:ab:fc:64:52:f3: + 30:41:fc:10:5a:ac:a6:9b:0a:93:d0:d0:c9:bf:96: + 14:a7:cf:5c:3e:23:91:7e:54:ec:fe:2d:9f:c9:34: + d1:4e:95:2f:85:9c:cc:be:90:a3:a4:cb:4d:a4:72: + d2:84:e0:c7:42:c4:bf:70:b6:fa:d2:45:8b:83:66: + 1e:a4:e9:0e:06:a3:46:ea:a7:18:cd:33:b9:f1:ff: + 76:91:72:8f:cd:f9:93:43:c3:6e:17:1f:2d:86:df: + b6:fb:2d:d6:be:2d:98:ad:de:00:c7:de:f9:68:b5: + 40:40:56:49:ae:23:e5:a1:3b:5f:15:5a:44:50:da: + fb:02:d3:42:c6:87:0d:c0:8d:3a:e6:e2:aa:73:31: + ab:79:58:51:cd:03:80:f3:12:ce:2f:35:04:8b:39: + 5f:b0:cc:b8:41:99:47:c1:17:96:8b:c2:44:84:b5: + 21:8a:15:52:fe:1a:5a:f9:88:cc:11:17:ee:48:dd: + ba:bf:ed:67:6e:27:35:42:cf:07:5e:b1:8b:81:55: + 92:01:8e:61:fd:8e:82:74:b1:70:7a:3d:52:1f:16: + 78:12:bb:b5:09:62:ce:6d:18:4a:e9:f5:27:19:bc: + 93:4e:ed:dd:53:a8:c1:bb:48:b7:18:20:7b:79:48: + 48:9d + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 0F:46:61:3E:6F:71:22:E6:1F:32:37:7C:B2:81:A6:CC:DB:9D:F5:7C + X509v3 Authority Key Identifier: + keyid:0F:46:61:3E:6F:71:22:E6:1F:32:37:7C:B2:81:A6:CC:DB:9D:F5:7C + + X509v3 Basic Constraints: critical + CA:TRUE + Signature Algorithm: sha256WithRSAEncryption + 91:e8:d8:c4:32:2e:80:5c:d4:cb:24:7a:81:43:a9:c7:95:90: + 1a:2e:7a:d3:0c:5d:b6:21:05:67:4d:98:5a:0d:71:ea:80:01: + 95:42:fe:fa:f1:7c:dc:bd:76:ff:05:26:3b:f0:94:b3:09:2c: + 34:dd:43:56:46:2b:15:35:99:d9:94:54:22:cf:a6:68:b0:d1: + 79:e2:f0:9f:0b:02:7c:cf:1f:bd:d0:f6:49:c6:82:28:a5:c6: + ae:94:65:cf:fd:ad:a8:6c:c2:17:da:db:f3:be:30:1a:1b:b4: + 2c:fa:08:71:9d:64:09:45:02:92:02:ad:eb:15:47:14:43:5b: + a8:2d:1a:ec:14:93:dc:ff:bb:51:33:a3:d5:4d:e2:77:ca:e1: + a5:98:5c:7a:b6:10:19:d3:d7:f5:14:a5:d5:08:f1:97:18:3d: + 5f:a6:4e:a2:4a:0d:4b:d4:bb:56:6b:a8:44:35:62:c5:d8:c6: + 67:11:93:1c:22:64:3e:aa:15:08:dc:87:39:dd:f6:e0:a0:d5: + 00:db:27:79:3d:f4:35:7c:46:a9:fa:0c:fa:fc:74:f5:bf:f4: + fe:71:40:45:33:22:35:83:f7:1a:96:2a:fc:b2:33:e0:1a:e8: + 24:48:91:5d:90:5c:4c:93:33:4c:40:de:26:bb:24:ac:48:9b: + ae:fe:19:34 +-----BEGIN CERTIFICATE----- +MIIDAzCCAeugAwIBAgIUd0/2z5nKd+inbh794s+sqdpo0kIwDQYJKoZIhvcNAQEL +BQAwETEPMA0GA1UEAwwGQ0FSb290MB4XDTIyMDUzMDEzMzgyNFoXDTMyMDUyNzEz +MzgyNFowETEPMA0GA1UEAwwGQ0FSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAuF7CYO3E7jxbq/xkUvMwQfwQWqymmwqT0NDJv5YUp89cPiORflTs +/i2fyTTRTpUvhZzMvpCjpMtNpHLShODHQsS/cLb60kWLg2YepOkOBqNG6qcYzTO5 +8f92kXKPzfmTQ8NuFx8tht+2+y3Wvi2Yrd4Ax975aLVAQFZJriPloTtfFVpEUNr7 +AtNCxocNwI065uKqczGreVhRzQOA8xLOLzUEizlfsMy4QZlHwReWi8JEhLUhihVS +/hpa+YjMERfuSN26v+1nbic1Qs8HXrGLgVWSAY5h/Y6CdLFwej1SHxZ4Eru1CWLO +bRhK6fUnGbyTTu3dU6jBu0i3GCB7eUhInQIDAQABo1MwUTAdBgNVHQ4EFgQUD0Zh +Pm9xIuYfMjd8soGmzNud9XwwHwYDVR0jBBgwFoAUD0ZhPm9xIuYfMjd8soGmzNud +9XwwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkejYxDIugFzU +yyR6gUOpx5WQGi560wxdtiEFZ02YWg1x6oABlUL++vF83L12/wUmO/CUswksNN1D +VkYrFTWZ2ZRUIs+maLDReeLwnwsCfM8fvdD2ScaCKKXGrpRlz/2tqGzCF9rb874w +Ghu0LPoIcZ1kCUUCkgKt6xVHFENbqC0a7BST3P+7UTOj1U3id8rhpZhcerYQGdPX +9RSl1Qjxlxg9X6ZOokoNS9S7VmuoRDVixdjGZxGTHCJkPqoVCNyHOd324KDVANsn +eT30NXxGqfoM+vx09b/0/nFARTMiNYP3GpYq/LIz4BroJEiRXZBcTJMzTEDeJrsk +rEibrv4ZNA== +-----END CERTIFICATE----- diff --git a/tests/src/test/resources/tls/client-cert.pem b/tests/src/test/resources/tls/client-cert.pem new file mode 100644 index 000000000..192d68624 --- /dev/null +++ b/tests/src/test/resources/tls/client-cert.pem @@ -0,0 +1,72 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 61:e6:1b:07:90:6a:4f:f7:cd:46:b9:59:1d:3e:1c:39:0d:f2:5e:01 + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN = CARoot + Validity + Not Before: May 30 13:38:24 2022 GMT + Not After : May 27 13:38:24 2032 GMT + Subject: C = US, ST = CA, O = Apache, OU = Apache Pulsar, CN = superUser + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:cd:43:7d:98:40:f9:b0:5b:bc:ae:db:c0:0b:ad: + 26:90:96:e0:62:38:ed:68:b1:70:46:3b:de:44:f9: + 14:51:86:10:eb:ca:90:e7:88:e8:f9:91:85:e0:dd: + b5:b4:14:b9:78:e3:86:d5:54:6d:68:ec:14:92:b4: + f8:22:5b:05:3d:ed:31:25:65:08:05:84:ca:e6:0c: + 21:12:58:32:c7:1a:60:a3:4f:d2:4a:9e:28:19:7c: + 45:84:00:8c:89:dc:de:8a:e5:4f:88:91:cc:a4:f1: + 81:45:4c:7d:c2:ff:e2:c1:89:c6:12:73:95:e2:36: + bd:db:ae:8b:5a:68:6a:90:51:de:2b:88:5f:aa:67: + f4:a8:e3:63:dc:be:19:82:cc:9d:7f:e6:8d:fb:82: + be:22:01:3d:56:13:3b:5b:04:b4:e8:c5:18:e6:2e: + 0d:fa:ba:4a:8d:e8:c6:5a:a1:51:9a:4a:62:d7:af: + dd:b4:fc:e2:d5:cd:ae:99:6c:5c:61:56:0b:d7:0c: + 1a:77:5c:f5:3a:6a:54:b5:9e:33:ac:a9:75:28:9a: + 76:af:d0:7a:57:00:1b:91:13:31:fd:42:88:21:47: + 05:10:01:2f:59:bb:c7:3a:d9:e1:58:4c:1b:6c:71: + b6:98:ef:dd:03:82:58:a3:32:dc:90:a1:b6:a6:1e: + e1:0b + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:localhost, IP Address:127.0.0.1 + Signature Algorithm: sha256WithRSAEncryption + 96:c2:23:2d:46:d0:3d:23:0e:ab:3d:b6:1e:31:96:00:eb:ae: + 17:ac:6e:c0:d4:1a:8d:0f:36:63:27:02:49:4e:24:cf:d3:80: + 88:3a:4f:d0:f1:e5:1c:df:2d:8a:ab:ae:8d:48:77:a0:d0:dc: + d5:80:1c:a1:3d:0d:49:64:bf:cb:39:84:c9:f3:5d:e0:2d:ba: + a0:f2:ac:03:85:44:a1:97:6b:0b:de:ed:a7:49:19:46:b2:18: + 49:21:62:43:52:36:6f:47:6c:21:6b:5e:41:85:28:71:6c:22: + 27:35:76:82:ed:ac:ad:d7:fa:9d:4c:7d:6f:44:7e:06:dd:8a: + 11:32:0c:d9:d0:f6:63:2a:40:ae:0d:5a:df:9e:d7:91:8a:db: + 2d:95:f3:19:f0:8f:1e:34:e3:b2:31:67:38:74:fd:3f:e6:49: + 5e:53:eb:88:ae:b1:45:71:0e:67:97:3c:99:4e:c7:ea:1e:02: + 67:b4:54:ef:4f:10:55:4a:70:c0:eb:41:e4:50:d4:48:5e:70: + c5:0f:79:f2:06:3d:35:ea:ce:5d:13:8e:14:65:fc:98:21:16: + 2d:5d:6d:f8:e0:6b:c7:c6:e4:8a:ca:c9:38:1f:93:27:86:28: + ef:96:e7:ad:6c:4a:9e:10:78:48:00:f4:4a:43:dc:87:1d:e3: + d3:39:53:68 +-----BEGIN CERTIFICATE----- +MIIDFDCCAfygAwIBAgIUYeYbB5BqT/fNRrlZHT4cOQ3yXgEwDQYJKoZIhvcNAQEL +BQAwETEPMA0GA1UEAwwGQ0FSb290MB4XDTIyMDUzMDEzMzgyNFoXDTMyMDUyNzEz +MzgyNFowVzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMQ8wDQYDVQQKEwZBcGFj +aGUxFjAUBgNVBAsTDUFwYWNoZSBQdWxzYXIxEjAQBgNVBAMTCXN1cGVyVXNlcjCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM1DfZhA+bBbvK7bwAutJpCW +4GI47WixcEY73kT5FFGGEOvKkOeI6PmRheDdtbQUuXjjhtVUbWjsFJK0+CJbBT3t +MSVlCAWEyuYMIRJYMscaYKNP0kqeKBl8RYQAjInc3orlT4iRzKTxgUVMfcL/4sGJ +xhJzleI2vduui1poapBR3iuIX6pn9KjjY9y+GYLMnX/mjfuCviIBPVYTO1sEtOjF +GOYuDfq6So3oxlqhUZpKYtev3bT84tXNrplsXGFWC9cMGndc9TpqVLWeM6ypdSia +dq/QelcAG5ETMf1CiCFHBRABL1m7xzrZ4VhMG2xxtpjv3QOCWKMy3JChtqYe4QsC +AwEAAaMeMBwwGgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/AAABMA0GCSqGSIb3DQEB +CwUAA4IBAQCWwiMtRtA9Iw6rPbYeMZYA664XrG7A1BqNDzZjJwJJTiTP04CIOk/Q +8eUc3y2Kq66NSHeg0NzVgByhPQ1JZL/LOYTJ813gLbqg8qwDhUShl2sL3u2nSRlG +shhJIWJDUjZvR2wha15BhShxbCInNXaC7ayt1/qdTH1vRH4G3YoRMgzZ0PZjKkCu +DVrfnteRitstlfMZ8I8eNOOyMWc4dP0/5kleU+uIrrFFcQ5nlzyZTsfqHgJntFTv +TxBVSnDA60HkUNRIXnDFD3nyBj016s5dE44UZfyYIRYtXW344GvHxuSKysk4H5Mn +hijvluetbEqeEHhIAPRKQ9yHHePTOVNo +-----END CERTIFICATE----- diff --git a/tests/src/test/resources/tls/client-key.pem b/tests/src/test/resources/tls/client-key.pem new file mode 100644 index 000000000..3835b3eac --- /dev/null +++ b/tests/src/test/resources/tls/client-key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDNQ32YQPmwW7yu +28ALrSaQluBiOO1osXBGO95E+RRRhhDrypDniOj5kYXg3bW0FLl444bVVG1o7BSS +tPgiWwU97TElZQgFhMrmDCESWDLHGmCjT9JKnigZfEWEAIyJ3N6K5U+Ikcyk8YFF +TH3C/+LBicYSc5XiNr3brotaaGqQUd4riF+qZ/So42PcvhmCzJ1/5o37gr4iAT1W +EztbBLToxRjmLg36ukqN6MZaoVGaSmLXr920/OLVza6ZbFxhVgvXDBp3XPU6alS1 +njOsqXUomnav0HpXABuREzH9QoghRwUQAS9Zu8c62eFYTBtscbaY790DglijMtyQ +obamHuELAgMBAAECggEBALGnokJuqiz7mTj2NSdl+6TVEOuyPbiJKpV/J4cm1XEh +ye9qaTQcCRhH3UmcWrG75jM9KevloLRY8A1x1/lUMhtA+XJWGTU9k6a8BLut3nT4 +3X87jNTMQgSczEXNe9WudmZcxhN7rVVtOOdTpt1pP0cnCWna5HTf0D8cuLvM975j +r1YGTjKsCF1W+tp6ZAIIMfJkUI2qBRKvSxVCSs1vZBraox3yUVnq9oRLHxZZoqOd +d51G5phRtn6ReVPBdT8fGUBEGg3jKxTu2/vLQMUyHy0hyCAM20gzOP4FIc2g+QZU +y42byAuc89m0OrdRWsmzHCOxcq9DwY9npaz1RscR/2ECgYEA9bHJQ0Y1afpS5gn2 +KnXenRIw9oal1utQZnohCEJ4um+K/BCEHtDnI825LPNf34IKM2rSmssvHrYN51o0 +92j9lHHXsf6MVluwsTsIu8MtNaJ1BLt96dub4ScGT6vvzObKTwsajUfIHk+FNsKq +zps8yh1q0qyyfAcvR82+Xr6JIsMCgYEA1d+RHGewi/Ub/GCG99A1KFKsgbiIJnWB +IFmrcyPWignhzDUcw2SV9XqAzeK8EOIHNq3e5U/tkA7aCWxtLb5UsQ8xvmwQY2cy +X2XvSdIhO4K2PgRLgjlzZ8RHSULglqyjB2i6TjwjFl8TsRzYr6JlV6+2cMujw4Bl +g3a8gz071BkCgYBLP7BMkmw5kRliqxph1sffg3rLhmG0eU2elTkYtoMTVqZSnRxZ +89FW/eMBCWkLo2BMbyMhlalQ1qFbgh1GyTkhBdzx/uwsZtiu7021dAmcq6z7ThE6 +VrBfPPyJ2jcPon/DxbrUGnAIGILMSsLVlGYB4RCehZYEto6chz8O9Xw60QKBgCnd +us1BqviqwZC04JbQJie/j09RbS2CIQXRJ9PBNzUMXCwaVYgWP5ivI1mqQcBYTqsw +fAqNi+aAUcQ4emLS+Ec0vzsUclzTDbRJAv+DZ8f7fWtEcfeLAYFVldLMiaRVJRDF +OnsoIII3mGY6TFyNQKNanS8VXfheQQDsFFjoera5AoGBALXYEXkESXpw4LT6qJFz +ktQuTZDfS6LtR14/+NkYL9c5wBC4Otkg4bNbT8xGlUjethRfpkm8xRTB6zfC1/p/ +Cg6YU1cwqlkRurAhE3PEv1dCc1IDbzou8xnwqHrd6sGPDQmQ3aEtU5eJhDZKIZfx +nQqPGK92+Jtne7+W1mFZooxs +-----END PRIVATE KEY----- diff --git a/tests/src/test/resources/tls/server-cert.pem b/tests/src/test/resources/tls/server-cert.pem new file mode 100644 index 000000000..c09434c85 --- /dev/null +++ b/tests/src/test/resources/tls/server-cert.pem @@ -0,0 +1,72 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 61:e6:1b:07:90:6a:4f:f7:cd:46:b9:59:1d:3e:1c:39:0d:f2:5e:02 + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN = CARoot + Validity + Not Before: May 30 13:38:24 2022 GMT + Not After : May 27 13:38:24 2032 GMT + Subject: C = US, ST = CA, O = Apache, OU = Apache Pulsar, CN = localhost + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:af:bf:b7:2d:98:ad:9d:f6:da:a3:13:d4:62:0f: + 98:be:1c:a2:89:22:ba:6f:d5:fd:1f:67:e3:91:03: + 98:80:81:0e:ed:d8:f6:70:7f:2c:36:68:3d:53:ea: + 58:3a:a6:d5:89:66:4b:bd:1e:57:71:13:6d:4b:11: + e5:40:a5:76:84:24:92:40:58:80:96:c9:1f:2c:c4: + 55:eb:a3:79:73:70:5c:37:9a:89:ed:2f:ba:6b:e3: + 82:7c:69:4a:02:54:8b:81:5e:3c:bf:4c:8a:cb:ea: + 2c:5e:83:e7:b7:10:08:5f:82:58:a3:89:d1:da:92: + ba:2a:28:ee:30:28:3f:5b:ae:10:71:96:c7:e1:12: + c5:b0:1a:ad:44:6f:44:3a:11:4a:9a:3c:0f:8d:06: + 80:7b:34:ef:3f:6c:f4:5e:c5:44:54:1e:c8:dd:c7: + 80:85:80:d9:68:e6:c6:53:03:77:e1:fe:18:61:07: + 77:05:4c:ed:59:bc:5d:41:38:6a:ef:5d:a1:b2:60: + 98:d4:48:28:95:02:8a:0e:fd:cf:7b:1b:d2:11:cc: + 10:0c:50:73:d7:cc:38:6c:83:dd:79:26:aa:90:c8: + 9b:84:86:bc:59:e9:62:69:f4:98:1b:c4:80:78:7e: + a0:1a:81:9d:d2:e1:66:dd:c4:cc:fc:63:04:ac:ec: + a7:35 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Alternative Name: + DNS:localhost, IP Address:127.0.0.1 + Signature Algorithm: sha256WithRSAEncryption + 88:89:d7:52:b3:61:49:73:7d:ee:aa:6f:47:11:cd:52:f1:ef: + 9a:63:5f:43:a9:4f:66:c8:36:dd:44:24:ba:4f:c3:6c:94:90: + 85:5e:29:fb:65:cf:03:3b:37:16:5e:88:07:70:97:54:93:f0: + f3:09:d7:65:60:09:00:fd:7f:dd:6a:ab:25:3a:30:c4:89:34: + 43:82:f6:f5:f4:2d:39:3d:21:90:c4:00:27:c5:6a:23:41:20: + c6:42:35:56:91:17:fa:31:90:09:6a:4c:e4:a7:53:ae:61:b6: + d3:5b:82:71:08:d0:0b:af:34:0f:9b:bd:bc:8c:1c:31:43:43: + 97:82:9a:ac:2a:53:ca:11:ce:6f:64:ac:86:c1:f0:62:14:aa: + c3:dd:15:5b:1c:02:6f:bb:40:87:17:b7:e5:9d:93:9a:51:c9: + 1e:7a:8c:d1:22:75:44:f1:9d:90:4b:3e:1f:6c:ab:6f:e3:be: + cd:c7:15:9d:04:84:4a:1b:a7:ac:64:5d:d7:3e:23:98:b9:49: + dd:85:dd:80:4c:46:08:9b:f5:df:eb:19:c8:57:70:ac:43:f9: + d6:9c:1b:1b:2a:94:cf:c1:35:56:a2:f4:b1:00:5d:9e:1e:36: + 54:72:ab:aa:ef:49:b2:f0:dc:cf:5b:22:51:bf:e4:c9:57:dc: + d0:48:0d:f2 +-----BEGIN CERTIFICATE----- +MIIDFDCCAfygAwIBAgIUYeYbB5BqT/fNRrlZHT4cOQ3yXgIwDQYJKoZIhvcNAQEL +BQAwETEPMA0GA1UEAwwGQ0FSb290MB4XDTIyMDUzMDEzMzgyNFoXDTMyMDUyNzEz +MzgyNFowVzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMQ8wDQYDVQQKEwZBcGFj +aGUxFjAUBgNVBAsTDUFwYWNoZSBQdWxzYXIxEjAQBgNVBAMTCWxvY2FsaG9zdDCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK+/ty2YrZ322qMT1GIPmL4c +ookium/V/R9n45EDmICBDu3Y9nB/LDZoPVPqWDqm1YlmS70eV3ETbUsR5UCldoQk +kkBYgJbJHyzEVeujeXNwXDeaie0vumvjgnxpSgJUi4FePL9MisvqLF6D57cQCF+C +WKOJ0dqSuioo7jAoP1uuEHGWx+ESxbAarURvRDoRSpo8D40GgHs07z9s9F7FRFQe +yN3HgIWA2WjmxlMDd+H+GGEHdwVM7Vm8XUE4au9dobJgmNRIKJUCig79z3sb0hHM +EAxQc9fMOGyD3XkmqpDIm4SGvFnpYmn0mBvEgHh+oBqBndLhZt3EzPxjBKzspzUC +AwEAAaMeMBwwGgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/AAABMA0GCSqGSIb3DQEB +CwUAA4IBAQCIiddSs2FJc33uqm9HEc1S8e+aY19DqU9myDbdRCS6T8NslJCFXin7 +Zc8DOzcWXogHcJdUk/DzCddlYAkA/X/daqslOjDEiTRDgvb19C05PSGQxAAnxWoj +QSDGQjVWkRf6MZAJakzkp1OuYbbTW4JxCNALrzQPm728jBwxQ0OXgpqsKlPKEc5v +ZKyGwfBiFKrD3RVbHAJvu0CHF7flnZOaUckeeozRInVE8Z2QSz4fbKtv477NxxWd +BIRKG6esZF3XPiOYuUndhd2ATEYIm/Xf6xnIV3CsQ/nWnBsbKpTPwTVWovSxAF2e +HjZUcquq70my8NzPWyJRv+TJV9zQSA3y +-----END CERTIFICATE----- diff --git a/tests/src/test/resources/tls/server-key.pem b/tests/src/test/resources/tls/server-key.pem new file mode 100644 index 000000000..004bf8e21 --- /dev/null +++ b/tests/src/test/resources/tls/server-key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCvv7ctmK2d9tqj +E9RiD5i+HKKJIrpv1f0fZ+ORA5iAgQ7t2PZwfyw2aD1T6lg6ptWJZku9HldxE21L +EeVApXaEJJJAWICWyR8sxFXro3lzcFw3montL7pr44J8aUoCVIuBXjy/TIrL6ixe +g+e3EAhfglijidHakroqKO4wKD9brhBxlsfhEsWwGq1Eb0Q6EUqaPA+NBoB7NO8/ +bPRexURUHsjdx4CFgNlo5sZTA3fh/hhhB3cFTO1ZvF1BOGrvXaGyYJjUSCiVAooO +/c97G9IRzBAMUHPXzDhsg915JqqQyJuEhrxZ6WJp9JgbxIB4fqAagZ3S4WbdxMz8 +YwSs7Kc1AgMBAAECggEAAaWEK9MwXTiA1+JJrRmETtOp2isPIBkbI/4vLZ6hASM0 +ZpoPxQIMAf58BJs/dF03xu/EaeMs4oxSC9ABG9fxAk/tZtjta3w65Ip6W5jOfHxj +AMpb3HMEBhq9kDjUTq1IGVAutYQcEMkC3WfS9e4ahfqMpguWgbu6LsbvZFgcL9mv +pGnKv9YVe6Xk6isvqtq6G1af0rd7c//xF0i0e/qEo83Buok3gLEZOELZbcRxjUYc +jnyglnXnwkGjuL4E3wgS3l73ZKsb6+AYoqhMPVz8t4/PN3tTrsBJKOSYo8KzIm0U +ek9T8XmPbP0cuheRxp9Dp8TXJJQZK0N9jz+EL0ogQQKBgQDnavm8GpR4pap9cDOc ++YI5s823b507pNdSU8elO9gLsP0JlFzv+sqghVko29r85D7Vn3MkgYTy0S4ANLCs +0NFDY8N2QH6U1dTkk1QXZydVZDuKJ5SSpC4v+Vafl8yDxhB4Nlxhbm9vJEMfLcXh +2kL6UlAuFDtYD0AdczwnHu5DjQKBgQDCauocm55FpcyDMMBO2CjurxcjBYS3S1xT +Bz+sPtxJLjlKbAt8kSHUQcCcX9zhrQBfsT38LATCmKaOFqUW5/PPh2LcrxiMqlL1 +OJBUJ3Te2LTjlUn8r+DHv/69UIh5tchwRr3YgB0DuIs7jfmr4VfiOWTBtPVhoGFR +1Wt60j30SQKBgHzreS26J2VNAFBALgxRf6OIVMbtgDG/FOCDCyU9vazp+F2gcd61 +QYYPFYcBzx9uUiDctroBFHRCyJMh3jEbc6ruAogl3m6XUxmkEeOkMk5dEerM3N2f +tLL+5Gy385U6aI+LwKhzhcG4EGeXPNdjC362ykNldnddnB2Jo/H2N2XNAoGAdnft +xpbxP+GDGKIZXTIM5zzcLWQMdiC+1n1BSHVZiGJZWMczzKknYw7aDq+/iekApE79 +xW8RS373ZvfXi3i2Mcx+6pjrrbOQL4tTL2SHq8+DknaDCi4mG7IbyUKMlxW1WO1S +e929UGogtZ6S+DCte9WbVwosyFuRUetpvgLk67kCgYBWetihZjgBWrqVYT24TTRH +KxzSzH1JgzzF9qgTdlhXDv9hC+Kc0uTKsgViesDqVuCOjkwzY5OQr9c6duO0fwwP +qNk/qltdgjMC5iiv7duyukfbEuqKEdGGer9HFb7en96dZdVQJpYHaaslAGurtD80 +ejCQZgzR2XaHSuIQb0IUVQ== +-----END PRIVATE KEY-----