GEODE-3023: TcpServer move soTimout for the socket for SSL Locators
Project: http://git-wip-us.apache.org/repos/asf/geode/repo Commit: http://git-wip-us.apache.org/repos/asf/geode/commit/214cd732 Tree: http://git-wip-us.apache.org/repos/asf/geode/tree/214cd732 Diff: http://git-wip-us.apache.org/repos/asf/geode/diff/214cd732 Branch: refs/heads/feature/GEM-1483 Commit: 214cd732d17b20252f8b52b24dedfa088ec3b245 Parents: 76784eb Author: Udo Kohlmeyer <ukohlme...@pivotal.io> Authored: Fri Jun 9 15:06:14 2017 -0700 Committer: Udo Kohlmeyer <ukohlme...@pivotal.io> Committed: Fri Jun 9 15:06:14 2017 -0700 ---------------------------------------------------------------------- .../internal/tcpserver/TcpServer.java | 67 ++++---- .../tcpserver/TCPServerSSLJUnitTest.java | 167 +++++++++++++++++++ .../internal/tcpserver/TcpServerJUnitTest.java | 40 ++--- .../geode/internal/net/DummySocketCreator.java | 45 +++++ 4 files changed, 266 insertions(+), 53 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/geode/blob/214cd732/geode-core/src/main/java/org/apache/geode/distributed/internal/tcpserver/TcpServer.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/tcpserver/TcpServer.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/tcpserver/TcpServer.java index 86fe532..976f504 100755 --- a/geode-core/src/main/java/org/apache/geode/distributed/internal/tcpserver/TcpServer.java +++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/tcpserver/TcpServer.java @@ -14,32 +14,6 @@ */ package org.apache.geode.distributed.internal.tcpserver; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.EOFException; -import java.io.File; -import java.io.IOException; -import java.io.StreamCorruptedException; -import java.net.InetAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.SocketAddress; -import java.net.URL; -import java.util.Date; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Properties; -import java.util.concurrent.SynchronousQueue; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -import javax.net.ssl.SSLException; - -import org.apache.logging.log4j.Logger; - import org.apache.geode.CancelException; import org.apache.geode.DataSerializer; import org.apache.geode.SystemFailure; @@ -62,6 +36,31 @@ import org.apache.geode.internal.logging.LogService; import org.apache.geode.internal.net.SocketCreator; import org.apache.geode.internal.net.SocketCreatorFactory; import org.apache.geode.internal.security.SecurableCommunicationChannel; +import org.apache.logging.log4j.Logger; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.EOFException; +import java.io.File; +import java.io.IOException; +import java.io.StreamCorruptedException; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.URL; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import javax.net.ssl.SSLException; /** * TCP server which listens on a port and delegates requests to a request handler. The server uses @@ -128,7 +127,7 @@ public class TcpServer { private final String threadName; private volatile Thread serverThread; - private SocketCreator socketCreator; + protected SocketCreator socketCreator; /* * GemStoneAddition - Initialize versions map. Warning: This map must be compatible with all @@ -164,13 +163,14 @@ public class TcpServer { } cfg = new DistributionConfigImpl(sslConfig); } + } + protected SocketCreator getSocketCreator() { if (this.socketCreator == null) { this.socketCreator = SocketCreatorFactory.getSocketCreatorForComponent(SecurableCommunicationChannel.LOCATOR); - } else { - throw new RuntimeException("The socket Creator already exists"); } + return socketCreator; } private static PooledExecutorWithDMStats createExecutor(PoolStatHelper poolHelper, @@ -210,10 +210,10 @@ public class TcpServer { private void startServerThread() throws IOException { if (srv_sock == null || srv_sock.isClosed()) { if (bind_address == null) { - srv_sock = socketCreator.createServerSocket(port, BACKLOG); + srv_sock = getSocketCreator().createServerSocket(port, BACKLOG); bind_address = srv_sock.getInetAddress(); } else { - srv_sock = socketCreator.createServerSocket(port, BACKLOG, bind_address); + srv_sock = getSocketCreator().createServerSocket(port, BACKLOG, bind_address); } if (log.isInfoEnabled()) { @@ -340,8 +340,10 @@ public class TcpServer { DataInputStream input = null; Object request, response; try { - socketCreator.configureServerSSLSocket(sock); + sock.setSoTimeout(READ_TIMEOUT); + getSocketCreator().configureServerSSLSocket(sock); + try { input = new DataInputStream(sock.getInputStream()); } catch (StreamCorruptedException e) { @@ -351,7 +353,6 @@ public class TcpServer { + (sock.getInetAddress().getHostAddress() + ":" + sock.getPort()), e); return; } - int gossipVersion = readGossipVersion(sock, input); short versionOrdinal; http://git-wip-us.apache.org/repos/asf/geode/blob/214cd732/geode-core/src/test/java/org/apache/geode/distributed/internal/tcpserver/TCPServerSSLJUnitTest.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/distributed/internal/tcpserver/TCPServerSSLJUnitTest.java b/geode-core/src/test/java/org/apache/geode/distributed/internal/tcpserver/TCPServerSSLJUnitTest.java new file mode 100644 index 0000000..b3a0901 --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/distributed/internal/tcpserver/TCPServerSSLJUnitTest.java @@ -0,0 +1,167 @@ +/* + * 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.geode.distributed.internal.tcpserver; + +import static org.apache.geode.distributed.ConfigurationProperties.SSL_CIPHERS; +import static org.apache.geode.distributed.ConfigurationProperties.SSL_ENABLED_COMPONENTS; +import static org.apache.geode.distributed.ConfigurationProperties.SSL_KEYSTORE; +import static org.apache.geode.distributed.ConfigurationProperties.SSL_KEYSTORE_PASSWORD; +import static org.apache.geode.distributed.ConfigurationProperties.SSL_KEYSTORE_TYPE; +import static org.apache.geode.distributed.ConfigurationProperties.SSL_PROTOCOLS; +import static org.apache.geode.distributed.ConfigurationProperties.SSL_TRUSTSTORE; +import static org.apache.geode.distributed.ConfigurationProperties.SSL_TRUSTSTORE_PASSWORD; + +import org.apache.geode.distributed.internal.DistributionConfig; +import org.apache.geode.distributed.internal.DistributionConfigImpl; +import org.apache.geode.distributed.internal.PoolStatHelper; +import org.apache.geode.internal.AvailablePort; +import org.apache.geode.internal.admin.SSLConfig; +import org.apache.geode.internal.net.DummySocketCreator; +import org.apache.geode.internal.net.SSLConfigurationFactory; +import org.apache.geode.internal.net.SocketCreator; +import org.apache.geode.internal.net.SocketCreatorFactory; +import org.apache.geode.internal.security.SecurableCommunicationChannel; +import org.apache.geode.test.junit.categories.IntegrationTest; +import org.apache.geode.test.junit.categories.MembershipTest; +import org.apache.geode.util.test.TestUtil; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.contrib.java.lang.system.RestoreSystemProperties; +import org.junit.experimental.categories.Category; +import org.mockito.Mockito; + +import java.io.IOException; +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +@Category({IntegrationTest.class, MembershipTest.class}) +public class TCPServerSSLJUnitTest { + + private InetAddress localhost; + private int port; + private DummyTcpServer server; + + @Rule + public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties(); + private final String expectedSocketTimeout = "2000"; + + @Before + public void setup() { + SocketCreatorFactory.setDistributionConfig(new DistributionConfigImpl(new Properties())); + } + + @After + public void teardown() { + SocketCreatorFactory.close(); + } + + private void startTimeDelayedTcpServer(Properties sslProperties) throws IOException { + localhost = InetAddress.getLocalHost(); + port = AvailablePort.getRandomAvailablePort(AvailablePort.SOCKET); + + server = + new DummyTcpServer(port, localhost, sslProperties, null, Mockito.mock(TcpHandler.class), + Mockito.mock(PoolStatHelper.class), Thread.currentThread().getThreadGroup(), + "server thread"); + server.start(); + } + + @Test + public void testSSLSocketTimeOut() throws IOException { + boolean caughtLocatorException = false; + try { + + System.setProperty(DistributionConfig.GEMFIRE_PREFIX + "TcpServer.READ_TIMEOUT", + expectedSocketTimeout); + Properties sslProperties = getSSLConfigurationProperties(); + startTimeDelayedTcpServer(sslProperties); + + createTcpClientConnection(); + + } catch (LocatorCancelException e) { + // we catching the LocatorCancelException. Expected to have the exception thrown + caughtLocatorException = true; + } + + Assert.assertTrue(caughtLocatorException); + List<Integer> recordedSocketsForSocketCreator = server.getRecordedSocketTimeouts(); + + Assert.assertEquals(1, recordedSocketsForSocketCreator.size()); + for (Integer socketTimeOut : recordedSocketsForSocketCreator) { + Assert.assertEquals(Integer.parseInt(expectedSocketTimeout), socketTimeOut.intValue()); + } + } + + private Properties getSSLConfigurationProperties() { + Properties sslProperties = new Properties(); + sslProperties.setProperty(SSL_ENABLED_COMPONENTS, + SecurableCommunicationChannel.LOCATOR.getConstant()); + sslProperties.setProperty(SSL_KEYSTORE, + TestUtil.getResourcePath(getClass(), "/org/apache/geode/internal/net/multiKey.jks")); + sslProperties.setProperty(SSL_TRUSTSTORE, + TestUtil.getResourcePath(getClass(), "/org/apache/geode/internal/net/multiKeyTrust.jks")); + sslProperties.setProperty(SSL_KEYSTORE_PASSWORD, "password"); + sslProperties.setProperty(SSL_TRUSTSTORE_PASSWORD, "password"); + sslProperties.setProperty(SSL_KEYSTORE_TYPE, "JKS"); + sslProperties.setProperty(SSL_CIPHERS, "any"); + sslProperties.setProperty(SSL_PROTOCOLS, "any"); + return sslProperties; + } + + private void createTcpClientConnection() { + try { + new TcpClient().requestToServer(localhost, port, Boolean.valueOf(false), 5 * 1000); + } catch (IOException e) { + e.printStackTrace(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } + + private class DummyTcpServer extends TcpServer { + private DistributionConfig distributionConfig; + private List<Integer> recordedSocketsTimeouts = new ArrayList<>(); + + public DummyTcpServer(int port, InetAddress bind_address, Properties sslConfig, + DistributionConfigImpl cfg, TcpHandler handler, PoolStatHelper poolHelper, + ThreadGroup threadGroup, String threadName) { + super(port, bind_address, sslConfig, cfg, handler, poolHelper, threadGroup, threadName); + if (cfg == null) { + cfg = new DistributionConfigImpl(sslConfig); + } + this.distributionConfig = cfg; + } + + @Override + protected SocketCreator getSocketCreator() { + if (this.socketCreator == null) { + SSLConfigurationFactory.setDistributionConfig(distributionConfig); + SSLConfig sslConfig = + SSLConfigurationFactory.getSSLConfigForComponent(SecurableCommunicationChannel.LOCATOR); + this.socketCreator = new DummySocketCreator(sslConfig, recordedSocketsTimeouts); + } + return socketCreator; + } + + public List<Integer> getRecordedSocketTimeouts() { + return recordedSocketsTimeouts; + } + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/214cd732/geode-core/src/test/java/org/apache/geode/distributed/internal/tcpserver/TcpServerJUnitTest.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/distributed/internal/tcpserver/TcpServerJUnitTest.java b/geode-core/src/test/java/org/apache/geode/distributed/internal/tcpserver/TcpServerJUnitTest.java index 7c7a2b3..eda0641 100644 --- a/geode-core/src/test/java/org/apache/geode/distributed/internal/tcpserver/TcpServerJUnitTest.java +++ b/geode-core/src/test/java/org/apache/geode/distributed/internal/tcpserver/TcpServerJUnitTest.java @@ -14,7 +14,25 @@ */ package org.apache.geode.distributed.internal.tcpserver; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import org.apache.geode.DataSerializable; +import org.apache.geode.cache.GemFireCache; +import org.apache.geode.distributed.DistributedSystem; +import org.apache.geode.distributed.internal.ClusterConfigurationService; +import org.apache.geode.distributed.internal.DistributionConfigImpl; +import org.apache.geode.distributed.internal.PoolStatHelper; +import org.apache.geode.internal.AvailablePort; +import org.apache.geode.internal.net.SocketCreatorFactory; +import org.apache.geode.test.junit.categories.IntegrationTest; +import org.apache.geode.test.junit.categories.MembershipTest; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; import java.io.DataInput; import java.io.DataOutput; @@ -27,22 +45,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import org.apache.geode.distributed.internal.ClusterConfigurationService; -import org.apache.geode.test.junit.categories.MembershipTest; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import org.apache.geode.DataSerializable; -import org.apache.geode.cache.GemFireCache; -import org.apache.geode.distributed.DistributedSystem; -import org.apache.geode.distributed.internal.DistributionConfigImpl; -import org.apache.geode.distributed.internal.PoolStatHelper; -import org.apache.geode.internal.AvailablePort; -import org.apache.geode.internal.net.SocketCreatorFactory; -import org.apache.geode.test.junit.categories.IntegrationTest; - @Category({IntegrationTest.class, MembershipTest.class}) public class TcpServerJUnitTest { @@ -205,10 +207,8 @@ public class TcpServerJUnitTest { } catch (InterruptedException e) { Thread.currentThread().interrupt(); } - return delay; - } else { - return delay; } + return delay; } public void shutDown() {} http://git-wip-us.apache.org/repos/asf/geode/blob/214cd732/geode-core/src/test/java/org/apache/geode/internal/net/DummySocketCreator.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/internal/net/DummySocketCreator.java b/geode-core/src/test/java/org/apache/geode/internal/net/DummySocketCreator.java new file mode 100644 index 0000000..2c5ff92 --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/internal/net/DummySocketCreator.java @@ -0,0 +1,45 @@ +/* + * 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.geode.internal.net; + +import org.apache.geode.internal.admin.SSLConfig; + +import java.io.IOException; +import java.net.Socket; +import java.util.List; +import javax.net.ssl.SSLException; + +public class DummySocketCreator extends SocketCreator { + + private List<Integer> socketSoTimeouts; + + /** + * Constructs new SocketCreator instance. + */ + public DummySocketCreator(SSLConfig sslConfig, List<Integer> sockets) { + super(sslConfig); + this.socketSoTimeouts = sockets; + } + + @Override + public void configureServerSSLSocket(Socket socket) throws IOException { + this.socketSoTimeouts.add(socket.getSoTimeout()); + throw new SSLException("This is a test SSLException"); + } + + public List<Integer> getSocketSoTimeouts() { + return socketSoTimeouts; + } +}