Repository: incubator-rocketmq Updated Branches: refs/heads/tls 1cf9099e9 -> 56509394a
Refactor to support multiple SSL modes: disabled, permissive and enforcing. Project: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/commit/56509394 Tree: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/tree/56509394 Diff: http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/diff/56509394 Branch: refs/heads/tls Commit: 56509394a486828d0a04f1e68ae287b0a57ab126 Parents: 1cf9099 Author: Li Zhanhui <[email protected]> Authored: Thu Jun 15 16:15:48 2017 +0800 Committer: Li Zhanhui <[email protected]> Committed: Thu Jun 15 16:15:48 2017 +0800 ---------------------------------------------------------------------- .../apache/rocketmq/broker/BrokerStartup.java | 3 +- .../rocketmq/remoting/common/SslMode.java | 53 +++++++++++++++++ .../remoting/netty/NettyRemotingClient.java | 13 +++-- .../remoting/netty/NettyRemotingServer.java | 61 +++++++++++++++----- .../remoting/netty/NettySystemConfig.java | 18 ++++-- 5 files changed, 124 insertions(+), 24 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/56509394/broker/src/main/java/org/apache/rocketmq/broker/BrokerStartup.java ---------------------------------------------------------------------- diff --git a/broker/src/main/java/org/apache/rocketmq/broker/BrokerStartup.java b/broker/src/main/java/org/apache/rocketmq/broker/BrokerStartup.java index dbea561..255b374 100644 --- a/broker/src/main/java/org/apache/rocketmq/broker/BrokerStartup.java +++ b/broker/src/main/java/org/apache/rocketmq/broker/BrokerStartup.java @@ -32,6 +32,7 @@ import org.apache.rocketmq.common.MQVersion; import org.apache.rocketmq.common.MixAll; import org.apache.rocketmq.common.constant.LoggerName; import org.apache.rocketmq.remoting.common.RemotingUtil; +import org.apache.rocketmq.remoting.common.SslMode; import org.apache.rocketmq.remoting.netty.NettyClientConfig; import org.apache.rocketmq.remoting.netty.NettyServerConfig; import org.apache.rocketmq.remoting.netty.NettySystemConfig; @@ -95,7 +96,7 @@ public class BrokerStartup { final BrokerConfig brokerConfig = new BrokerConfig(); final NettyServerConfig nettyServerConfig = new NettyServerConfig(); final NettyClientConfig nettyClientConfig = new NettyClientConfig(); - nettyClientConfig.setUseTLS(NettySystemConfig.enableSSL); + nettyClientConfig.setUseTLS(NettySystemConfig.sslMode != SslMode.DISABLED); nettyServerConfig.setListenPort(10911); final MessageStoreConfig messageStoreConfig = new MessageStoreConfig(); http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/56509394/remoting/src/main/java/org/apache/rocketmq/remoting/common/SslMode.java ---------------------------------------------------------------------- diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/common/SslMode.java b/remoting/src/main/java/org/apache/rocketmq/remoting/common/SslMode.java new file mode 100644 index 0000000..8801736 --- /dev/null +++ b/remoting/src/main/java/org/apache/rocketmq/remoting/common/SslMode.java @@ -0,0 +1,53 @@ +/* + * 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.rocketmq.remoting.common; + +/** + * For server, three SSL modes are supported: disabled, permissive and enforcing. + * <ol> + * <li><strong>disable:</strong> SSL is not supported; any incoming SSL handshake will be rejected, causing connection closed.</li> + * <li><strong>permissive:</strong> SSL is optional, aka, server in this mode can serve client connections with or without SSL;</li> + * <li><strong>enforcing:</strong> SSL is required, aka, non SSL connection will be rejected.</li> + * </ol> + */ +public enum SslMode { + + DISABLED("disabled"), + PERMISSIVE("permissive"), + ENFORCING("enforcing"); + + private String name; + + SslMode(String name) { + this.name = name; + } + + public static SslMode parse(String mode) { + for (SslMode sslMode: SslMode.values()) { + if (sslMode.name.equals(mode)) { + return sslMode; + } + } + + return PERMISSIVE; + } + + public String getName() { + return name; + } +} http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/56509394/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java ---------------------------------------------------------------------- diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java index 9f2d062..8294529 100644 --- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java +++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingClient.java @@ -60,6 +60,7 @@ import org.apache.rocketmq.remoting.RemotingClient; import org.apache.rocketmq.remoting.common.Pair; import org.apache.rocketmq.remoting.common.RemotingHelper; import org.apache.rocketmq.remoting.common.RemotingUtil; +import org.apache.rocketmq.remoting.common.SslMode; import org.apache.rocketmq.remoting.exception.RemotingConnectException; import org.apache.rocketmq.remoting.exception.RemotingSendRequestException; import org.apache.rocketmq.remoting.exception.RemotingTimeoutException; @@ -124,7 +125,7 @@ public class NettyRemotingClient extends NettyRemotingAbstract implements Remoti } }); - if (NettySystemConfig.enableSSL) { + if (nettyClientConfig.isUseTLS()) { try { sslContext = SslHelper.buildSslContext(true); log.info("SSL enabled for client"); @@ -167,9 +168,13 @@ public class NettyRemotingClient extends NettyRemotingAbstract implements Remoti @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); - if (nettyClientConfig.isUseTLS() && null != sslContext) { - pipeline.addFirst(defaultEventExecutorGroup, "sslHandler", sslContext.newHandler(ch.alloc())); - log.info("Prepend SSL handler"); + if (nettyClientConfig.isUseTLS()) { + if (null != sslContext) { + pipeline.addFirst(defaultEventExecutorGroup, "sslHandler", sslContext.newHandler(ch.alloc())); + log.info("Prepend SSL handler"); + } else { + log.warn("Connections are insecure as SSLContext is null!"); + } } pipeline.addLast( defaultEventExecutorGroup, http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/56509394/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingServer.java ---------------------------------------------------------------------- diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingServer.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingServer.java index 70e5bae..d1158c4 100644 --- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingServer.java +++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettyRemotingServer.java @@ -25,6 +25,7 @@ import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; +import io.netty.channel.ChannelPipeline; import io.netty.channel.EventLoopGroup; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.epoll.Epoll; @@ -39,6 +40,7 @@ import io.netty.handler.timeout.IdleStateHandler; import io.netty.util.concurrent.DefaultEventExecutorGroup; import java.net.InetSocketAddress; import java.security.cert.CertificateException; +import java.util.NoSuchElementException; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.ExecutorService; @@ -53,6 +55,7 @@ import org.apache.rocketmq.remoting.RemotingServer; import org.apache.rocketmq.remoting.common.Pair; import org.apache.rocketmq.remoting.common.RemotingHelper; import org.apache.rocketmq.remoting.common.RemotingUtil; +import org.apache.rocketmq.remoting.common.SslMode; import org.apache.rocketmq.remoting.exception.RemotingSendRequestException; import org.apache.rocketmq.remoting.exception.RemotingTimeoutException; import org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException; @@ -136,16 +139,17 @@ public class NettyRemotingServer extends NettyRemotingAbstract implements Remoti }); } - if (NettySystemConfig.enableSSL) { + SslMode sslMode = NettySystemConfig.sslMode; + log.info("Server is running in TLS {} mode", sslMode.getName()); + + if (sslMode != SslMode.DISABLED) { try { sslContext = SslHelper.buildSslContext(false); - log.info("SSL enabled for server"); + log.info("SSLContext created for server"); } catch (CertificateException e) { log.error("Failed to create SSLContext for server", e); - throw new RuntimeException(e); } catch (SSLException e) { log.error("Failed to create SSLContext for server", e); - throw new RuntimeException(e); } } } @@ -184,7 +188,8 @@ public class NettyRemotingServer extends NettyRemotingAbstract implements Remoti @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline() - .addLast(defaultEventExecutorGroup, HANDSHAKE_HANDLER_NAME, new HandshakeHandler()) + .addLast(defaultEventExecutorGroup, HANDSHAKE_HANDLER_NAME, + new HandshakeHandler(NettySystemConfig.sslMode)) .addLast(defaultEventExecutorGroup, new NettyEncoder(), new NettyDecoder(), @@ -321,8 +326,14 @@ public class NettyRemotingServer extends NettyRemotingAbstract implements Remoti class HandshakeHandler extends SimpleChannelInboundHandler<ByteBuf> { + private final SslMode sslMode; + private static final byte HANDSHAKE_MAGIC_CODE = 0x16; + HandshakeHandler(SslMode sslMode) { + this.sslMode = sslMode; + } + @Override protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception { @@ -333,22 +344,42 @@ public class NettyRemotingServer extends NettyRemotingAbstract implements Remoti byte b = msg.getByte(0); if (b == HANDSHAKE_MAGIC_CODE) { - if (null != sslContext) { - ctx.pipeline() - .addAfter(defaultEventExecutorGroup, HANDSHAKE_HANDLER_NAME, TLS_HANDLER_NAME, sslContext.newHandler(ctx.channel().alloc())) - .addAfter(defaultEventExecutorGroup, TLS_HANDLER_NAME, FILE_REGION_ENCODER_NAME, new FileRegionEncoder()); - log.info("SSL handler prepended to channel pipeline"); - } else { - ctx.close(); - log.error("Requiring SSL handler but sslContext is being null"); + switch (sslMode) { + case DISABLED: + ctx.close(); + log.warn("Clients intend to establish a SSL connection while this server is running in SSL disabled mode"); + break; + case PERMISSIVE: + case ENFORCING: + if (null != sslContext) { + ctx.pipeline() + .addAfter(defaultEventExecutorGroup, HANDSHAKE_HANDLER_NAME, TLS_HANDLER_NAME, sslContext.newHandler(ctx.channel().alloc())) + .addAfter(defaultEventExecutorGroup, TLS_HANDLER_NAME, FILE_REGION_ENCODER_NAME, new FileRegionEncoder()); + log.info("Handlers prepended to channel pipeline to establish SSL connection"); + } else { + ctx.close(); + log.error("Trying to establish a SSL connection but sslContext is null"); + } + break; + + default: + log.warn("Unknown TLS mode"); + break; } + } else if (sslMode == SslMode.ENFORCING) { + ctx.close(); + log.warn("Clients intend to establish an insecure connection while this server is running in SSL enforcing mode"); } // reset the reader index so that handshake negotiation may proceed as normal. msg.resetReaderIndex(); - // Remove this handler - ctx.pipeline().remove(HANDSHAKE_HANDLER_NAME); + try { + // Remove this handler + ctx.pipeline().remove(this); + } catch (NoSuchElementException e) { + log.error("Error while removing HandshakeHandler", e); + } // Hand over this message to the next . ctx.fireChannelRead(msg.retain()); http://git-wip-us.apache.org/repos/asf/incubator-rocketmq/blob/56509394/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettySystemConfig.java ---------------------------------------------------------------------- diff --git a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettySystemConfig.java b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettySystemConfig.java index 4a071c5..8e85193 100644 --- a/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettySystemConfig.java +++ b/remoting/src/main/java/org/apache/rocketmq/remoting/netty/NettySystemConfig.java @@ -17,6 +17,8 @@ package org.apache.rocketmq.remoting.netty; +import org.apache.rocketmq.remoting.common.SslMode; + public class NettySystemConfig { public static final String COM_ROCKETMQ_REMOTING_NETTY_POOLED_BYTE_BUF_ALLOCATOR_ENABLE = "com.rocketmq.remoting.nettyPooledByteBufAllocatorEnable"; @@ -29,8 +31,8 @@ public class NettySystemConfig { public static final String COM_ROCKETMQ_REMOTING_CLIENT_ONEWAY_SEMAPHORE_VALUE = // "com.rocketmq.remoting.clientOnewaySemaphoreValue"; - public static final String ORG_APACHE_ROCKETMQ_REMOTING_SSL_ENABLE = // - "org.apache.rocketmq.remoting.ssl.enable"; + public static final String ORG_APACHE_ROCKETMQ_REMOTING_SSL_MODE = // + "org.apache.rocketmq.remoting.ssl.mode"; public static final String ORG_APACHE_ROCKETMQ_REMOTING_SSL_CONFIG_FILE = // "org.apache.rocketmq.remoting.ssl.config.file"; @@ -46,8 +48,16 @@ public class NettySystemConfig { public static int socketRcvbufSize = // Integer.parseInt(System.getProperty(COM_ROCKETMQ_REMOTING_SOCKET_RCVBUF_SIZE, "65535")); - public static boolean enableSSL = // - Boolean.parseBoolean(System.getProperty(ORG_APACHE_ROCKETMQ_REMOTING_SSL_ENABLE, "true")); + /** + * For server, three SSL modes are supported: disabled, permissive and enforcing. + * <ol> + * <li><strong>disable:</strong> SSL is not supported; any incoming SSL handshake will be rejected, causing connection closed.</li> + * <li><strong>permissive:</strong> SSL is optional, aka, server in this mode can serve client connections with or without SSL;</li> + * <li><strong>enforcing:</strong> SSL is required, aka, non SSL connection will be rejected.</li> + * </ol> + */ + public static SslMode sslMode = // + SslMode.parse(System.getProperty(ORG_APACHE_ROCKETMQ_REMOTING_SSL_MODE, "permissive")); public static String sslConfigFile = // System.getProperty(ORG_APACHE_ROCKETMQ_REMOTING_SSL_CONFIG_FILE, "/etc/rocketmq/ssl.properties");
