Repository: kudu Updated Branches: refs/heads/master f62e4cd0e -> cd7166cb7
[java] add test to reproduce KUDU-2267 Currently, if a master has never been a leader from the very start of the cluster, it has just self-signed server TLS certificate. In that case if a client does not have any valid Kerberos credentials but only authn token, then the client may see negotiation failure error and is not able to connect. This patch adds a regression test for this issue. Change-Id: I4879749988dc884fe81cf36838819379db91ae72 Reviewed-on: http://gerrit.cloudera.org:8080/9071 Tested-by: Kudu Jenkins Reviewed-by: Alexey Serbin <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/kudu/repo Commit: http://git-wip-us.apache.org/repos/asf/kudu/commit/0f0e4214 Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/0f0e4214 Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/0f0e4214 Branch: refs/heads/master Commit: 0f0e42144a0d37f57394b373eb75eeb18bc28174 Parents: f62e4cd Author: hahao <[email protected]> Authored: Thu Jan 18 16:06:46 2018 -0800 Committer: Hao Hao <[email protected]> Committed: Thu Jan 25 03:05:16 2018 +0000 ---------------------------------------------------------------------- .../org/apache/kudu/client/AsyncKuduClient.java | 5 +++ .../apache/kudu/client/ConnectToCluster.java | 20 ++++++++-- .../org/apache/kudu/client/TestSecurity.java | 40 +++++++++++++++++++- 3 files changed, 59 insertions(+), 6 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/kudu/blob/0f0e4214/java/kudu-client/src/main/java/org/apache/kudu/client/AsyncKuduClient.java ---------------------------------------------------------------------- diff --git a/java/kudu-client/src/main/java/org/apache/kudu/client/AsyncKuduClient.java b/java/kudu-client/src/main/java/org/apache/kudu/client/AsyncKuduClient.java index dd282ff..de36e3d 100644 --- a/java/kudu-client/src/main/java/org/apache/kudu/client/AsyncKuduClient.java +++ b/java/kudu-client/src/main/java/org/apache/kudu/client/AsyncKuduClient.java @@ -745,6 +745,11 @@ public class AsyncKuduClient implements AutoCloseable { return requestTracker; } + @VisibleForTesting + KuduTable getMasterTable() { + return masterTable; + } + /** * Creates a new {@link AsyncKuduScanner.AsyncKuduScannerBuilder} for a particular table. * @param table the name of the table you intend to scan. http://git-wip-us.apache.org/repos/asf/kudu/blob/0f0e4214/java/kudu-client/src/main/java/org/apache/kudu/client/ConnectToCluster.java ---------------------------------------------------------------------- diff --git a/java/kudu-client/src/main/java/org/apache/kudu/client/ConnectToCluster.java b/java/kudu-client/src/main/java/org/apache/kudu/client/ConnectToCluster.java index d69bd76..f3341a7 100644 --- a/java/kudu-client/src/main/java/org/apache/kudu/client/ConnectToCluster.java +++ b/java/kudu-client/src/main/java/org/apache/kudu/client/ConnectToCluster.java @@ -86,6 +86,11 @@ final class ConnectToCluster { return responseD; } + @VisibleForTesting + List<Exception> getExceptionsReceived() { + return exceptionsReceived; + } + private static Deferred<ConnectToMasterResponsePB> connectToMaster( final KuduTable masterTable, final RpcProxy masterProxy, @@ -148,11 +153,20 @@ final class ConnectToCluster { long defaultTimeoutMs, Connection.CredentialsPolicy credentialsPolicy) { ConnectToCluster connector = new ConnectToCluster(masterAddresses); + connector.connectToMasters(masterTable, parentRpc, + defaultTimeoutMs, credentialsPolicy); + return connector.responseD; + } + @VisibleForTesting + void connectToMasters(KuduTable masterTable, + KuduRpc<?> parentRpc, + long defaultTimeoutMs, + Connection.CredentialsPolicy credentialsPolicy) { // Try to connect to each master. The ConnectToCluster instance // waits until it gets a good response before firing the returned // deferred. - for (HostAndPort hostAndPort : masterAddresses) { + for (HostAndPort hostAndPort : masterAddrs) { Deferred<ConnectToMasterResponsePB> d; RpcProxy proxy = masterTable.getAsyncClient().newMasterRpcProxy( hostAndPort, credentialsPolicy); @@ -164,10 +178,8 @@ final class ConnectToCluster { Status statusIOE = Status.IOError(message); d = Deferred.fromError(new NonRecoverableException(statusIOE)); } - d.addCallbacks(connector.callbackForNode(hostAndPort), - connector.errbackForNode(hostAndPort)); + d.addCallbacks(callbackForNode(hostAndPort), errbackForNode(hostAndPort)); } - return connector.responseD; } /** http://git-wip-us.apache.org/repos/asf/kudu/blob/0f0e4214/java/kudu-client/src/test/java/org/apache/kudu/client/TestSecurity.java ---------------------------------------------------------------------- diff --git a/java/kudu-client/src/test/java/org/apache/kudu/client/TestSecurity.java b/java/kudu-client/src/test/java/org/apache/kudu/client/TestSecurity.java index c9881c4..863ed03 100644 --- a/java/kudu-client/src/test/java/org/apache/kudu/client/TestSecurity.java +++ b/java/kudu-client/src/test/java/org/apache/kudu/client/TestSecurity.java @@ -13,14 +13,17 @@ */ package org.apache.kudu.client; +import static org.apache.kudu.util.AssertHelpers.assertEventuallyTrue; import static org.junit.Assert.assertNotNull; +import java.util.List; + +import org.apache.kudu.util.AssertHelpers.BooleanExpression; +import org.apache.kudu.util.SecurityUtil; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; -import org.apache.kudu.util.SecurityUtil; - public class TestSecurity extends BaseKuduTest { private static final String TABLE_NAME = "TestSecurity-table"; @@ -73,6 +76,39 @@ public class TestSecurity extends BaseKuduTest { } /** + * Regression test for KUDU-2267, client with valid token but without valid + * Kerberos credentials should be able to connect to all the masters. + */ + @Test + public void testKudu2267() throws Exception { + byte[] authnData = client.exportAuthenticationCredentials().join(); + assertNotNull(authnData); + String oldTicketCache = System.getProperty(SecurityUtil.KUDU_TICKETCACHE_PROPERTY); + System.clearProperty(SecurityUtil.KUDU_TICKETCACHE_PROPERTY); + try { + final KuduClient newClient = new KuduClient.KuduClientBuilder(masterAddresses).build(); + newClient.importAuthenticationCredentials(authnData); + + // Try to connect to all the masters and assert there is no + // authentication failures. + assertEventuallyTrue("Not able to connect to all the masters", + new BooleanExpression() { + @Override + public boolean get() throws Exception { + ConnectToCluster connector = new ConnectToCluster(masterHostPorts); + connector.connectToMasters(newClient.asyncClient.getMasterTable(), null, + DEFAULT_SLEEP, Connection.CredentialsPolicy.ANY_CREDENTIALS); + connector.getDeferred().join(); + List<Exception> s = connector.getExceptionsReceived(); + return s.size() == 0; + } + }, DEFAULT_SLEEP); + } finally { + System.setProperty(SecurityUtil.KUDU_TICKETCACHE_PROPERTY, oldTicketCache); + } + } + + /** * Test that a client is able to connect to masters using valid tokens * after all masters were killed and restarted, and before a leader is * elected. Leader election time is configured to be long enough using
