ignite-4044 always authenticate local node
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/bac0cba7 Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/bac0cba7 Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/bac0cba7 Branch: refs/heads/ignite-4242 Commit: bac0cba7fddd412dfbff98163afbc15d81d5e0d4 Parents: cdae2ab Author: Dmitriy Govorukhin <[email protected]> Authored: Thu Nov 10 09:02:41 2016 +0300 Committer: Dmitriy Govorukhin <[email protected]> Committed: Thu Nov 10 09:02:41 2016 +0300 ---------------------------------------------------------------------- .../ignite/spi/discovery/tcp/ServerImpl.java | 112 +++++++++++++++---- 1 file changed, 89 insertions(+), 23 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/bac0cba7/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java index 55e5c89..0de787d 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java @@ -815,33 +815,24 @@ class ServerImpl extends TcpDiscoveryImpl { SecurityCredentials locCred = (SecurityCredentials)locNode.getAttributes() .get(IgniteNodeAttributes.ATTR_SECURITY_CREDENTIALS); + boolean auth = false; + + if (spi.nodeAuth != null && spi.nodeAuth.isGlobalNodeAuthentication()) { + localAuthentication(locCred); + + auth = true; + } + // Marshal credentials for backward compatibility and security. - marshalCredentials(locNode); + marshalCredentials(locNode, locCred); while (true) { if (!sendJoinRequestMessage()) { if (log.isDebugEnabled()) log.debug("Join request message has not been sent (local node is the first in the topology)."); - if (spi.nodeAuth != null) { - // Authenticate local node. - try { - SecurityContext subj = spi.nodeAuth.authenticateNode(locNode, locCred); - - if (subj == null) - throw new IgniteSpiException("Authentication failed for local node: " + locNode.id()); - - Map<String, Object> attrs = new HashMap<>(locNode.attributes()); - - attrs.put(IgniteNodeAttributes.ATTR_SECURITY_SUBJECT, U.marshal(spi.marshaller(), subj)); - attrs.remove(IgniteNodeAttributes.ATTR_SECURITY_CREDENTIALS); - - locNode.setAttributes(attrs); - } - catch (IgniteException | IgniteCheckedException e) { - throw new IgniteSpiException("Failed to authenticate local node (will shutdown local node).", e); - } - } + if (!auth && spi.nodeAuth != null) + localAuthentication(locCred); locNode.order(1); locNode.internalOrder(1); @@ -920,6 +911,8 @@ class ServerImpl extends TcpDiscoveryImpl { } } + locNode.attributes().remove(IgniteNodeAttributes.ATTR_SECURITY_CREDENTIALS); + assert locNode.order() != 0; assert locNode.internalOrder() != 0; @@ -928,6 +921,33 @@ class ServerImpl extends TcpDiscoveryImpl { } /** + * Authenticate local node. + * + * @param locCred Local security credentials for authentication. + * @throws IgniteSpiException If any error occurs. + */ + private void localAuthentication(SecurityCredentials locCred){ + assert spi.nodeAuth != null; + assert locCred != null; + + try { + SecurityContext subj = spi.nodeAuth.authenticateNode(locNode, locCred); + + if (subj == null) + throw new IgniteSpiException("Authentication failed for local node: " + locNode.id()); + + Map<String, Object> attrs = new HashMap<>(locNode.attributes()); + + attrs.put(IgniteNodeAttributes.ATTR_SECURITY_SUBJECT, U.marshal(spi.marshaller(), subj)); + + locNode.setAttributes(attrs); + + } catch (IgniteException | IgniteCheckedException e) { + throw new IgniteSpiException("Failed to authenticate local node (will shutdown local node).", e); + } + } + + /** * Tries to send join request message to a random node presenting in topology. * Address is provided by {@link org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder} and message is * sent to first node connection succeeded to. @@ -1241,15 +1261,15 @@ class ServerImpl extends TcpDiscoveryImpl { * Marshalls credentials with discovery SPI marshaller (will replace attribute value). * * @param node Node to marshall credentials for. + * @param cred Credentials for marshall. * @throws IgniteSpiException If marshalling failed. */ - private void marshalCredentials(TcpDiscoveryNode node) throws IgniteSpiException { + private void marshalCredentials(TcpDiscoveryNode node, SecurityCredentials cred) throws IgniteSpiException { try { // Use security-unsafe getter. Map<String, Object> attrs = new HashMap<>(node.getAttributes()); - attrs.put(IgniteNodeAttributes.ATTR_SECURITY_CREDENTIALS, - U.marshal(spi.marshaller(), attrs.get(IgniteNodeAttributes.ATTR_SECURITY_CREDENTIALS))); + attrs.put(IgniteNodeAttributes.ATTR_SECURITY_CREDENTIALS, spi.marshaller().marshal(cred)); node.setAttributes(attrs); } @@ -3906,6 +3926,52 @@ class ServerImpl extends TcpDiscoveryImpl { if (top != null && !top.isEmpty()) { spi.gridStartTime = msg.gridStartTime(); + if (spi.nodeAuth != null && spi.nodeAuth.isGlobalNodeAuthentication()) { + TcpDiscoveryAbstractMessage authFail = + new TcpDiscoveryAuthFailedMessage(locNodeId, spi.locHost); + + try { + ClassLoader cl = U.resolveClassLoader(spi.ignite().configuration()); + + byte[] rmSubj = node.attribute(IgniteNodeAttributes.ATTR_SECURITY_SUBJECT); + byte[] locSubj = locNode.attribute(IgniteNodeAttributes.ATTR_SECURITY_SUBJECT); + + SecurityContext rmCrd = spi.marshaller().unmarshal(rmSubj, cl); + SecurityContext locCrd = spi.marshaller().unmarshal(locSubj, cl); + + if (!permissionsEqual(locCrd.subject().permissions(), + rmCrd.subject().permissions())) { + // Node has not pass authentication. + LT.warn(log, + null, + "Failed to authenticate local node " + + "(local authentication result is different from rest of topology) " + + "[nodeId=" + node.id() + ", addrs=" + U.addressesAsString(node) + ']', + "Authentication failed [nodeId=" + U.id8(node.id()) + + ", addrs=" + U.addressesAsString(node) + ']'); + + joinRes.set(authFail); + + spiState = AUTH_FAILED; + + mux.notifyAll(); + + return; + } + } + catch (IgniteCheckedException e) { + U.error(log, "Failed to verify node permissions consistency (will drop the node): " + node, e); + + joinRes.set(authFail); + + spiState = AUTH_FAILED; + + mux.notifyAll(); + + return; + } + } + for (TcpDiscoveryNode n : top) { assert n.internalOrder() < node.internalOrder() : "Invalid node [topNode=" + n + ", added=" + node + ']';
