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");

Reply via email to