You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by is...@apache.org on 2019/06/20 15:41:50 UTC

[ignite] branch master updated: IGNITE-11875: Removed password length limit in thin client handshake

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

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


The following commit(s) were added to refs/heads/master by this push:
     new a0cd1e5  IGNITE-11875: Removed password length limit in thin client handshake
a0cd1e5 is described below

commit a0cd1e5cf571db4cdee15e5091bbf1d1c4f2ac92
Author: Igor Sapego <is...@apache.org>
AuthorDate: Thu Jun 20 18:40:41 2019 +0300

    IGNITE-11875: Removed password length limit in thin client handshake
    
    This closes #6570
---
 .../ClientConnectorConfiguration.java              | 38 +++++++++
 .../odbc/ClientListenerBufferedParser.java         |  4 +-
 .../processors/odbc/ClientListenerNioListener.java | 63 ++++++++++++--
 .../odbc/ClientListenerNioServerBuffer.java        | 10 +--
 .../platform/utils/PlatformConfigurationUtils.java | 22 +++--
 .../cpp/thin-client-test/config/non-ssl-32.xml     | 48 +++++++++++
 .../thin-client-test/config/non-ssl-default.xml    | 72 ++++++++++++++++
 .../cpp/thin-client-test/config/non-ssl.xml        | 31 +++++++
 .../project/vs/thin-client-test.vcxproj            |  3 +
 .../project/vs/thin-client-test.vcxproj.filters    | 11 ++-
 .../cpp/thin-client-test/src/ssl_test.cpp          | 38 +++++++--
 .../Client/ClientConnectionTest.cs                 | 98 +++++++++++++---------
 .../IgniteConfigurationTest.cs                     |  4 +-
 .../Configuration/ClientConnectorConfiguration.cs  | 26 +++++-
 .../Apache.Ignite.Core/IgniteConfiguration.cs      |  4 +-
 .../IgniteConfigurationSection.xsd                 |  5 ++
 16 files changed, 402 insertions(+), 75 deletions(-)

diff --git a/modules/core/src/main/java/org/apache/ignite/configuration/ClientConnectorConfiguration.java b/modules/core/src/main/java/org/apache/ignite/configuration/ClientConnectorConfiguration.java
index ed30db3..dac0616 100644
--- a/modules/core/src/main/java/org/apache/ignite/configuration/ClientConnectorConfiguration.java
+++ b/modules/core/src/main/java/org/apache/ignite/configuration/ClientConnectorConfiguration.java
@@ -45,6 +45,9 @@ public class ClientConnectorConfiguration {
     /** Default size of thread pool. */
     public static final int DFLT_THREAD_POOL_SIZE = IgniteConfiguration.DFLT_PUBLIC_THREAD_CNT;
 
+    /** Default handshake timeout. */
+    public static final int DFLT_HANDSHAKE_TIMEOUT = 10_000;
+
     /** Default idle timeout. */
     public static final int DFLT_IDLE_TIMEOUT = 0;
 
@@ -78,6 +81,9 @@ public class ClientConnectorConfiguration {
     /** Idle timeout. */
     private long idleTimeout = DFLT_IDLE_TIMEOUT;
 
+    /** Handshake timeout. */
+    private long handshakeTimeout = DFLT_HANDSHAKE_TIMEOUT;
+
     /** JDBC connections enabled flag. */
     private boolean jdbcEnabled = true;
 
@@ -123,6 +129,10 @@ public class ClientConnectorConfiguration {
         tcpNoDelay = cfg.isTcpNoDelay();
         threadPoolSize = cfg.getThreadPoolSize();
         idleTimeout = cfg.getIdleTimeout();
+        handshakeTimeout = cfg.getHandshakeTimeout();
+        jdbcEnabled = cfg.jdbcEnabled;
+        odbcEnabled = cfg.odbcEnabled;
+        thinCliEnabled = cfg.thinCliEnabled;
         sslEnabled = cfg.isSslEnabled();
         sslClientAuth = cfg.isSslClientAuth();
         useIgniteSslCtxFactory = cfg.isUseIgniteSslContextFactory();
@@ -333,6 +343,34 @@ public class ClientConnectorConfiguration {
     }
 
     /**
+     * Gets handshake timeout for client connections.
+     * If no successful handshake is performed within this timeout upon successful establishment of TCP connection,
+     * the connection is closed.
+     * Zero or negative means no timeout.
+     *
+     * @return Handshake timeout in milliseconds.
+     */
+    public long getHandshakeTimeout() {
+        return handshakeTimeout;
+    }
+
+    /**
+     * Sets handshake timeout for client connections.
+     * If no successful handshake is performed within this timeout upon successful establishment of TCP connection,
+     * the connection is closed.
+     * Zero or negative means no timeout.
+     *
+     * @param handshakeTimeout Idle timeout in milliseconds.
+     * @see #getHandshakeTimeout()
+     * @return {@code this} for chaining.
+     */
+    public ClientConnectorConfiguration setHandshakeTimeout(long handshakeTimeout) {
+        this.handshakeTimeout = handshakeTimeout;
+
+        return this;
+    }
+
+    /**
      * Gets whether access through JDBC is enabled.
      * <p>
      * Defaults to {@code true}.
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/ClientListenerBufferedParser.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/ClientListenerBufferedParser.java
index 8dd26b6..01af95c 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/ClientListenerBufferedParser.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/ClientListenerBufferedParser.java
@@ -55,9 +55,7 @@ public class ClientListenerBufferedParser implements GridNioParser {
             assert old == null;
         }
 
-        boolean checkHandshake = ses.meta(ClientListenerNioListener.CONN_CTX_HANDSHAKE_PASSED) == null;
-
-        return nioBuf.read(buf, checkHandshake);
+        return nioBuf.read(buf);
     }
 
     /** {@inheritDoc} */
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/ClientListenerNioListener.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/ClientListenerNioListener.java
index 0e9d1dc..1ddef04 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/ClientListenerNioListener.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/ClientListenerNioListener.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.internal.processors.odbc;
 
+import java.io.Closeable;
 import java.util.concurrent.atomic.AtomicInteger;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.IgniteLogger;
@@ -54,11 +55,8 @@ public class ClientListenerNioListener extends GridNioServerListenerAdapter<byte
     /** Thin client handshake code. */
     public static final byte THIN_CLIENT = 2;
 
-    /** Connection handshake passed. */
-    public static final int CONN_CTX_HANDSHAKE_PASSED = GridNioSessionMetaKey.nextUniqueKey();
-
-    /** Maximum size of the handshake message. */
-    public static final int MAX_HANDSHAKE_MSG_SIZE = 128;
+    /** Connection handshake timeout task. */
+    public static final int CONN_CTX_HANDSHAKE_TIMEOUT_TASK = GridNioSessionMetaKey.nextUniqueKey();
 
     /** Connection-related metadata key. */
     public static final int CONN_CTX_META_KEY = GridNioSessionMetaKey.nextUniqueKey();
@@ -94,9 +92,9 @@ public class ClientListenerNioListener extends GridNioServerListenerAdapter<byte
 
         this.ctx = ctx;
         this.busyLock = busyLock;
-        this.maxCursors = cliConnCfg.getMaxOpenCursorsPerConnection();
         this.cliConnCfg = cliConnCfg;
 
+        maxCursors = cliConnCfg.getMaxOpenCursorsPerConnection();
         log = ctx.log(getClass());
     }
 
@@ -104,6 +102,11 @@ public class ClientListenerNioListener extends GridNioServerListenerAdapter<byte
     @Override public void onConnected(GridNioSession ses) {
         if (log.isDebugEnabled())
             log.debug("Client connected: " + ses.remoteAddress());
+
+        long handshakeTimeout = cliConnCfg.getHandshakeTimeout();
+
+        if (handshakeTimeout > 0)
+            scheduleHandshakeTimeout(ses, handshakeTimeout);
     }
 
     /** {@inheritDoc} */
@@ -128,7 +131,13 @@ public class ClientListenerNioListener extends GridNioServerListenerAdapter<byte
         ClientListenerConnectionContext connCtx = ses.meta(CONN_CTX_META_KEY);
 
         if (connCtx == null) {
-            onHandshake(ses, msg);
+            try {
+                onHandshake(ses, msg);
+            }
+            catch (Exception e) {
+                U.error(log, "Failed to handle handshake request " +
+                    "(probably, connection has already been closed).", e);
+            }
 
             return;
         }
@@ -211,6 +220,42 @@ public class ClientListenerNioListener extends GridNioServerListenerAdapter<byte
     }
 
     /**
+     * Schedule handshake timeout.
+     * @param ses Connection session.
+     * @param handshakeTimeout Handshake timeout.
+     */
+    private void scheduleHandshakeTimeout(GridNioSession ses, long handshakeTimeout) {
+        assert handshakeTimeout > 0;
+
+        Closeable timeoutTask = ctx.timeout().schedule(new Runnable() {
+            @Override public void run() {
+                ses.close();
+
+                U.warn(log, "Unable to perform handshake within timeout " +
+                    "[timeout=" + handshakeTimeout + ", remoteAddr=" + ses.remoteAddress() + ']');
+            }
+        }, handshakeTimeout, -1);
+
+        ses.addMeta(CONN_CTX_HANDSHAKE_TIMEOUT_TASK, timeoutTask);
+    }
+
+    /**
+     * Cancel handshake timeout task execution.
+     * @param ses Connection session.
+     */
+    private void cancelHandshakeTimeout(GridNioSession ses) {
+        Closeable timeoutTask = ses.removeMeta(CONN_CTX_HANDSHAKE_TIMEOUT_TASK);
+
+        try {
+            if (timeoutTask != null)
+                timeoutTask.close();
+        } catch (Exception e) {
+            U.warn(log, "Failed to cancel handshake timeout task " +
+                "[remoteAddr=" + ses.remoteAddress() + ", err=" + e + ']');
+        }
+    }
+
+    /**
      * Perform handshake.
      *
      * @param ses Session.
@@ -256,9 +301,9 @@ public class ClientListenerNioListener extends GridNioServerListenerAdapter<byte
             else
                 throw new IgniteCheckedException("Unsupported version.");
 
-            connCtx.handler().writeHandshake(writer);
+            cancelHandshakeTimeout(ses);
 
-            ses.addMeta(CONN_CTX_HANDSHAKE_PASSED, true);
+            connCtx.handler().writeHandshake(writer);
         }
         catch (IgniteAccessControlException authEx) {
             writer.writeBoolean(false);
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/ClientListenerNioServerBuffer.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/ClientListenerNioServerBuffer.java
index 6ee6e71..cb8303e 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/ClientListenerNioServerBuffer.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/ClientListenerNioServerBuffer.java
@@ -64,11 +64,10 @@ public class ClientListenerNioServerBuffer {
 
     /**
      * @param buf Buffer.
-     * @param checkHandshake Check handshake.
      * @return Message bytes or {@code null} if message is not fully read yet.
      * @throws IgniteCheckedException If failed to parse message.
      */
-    @Nullable public byte[] read(ByteBuffer buf, boolean checkHandshake) throws IgniteCheckedException {
+    @Nullable public byte[] read(ByteBuffer buf) throws IgniteCheckedException {
         if (cnt < 0) {
             for (; cnt < 0 && buf.hasRemaining(); cnt++)
                 msgSize |= (buf.get() & 0xFF) << (8*(4 + cnt));
@@ -109,12 +108,7 @@ public class ClientListenerNioServerBuffer {
 
             return data0;
         }
-        else {
-            if (checkHandshake && cnt > 0 && (msgSize > ClientListenerNioListener.MAX_HANDSHAKE_MSG_SIZE
-                || data[0] != ClientListenerRequest.HANDSHAKE))
-                throw new IgniteCheckedException("Invalid handshake message");
 
-            return null;
-        }
+        return null;
     }
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformConfigurationUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformConfigurationUtils.java
index 4faec0d..872ec9c 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformConfigurationUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/utils/PlatformConfigurationUtils.java
@@ -808,7 +808,7 @@ public class PlatformConfigurationUtils {
             cfg.setSqlConnectorConfiguration(readSqlConnectorConfiguration(in));
 
         if (in.readBoolean())
-            cfg.setClientConnectorConfiguration(readClientConnectorConfiguration(in));
+            cfg.setClientConnectorConfiguration(readClientConnectorConfiguration(in, ver));
 
         if (!in.readBoolean())  // ClientConnectorConfigurationEnabled override
             cfg.setClientConnectorConfiguration(null);
@@ -1406,7 +1406,7 @@ public class PlatformConfigurationUtils {
 
         writeSqlConnectorConfiguration(w, cfg.getSqlConnectorConfiguration());
 
-        writeClientConnectorConfiguration(w, cfg.getClientConnectorConfiguration());
+        writeClientConnectorConfiguration(w, cfg.getClientConnectorConfiguration(), ver);
 
         w.writeBoolean(cfg.getClientConnectorConfiguration() != null);
 
@@ -1804,10 +1804,12 @@ public class PlatformConfigurationUtils {
      * Reads the client connector configuration.
      *
      * @param in Reader.
+     * @param ver Protocol version.
      * @return Config.
      */
-    private static ClientConnectorConfiguration readClientConnectorConfiguration(BinaryRawReader in) {
-        return new ClientConnectorConfiguration()
+    private static ClientConnectorConfiguration readClientConnectorConfiguration(BinaryRawReader in,
+        ClientListenerProtocolVersion ver) {
+        ClientConnectorConfiguration cfg = new ClientConnectorConfiguration()
                 .setHost(in.readString())
                 .setPort(in.readInt())
                 .setPortRange(in.readInt())
@@ -1820,14 +1822,21 @@ public class PlatformConfigurationUtils {
                 .setThinClientEnabled(in.readBoolean())
                 .setOdbcEnabled(in.readBoolean())
                 .setJdbcEnabled(in.readBoolean());
+
+        if (ver.compareTo(VER_1_3_0) >= 0)
+            cfg.setHandshakeTimeout(in.readLong());
+
+        return cfg;
     }
 
     /**
      * Writes the client connector configuration.
      *
      * @param w Writer.
+     * @param ver Protocol version.
      */
-    private static void writeClientConnectorConfiguration(BinaryRawWriter w, ClientConnectorConfiguration cfg) {
+    private static void writeClientConnectorConfiguration(BinaryRawWriter w, ClientConnectorConfiguration cfg,
+        ClientListenerProtocolVersion ver) {
         assert w != null;
 
         if (cfg != null) {
@@ -1846,6 +1855,9 @@ public class PlatformConfigurationUtils {
             w.writeBoolean(cfg.isThinClientEnabled());
             w.writeBoolean(cfg.isOdbcEnabled());
             w.writeBoolean(cfg.isJdbcEnabled());
+
+            if (ver.compareTo(VER_1_3_0) >= 0)
+                w.writeLong(cfg.getIdleTimeout());
         } else {
             w.writeBoolean(false);
         }
diff --git a/modules/platforms/cpp/thin-client-test/config/non-ssl-32.xml b/modules/platforms/cpp/thin-client-test/config/non-ssl-32.xml
new file mode 100644
index 0000000..8eb03bb
--- /dev/null
+++ b/modules/platforms/cpp/thin-client-test/config/non-ssl-32.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+    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.
+-->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:util="http://www.springframework.org/schema/util"
+       xsi:schemaLocation="
+        http://www.springframework.org/schema/beans
+        http://www.springframework.org/schema/beans/spring-beans.xsd">
+
+    <import resource="non-ssl-default.xml"/>
+
+    <bean parent="test.cfg">
+        <property name="memoryConfiguration">
+            <bean class="org.apache.ignite.configuration.MemoryConfiguration">
+                <property name="systemCacheInitialSize" value="#{10 * 1024 * 1024}"/>
+                <property name="systemCacheMaxSize" value="#{40 * 1024 * 1024}"/>
+                <property name="defaultMemoryPolicyName" value="dfltPlc"/>
+
+                <property name="memoryPolicies">
+                    <list>
+                        <bean class="org.apache.ignite.configuration.MemoryPolicyConfiguration">
+                            <property name="name" value="dfltPlc"/>
+                            <property name="maxSize" value="#{100 * 1024 * 1024}"/>
+                            <property name="initialSize" value="#{10 * 1024 * 1024}"/>
+                        </bean>
+                    </list>
+                </property>
+            </bean>
+        </property>
+    </bean>
+</beans>
diff --git a/modules/platforms/cpp/thin-client-test/config/non-ssl-default.xml b/modules/platforms/cpp/thin-client-test/config/non-ssl-default.xml
new file mode 100644
index 0000000..26771ee
--- /dev/null
+++ b/modules/platforms/cpp/thin-client-test/config/non-ssl-default.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+    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.
+-->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:util="http://www.springframework.org/schema/util"
+       xsi:schemaLocation="
+        http://www.springframework.org/schema/beans
+        http://www.springframework.org/schema/beans/spring-beans.xsd
+        http://www.springframework.org/schema/util
+        http://www.springframework.org/schema/util/spring-util.xsd">
+
+    <!--
+        Initialize property configurer so we can reference environment variables.
+    -->
+    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
+        <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_FALLBACK"/>
+        <property name="searchSystemEnvironment" value="true"/>
+    </bean>
+
+    <bean abstract="true" id="test.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
+        <property name="localHost" value="127.0.0.1"/>
+        <property name="connectorConfiguration"><null/></property>
+
+        <property name="clientConnectorConfiguration">
+            <bean class="org.apache.ignite.configuration.ClientConnectorConfiguration">
+                <property name="host" value="127.0.0.1"/>
+                <property name="port" value="11110"/>
+                <property name="portRange" value="10"/>
+                <property name="handshakeTimeout" value="300"/>
+            </bean>
+        </property>
+
+        <!-- Explicitly configure TCP discovery SPI to provide list of initial nodes. -->
+        <property name="discoverySpi">
+            <bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
+                <property name="ipFinder">
+                    <!--
+                        Ignite provides several options for automatic discovery that can be used
+                        instead os static IP based discovery.
+                    -->
+                    <!-- Uncomment static IP finder to enable static-based discovery of initial nodes. -->
+                    <bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder">
+                        <property name="addresses">
+                            <list>
+                                <!-- In distributed environment, replace with actual host IP address. -->
+                                <value>127.0.0.1:47500</value>
+                            </list>
+                        </property>
+                    </bean>
+                </property>
+                <property name="socketTimeout" value="300" />
+            </bean>
+        </property>
+    </bean>
+</beans>
diff --git a/modules/platforms/cpp/thin-client-test/config/non-ssl.xml b/modules/platforms/cpp/thin-client-test/config/non-ssl.xml
new file mode 100644
index 0000000..d14754d
--- /dev/null
+++ b/modules/platforms/cpp/thin-client-test/config/non-ssl.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+    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.
+-->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:util="http://www.springframework.org/schema/util"
+       xsi:schemaLocation="
+        http://www.springframework.org/schema/beans
+        http://www.springframework.org/schema/beans/spring-beans.xsd">
+
+    <import resource="non-ssl-default.xml"/>
+
+    <bean parent="test.cfg"/>
+
+</beans>
diff --git a/modules/platforms/cpp/thin-client-test/project/vs/thin-client-test.vcxproj b/modules/platforms/cpp/thin-client-test/project/vs/thin-client-test.vcxproj
index ee719f1..ad13f6f 100644
--- a/modules/platforms/cpp/thin-client-test/project/vs/thin-client-test.vcxproj
+++ b/modules/platforms/cpp/thin-client-test/project/vs/thin-client-test.vcxproj
@@ -56,6 +56,9 @@
     <None Include="..\..\config\cache-32.xml" />
     <None Include="..\..\config\cache-default.xml" />
     <None Include="..\..\config\cache.xml" />
+    <None Include="..\..\config\non-ssl-32.xml" />
+    <None Include="..\..\config\non-ssl-default.xml" />
+    <None Include="..\..\config\non-ssl.xml" />
     <None Include="..\..\config\ssl-32.xml" />
     <None Include="..\..\config\ssl-default.xml" />
     <None Include="..\..\config\ssl.xml" />
diff --git a/modules/platforms/cpp/thin-client-test/project/vs/thin-client-test.vcxproj.filters b/modules/platforms/cpp/thin-client-test/project/vs/thin-client-test.vcxproj.filters
index e8aee85..17c63e0 100644
--- a/modules/platforms/cpp/thin-client-test/project/vs/thin-client-test.vcxproj.filters
+++ b/modules/platforms/cpp/thin-client-test/project/vs/thin-client-test.vcxproj.filters
@@ -78,5 +78,14 @@
     <None Include="..\..\config\auth-default.xml">
       <Filter>Configs</Filter>
     </None>
+    <None Include="..\..\config\non-ssl.xml">
+      <Filter>Configs</Filter>
+    </None>
+    <None Include="..\..\config\non-ssl-32.xml">
+      <Filter>Configs</Filter>
+    </None>
+    <None Include="..\..\config\non-ssl-default.xml">
+      <Filter>Configs</Filter>
+    </None>
   </ItemGroup>
-</Project>
+</Project>
\ No newline at end of file
diff --git a/modules/platforms/cpp/thin-client-test/src/ssl_test.cpp b/modules/platforms/cpp/thin-client-test/src/ssl_test.cpp
index deac62f..845360b 100644
--- a/modules/platforms/cpp/thin-client-test/src/ssl_test.cpp
+++ b/modules/platforms/cpp/thin-client-test/src/ssl_test.cpp
@@ -30,9 +30,19 @@ using namespace boost::unit_test;
 class SslTestSuiteFixture
 {
 public:
+    ignite::Ignite StartSslNode()
+    {
+        return ignite_test::StartCrossPlatformServerNode("ssl.xml", "ServerNode");
+    }
+    
+    ignite::Ignite StartNonSslNode()
+    {
+        return ignite_test::StartCrossPlatformServerNode("non-ssl.xml", "ServerNode");
+    }
+
     SslTestSuiteFixture()
     {
-        serverNode = ignite_test::StartCrossPlatformServerNode("ssl.xml", "ServerNode");
+        // No-op.
     }
 
     ~SslTestSuiteFixture()
@@ -49,16 +59,14 @@ public:
 
         return pathBuilder.str();
     }
-
-private:
-    /** Server node. */
-    ignite::Ignite serverNode;
 };
 
 BOOST_FIXTURE_TEST_SUITE(SslTestSuite, SslTestSuiteFixture)
 
 BOOST_AUTO_TEST_CASE(SslConnectionSuccess)
 {
+    StartSslNode();
+
     IgniteClientConfiguration cfg;
 
     cfg.SetEndPoints("127.0.0.1:11110");
@@ -73,6 +81,8 @@ BOOST_AUTO_TEST_CASE(SslConnectionSuccess)
 
 BOOST_AUTO_TEST_CASE(SslConnectionReject)
 {
+    StartSslNode();
+
     IgniteClientConfiguration cfg;
 
     cfg.SetEndPoints("127.0.0.1:11110");
@@ -87,6 +97,8 @@ BOOST_AUTO_TEST_CASE(SslConnectionReject)
 
 BOOST_AUTO_TEST_CASE(SslConnectionReject2)
 {
+    StartSslNode();
+
     IgniteClientConfiguration cfg;
 
     cfg.SetEndPoints("127.0.0.1:11110");
@@ -96,4 +108,20 @@ BOOST_AUTO_TEST_CASE(SslConnectionReject2)
     BOOST_CHECK_THROW(IgniteClient::Start(cfg), ignite::IgniteError);
 }
 
+BOOST_AUTO_TEST_CASE(SslConnectionTimeout)
+{
+    StartNonSslNode();
+
+    IgniteClientConfiguration cfg;
+ 
+    cfg.SetEndPoints("127.0.0.1:11110");
+    
+    cfg.SetSslMode(SslMode::REQUIRE);
+    cfg.SetSslCertFile(GetConfigFile("client_full.pem"));
+    cfg.SetSslKeyFile(GetConfigFile("client_full.pem"));
+    cfg.SetSslCaFile(GetConfigFile("ca.pem"));
+
+    BOOST_CHECK_THROW(IgniteClient::Start(cfg), ignite::IgniteError);
+}
+
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientConnectionTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientConnectionTest.cs
index a882176..c185fab 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientConnectionTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Client/ClientConnectionTest.cs
@@ -137,46 +137,19 @@ namespace Apache.Ignite.Core.Tests.Client
         [Test]
         public void TestAuthentication()
         {
-            using (var srv = Ignition.Start(SecureServerConfig()))
-            {
-                srv.GetCluster().SetActive(true);
-
-                using (var cli = Ignition.StartClient(GetSecureClientConfig()))
-                {
-                    CacheClientConfiguration ccfg = new CacheClientConfiguration
-                    {
-                        Name = "TestCache",
-                        QueryEntities = new[]
-                        {
-                            new QueryEntity
-                            {
-                                KeyType = typeof(string),
-                                ValueType = typeof(string),
-                            },
-                        },
-                    };
-
-                    ICacheClient<string, string> cache = cli.GetOrCreateCache<string, string>(ccfg);
-
-                    cache.Put("key1", "val1");
-
-                    cache.Query(new SqlFieldsQuery("CREATE USER \"my_User\" WITH PASSWORD 'my_Password'")).GetAll();
-                }
-
-                var cliCfg = GetSecureClientConfig();
-
-                cliCfg.UserName = "my_User";
-                cliCfg.Password = "my_Password";
-
-                using (var cli = Ignition.StartClient(cliCfg))
-                {
-                    ICacheClient<string, string> cache = cli.GetCache<string, string>("TestCache");
+            CreateNewUserAndAuthenticate("my_User", "my_Password");
+        }
 
-                    string val = cache.Get("key1");
+        /// <summary>
+        /// Test authentication.
+        /// </summary>
+        [Test]
+        public void TestAuthenticationLongToken()
+        {
+            string user = new string('G', 59);
+            string pass = new string('q', 16 * 1024);
 
-                    Assert.True(val == "val1");
-                }
-            }
+            CreateNewUserAndAuthenticate(user, pass);
         }
 
         /// <summary>
@@ -694,5 +667,54 @@ namespace Apache.Ignite.Core.Tests.Client
                 Password = "ignite"
             };
         }
+
+        /// <summary>
+        /// Start new node, create new user with given credentials and try to authenticate.
+        /// </summary>
+        /// <param name="user">Username</param>
+        /// <param name="pass">Password</param>
+        private void CreateNewUserAndAuthenticate(string user, string pass)
+        {
+            using (var srv = Ignition.Start(SecureServerConfig()))
+            {
+                srv.GetCluster().SetActive(true);
+
+                using (var cli = Ignition.StartClient(GetSecureClientConfig()))
+                {
+                    CacheClientConfiguration ccfg = new CacheClientConfiguration
+                    {
+                        Name = "TestCache",
+                        QueryEntities = new[]
+                        {
+                            new QueryEntity
+                            {
+                                KeyType = typeof(string),
+                                ValueType = typeof(string),
+                            },
+                        },
+                    };
+
+                    ICacheClient<string, string> cache = cli.GetOrCreateCache<string, string>(ccfg);
+
+                    cache.Put("key1", "val1");
+
+                    cache.Query(new SqlFieldsQuery("CREATE USER \"" + user + "\" WITH PASSWORD '" + pass + "'")).GetAll();
+                }
+
+                var cliCfg = GetSecureClientConfig();
+
+                cliCfg.UserName = user;
+                cliCfg.Password = pass;
+
+                using (var cli = Ignition.StartClient(cliCfg))
+                {
+                    ICacheClient<string, string> cache = cli.GetCache<string, string>("TestCache");
+
+                    string val = cache.Get("key1");
+
+                    Assert.True(val == "val1");
+                }
+            }
+        }
     }
 }
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationTest.cs
index 4cbf7ce..0be9dc8 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationTest.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/IgniteConfigurationTest.cs
@@ -657,8 +657,8 @@ namespace Apache.Ignite.Core.Tests
             var props = obj.GetType().GetProperties();
 
             foreach (var prop in props.Where(p => p.Name != "SelectorsCount" && p.Name != "ReadStripesNumber" &&
-                                                  !p.Name.Contains("ThreadPoolSize") &&
-                                                  p.Name != "MaxSize"))
+                                                  !p.Name.Contains("ThreadPoolSize") && p.Name != "MaxSize" &&
+                                                  p.Name != "HandshakeTimeout"))
             {
                 var attr = prop.GetCustomAttributes(true).OfType<DefaultValueAttribute>().FirstOrDefault();
                 var propValue = prop.GetValue(obj, null);
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Configuration/ClientConnectorConfiguration.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Configuration/ClientConnectorConfiguration.cs
index 090ebd1..0159054 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/Configuration/ClientConnectorConfiguration.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/Configuration/ClientConnectorConfiguration.cs
@@ -22,6 +22,7 @@ namespace Apache.Ignite.Core.Configuration
     using System.Diagnostics;
     using Apache.Ignite.Core.Binary;
     using Apache.Ignite.Core.Impl.Binary;
+    using Apache.Ignite.Core.Impl.Client;
 
     /// <summary>
     /// Client connector configuration (ODBC, JDBC, Thin Client).
@@ -64,6 +65,11 @@ namespace Apache.Ignite.Core.Configuration
         public static readonly TimeSpan DefaultIdleTimeout = TimeSpan.Zero;
 
         /// <summary>
+        /// Default handshake timeout.
+        /// </summary>
+        public static readonly TimeSpan DefaultHandshakeTimeout = TimeSpan.FromSeconds(10);
+
+        /// <summary>
         /// Default value for <see cref="ThinClientEnabled"/> property.
         /// </summary>
         public const bool DefaultThinClientEnabled = true;
@@ -91,6 +97,7 @@ namespace Apache.Ignite.Core.Configuration
             MaxOpenCursorsPerConnection = DefaultMaxOpenCursorsPerConnection;
             ThreadPoolSize = DefaultThreadPoolSize;
             IdleTimeout = DefaultIdleTimeout;
+            HandshakeTimeout = DefaultHandshakeTimeout;
 
             ThinClientEnabled = DefaultThinClientEnabled;
             OdbcEnabled = DefaultOdbcEnabled;
@@ -100,7 +107,7 @@ namespace Apache.Ignite.Core.Configuration
         /// <summary>
         /// Initializes a new instance of the <see cref="ClientConnectorConfiguration"/> class.
         /// </summary>
-        internal ClientConnectorConfiguration(IBinaryRawReader reader)
+        internal ClientConnectorConfiguration(ClientProtocolVersion ver, IBinaryRawReader reader)
         {
             Debug.Assert(reader != null);
 
@@ -117,12 +124,16 @@ namespace Apache.Ignite.Core.Configuration
             ThinClientEnabled = reader.ReadBoolean();
             OdbcEnabled = reader.ReadBoolean();
             JdbcEnabled = reader.ReadBoolean();
+
+            if (ver.CompareTo(ClientSocket.Ver130) >= 0) {
+                HandshakeTimeout = reader.ReadLongAsTimespan();
+            }
         }
 
         /// <summary>
         /// Writes to the specified writer.
         /// </summary>
-        internal void Write(IBinaryRawWriter writer)
+        internal void Write(ClientProtocolVersion ver, IBinaryRawWriter writer)
         {
             Debug.Assert(writer != null);
             
@@ -139,6 +150,10 @@ namespace Apache.Ignite.Core.Configuration
             writer.WriteBoolean(ThinClientEnabled);
             writer.WriteBoolean(OdbcEnabled);
             writer.WriteBoolean(JdbcEnabled);
+
+            if (ver.CompareTo(ClientSocket.Ver130) >= 0) {
+                writer.WriteTimeSpanAsLong(HandshakeTimeout);
+            }
         }
 
         /// <summary>
@@ -201,6 +216,13 @@ namespace Apache.Ignite.Core.Configuration
         public TimeSpan IdleTimeout { get; set; }
 
         /// <summary>
+        /// Gets or sets handshake timeout for client connections on the server side.
+        /// If no successful handshake is performed within this timeout upon successful establishment of TCP connection
+        /// the connection is closed.
+        /// </summary>
+        public TimeSpan HandshakeTimeout { get; set; }
+
+        /// <summary>
         /// Gets or sets a value indicating whether thin client connector is enabled.
         /// </summary>
         [DefaultValue(DefaultThinClientEnabled)]
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs
index b4b4e5d..216f8fe 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfiguration.cs
@@ -549,7 +549,7 @@ namespace Apache.Ignite.Core
             if (ClientConnectorConfiguration != null)
             {
                 writer.WriteBoolean(true);
-                ClientConnectorConfiguration.Write(writer);
+                ClientConnectorConfiguration.Write(srvVer, writer);
             }
             else
             {
@@ -848,7 +848,7 @@ namespace Apache.Ignite.Core
             // Client.
             if (r.ReadBoolean())
             {
-                ClientConnectorConfiguration = new ClientConnectorConfiguration(r);
+                ClientConnectorConfiguration = new ClientConnectorConfiguration(srvVer, r);
             }
 
             ClientConnectorConfigurationEnabled = r.ReadBoolean();
diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd
index 0b1fae8..d593221 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd
+++ b/modules/platforms/dotnet/Apache.Ignite.Core/IgniteConfigurationSection.xsd
@@ -1529,6 +1529,11 @@
                                 <xs:documentation>Idle timeout for client connections on the server side. If no packets come within idle timeout, the connection is closed by the server. Zero or negative for no timeout.</xs:documentation>
                             </xs:annotation>
                         </xs:attribute>
+                        <xs:attribute name="handshakeTimeout" type="xs:string">
+                            <xs:annotation>
+                                <xs:documentation>Handshake timeout for client connections on the server side. If no successful handshake is performed within this timeout upon successful establishment of TCP connection, the connection is closed by the server. Zero or negative for no timeout.</xs:documentation>
+                            </xs:annotation>
+                        </xs:attribute>
                         <xs:attribute name="thinClientEnabled" type="xs:boolean">
                             <xs:annotation>
                                 <xs:documentation>Enables thin client connector.</xs:documentation>