kudu-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From danburk...@apache.org
Subject [1/2] kudu git commit: java: support TLS_AUTHENTICATION_ONLY
Date Wed, 22 Feb 2017 22:35:54 GMT
Repository: kudu
Updated Branches:
  refs/heads/master 07e55ed0b -> ed44a20df


java: support TLS_AUTHENTICATION_ONLY

This is tested by a new unit test. Unfortunately an integration test is
slightly tricky since the daemons run on a different loopback IP than
they connect from.

Change-Id: I3c0dcca560a4a96a449fc0f5324e404f10247905
Reviewed-on: http://gerrit.cloudera.org:8080/6087
Tested-by: Kudu Jenkins
Reviewed-by: Alexey Serbin <aserbin@cloudera.com>
Reviewed-by: Dan Burkert <danburkert@apache.org>


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

Branch: refs/heads/master
Commit: 73aa301342200c3f5e06dacdcf59fdb5eb722925
Parents: 07e55ed
Author: Todd Lipcon <todd@apache.org>
Authored: Mon Feb 20 14:52:18 2017 -0800
Committer: Todd Lipcon <todd@apache.org>
Committed: Wed Feb 22 21:45:04 2017 +0000

----------------------------------------------------------------------
 .../java/org/apache/kudu/client/Negotiator.java | 40 +++++++++++++++--
 .../org/apache/kudu/client/TestNegotiator.java  | 47 +++++++++++++++++---
 2 files changed, 77 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/kudu/blob/73aa3013/java/kudu-client/src/main/java/org/apache/kudu/client/Negotiator.java
----------------------------------------------------------------------
diff --git a/java/kudu-client/src/main/java/org/apache/kudu/client/Negotiator.java b/java/kudu-client/src/main/java/org/apache/kudu/client/Negotiator.java
index 856a2bc..1457fcf 100644
--- a/java/kudu-client/src/main/java/org/apache/kudu/client/Negotiator.java
+++ b/java/kudu-client/src/main/java/org/apache/kudu/client/Negotiator.java
@@ -26,6 +26,8 @@
 
 package org.apache.kudu.client;
 
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
 import java.security.PrivilegedExceptionAction;
 import java.security.cert.Certificate;
 import java.util.List;
@@ -45,6 +47,7 @@ import javax.security.sasl.Sasl;
 import javax.security.sasl.SaslClient;
 import javax.security.sasl.SaslException;
 
+import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Joiner;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Throwables;
@@ -157,6 +160,9 @@ public class Negotiator extends SimpleChannelUpstreamHandler {
 
   private Certificate peerCert;
 
+  @VisibleForTesting
+  boolean overrideLoopbackForTests;
+
   public Negotiator(String remoteHostname, SecurityContext securityContext) {
     this.remoteHostname = remoteHostname;
     this.securityContext = securityContext;
@@ -176,8 +182,9 @@ public class Negotiator extends SimpleChannelUpstreamHandler {
     for (RpcHeader.RpcFeatureFlag flag : SUPPORTED_RPC_FEATURES) {
       builder.addSupportedFeatures(flag);
     }
-    // TODO(todd): if we are on a loopback connection, advertise and support
-    // TLS_AUTHENTICATION_ONLY.
+    if (isLoopbackConnection(channel)) {
+      builder.addSupportedFeatures(RpcFeatureFlag.TLS_AUTHENTICATION_ONLY);
+    }
 
     // Advertise our authentication types.
     // ----------------------------------
@@ -297,6 +304,25 @@ public class Negotiator extends SimpleChannelUpstreamHandler {
     }
   }
 
+  /**
+   * Determine whether the given channel is a loopback connection (i.e. the server
+   * and client are on the same host).
+   */
+  private boolean isLoopbackConnection(Channel channel) {
+    if (overrideLoopbackForTests) {
+      return true;
+    }
+    try {
+      InetAddress local = ((InetSocketAddress)channel.getLocalAddress()).getAddress();
+      InetAddress remote = ((InetSocketAddress)channel.getRemoteAddress()).getAddress();
+      return local.equals(remote);
+    } catch (ClassCastException cce) {
+      // In the off chance that we have some other type of local/remote address,
+      // we'll just assume it's not loopback.
+      return false;
+    }
+  }
+
   private void chooseAndInitializeSaslMech(NegotiatePB response) throws SaslException {
     // Gather the set of server-supported mechanisms.
     Set<String> serverMechs = Sets.newHashSet();
@@ -371,7 +397,7 @@ public class Negotiator extends SimpleChannelUpstreamHandler {
   private Set<RpcFeatureFlag> getFeatureFlags(NegotiatePB response) {
     ImmutableSet.Builder<RpcHeader.RpcFeatureFlag> features = ImmutableSet.builder();
     for (RpcHeader.RpcFeatureFlag feature : response.getSupportedFeaturesList()) {
-      if (SUPPORTED_RPC_FEATURES.contains(feature)) {
+      if (feature != RpcFeatureFlag.UNKNOWN) {
         features.add(feature);
       }
     }
@@ -420,6 +446,7 @@ public class Negotiator extends SimpleChannelUpstreamHandler {
       // Data was sent -- we must continue the handshake process.
       return;
     }
+
     // The handshake completed.
     // Insert the SSL handler into the pipeline so that all following traffic
     // gets encrypted, and then move on to the SASL portion of negotiation.
@@ -436,7 +463,12 @@ public class Negotiator extends SimpleChannelUpstreamHandler {
       throw Throwables.propagate(e);
     }
 
-    chan.getPipeline().addFirst("tls", handler);
+    // Don't wrap the TLS socket if we are using TLS for authentication only.
+    boolean isAuthOnly = serverFeatures.contains(RpcFeatureFlag.TLS_AUTHENTICATION_ONLY)
&&
+        isLoopbackConnection(chan);
+    if (!isAuthOnly) {
+      chan.getPipeline().addFirst("tls", handler);
+    }
     startAuthentication(chan);
   }
 

http://git-wip-us.apache.org/repos/asf/kudu/blob/73aa3013/java/kudu-client/src/test/java/org/apache/kudu/client/TestNegotiator.java
----------------------------------------------------------------------
diff --git a/java/kudu-client/src/test/java/org/apache/kudu/client/TestNegotiator.java b/java/kudu-client/src/test/java/org/apache/kudu/client/TestNegotiator.java
index 6df45de..b4885f3 100644
--- a/java/kudu-client/src/test/java/org/apache/kudu/client/TestNegotiator.java
+++ b/java/kudu-client/src/test/java/org/apache/kudu/client/TestNegotiator.java
@@ -95,11 +95,11 @@ public class TestNegotiator {
         AccessController.getContext()));
   }
 
-  private Negotiator startNegotiation() {
+  private void startNegotiation(boolean fakeLoopback) {
     Negotiator negotiator = new Negotiator("127.0.0.1", secContext);
+    negotiator.overrideLoopbackForTests = fakeLoopback;
     embedder = new DecoderEmbedder<Object>(negotiator);
     negotiator.sendHello(embedder.getPipeline().getChannel());
-    return negotiator;
   }
 
   static CallResponse fakeResponse(ResponseHeader header, Message body) {
@@ -157,7 +157,7 @@ public class TestNegotiator {
    */
   @Test
   public void testNegotiation() {
-    startNegotiation();
+    startNegotiation(false);
 
     // Expect client->server: NEGOTIATE.
     RpcOutboundMessage msg = (RpcOutboundMessage) embedder.poll();
@@ -262,7 +262,7 @@ public class TestNegotiator {
 
   @Test
   public void testTlsNegotiation() throws Exception {
-    startNegotiation();
+    startNegotiation(false);
 
     // Expect client->server: NEGOTIATE, TLS included.
     RpcOutboundMessage msg = (RpcOutboundMessage) embedder.poll();
@@ -295,6 +295,41 @@ public class TestNegotiator {
     assertEquals(NegotiateStep.SASL_INITIATE, body.getStep());
   }
 
+  @Test
+  public void testTlsNegotiationAuthOnly() throws Exception {
+    startNegotiation(true);
+
+    // Expect client->server: NEGOTIATE, TLS and TLS_AUTHENTICATION_ONLY included.
+    RpcOutboundMessage msg = (RpcOutboundMessage) embedder.poll();
+    NegotiatePB body = (NegotiatePB) msg.getBody();
+    assertEquals(NegotiateStep.NEGOTIATE, body.getStep());
+    assertTrue(body.getSupportedFeaturesList().contains(RpcFeatureFlag.TLS));
+    assertTrue(body.getSupportedFeaturesList().contains(
+        RpcFeatureFlag.TLS_AUTHENTICATION_ONLY));
+
+    // Fake a server response with TLS and TLS_AUTHENTICATION_ONLY enabled.
+    embedder.offer(fakeResponse(
+        ResponseHeader.newBuilder().setCallId(Negotiator.SASL_CALL_ID).build(),
+        NegotiatePB.newBuilder()
+          .addSaslMechanisms(NegotiatePB.SaslMechanism.newBuilder().setMechanism("PLAIN"))
+          .addSupportedFeatures(RpcFeatureFlag.TLS)
+          .addSupportedFeatures(RpcFeatureFlag.TLS_AUTHENTICATION_ONLY)
+          .setStep(NegotiateStep.NEGOTIATE)
+          .build()));
+
+    // Expect client->server: TLS_HANDSHAKE.
+    runTlsHandshake();
+
+    // The pipeline should *not* have an SSL handler as the first handler,
+    // since we used TLS for authentication only.
+    assertFalse(embedder.getPipeline().getFirst() instanceof SslHandler);
+
+    // The Negotiator should have sent the SASL_INITIATE at this point.
+    msg = (RpcOutboundMessage) embedder.poll();
+    body = (NegotiatePB) msg.getBody();
+    assertEquals(NegotiateStep.SASL_INITIATE, body.getStep());
+  }
+
   /**
    * Test that, if we don't have any trusted certs, we don't expose
    * token authentication as an option.
@@ -302,7 +337,7 @@ public class TestNegotiator {
   @Test
   public void testNoTokenAuthWhenNoTrustedCerts() throws Exception {
     secContext.setAuthenticationToken(SignedTokenPB.getDefaultInstance());
-    startNegotiation();
+    startNegotiation(false);
 
     // Expect client->server: NEGOTIATE, TLS included, Token not included.
     RpcOutboundMessage msg = (RpcOutboundMessage) embedder.poll();
@@ -321,7 +356,7 @@ public class TestNegotiator {
   public void testTokenAuthWithTrustedCerts() throws Exception {
     secContext.trustCertificate(ByteString.copyFromUtf8(CA_CERT_DER));
     secContext.setAuthenticationToken(SignedTokenPB.getDefaultInstance());
-    startNegotiation();
+    startNegotiation(false);
 
     // Expect client->server: NEGOTIATE, TLS included, Token included.
     RpcOutboundMessage msg = (RpcOutboundMessage) embedder.poll();


Mime
View raw message