You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by vo...@apache.org on 2018/03/22 11:47:17 UTC

[4/4] ignite git commit: IGNITE-7436: Simple username/password authentication. This closes #3483.

IGNITE-7436: Simple username/password authentication. This closes #3483.


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/edef7add
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/edef7add
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/edef7add

Branch: refs/heads/master
Commit: edef7add03696eab54f02ac3f8ebbb174a2f26ab
Parents: 664f1aa
Author: tledkov-gridgain <tl...@gridgain.com>
Authored: Thu Mar 22 14:47:06 2018 +0300
Committer: devozerov <vo...@gridgain.com>
Committed: Thu Mar 22 14:47:06 2018 +0300

----------------------------------------------------------------------
 .../jdbc/suite/IgniteJdbcDriverTestSuite.java   |    2 +
 .../JdbcThinAuthenticateConnectionSelfTest.java |  235 +++
 .../jdbc/thin/JdbcThinConnectionSelfTest.java   |   12 +
 modules/core/licenses/jBCrypt-license.txt       |   17 +
 .../configuration/IgniteConfiguration.java      |   26 +
 .../apache/ignite/internal/GridComponent.java   |    5 +-
 .../ignite/internal/GridKernalContext.java      |    8 +
 .../ignite/internal/GridKernalContextImpl.java  |   18 +-
 .../org/apache/ignite/internal/GridTopic.java   |    5 +-
 .../apache/ignite/internal/IgniteKernal.java    |    3 +
 .../ignite/internal/IgniteNodeAttributes.java   |    3 +
 .../jdbc/thin/ConnectionProperties.java         |   20 +
 .../jdbc/thin/ConnectionPropertiesImpl.java     |  120 +-
 .../internal/jdbc/thin/JdbcThinConnection.java  |    7 +-
 .../internal/jdbc/thin/JdbcThinTcpIo.java       |   18 +-
 .../communication/GridIoMessageFactory.java     |   20 +-
 .../discovery/CustomMessageWrapper.java         |    2 +-
 .../DiscoveryServerOnlyCustomMessage.java       |   26 +
 .../discovery/GridDiscoveryManager.java         |    6 +-
 .../processors/GridProcessorAdapter.java        |    1 -
 .../authentication/AuthorizationContext.java    |   89 ++
 .../IgniteAccessControlException.java           |   48 +
 .../IgniteAuthenticationProcessor.java          | 1346 ++++++++++++++++++
 .../processors/authentication/User.java         |  147 ++
 .../authentication/UserAcceptedMessage.java     |   98 ++
 .../UserAuthenticateRequestMessage.java         |  171 +++
 .../UserAuthenticateResponseMessage.java        |  154 ++
 .../authentication/UserManagementException.java |   48 +
 .../authentication/UserManagementOperation.java |  105 ++
 .../UserManagementOperationFinishedMessage.java |  155 ++
 .../authentication/UserProposedMessage.java     |   91 ++
 .../processors/cache/GridCacheProcessor.java    |    1 +
 .../GridDhtPartitionsExchangeFuture.java        |    2 +
 .../persistence/metastorage/MetaStorage.java    |    2 +-
 .../metastorage/ReadOnlyMetastorage.java        |    2 +-
 .../wal/reader/StandaloneGridKernalContext.java |    6 +
 .../cluster/GridClusterStateProcessor.java      |    3 +
 .../odbc/ClientListenerConnectionContext.java   |    5 +-
 .../odbc/jdbc/JdbcConnectionContext.java        |   33 +-
 .../odbc/jdbc/JdbcRequestHandler.java           |   13 +-
 .../apache/ignite/internal/sql/SqlKeyword.java  |    9 +
 .../apache/ignite/internal/sql/SqlLexer.java    |   26 +
 .../ignite/internal/sql/SqlLexerTokenType.java  |    3 +
 .../apache/ignite/internal/sql/SqlParser.java   |   20 +
 .../ignite/internal/sql/SqlParserUtils.java     |   28 +
 .../sql/command/SqlAlterUserCommand.java        |   79 +
 .../sql/command/SqlCreateUserCommand.java       |   79 +
 .../sql/command/SqlDropUserCommand.java         |   59 +
 .../ignite/internal/util/IgniteUtils.java       |   38 +
 .../ignite/spi/discovery/DiscoveryDataBag.java  |   18 +-
 .../ignite/spi/discovery/tcp/ClientImpl.java    |   15 +-
 .../ignite/spi/discovery/tcp/ServerImpl.java    |   19 +-
 .../tcp/internal/DiscoveryDataPacket.java       |   16 +-
 ...cpDiscoveryServerOnlyCustomEventMessage.java |   43 +
 .../core/src/main/java/org/mindrot/BCrypt.java  |  783 ++++++++++
 .../src/main/java/org/mindrot/package-info.java |   16 +
 .../resources/META-INF/classnames.properties    |    1 +
 .../Authentication1kUsersNodeRestartTest.java   |  107 ++
 .../AuthenticationConfigurationClusterTest.java |  204 +++
 .../AuthenticationOnNotActiveClusterTest.java   |  122 ++
 .../AuthenticationProcessorNodeRestartTest.java |  425 ++++++
 .../AuthenticationProcessorSelfTest.java        |  637 +++++++++
 .../WalModeChangeCommonAbstractSelfTest.java    |   16 +-
 .../internal/sql/SqlParserUserSelfTest.java     |  134 ++
 .../FilterDataForClientNodeDiscoveryTest.java   |  214 +++
 .../testsuites/IgniteCacheTestSuite6.java       |    9 +
 .../IgniteSpiDiscoverySelfTestSuite.java        |    3 +
 .../processors/query/h2/IgniteH2Indexing.java   |   15 +-
 .../query/h2/ddl/DdlStatementsProcessor.java    |   20 +-
 .../authentication/SqlUserCommandSelfTest.java  |  294 ++++
 .../IgniteCacheQuerySelfTestSuite.java          |    6 +
 parent/pom.xml                                  |    1 +
 72 files changed, 6472 insertions(+), 60 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/edef7add/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java
----------------------------------------------------------------------
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java
index 9ee6613..a88ebe8 100644
--- a/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java
+++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java
@@ -33,6 +33,7 @@ import org.apache.ignite.jdbc.JdbcPojoQuerySelfTest;
 import org.apache.ignite.jdbc.JdbcPreparedStatementSelfTest;
 import org.apache.ignite.jdbc.JdbcResultSetSelfTest;
 import org.apache.ignite.jdbc.JdbcStatementSelfTest;
+import org.apache.ignite.jdbc.thin.JdbcThinAuthenticateConnectionSelfTest;
 import org.apache.ignite.jdbc.thin.JdbcThinAutoCloseServerCursorTest;
 import org.apache.ignite.jdbc.thin.JdbcThinBatchSelfTest;
 import org.apache.ignite.jdbc.thin.JdbcThinBulkLoadAtomicPartitionedNearSelfTest;
@@ -192,6 +193,7 @@ public class IgniteJdbcDriverTestSuite extends TestSuite {
 
         // Various commands.
         suite.addTest(new TestSuite(JdbcThinWalModeChangeSelfTest.class));
+        suite.addTest(new TestSuite(JdbcThinAuthenticateConnectionSelfTest.class));
 
         return suite;
     }

http://git-wip-us.apache.org/repos/asf/ignite/blob/edef7add/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinAuthenticateConnectionSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinAuthenticateConnectionSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinAuthenticateConnectionSelfTest.java
new file mode 100644
index 0000000..97218fb
--- /dev/null
+++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinAuthenticateConnectionSelfTest.java
@@ -0,0 +1,235 @@
+/*
+ * 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.ignite.jdbc.thin;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.util.concurrent.Callable;
+import org.apache.ignite.configuration.DataRegionConfiguration;
+import org.apache.ignite.configuration.DataStorageConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.binary.BinaryMarshaller;
+import org.apache.ignite.internal.processors.authentication.AuthorizationContext;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.GridTestUtils;
+
+/**
+ * Tests for authenticated an non authenticated JDBC thin connection.
+ */
+@SuppressWarnings("ThrowableNotThrown")
+public class JdbcThinAuthenticateConnectionSelfTest extends JdbcThinAbstractSelfTest {
+    /** IP finder. */
+    private static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true);
+
+    /** */
+    private static final String URL = "jdbc:ignite:thin://127.0.0.1";
+
+    /** {@inheritDoc} */
+    @SuppressWarnings("deprecation")
+    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+        TcpDiscoverySpi disco = new TcpDiscoverySpi();
+
+        disco.setIpFinder(IP_FINDER);
+
+        cfg.setDiscoverySpi(disco);
+
+        cfg.setMarshaller(new BinaryMarshaller());
+
+        cfg.setAuthenticationEnabled(true);
+
+        cfg.setDataStorageConfiguration(new DataStorageConfiguration()
+            .setDefaultDataRegionConfiguration(new DataRegionConfiguration()
+                .setPersistenceEnabled(true)));
+
+        return cfg;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTest() throws Exception {
+        super.beforeTest();
+
+        U.resolveWorkDirectory(U.defaultWorkDirectory(), "db", true);
+
+        startGrids(2);
+
+        grid(0).cluster().active(true);
+
+        AuthorizationContext.context(grid(0).context().authentication().authenticate("ignite", "ignite"));
+
+        grid(0).context().authentication().addUser("another_user", "passwd");
+
+        AuthorizationContext.clear();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        stopAllGrids();
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testConnection() throws Exception {
+        checkConnection(URL, "ignite", "ignite");
+        checkConnection(URL, "another_user", "passwd");
+        checkConnection(URL + "?user=ignite&password=ignite", null, null);
+        checkConnection(URL + "?user=another_user&password=passwd", null, null);
+    }
+
+    /**
+     */
+    public void testInvalidUserPassword() {
+        String err = "Unauthenticated sessions are prohibited";
+        checkInvalidUserPassword(URL, null, null, err);
+
+        err = "The user name or password is incorrect";
+        checkInvalidUserPassword(URL, "ignite", null, err);
+        checkInvalidUserPassword(URL, "another_user", null, err);
+        checkInvalidUserPassword(URL, "ignite", "", err);
+        checkInvalidUserPassword(URL, "ignite", "password", err);
+        checkInvalidUserPassword(URL, "another_user", "ignite", err);
+        checkInvalidUserPassword(URL, "another_user", "password", err);
+        checkInvalidUserPassword(URL, "another_user", "password", err);
+    }
+
+    /**
+     * @throws SQLException On failed.
+     */
+    public void testUserSqlOnAuthorized() throws SQLException {
+        try (Connection conn = DriverManager.getConnection(URL, "ignite", "ignite")) {
+            conn.createStatement().execute("CREATE USER test WITH PASSWORD 'test'");
+
+            checkConnection(URL, "TEST", "test");
+
+            conn.createStatement().execute("ALTER USER test WITH PASSWORD 'newpasswd'");
+
+            checkConnection(URL, "TEST", "newpasswd");
+
+            conn.createStatement().execute("DROP USER test");
+
+            checkInvalidUserPassword(URL, "TEST", "newpasswd",
+                "The user name or password is incorrect");
+        }
+    }
+
+    /**
+     * @throws SQLException On error.
+     */
+    public void testUserSqlWithNotIgniteUser() throws SQLException {
+        try (Connection conn = DriverManager.getConnection(URL, "another_user", "passwd")) {
+            String err = "User management operations are not allowed for user";
+
+            checkUnauthorizedOperation(conn, "CREATE USER test WITH PASSWORD 'test'", err);
+            checkUnauthorizedOperation(conn, "ALTER USER test WITH PASSWORD 'newpasswd'", err);
+            checkUnauthorizedOperation(conn, "DROP USER test", err);
+            checkUnauthorizedOperation(conn, "DROP USER \"another_user\"", err);
+
+            conn.createStatement().execute("ALTER USER \"another_user\" WITH PASSWORD 'newpasswd'");
+
+            checkConnection(URL, "another_user", "newpasswd");
+        }
+    }
+
+    /**
+     * @throws SQLException On error.
+     */
+    public void testQuotedUsername() throws SQLException {
+        // Spaces
+        checkUserPassword(" test", "    ");
+        checkUserPassword(" test ", " test ");
+        checkUserPassword("test ", " ");
+        checkUserPassword(" ", " ");
+        checkUserPassword("user", "&/:=?");
+        checkUserPassword("user", "&");
+        checkUserPassword("user", "/");
+        checkUserPassword("user", ":");
+        checkUserPassword("user", "=");
+        checkUserPassword("user", "?");
+
+        // Nationals "user / password" in Russian.
+        checkUserPassword("\\u044E\\u0437\\u0435\\u0440", "\\u043F\\u0430\\u0440\\u043E\\u043B\\u044C");
+
+        // Nationals "user / password" in Chinese.
+        checkUserPassword("\\u7528\\u6236", "\\u5BC6\\u78BC");
+    }
+
+    /**
+     * @param user User name.
+     * @param passwd User's password.
+     * @throws SQLException On error.
+     */
+    private void checkUserPassword(String user, String passwd) throws SQLException {
+        try (Connection conn = DriverManager.getConnection(URL, "ignite", "ignite")) {
+            conn.createStatement().execute(String.format("CREATE USER \"%s\" WITH PASSWORD '%s'", user, passwd));
+
+            checkConnection(URL, user, passwd);
+            checkConnection(URL + String.format("?user={%s}&password={%s}", user, passwd), null, null);
+
+            conn.createStatement().execute(String.format("DROP USER \"%s\"", user));
+        }
+    }
+
+    /**
+     * @param url Connection URL.
+     * @param user User name.
+     * @param passwd User password.
+     * @throws SQLException On failed.
+     */
+    private void checkConnection(String url, String user, String passwd) throws SQLException {
+        try (Connection conn = DriverManager.getConnection(url, user, passwd)) {
+            conn.createStatement().execute("SELECT 1");
+        }
+    }
+
+    /**
+     * @param url Connection URL.
+     * @param user User name.
+     * @param passwd User password.
+     * @param err Error message pattern.
+     */
+    private void checkInvalidUserPassword(final String url, final String user, final String passwd, String err) {
+        GridTestUtils.assertThrows(log, new Callable<Void>() {
+            @Override public Void call() throws Exception {
+                checkConnection(url, user, passwd);
+
+                return null;
+            }
+        }, SQLException.class, err);
+    }
+
+    /**
+     * @param conn JDBC connection.
+     * @param sql SQL query.
+     * @param err Error message pattern.
+     */
+    private void checkUnauthorizedOperation(final Connection conn, final String sql, String err) {
+        GridTestUtils.assertThrows(log, new Callable<Void>() {
+            @Override public Void call() throws Exception {
+                conn.createStatement().execute(sql);
+
+                return null;
+            }
+        }, SQLException.class, err);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/edef7add/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinConnectionSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinConnectionSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinConnectionSelfTest.java
index b8746e4..14b91b2 100644
--- a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinConnectionSelfTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinConnectionSelfTest.java
@@ -1781,6 +1781,18 @@ public class JdbcThinConnectionSelfTest extends JdbcThinAbstractSelfTest {
     }
 
     /**
+     */
+    public void testAuthenticateDisableOnServerClientTryAuthenticate()  {
+        GridTestUtils.assertThrows(log, new Callable<Object>() {
+            @Override public Object call() throws Exception {
+                DriverManager.getConnection("jdbc:ignite:thin://127.0.0.1/?user=test&password=test");
+
+                return null;
+            }
+        }, SQLException.class, "Can not perform the operation because the authentication is not enabled for the cluster");
+    }
+
+    /**
      * @return Savepoint.
      */
     private Savepoint getFakeSavepoint() {

http://git-wip-us.apache.org/repos/asf/ignite/blob/edef7add/modules/core/licenses/jBCrypt-license.txt
----------------------------------------------------------------------
diff --git a/modules/core/licenses/jBCrypt-license.txt b/modules/core/licenses/jBCrypt-license.txt
new file mode 100644
index 0000000..e0e23ed
--- /dev/null
+++ b/modules/core/licenses/jBCrypt-license.txt
@@ -0,0 +1,17 @@
+jBCrypt is subject to the following license:
+
+/*
+ * Copyright (c) 2006 Damien Miller <dj...@mindrot.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/edef7add/modules/core/src/main/java/org/apache/ignite/configuration/IgniteConfiguration.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/configuration/IgniteConfiguration.java b/modules/core/src/main/java/org/apache/ignite/configuration/IgniteConfiguration.java
index 7dc4711..aa2fb00 100644
--- a/modules/core/src/main/java/org/apache/ignite/configuration/IgniteConfiguration.java
+++ b/modules/core/src/main/java/org/apache/ignite/configuration/IgniteConfiguration.java
@@ -486,6 +486,9 @@ public class IgniteConfiguration {
     /** Client connector configuration. */
     private ClientConnectorConfiguration cliConnCfg = ClientListenerProcessor.DFLT_CLI_CFG;
 
+    /** User authentication enabled. */
+    private boolean authEnabled;
+
     /**
      * Creates valid grid configuration with all default values.
      */
@@ -595,6 +598,7 @@ public class IgniteConfiguration {
         utilityCachePoolSize = cfg.getUtilityCacheThreadPoolSize();
         waitForSegOnStart = cfg.isWaitForSegmentOnStart();
         warmupClos = cfg.getWarmupClosure();
+        authEnabled = cfg.isAuthenticationEnabled();
     }
 
     /**
@@ -2927,6 +2931,28 @@ public class IgniteConfiguration {
         return cliConnCfg;
     }
 
+    /**
+     * Returns {@code true} if user authentication is enabled for cluster. Otherwise returns {@code false}.
+     * Default value is false; authentication is disabled.
+     *
+     * @return {@code true} if user authentication is enabled for cluster. Otherwise returns {@code false}.
+     */
+    public boolean isAuthenticationEnabled() {
+        return authEnabled;
+    }
+
+    /**
+     * Sets flag indicating whether the user authentication is enabled for cluster.
+     *
+     * @param authEnabled User authentication enabled flag. {@code true} enab
+     * @return {@code this} for chaining.
+     */
+    public IgniteConfiguration setAuthenticationEnabled(boolean authEnabled) {
+        this.authEnabled = authEnabled;
+
+        return this;
+    }
+
     /** {@inheritDoc} */
     @Override public String toString() {
         return S.toString(IgniteConfiguration.class, this);

http://git-wip-us.apache.org/repos/asf/ignite/blob/edef7add/modules/core/src/main/java/org/apache/ignite/internal/GridComponent.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/GridComponent.java b/modules/core/src/main/java/org/apache/ignite/internal/GridComponent.java
index 1e32e4f..504c83f 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/GridComponent.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/GridComponent.java
@@ -61,7 +61,10 @@ public interface GridComponent {
         BINARY_PROC,
 
         /** Query processor. */
-        QUERY_PROC
+        QUERY_PROC,
+
+        /** Authentication processor. */
+        AUTH_PROC
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/edef7add/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContext.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContext.java b/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContext.java
index a260327..ce53b47 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContext.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContext.java
@@ -33,6 +33,7 @@ import org.apache.ignite.internal.managers.failover.GridFailoverManager;
 import org.apache.ignite.internal.managers.indexing.GridIndexingManager;
 import org.apache.ignite.internal.managers.loadbalancer.GridLoadBalancerManager;
 import org.apache.ignite.internal.processors.affinity.GridAffinityProcessor;
+import org.apache.ignite.internal.processors.authentication.IgniteAuthenticationProcessor;
 import org.apache.ignite.internal.processors.cache.GridCacheProcessor;
 import org.apache.ignite.internal.processors.cache.persistence.filename.PdsFoldersResolver;
 import org.apache.ignite.internal.processors.cacheobject.IgniteCacheObjectProcessor;
@@ -255,6 +256,13 @@ public interface GridKernalContext extends Iterable<GridComponent> {
     public <K, V> DataStreamProcessor<K, V> dataStream();
 
     /**
+     * Gets authentication processor.
+     *
+     * @return Authentication processor.
+     */
+    public IgniteAuthenticationProcessor authentication();
+
+    /**
      * Gets file system processor.
      *
      * @return File system processor.

http://git-wip-us.apache.org/repos/asf/ignite/blob/edef7add/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java
index aaf2e8f..430b671 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/GridKernalContextImpl.java
@@ -47,6 +47,7 @@ import org.apache.ignite.internal.managers.failover.GridFailoverManager;
 import org.apache.ignite.internal.managers.indexing.GridIndexingManager;
 import org.apache.ignite.internal.managers.loadbalancer.GridLoadBalancerManager;
 import org.apache.ignite.internal.processors.affinity.GridAffinityProcessor;
+import org.apache.ignite.internal.processors.authentication.IgniteAuthenticationProcessor;
 import org.apache.ignite.internal.processors.cache.CacheConflictResolutionManager;
 import org.apache.ignite.internal.processors.cache.GridCacheProcessor;
 import org.apache.ignite.internal.processors.cache.binary.CacheObjectBinaryProcessorImpl;
@@ -151,7 +152,7 @@ public class GridKernalContextImpl implements GridKernalContext, Externalizable
 
     /** */
     @GridToStringExclude
-    private GridSecurityProcessor authProc;
+    private GridSecurityProcessor securityProc;
 
     /** */
     @GridToStringExclude
@@ -288,6 +289,10 @@ public class GridKernalContextImpl implements GridKernalContext, Externalizable
 
     /** */
     @GridToStringExclude
+    private IgniteAuthenticationProcessor authProc;
+
+    /** */
+    @GridToStringExclude
     private List<GridComponent> comps = new LinkedList<>();
 
     /** */
@@ -526,7 +531,7 @@ public class GridKernalContextImpl implements GridKernalContext, Externalizable
         else if (comp instanceof GridCollisionManager)
             colMgr = (GridCollisionManager)comp;
         else if (comp instanceof GridSecurityProcessor)
-            authProc = (GridSecurityProcessor)comp;
+            securityProc = (GridSecurityProcessor)comp;
         else if (comp instanceof GridLoadBalancerManager)
             loadMgr = (GridLoadBalancerManager)comp;
         else if (comp instanceof GridIndexingManager)
@@ -597,6 +602,8 @@ public class GridKernalContextImpl implements GridKernalContext, Externalizable
             pdsFolderRslvr = (PdsFoldersResolver)comp;
         else if (comp instanceof GridInternalSubscriptionProcessor)
             internalSubscriptionProc = (GridInternalSubscriptionProcessor)comp;
+        else if (comp instanceof IgniteAuthenticationProcessor)
+            authProc = (IgniteAuthenticationProcessor)comp;
         else if (!(comp instanceof DiscoveryNodeValidationProcessor
             || comp instanceof PlatformPluginProcessor))
             assert (comp instanceof GridPluginComponent) : "Unknown manager class: " + comp.getClass();
@@ -756,7 +763,7 @@ public class GridKernalContextImpl implements GridKernalContext, Externalizable
 
     /** {@inheritDoc} */
     @Override public GridSecurityProcessor security() {
-        return authProc;
+        return securityProc;
     }
 
     /** {@inheritDoc} */
@@ -856,6 +863,11 @@ public class GridKernalContextImpl implements GridKernalContext, Externalizable
     }
 
     /** {@inheritDoc} */
+    @Override public IgniteAuthenticationProcessor authentication() {
+        return authProc;
+    }
+
+    /** {@inheritDoc} */
     @Override public IgniteLogger log(String ctgr) {
         return config().getGridLogger().getLogger(ctgr);
     }

http://git-wip-us.apache.org/repos/asf/ignite/blob/edef7add/modules/core/src/main/java/org/apache/ignite/internal/GridTopic.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/GridTopic.java b/modules/core/src/main/java/org/apache/ignite/internal/GridTopic.java
index 7522881..4932e67 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/GridTopic.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/GridTopic.java
@@ -118,7 +118,10 @@ public enum GridTopic {
     TOPIC_INTERNAL_DIAGNOSTIC,
 
     /** */
-    TOPIC_WAL;
+    TOPIC_WAL,
+
+    /** */
+    TOPIC_AUTH;
 
     /** Enum values. */
     private static final GridTopic[] VALS = values();

http://git-wip-us.apache.org/repos/asf/ignite/blob/edef7add/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
index 9bfa8e7..843b6e1 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java
@@ -118,11 +118,13 @@ import org.apache.ignite.internal.managers.loadbalancer.GridLoadBalancerManager;
 import org.apache.ignite.internal.marshaller.optimized.OptimizedMarshaller;
 import org.apache.ignite.internal.processors.GridProcessor;
 import org.apache.ignite.internal.processors.affinity.GridAffinityProcessor;
+import org.apache.ignite.internal.processors.authentication.IgniteAuthenticationProcessor;
 import org.apache.ignite.internal.processors.cache.CacheConfigurationOverride;
 import org.apache.ignite.internal.processors.cache.GridCacheAdapter;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
 import org.apache.ignite.internal.processors.cache.GridCacheProcessor;
 import org.apache.ignite.internal.processors.cache.GridCacheUtilityKey;
+import org.apache.ignite.internal.processors.cache.GridCacheUtils;
 import org.apache.ignite.internal.processors.cache.IgniteCacheProxy;
 import org.apache.ignite.internal.processors.cache.IgniteInternalCache;
 import org.apache.ignite.internal.processors.cache.binary.CacheObjectBinaryProcessorImpl;
@@ -950,6 +952,7 @@ public class IgniteKernal implements IgniteEx, IgniteMXBean, Externalizable {
                 startProcessor(createComponent(GridSegmentationProcessor.class, ctx));
                 startProcessor(createComponent(IgniteCacheObjectProcessor.class, ctx));
                 startProcessor(createComponent(IGridClusterStateProcessor.class, ctx));
+                startProcessor(new IgniteAuthenticationProcessor(ctx));
                 startProcessor(new GridCacheProcessor(ctx));
                 startProcessor(new GridQueryProcessor(ctx));
                 startProcessor(new ClientListenerProcessor(ctx));

http://git-wip-us.apache.org/repos/asf/ignite/blob/edef7add/modules/core/src/main/java/org/apache/ignite/internal/IgniteNodeAttributes.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteNodeAttributes.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteNodeAttributes.java
index c78773f..073369f 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteNodeAttributes.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteNodeAttributes.java
@@ -193,6 +193,9 @@ public final class IgniteNodeAttributes {
     /** Data storage configuration. */
     public static final String ATTR_DATA_STORAGE_CONFIG = ATTR_PREFIX + ".data.storage.config";
 
+    /** User authentication enabled flag. */
+    public static final String ATTR_AUTHENTICATION_ENABLED = ATTR_PREFIX + ".authentication.enabled";
+
     /**
      * Enforces singleton.
      */

http://git-wip-us.apache.org/repos/asf/ignite/blob/edef7add/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/ConnectionProperties.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/ConnectionProperties.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/ConnectionProperties.java
index b368b9a..92355a0 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/ConnectionProperties.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/ConnectionProperties.java
@@ -362,4 +362,24 @@ public interface ConnectionProperties {
      * @param sslFactory Custom class name that implements Factory&lt;SSLSocketFactory&gt;.
      */
     public void setSslFactory(String sslFactory);
+
+    /**
+     * @param name User name to authentication.
+     */
+    public void setUsername(String name);
+
+    /**
+     * @return User name to authentication.
+     */
+    public String getUsername();
+
+    /**
+     * @param passwd User's password.
+     */
+    public void setPassword(String passwd);
+
+    /**
+     * @return User's password.
+     */
+    public String getPassword();
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/edef7add/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/ConnectionPropertiesImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/ConnectionPropertiesImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/ConnectionPropertiesImpl.java
index 4996781..5d77005 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/ConnectionPropertiesImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/ConnectionPropertiesImpl.java
@@ -22,6 +22,7 @@ import java.sql.DriverPropertyInfo;
 import java.sql.SQLException;
 import java.util.Arrays;
 import java.util.Properties;
+import java.util.StringTokenizer;
 import javax.naming.RefAddr;
 import javax.naming.Reference;
 import org.apache.ignite.IgniteCheckedException;
@@ -152,6 +153,14 @@ public class ConnectionPropertiesImpl implements ConnectionProperties, Serializa
     private StringProperty sslFactory = new StringProperty("sslFactory",
         "Custom class name that implements Factory<SSLSocketFactory>", null, null, false, null);
 
+    /** User name to authenticate the client on the server side. */
+    private StringProperty user = new StringProperty(
+        "user", "User name to authenticate the client on the server side", null, null, false, null);
+
+    /** User's password. */
+    private StringProperty passwd = new StringProperty(
+        "password", "User's password", null, null, false, null);
+
     /** Properties array. */
     private final ConnectionProperty [] propsArray = {
         distributedJoins, enforceJoinOrder, collocated, replicatedOnly, autoCloseServerCursor,
@@ -159,7 +168,8 @@ public class ConnectionPropertiesImpl implements ConnectionProperties, Serializa
         sslMode, sslProtocol, sslKeyAlgorithm,
         sslClientCertificateKeyStoreUrl, sslClientCertificateKeyStorePassword, sslClientCertificateKeyStoreType,
         sslTrustCertificateKeyStoreUrl, sslTrustCertificateKeyStorePassword, sslTrustCertificateKeyStoreType,
-        sslTrustAll, sslFactory
+        sslTrustAll, sslFactory,
+        user, passwd
     };
 
     /** {@inheritDoc} */
@@ -421,6 +431,26 @@ public class ConnectionPropertiesImpl implements ConnectionProperties, Serializa
         this.sslFactory.setValue(sslFactory);
     }
 
+    /** {@inheritDoc} */
+    @Override public void setUsername(String name) {
+        user.setValue(name);
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getUsername() {
+        return user.value();
+    }
+
+    /** {@inheritDoc} */
+    @Override public void setPassword(String passwd) {
+        this.passwd.setValue(passwd);
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getPassword() {
+        return passwd.value();
+    }
+
     /**
      * @param url URL connection.
      * @param props Environment properties.
@@ -434,6 +464,11 @@ public class ConnectionPropertiesImpl implements ConnectionProperties, Serializa
 
         for (ConnectionProperty aPropsArray : propsArray)
             aPropsArray.init(props0);
+
+        if (!F.isEmpty(props.getProperty("user"))) {
+            setUsername(props.getProperty("user"));
+            setPassword(props.getProperty("password"));
+        }
     }
 
     /**
@@ -452,12 +487,19 @@ public class ConnectionPropertiesImpl implements ConnectionProperties, Serializa
 
         String nakedUrl = url.substring(JdbcThinUtils.URL_PREFIX.length()).trim();
 
-        String[] nakedUrlParts = nakedUrl.split("\\?");
+        int pathPartEndPos = nakedUrl.indexOf('?');
+
+        if (pathPartEndPos == -1)
+            pathPartEndPos = nakedUrl.length();
+
+        String pathPart = nakedUrl.substring(0, pathPartEndPos);
 
-        if (nakedUrlParts.length > 2)
-            throw new SQLException("Invalid URL format (only one ? character is allowed): " + url);
+        String paramPart = null;
 
-        String[] pathParts = nakedUrlParts[0].split("/");
+        if (pathPartEndPos > 0 && pathPartEndPos < nakedUrl.length())
+            paramPart = nakedUrl.substring(pathPartEndPos + 1, nakedUrl.length());
+
+        String[] pathParts = pathPart.split("/");
 
         String [] endpoints = pathParts[0].split(",");
 
@@ -478,45 +520,79 @@ public class ConnectionPropertiesImpl implements ConnectionProperties, Serializa
         if (F.isEmpty(addrs) || F.isEmpty(addrs[0].host()))
             throw new SQLException("Host name is empty", SqlStateCode.CLIENT_CONNECTION_FAILED);
 
-        if (nakedUrlParts.length == 2)
-            parseParameters(nakedUrlParts[1], props);
-
         if (pathParts.length > 2) {
             throw new SQLException("Invalid URL format (only schema name is allowed in URL path parameter " +
                 "'host:port[/schemaName]'): " + url, SqlStateCode.CLIENT_CONNECTION_FAILED);
         }
 
         setSchema(pathParts.length == 2 ? pathParts[1] : null);
+
+        if (!F.isEmpty(paramPart))
+            parseParameters(paramPart, props);
     }
 
     /**
      * Validates and parses URL parameters.
      *
-     * @param str Parameters string.
+     * @param paramStr Parameters string.
      * @param props Properties.
      * @throws SQLException If failed.
      */
-    private void parseParameters(String str, Properties props) throws SQLException {
-        String[] params = str.split("&");
+    private void parseParameters(String paramStr, Properties props) throws SQLException {
+        StringTokenizer st = new StringTokenizer(paramStr, "&");
 
-        for (String param : params) {
-            String[] pair = param.split("=");
+        boolean insideBrace = false;
 
-            if (pair.length != 2)
-                throw new SQLException("Invalid parameter format (only one = character is allowed per key/value " +
-                    "pair: " + param, SqlStateCode.CLIENT_CONNECTION_FAILED);
+        String key = null;
+        String val = null;
 
-            String key = pair[0].trim();
-            String val = pair[1].trim();
+        while (st.hasMoreTokens()) {
+            String token = st.nextToken();
 
-            if (key.isEmpty() || val.isEmpty())
-                throw new SQLException("Invalid parameter format (key and value cannot be empty): " + param,
-                    SqlStateCode.CLIENT_CONNECTION_FAILED);
+            if (!insideBrace) {
+                int eqSymPos = token.indexOf('=');
+
+                if (eqSymPos < 0) {
+                    throw new SQLException("Invalid parameter format " +
+                        "(URL properties format: key0=value0&key1=value1&... etc. pair: " + token);
+                }
+
+                if (eqSymPos == token.length())
+                    throw new SQLException("Invalid parameter format (key and value cannot be empty): " + token);
 
-            props.setProperty(PROP_PREFIX + key, val);
+                key = token.substring(0, eqSymPos);
+                val = token.substring(eqSymPos + 1, token.length());
+
+                if (val.startsWith("{")) {
+                    val = val.substring(1);
+
+                    insideBrace = true;
+                }
+            }
+            else
+                val += "&" + token;
+
+            if (val.endsWith("}")) {
+                insideBrace = false;
+
+                val = val.substring(0, val.length() - 1);
+            }
+
+            if (val.contains("{") || val.contains("}")) {
+                throw new SQLException("Braces cannot be escaped in the value. " +
+                    "Please use the connection Properties for such values. [property=" + key + ']');
+            }
+
+            if (!insideBrace) {
+                if (key.isEmpty() || val.isEmpty())
+                    throw new SQLException("Invalid parameter format (key and value cannot be empty): " + token);
+
+                props.setProperty(PROP_PREFIX + key, val);
+            }
         }
     }
 
+
     /**
      * @return Driver's properties info array.
      */

http://git-wip-us.apache.org/repos/asf/ignite/blob/edef7add/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinConnection.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinConnection.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinConnection.java
index fb495d2..6bf768b 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinConnection.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinConnection.java
@@ -72,9 +72,6 @@ public class JdbcThinConnection implements Connection {
     /** Logger. */
     private static final Logger LOG = Logger.getLogger(JdbcThinConnection.class.getName());
 
-    /** Connection URL. */
-    private String url;
-
     /** Schema name. */
     private String schema;
 
@@ -130,8 +127,6 @@ public class JdbcThinConnection implements Connection {
      * @throws SQLException In case Ignite client failed to start.
      */
     public JdbcThinConnection(ConnectionProperties connProps) throws SQLException {
-        url = connProps.getUrl();
-
         this.connProps = connProps;
 
         holdability = HOLD_CURSORS_OVER_COMMIT;
@@ -799,7 +794,7 @@ public class JdbcThinConnection implements Connection {
      * @return Connection URL.
      */
     public String url() {
-        return url;
+        return connProps.getUrl();
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/edef7add/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java
index a60d0f9..bfd553d 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java
@@ -66,8 +66,11 @@ public class JdbcThinTcpIo {
     /** Version 2.4.0. */
     private static final ClientListenerProtocolVersion VER_2_4_0 = ClientListenerProtocolVersion.create(2, 4, 0);
 
+    /** Version 2.5.0. */
+    private static final ClientListenerProtocolVersion VER_2_5_0 = ClientListenerProtocolVersion.create(2, 5, 0);
+
     /** Current version. */
-    private static final ClientListenerProtocolVersion CURRENT_VER = VER_2_4_0;
+    private static final ClientListenerProtocolVersion CURRENT_VER = VER_2_5_0;
 
     /** Initial output stream capacity for handshake. */
     private static final int HANDSHAKE_MSG_SIZE = 13;
@@ -286,6 +289,13 @@ public class JdbcThinTcpIo {
         writer.writeBoolean(connProps.isLazy());
         writer.writeBoolean(connProps.isSkipReducerOnUpdate());
 
+        if (!F.isEmpty(connProps.getUsername())) {
+            assert ver.compareTo(VER_2_5_0) >= 0 : "Authentication is supported since 2.5";
+
+            writer.writeString(connProps.getUsername());
+            writer.writeString(connProps.getPassword());
+        }
+
         send(writer.array());
 
         BinaryReaderExImpl reader = new BinaryReaderExImpl(null, new BinaryHeapInputStream(read()),
@@ -318,6 +328,12 @@ public class JdbcThinTcpIo {
 
             ClientListenerProtocolVersion srvProtocolVer = ClientListenerProtocolVersion.create(maj, min, maintenance);
 
+            if (srvProtocolVer.compareTo(VER_2_5_0) < 0 && !F.isEmpty(connProps.getUsername())) {
+                throw new SQLException("Authentication doesn't support by remote server[driverProtocolVer=" + CURRENT_VER +
+                    ", remoteNodeProtocolVer=" + srvProtocolVer + ", err=" + err + ", url=" + connProps.getUrl() + ']',
+                    SqlStateCode.CONNECTION_REJECTED);
+            }
+
             if (VER_2_4_0.equals(srvProtocolVer) || VER_2_3_0.equals(srvProtocolVer) ||
                 VER_2_1_5.equals(srvProtocolVer))
                 handshake(srvProtocolVer);

http://git-wip-us.apache.org/repos/asf/ignite/blob/edef7add/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java
index 0f952d9..a0fc2f8 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessageFactory.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.internal.managers.communication;
 
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 import org.apache.ignite.IgniteException;
 import org.apache.ignite.internal.GridJobCancelRequest;
 import org.apache.ignite.internal.GridJobExecuteRequest;
@@ -35,6 +36,9 @@ import org.apache.ignite.internal.managers.deployment.GridDeploymentRequest;
 import org.apache.ignite.internal.managers.deployment.GridDeploymentResponse;
 import org.apache.ignite.internal.managers.eventstorage.GridEventStorageMessage;
 import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
+import org.apache.ignite.internal.processors.authentication.UserAuthenticateRequestMessage;
+import org.apache.ignite.internal.processors.authentication.UserAuthenticateResponseMessage;
+import org.apache.ignite.internal.processors.authentication.UserManagementOperationFinishedMessage;
 import org.apache.ignite.internal.processors.cache.CacheEntryInfoCollection;
 import org.apache.ignite.internal.processors.cache.CacheEntryPredicateContainsValue;
 import org.apache.ignite.internal.processors.cache.CacheEntrySerializablePredicate;
@@ -160,7 +164,6 @@ import org.apache.ignite.spi.communication.tcp.messages.HandshakeMessage;
 import org.apache.ignite.spi.communication.tcp.messages.HandshakeMessage2;
 import org.apache.ignite.spi.communication.tcp.messages.NodeIdMessage;
 import org.apache.ignite.spi.communication.tcp.messages.RecoveryLastReceivedMessage;
-import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * Message factory implementation.
@@ -891,6 +894,21 @@ public class GridIoMessageFactory implements MessageFactory {
 
                 break;
 
+            case 130:
+                msg = new UserManagementOperationFinishedMessage();
+
+                break;
+
+            case 131:
+                msg = new UserAuthenticateRequestMessage();
+
+                break;
+
+            case 132:
+                msg = new UserAuthenticateResponseMessage();
+
+                break;
+
             // [-3..119] [124..129] [-23..-27] [-36..-55]- this
             // [120..123] - DR
             // [-4..-22, -30..-35] - SQL

http://git-wip-us.apache.org/repos/asf/ignite/blob/edef7add/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/CustomMessageWrapper.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/CustomMessageWrapper.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/CustomMessageWrapper.java
index 8f56248..4268886 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/CustomMessageWrapper.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/CustomMessageWrapper.java
@@ -23,7 +23,7 @@ import org.jetbrains.annotations.Nullable;
 /**
  *
  */
-class CustomMessageWrapper implements DiscoverySpiCustomMessage {
+public class CustomMessageWrapper implements DiscoverySpiCustomMessage {
     /** */
     private static final long serialVersionUID = 0L;
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/edef7add/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/DiscoveryServerOnlyCustomMessage.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/DiscoveryServerOnlyCustomMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/DiscoveryServerOnlyCustomMessage.java
new file mode 100644
index 0000000..7c341a0
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/DiscoveryServerOnlyCustomMessage.java
@@ -0,0 +1,26 @@
+/*
+ * 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.ignite.internal.managers.discovery;
+
+/**
+ * <b>DiscoveryServerOnlyCustomMessage</b> is the special subtype of the <b>DiscoveryCustomMessage</b> message
+ * that is delivered only on server nodes of the cluster.
+ */
+public interface DiscoveryServerOnlyCustomMessage extends DiscoveryCustomMessage {
+    // No-op.
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/edef7add/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java
index e336667..707b1ba 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java
@@ -75,6 +75,7 @@ import org.apache.ignite.internal.processors.cache.DynamicCacheChangeRequest;
 import org.apache.ignite.internal.processors.cache.DynamicCacheDescriptor;
 import org.apache.ignite.internal.processors.cache.GridCacheAdapter;
 import org.apache.ignite.internal.processors.cache.GridCacheContext;
+import org.apache.ignite.internal.processors.cache.GridCacheUtils;
 import org.apache.ignite.internal.processors.cache.persistence.GridCacheDatabaseSharedManager;
 import org.apache.ignite.internal.processors.cluster.BaselineTopology;
 import org.apache.ignite.internal.processors.cluster.ChangeGlobalStateFinishMessage;
@@ -754,9 +755,12 @@ public class GridDiscoveryManager extends GridManagerAdapter<DiscoverySpi> {
 
                     discoWrk.discoCache = discoCache;
 
-                    if (!isLocDaemon && !ctx.clientDisconnected())
+                    if (!isLocDaemon && !ctx.clientDisconnected()) {
                         ctx.cache().context().exchange().onLocalJoin(discoEvt, discoCache);
 
+                        ctx.authentication().onLocalJoin();
+                    }
+
                     IgniteInternalFuture<Boolean> transitionWaitFut = ctx.state().onLocalJoin(discoCache);
 
                     locJoin.onDone(new DiscoveryLocalJoinData(discoEvt,

http://git-wip-us.apache.org/repos/asf/ignite/blob/edef7add/modules/core/src/main/java/org/apache/ignite/internal/processors/GridProcessorAdapter.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/GridProcessorAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/GridProcessorAdapter.java
index cda6850..6496b6c 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/GridProcessorAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/GridProcessorAdapter.java
@@ -19,7 +19,6 @@ package org.apache.ignite.internal.processors;
 
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.IgniteLogger;
-import org.apache.ignite.IgniteSystemProperties;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.internal.GridKernalContext;
 import org.apache.ignite.internal.IgniteInternalFuture;

http://git-wip-us.apache.org/repos/asf/ignite/blob/edef7add/modules/core/src/main/java/org/apache/ignite/internal/processors/authentication/AuthorizationContext.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/authentication/AuthorizationContext.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/authentication/AuthorizationContext.java
new file mode 100644
index 0000000..8f22158
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/authentication/AuthorizationContext.java
@@ -0,0 +1,89 @@
+/*
+ * 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.ignite.internal.processors.authentication;
+
+/**
+ * Ignite authentication context.
+ */
+public class AuthorizationContext {
+    /** User. */
+    private final User user;
+
+    /** Current authorization context. */
+    private static ThreadLocal<AuthorizationContext> actx = new ThreadLocal<>();
+
+    /**
+     * Creates authentication context.
+     *
+     * @param user Authorized user.
+     */
+    public AuthorizationContext(User user) {
+        assert user != null;
+
+        this.user = user;
+    }
+
+    /**
+     * @return Authorized user.
+     */
+    public String userName() {
+        return user.name();
+    }
+
+    /**
+     * @param op User operation to check.
+     * @throws IgniteAccessControlException If operation check fails: user hasn't permissions for user management
+     *      or try to remove default user.
+     */
+    public void checkUserOperation(UserManagementOperation op) throws IgniteAccessControlException {
+        assert op != null;
+
+        if (user == null)
+            throw new IgniteAccessControlException("Operation not allowed: authorized context is empty.");
+
+        if (!User.DFAULT_USER_NAME.equals(user.name())
+            && !(UserManagementOperation.OperationType.UPDATE == op.type() && user.name().equals(op.user().name())))
+            throw new IgniteAccessControlException("User management operations are not allowed for user. " +
+                "[curUser=" + user.name() + ']');
+
+        if (op.type() == UserManagementOperation.OperationType.REMOVE
+            && User.DFAULT_USER_NAME.equals(op.user().name()))
+            throw new IgniteAccessControlException("Default user cannot be removed.");
+    }
+
+    /**
+     * @param actx Authorization context to set.
+     */
+    public static void context(AuthorizationContext actx) {
+        AuthorizationContext.actx.set(actx);
+    }
+
+    /**
+     * Clear authentication context.
+     */
+    public static void clear() {
+        actx.set(null);
+    }
+
+    /**
+     * @return Current authorization context.
+     */
+    public static AuthorizationContext context() {
+        return actx.get();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/edef7add/modules/core/src/main/java/org/apache/ignite/internal/processors/authentication/IgniteAccessControlException.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/authentication/IgniteAccessControlException.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/authentication/IgniteAccessControlException.java
new file mode 100644
index 0000000..7f2de39
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/authentication/IgniteAccessControlException.java
@@ -0,0 +1,48 @@
+/*
+ * 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.ignite.internal.processors.authentication;
+
+import org.apache.ignite.IgniteCheckedException;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Exception that represents authentication / authorization failure.
+ */
+public class IgniteAccessControlException extends IgniteCheckedException {
+    /** */
+    private static final long serialVersionUID = 0L;
+
+    /**
+     * Creates access control exception.
+     *
+     * @param msg Error message.
+     */
+    public IgniteAccessControlException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Creates authentication exception with given error message.
+     *
+     * @param msg Error message.
+     * @param cause Optional nested exception (can be {@code null}).
+     */
+    public IgniteAccessControlException(String msg, @Nullable Throwable cause) {
+        super(msg, cause);
+    }
+}
\ No newline at end of file