You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@accumulo.apache.org by el...@apache.org on 2015/06/02 23:57:07 UTC

[2/7] accumulo git commit: ACCUMULO-3881 Fix *ProxyITs to work with Kerberos enabled.

ACCUMULO-3881 Fix *ProxyITs to work with Kerberos enabled.


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

Branch: refs/heads/master
Commit: 198c5fb8f7a21eb869528e2050e69479796541ab
Parents: 99c734c
Author: Josh Elser <el...@apache.org>
Authored: Tue Jun 2 16:44:52 2015 -0400
Committer: Josh Elser <el...@apache.org>
Committed: Tue Jun 2 16:48:44 2015 -0400

----------------------------------------------------------------------
 .../java/org/apache/accumulo/proxy/Proxy.java   |   8 +-
 .../apache/accumulo/proxy/TestProxyClient.java  |  21 +
 .../accumulo/harness/SharedMiniClusterIT.java   |   6 +-
 .../apache/accumulo/proxy/SimpleProxyBase.java  | 485 +++++++++++++++----
 4 files changed, 430 insertions(+), 90 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/accumulo/blob/198c5fb8/proxy/src/main/java/org/apache/accumulo/proxy/Proxy.java
----------------------------------------------------------------------
diff --git a/proxy/src/main/java/org/apache/accumulo/proxy/Proxy.java b/proxy/src/main/java/org/apache/accumulo/proxy/Proxy.java
index 55431fa..2290106 100644
--- a/proxy/src/main/java/org/apache/accumulo/proxy/Proxy.java
+++ b/proxy/src/main/java/org/apache/accumulo/proxy/Proxy.java
@@ -178,6 +178,11 @@ public class Proxy implements KeywordExecutable {
   }
 
   public static ServerAddress createProxyServer(HostAndPort address, TProtocolFactory protocolFactory, Properties properties) throws Exception {
+    return createProxyServer(address, protocolFactory, properties, ClientConfiguration.loadDefault());
+  }
+
+  public static ServerAddress createProxyServer(HostAndPort address, TProtocolFactory protocolFactory, Properties properties, ClientConfiguration clientConf)
+      throws Exception {
     final int numThreads = Integer.parseInt(properties.getProperty(THRIFT_THREAD_POOL_SIZE_KEY, THRIFT_THREAD_POOL_SIZE_DEFAULT));
     final long maxFrameSize = AccumuloConfiguration.getMemoryInBytes(properties.getProperty(THRIFT_MAX_FRAME_SIZE_KEY, THRIFT_MAX_FRAME_SIZE_DEFAULT));
     final int simpleTimerThreadpoolSize = Integer.parseInt(Property.GENERAL_SIMPLETIMER_THREADPOOL_SIZE.getDefaultValue());
@@ -205,7 +210,6 @@ public class Proxy implements KeywordExecutable {
       serverType = ThriftServerType.get(serverTypeStr);
     }
 
-    ClientConfiguration clientConf = ClientConfiguration.loadDefault();
     SslConnectionParams sslParams = null;
     SaslServerConnectionParams saslParams = null;
     switch (serverType) {
@@ -213,7 +217,7 @@ public class Proxy implements KeywordExecutable {
         sslParams = SslConnectionParams.forClient(ClientContext.convertClientConfig(clientConf));
         break;
       case SASL:
-        if (!clientConf.getBoolean(ClientProperty.INSTANCE_RPC_SASL_ENABLED.getKey())) {
+        if (!clientConf.getBoolean(ClientProperty.INSTANCE_RPC_SASL_ENABLED.getKey(), false)) {
           // ACCUMULO-3651 Changed level to error and added FATAL to message for slf4j capability
           log.error("FATAL: SASL thrift server was requested but it is disabled in client configuration");
           throw new RuntimeException("SASL is not enabled in configuration");

http://git-wip-us.apache.org/repos/asf/accumulo/blob/198c5fb8/proxy/src/main/java/org/apache/accumulo/proxy/TestProxyClient.java
----------------------------------------------------------------------
diff --git a/proxy/src/main/java/org/apache/accumulo/proxy/TestProxyClient.java b/proxy/src/main/java/org/apache/accumulo/proxy/TestProxyClient.java
index fb23484..4894f13 100644
--- a/proxy/src/main/java/org/apache/accumulo/proxy/TestProxyClient.java
+++ b/proxy/src/main/java/org/apache/accumulo/proxy/TestProxyClient.java
@@ -26,17 +26,22 @@ import java.util.List;
 import java.util.Map;
 import java.util.TreeMap;
 
+import javax.security.sasl.SaslException;
+
 import org.apache.accumulo.core.client.IteratorSetting;
 import org.apache.accumulo.core.iterators.user.RegExFilter;
+import org.apache.accumulo.core.rpc.UGIAssumingTransport;
 import org.apache.accumulo.proxy.thrift.AccumuloProxy;
 import org.apache.accumulo.proxy.thrift.ColumnUpdate;
 import org.apache.accumulo.proxy.thrift.Key;
 import org.apache.accumulo.proxy.thrift.ScanResult;
 import org.apache.accumulo.proxy.thrift.TimeType;
+import org.apache.hadoop.security.UserGroupInformation;
 import org.apache.thrift.protocol.TCompactProtocol;
 import org.apache.thrift.protocol.TProtocol;
 import org.apache.thrift.protocol.TProtocolFactory;
 import org.apache.thrift.transport.TFramedTransport;
+import org.apache.thrift.transport.TSaslClientTransport;
 import org.apache.thrift.transport.TSocket;
 import org.apache.thrift.transport.TTransport;
 import org.apache.thrift.transport.TTransportException;
@@ -59,6 +64,22 @@ public class TestProxyClient {
     transport.open();
   }
 
+  public TestProxyClient(String host, int port, TProtocolFactory protoFactory, String proxyPrimary, UserGroupInformation ugi) throws SaslException,
+      TTransportException {
+    TSocket socket = new TSocket(host, port);
+    TSaslClientTransport saslTransport = new TSaslClientTransport("GSSAPI", null, proxyPrimary, host, Collections.singletonMap("javax.security.sasl.qop",
+        "auth"), null, socket);
+
+    transport = new UGIAssumingTransport(saslTransport, ugi);
+
+    // UGI transport will perform the doAs for us
+    transport.open();
+
+    AccumuloProxy.Client.Factory factory = new AccumuloProxy.Client.Factory();
+    final TProtocol protocol = protoFactory.getProtocol(transport);
+    proxy = factory.getClient(protocol);
+  }
+
   public synchronized void close() {
     if (null != transport) {
       transport.close();

http://git-wip-us.apache.org/repos/asf/accumulo/blob/198c5fb8/test/src/test/java/org/apache/accumulo/harness/SharedMiniClusterIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/accumulo/harness/SharedMiniClusterIT.java b/test/src/test/java/org/apache/accumulo/harness/SharedMiniClusterIT.java
index 98ebddc..4a2501f 100644
--- a/test/src/test/java/org/apache/accumulo/harness/SharedMiniClusterIT.java
+++ b/test/src/test/java/org/apache/accumulo/harness/SharedMiniClusterIT.java
@@ -48,7 +48,7 @@ import org.slf4j.LoggerFactory;
  */
 public abstract class SharedMiniClusterIT extends AccumuloIT implements ClusterUsers {
   private static final Logger log = LoggerFactory.getLogger(SharedMiniClusterIT.class);
-  private static final String TRUE = Boolean.toString(true);
+  public static final String TRUE = Boolean.toString(true);
 
   private static String principal = "root";
   private static String rootPassword;
@@ -159,6 +159,10 @@ public abstract class SharedMiniClusterIT extends AccumuloIT implements ClusterU
     }
   }
 
+  public static TestingKdc getKdc() {
+    return krb;
+  }
+
   @Override
   public ClusterUser getAdminUser() {
     if (null == krb) {

http://git-wip-us.apache.org/repos/asf/accumulo/blob/198c5fb8/test/src/test/java/org/apache/accumulo/proxy/SimpleProxyBase.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/accumulo/proxy/SimpleProxyBase.java b/test/src/test/java/org/apache/accumulo/proxy/SimpleProxyBase.java
index 8895e9e..86051f6 100644
--- a/test/src/test/java/org/apache/accumulo/proxy/SimpleProxyBase.java
+++ b/test/src/test/java/org/apache/accumulo/proxy/SimpleProxyBase.java
@@ -26,8 +26,8 @@ import static org.junit.Assert.fail;
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.InputStreamReader;
+import java.net.InetAddress;
 import java.nio.ByteBuffer;
-import java.nio.file.Files;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -41,8 +41,11 @@ import java.util.Set;
 import java.util.TreeMap;
 import java.util.UUID;
 
+import org.apache.accumulo.cluster.ClusterUser;
+import org.apache.accumulo.core.client.ClientConfiguration;
 import org.apache.accumulo.core.client.Connector;
 import org.apache.accumulo.core.client.Instance;
+import org.apache.accumulo.core.client.security.tokens.KerberosToken;
 import org.apache.accumulo.core.client.security.tokens.PasswordToken;
 import org.apache.accumulo.core.conf.DefaultConfiguration;
 import org.apache.accumulo.core.conf.Property;
@@ -58,7 +61,9 @@ import org.apache.accumulo.core.security.Authorizations;
 import org.apache.accumulo.core.util.ByteBufferUtil;
 import org.apache.accumulo.core.util.UtilWaitThread;
 import org.apache.accumulo.examples.simple.constraints.NumericValueConstraint;
+import org.apache.accumulo.harness.MiniClusterHarness;
 import org.apache.accumulo.harness.SharedMiniClusterIT;
+import org.apache.accumulo.harness.TestingKdc;
 import org.apache.accumulo.minicluster.impl.MiniAccumuloClusterImpl;
 import org.apache.accumulo.proxy.thrift.AccumuloProxy.Client;
 import org.apache.accumulo.proxy.thrift.AccumuloSecurityException;
@@ -97,11 +102,14 @@ import org.apache.accumulo.proxy.thrift.UnknownWriter;
 import org.apache.accumulo.proxy.thrift.WriterOptions;
 import org.apache.accumulo.server.util.PortUtils;
 import org.apache.accumulo.test.functional.SlowIterator;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.CommonConfigurationKeysPublic;
 import org.apache.hadoop.fs.FSDataInputStream;
 import org.apache.hadoop.fs.FileSystem;
 import org.apache.hadoop.fs.FileUtil;
 import org.apache.hadoop.fs.Path;
 import org.apache.hadoop.io.Text;
+import org.apache.hadoop.security.UserGroupInformation;
 import org.apache.thrift.TApplicationException;
 import org.apache.thrift.TException;
 import org.apache.thrift.protocol.TProtocolFactory;
@@ -136,6 +144,8 @@ public abstract class SimpleProxyBase extends SharedMiniClusterIT {
 
   private static Map<String,String> properties = new HashMap<>();
   private static ByteBuffer creds = null;
+  private static String hostname, proxyPrincipal, proxyPrimary, clientPrincipal;
+  private static File proxyKeytab, clientKeytab;
 
   // Implementations can set this
   static TProtocolFactory factory = null;
@@ -144,6 +154,10 @@ public abstract class SimpleProxyBase extends SharedMiniClusterIT {
     Iterators.size(c.createScanner(MetadataTable.NAME, Authorizations.EMPTY).iterator());
   }
 
+  private static boolean isKerberosEnabled() {
+    return SharedMiniClusterIT.TRUE.equals(System.getProperty(MiniClusterHarness.USE_KERBEROS_FOR_IT_OPTION));
+  }
+
   /**
    * Does the actual test setup, invoked by the concrete test class
    */
@@ -154,20 +168,60 @@ public abstract class SimpleProxyBase extends SharedMiniClusterIT {
     Instance inst = c.getInstance();
     waitForAccumulo(c);
 
+    hostname = InetAddress.getLocalHost().getCanonicalHostName();
+
     Properties props = new Properties();
     props.put("instance", inst.getInstanceName());
     props.put("zookeepers", inst.getZooKeepers());
-    props.put("tokenClass", PasswordToken.class.getName());
-    // Avoid issues with locally installed client configuration files with custom properties
-    File emptyFile = Files.createTempFile(null, null).toFile();
-    emptyFile.deleteOnExit();
-    props.put("clientConfigurationFile", emptyFile.toString());
 
-    properties.put("password", SharedMiniClusterIT.getRootPassword());
-    properties.put("clientConfigurationFile", emptyFile.toString());
+    final String tokenClass;
+    if (isKerberosEnabled()) {
+      tokenClass = KerberosToken.class.getName();
+      TestingKdc kdc = getKdc();
+
+      // Create a principal+keytab for the proxy
+      proxyKeytab = new File(kdc.getKeytabDir(), "proxy.keytab");
+      hostname = InetAddress.getLocalHost().getCanonicalHostName();
+      // Set the primary because the client needs to know it
+      proxyPrimary = "proxy";
+      // Qualify with an instance
+      proxyPrincipal = proxyPrimary + "/" + hostname;
+      kdc.createPrincipal(proxyKeytab, proxyPrincipal);
+      // Tack on the realm too
+      proxyPrincipal = kdc.qualifyUser(proxyPrincipal);
+
+      props.setProperty("kerberosPrincipal", proxyPrincipal);
+      props.setProperty("kerberosKeytab", proxyKeytab.getCanonicalPath());
+      props.setProperty("thriftServerType", "sasl");
+
+      // Enabled kerberos auth
+      Configuration conf = new Configuration(false);
+      conf.set(CommonConfigurationKeysPublic.HADOOP_SECURITY_AUTHENTICATION, "kerberos");
+      UserGroupInformation.setConfiguration(conf);
+
+      // Login for the Proxy itself
+      UserGroupInformation.loginUserFromKeytab(proxyPrincipal, proxyKeytab.getAbsolutePath());
+
+      // User for tests
+      ClusterUser user = kdc.getRootUser();
+      clientPrincipal = user.getPrincipal();
+      clientKeytab = user.getKeytab();
+    } else {
+      clientPrincipal = "root";
+      tokenClass = PasswordToken.class.getName();
+      properties.put("password", SharedMiniClusterIT.getRootPassword());
+      hostname = "localhost";
+    }
+
+    props.put("tokenClass", tokenClass);
+
+    ClientConfiguration clientConfig = SharedMiniClusterIT.getCluster().getClientConfig();
+    String clientConfPath = new File(SharedMiniClusterIT.getCluster().getConfig().getConfDir(), "client.conf").getAbsolutePath();
+    props.put("clientConfigurationFile", clientConfPath);
+    properties.put("clientConfigurationFile", clientConfPath);
 
     proxyPort = PortUtils.getRandomFreePort();
-    proxyServer = Proxy.createProxyServer(HostAndPort.fromParts("localhost", proxyPort), factory, props).server;
+    proxyServer = Proxy.createProxyServer(HostAndPort.fromParts(hostname, proxyPort), factory, props, clientConfig).server;
     while (!proxyServer.isServing())
       UtilWaitThread.sleep(100);
   }
@@ -186,16 +240,44 @@ public abstract class SimpleProxyBase extends SharedMiniClusterIT {
   @Before
   public void setup() throws Exception {
     // Create a new client for each test
-    proxyClient = new TestProxyClient("localhost", proxyPort, factory);
-    client = proxyClient.proxy();
-    creds = client.login("root", properties);
+    if (isKerberosEnabled()) {
+      UserGroupInformation.loginUserFromKeytab(clientPrincipal, clientKeytab.getAbsolutePath());
+      proxyClient = new TestProxyClient(hostname, proxyPort, factory, proxyPrimary, UserGroupInformation.getCurrentUser());
+      client = proxyClient.proxy();
+      creds = client.login(clientPrincipal, properties);
+
+      TestingKdc kdc = getKdc();
+      final ClusterUser user = kdc.getClientPrincipal(0);
+      // Create another user
+      client.createLocalUser(creds, user.getPrincipal(), s2bb("unused"));
+      // Login in as that user we just created
+      UserGroupInformation.loginUserFromKeytab(user.getPrincipal(), user.getKeytab().getAbsolutePath());
+      final UserGroupInformation badUgi = UserGroupInformation.getCurrentUser();
+      // Get a "Credentials" object for the proxy
+      TestProxyClient badClient = new TestProxyClient(hostname, proxyPort, factory, proxyPrimary, badUgi);
+      try {
+        Client badProxy = badClient.proxy();
+        badLogin = badProxy.login(user.getPrincipal(), properties);
+      } finally {
+        badClient.close();
+      }
 
-    // Create 'user'
-    client.createLocalUser(creds, "user", s2bb(SharedMiniClusterIT.getRootPassword()));
-    // Log in as 'user'
-    badLogin = client.login("user", properties);
-    // Drop 'user', invalidating the credentials
-    client.dropLocalUser(creds, "user");
+      // Log back in as the test user
+      UserGroupInformation.loginUserFromKeytab(clientPrincipal, clientKeytab.getAbsolutePath());
+      // Drop test user, invalidating the credentials (not to mention not having the krb credentials anymore)
+      client.dropLocalUser(creds, user.getPrincipal());
+    } else {
+      proxyClient = new TestProxyClient(hostname, proxyPort, factory);
+      client = proxyClient.proxy();
+      creds = client.login("root", properties);
+
+      // Create 'user'
+      client.createLocalUser(creds, "user", s2bb(SharedMiniClusterIT.getRootPassword()));
+      // Log in as 'user'
+      badLogin = client.login("user", properties);
+      // Drop 'user', invalidating the credentials
+      client.dropLocalUser(creds, "user");
+    }
 
     // Create a general table to be used
     table = getUniqueNames(1)[0];
@@ -205,6 +287,9 @@ public abstract class SimpleProxyBase extends SharedMiniClusterIT {
   @After
   public void teardown() throws Exception {
     if (null != table) {
+      if (isKerberosEnabled()) {
+        UserGroupInformation.loginUserFromKeytab(clientPrincipal, clientKeytab.getAbsolutePath());
+      }
       try {
         if (client.tableExists(creds, table)) {
           client.deleteTable(creds, table);
@@ -392,9 +477,18 @@ public abstract class SimpleProxyBase extends SharedMiniClusterIT {
     client.testClassLoad(badLogin, DevNull.class.getName(), SortedKeyValueIterator.class.getName());
   }
 
-  @Test(expected = AccumuloSecurityException.class, timeout = 5000)
+  @Test(timeout = 5000)
   public void authenticateUserLoginFailure() throws Exception {
-    client.authenticateUser(badLogin, "root", s2pp(SharedMiniClusterIT.getRootPassword()));
+    if (!isKerberosEnabled()) {
+      try {
+        // Not really a relevant test for kerberos
+        client.authenticateUser(badLogin, "root", s2pp(SharedMiniClusterIT.getRootPassword()));
+        fail("Expected AccumuloSecurityException");
+      } catch (AccumuloSecurityException e) {
+        // Expected
+        return;
+      }
+    }
   }
 
   @Test(expected = AccumuloSecurityException.class, timeout = 5000)
@@ -897,13 +991,25 @@ public abstract class SimpleProxyBase extends SharedMiniClusterIT {
       @Override
       public void run() {
         String scanner;
+        TestProxyClient proxyClient2 = null;
         try {
-          Client client2 = new TestProxyClient("localhost", proxyPort, factory).proxy();
+          if (isKerberosEnabled()) {
+            UserGroupInformation.loginUserFromKeytab(clientPrincipal, clientKeytab.getAbsolutePath());
+            proxyClient2 = new TestProxyClient(hostname, proxyPort, factory, proxyPrimary, UserGroupInformation.getCurrentUser());
+          } else {
+            proxyClient2 = new TestProxyClient(hostname, proxyPort, factory);
+          }
+
+          Client client2 = proxyClient2.proxy();
           scanner = client2.createScanner(creds, "slow", null);
           client2.nextK(scanner, 10);
           client2.closeScanner(scanner);
         } catch (Exception e) {
           throw new RuntimeException(e);
+        } finally {
+          if (null != proxyClient2) {
+            proxyClient2.close();
+          }
         }
       }
     };
@@ -915,7 +1021,7 @@ public abstract class SimpleProxyBase extends SharedMiniClusterIT {
       for (String tserver : client.getTabletServers(creds)) {
         List<ActiveScan> scansForServer = client.getActiveScans(creds, tserver);
         for (ActiveScan scan : scansForServer) {
-          if ("root".equals(scan.getUser())) {
+          if (clientPrincipal.equals(scan.getUser())) {
             scans.add(scan);
           }
         }
@@ -927,12 +1033,12 @@ public abstract class SimpleProxyBase extends SharedMiniClusterIT {
     }
     t.join();
 
-    assertFalse(scans.isEmpty());
+    assertFalse("Expected to find scans, but found none", scans.isEmpty());
     boolean found = false;
     Map<String,String> map = null;
     for (int i = 0; i < scans.size() && !found; i++) {
       ActiveScan scan = scans.get(i);
-      if ("root".equals(scan.getUser())) {
+      if (clientPrincipal.equals(scan.getUser())) {
         assertTrue(ScanState.RUNNING.equals(scan.getState()) || ScanState.QUEUED.equals(scan.getState()));
         assertEquals(ScanType.SINGLE, scan.getType());
         assertEquals("slow", scan.getTable());
@@ -970,11 +1076,22 @@ public abstract class SimpleProxyBase extends SharedMiniClusterIT {
     Thread t = new Thread() {
       @Override
       public void run() {
+        TestProxyClient proxyClient2 = null;
         try {
-          Client client2 = new TestProxyClient("localhost", proxyPort, factory).proxy();
+          if (isKerberosEnabled()) {
+            UserGroupInformation.loginUserFromKeytab(clientPrincipal, clientKeytab.getAbsolutePath());
+            proxyClient2 = new TestProxyClient(hostname, proxyPort, factory, proxyPrimary, UserGroupInformation.getCurrentUser());
+          } else {
+            proxyClient2 = new TestProxyClient(hostname, proxyPort, factory);
+          }
+          Client client2 = proxyClient2.proxy();
           client2.compactTable(creds, "slow", null, null, null, true, true, null);
         } catch (Exception e) {
           throw new RuntimeException(e);
+        } finally {
+          if (null != proxyClient2) {
+            proxyClient2.close();
+          }
         }
       }
     };
@@ -1027,19 +1144,34 @@ public abstract class SimpleProxyBase extends SharedMiniClusterIT {
 
   @Test
   public void userAuthentication() throws Exception {
-    // check password
-    assertTrue(client.authenticateUser(creds, "root", s2pp(SharedMiniClusterIT.getRootPassword())));
-    assertFalse(client.authenticateUser(creds, "root", s2pp("")));
+    if (isKerberosEnabled()) {
+      assertTrue(client.authenticateUser(creds, clientPrincipal, Collections.<String,String> emptyMap()));
+      // Can't really authenticate "badly" at the application level w/ kerberos. It's going to fail to even set up an RPC
+    } else {
+      // check password
+      assertTrue(client.authenticateUser(creds, "root", s2pp(SharedMiniClusterIT.getRootPassword())));
+      assertFalse(client.authenticateUser(creds, "root", s2pp("")));
+    }
   }
 
   @Test
   public void userManagement() throws Exception {
-    String user = getUniqueNames(1)[0];
+
+    String user;
+    ClusterUser otherClient = null;
+    ByteBuffer password = s2bb("password");
+    if (isKerberosEnabled()) {
+      otherClient = getKdc().getClientPrincipal(1);
+      user = otherClient.getPrincipal();
+    } else {
+      user = getUniqueNames(1)[0];
+    }
+
     // create a user
-    client.createLocalUser(creds, user, s2bb("password"));
+    client.createLocalUser(creds, user, password);
     // change auths
     Set<String> users = client.listLocalUsers(creds);
-    Set<String> expectedUsers = new HashSet<String>(Arrays.asList("root", user));
+    Set<String> expectedUsers = new HashSet<String>(Arrays.asList(clientPrincipal, user));
     assertTrue("Did not find all expected users: " + expectedUsers, users.containsAll(expectedUsers));
     HashSet<ByteBuffer> auths = new HashSet<ByteBuffer>(Arrays.asList(s2bb("A"), s2bb("B")));
     client.changeUserAuthorizations(creds, user, auths);
@@ -1047,70 +1179,182 @@ public abstract class SimpleProxyBase extends SharedMiniClusterIT {
     assertEquals(auths, new HashSet<ByteBuffer>(update));
 
     // change password
-    client.changeLocalUserPassword(creds, user, s2bb(""));
-    assertTrue(client.authenticateUser(creds, user, s2pp("")));
+    if (!isKerberosEnabled()) {
+      password = s2bb("");
+      client.changeLocalUserPassword(creds, user, password);
+      assertTrue(client.authenticateUser(creds, user, s2pp(password.toString())));
+    }
 
-    // check login with new password
-    client.login(user, s2pp(""));
+    if (isKerberosEnabled()) {
+      UserGroupInformation.loginUserFromKeytab(otherClient.getPrincipal(), otherClient.getKeytab().getAbsolutePath());
+      final UserGroupInformation ugi = UserGroupInformation.getCurrentUser();
+      // Re-login in and make a new connection. Can't use the previous one
+
+      TestProxyClient otherProxyClient = null;
+      try {
+        otherProxyClient = new TestProxyClient(hostname, proxyPort, factory, proxyPrimary, ugi);
+        otherProxyClient.proxy().login(user, Collections.<String,String> emptyMap());
+      } finally {
+        if (null != otherProxyClient) {
+          otherProxyClient.close();
+        }
+      }
+    } else {
+      // check login with new password
+      client.login(user, s2pp(password.toString()));
+    }
   }
 
   @Test
   public void userPermissions() throws Exception {
     String userName = getUniqueNames(1)[0];
-    // create a user
-    client.createLocalUser(creds, userName, s2bb("password"));
-
-    ByteBuffer user = client.login(userName, s2pp("password"));
+    ClusterUser otherClient = null;
+    ByteBuffer password = s2bb("password");
+    ByteBuffer user;
+
+    TestProxyClient origProxyClient = null;
+    Client origClient = null;
+    TestProxyClient userProxyClient = null;
+    Client userClient = null;
+
+    if (isKerberosEnabled()) {
+      otherClient = getKdc().getClientPrincipal(1);
+      userName = otherClient.getPrincipal();
+
+      UserGroupInformation.loginUserFromKeytab(otherClient.getPrincipal(), otherClient.getKeytab().getAbsolutePath());
+      final UserGroupInformation ugi = UserGroupInformation.getCurrentUser();
+      // Re-login in and make a new connection. Can't use the previous one
+
+      userProxyClient = new TestProxyClient(hostname, proxyPort, factory, proxyPrimary, ugi);
+
+      origProxyClient = proxyClient;
+      origClient = client;
+      userClient = client = userProxyClient.proxy();
+
+      user = client.login(userName, Collections.<String,String> emptyMap());
+    } else {
+      userName = getUniqueNames(1)[0];
+      // create a user
+      client.createLocalUser(creds, userName, password);
+      user = client.login(userName, s2pp(password.toString()));
+    }
 
     // check permission failure
     try {
       client.createTable(user, "fail", true, TimeType.MILLIS);
       fail("should not create the table");
     } catch (AccumuloSecurityException ex) {
+      if (isKerberosEnabled()) {
+        // Switch back to original client
+        UserGroupInformation.loginUserFromKeytab(clientPrincipal, clientKeytab.getAbsolutePath());
+        client = origClient;
+      }
       assertFalse(client.listTables(creds).contains("fail"));
     }
     // grant permissions and test
     assertFalse(client.hasSystemPermission(creds, userName, SystemPermission.CREATE_TABLE));
     client.grantSystemPermission(creds, userName, SystemPermission.CREATE_TABLE);
     assertTrue(client.hasSystemPermission(creds, userName, SystemPermission.CREATE_TABLE));
+    if (isKerberosEnabled()) {
+      // Switch back to the extra user
+      UserGroupInformation.loginUserFromKeytab(otherClient.getPrincipal(), otherClient.getKeytab().getAbsolutePath());
+      client = userClient;
+    }
     client.createTable(user, "success", true, TimeType.MILLIS);
+    if (isKerberosEnabled()) {
+      // Switch back to original client
+      UserGroupInformation.loginUserFromKeytab(clientPrincipal, clientKeytab.getAbsolutePath());
+      client = origClient;
+    }
     client.listTables(creds).contains("succcess");
 
     // revoke permissions
     client.revokeSystemPermission(creds, userName, SystemPermission.CREATE_TABLE);
     assertFalse(client.hasSystemPermission(creds, userName, SystemPermission.CREATE_TABLE));
     try {
+      if (isKerberosEnabled()) {
+        // Switch back to the extra user
+        UserGroupInformation.loginUserFromKeytab(otherClient.getPrincipal(), otherClient.getKeytab().getAbsolutePath());
+        client = userClient;
+      }
       client.createTable(user, "fail", true, TimeType.MILLIS);
       fail("should not create the table");
     } catch (AccumuloSecurityException ex) {
+      if (isKerberosEnabled()) {
+        // Switch back to original client
+        UserGroupInformation.loginUserFromKeytab(clientPrincipal, clientKeytab.getAbsolutePath());
+        client = origClient;
+      }
       assertFalse(client.listTables(creds).contains("fail"));
     }
     // denied!
     try {
+      if (isKerberosEnabled()) {
+        // Switch back to the extra user
+        UserGroupInformation.loginUserFromKeytab(otherClient.getPrincipal(), otherClient.getKeytab().getAbsolutePath());
+        client = userClient;
+      }
       String scanner = client.createScanner(user, table, null);
       client.nextK(scanner, 100);
       fail("stooge should not read table test");
     } catch (AccumuloSecurityException ex) {}
+
+    if (isKerberosEnabled()) {
+      // Switch back to original client
+      UserGroupInformation.loginUserFromKeytab(clientPrincipal, clientKeytab.getAbsolutePath());
+      client = origClient;
+    }
+
     // grant
     assertFalse(client.hasTablePermission(creds, userName, table, TablePermission.READ));
     client.grantTablePermission(creds, userName, table, TablePermission.READ);
     assertTrue(client.hasTablePermission(creds, userName, table, TablePermission.READ));
+
+    if (isKerberosEnabled()) {
+      // Switch back to the extra user
+      UserGroupInformation.loginUserFromKeytab(otherClient.getPrincipal(), otherClient.getKeytab().getAbsolutePath());
+      client = userClient;
+    }
     String scanner = client.createScanner(user, table, null);
     client.nextK(scanner, 10);
     client.closeScanner(scanner);
+
+    if (isKerberosEnabled()) {
+      // Switch back to original client
+      UserGroupInformation.loginUserFromKeytab(clientPrincipal, clientKeytab.getAbsolutePath());
+      client = origClient;
+    }
+
     // revoke
     client.revokeTablePermission(creds, userName, table, TablePermission.READ);
     assertFalse(client.hasTablePermission(creds, userName, table, TablePermission.READ));
     try {
+      if (isKerberosEnabled()) {
+        // Switch back to the extra user
+        UserGroupInformation.loginUserFromKeytab(otherClient.getPrincipal(), otherClient.getKeytab().getAbsolutePath());
+        client = userClient;
+      }
       scanner = client.createScanner(user, table, null);
       client.nextK(scanner, 100);
       fail("stooge should not read table test");
     } catch (AccumuloSecurityException ex) {}
 
+    if (isKerberosEnabled()) {
+      // Switch back to original client
+      UserGroupInformation.loginUserFromKeytab(clientPrincipal, clientKeytab.getAbsolutePath());
+      client = origClient;
+    }
+
     // delete user
     client.dropLocalUser(creds, userName);
     Set<String> users = client.listLocalUsers(creds);
     assertFalse("Should not see user after they are deleted", users.contains(userName));
+
+    if (isKerberosEnabled()) {
+      userProxyClient.close();
+      proxyClient = origProxyClient;
+      client = origClient;
+    }
   }
 
   @Test
@@ -1563,7 +1807,7 @@ public abstract class SimpleProxyBase extends SharedMiniClusterIT {
     String scid = client.createScanner(creds, table, new ScanOptions());
     ScanResult keyValues = client.nextK(scid, expected.length + 1);
 
-    assertEquals(expected.length, keyValues.results.size());
+    assertEquals("Saw " + keyValues.results, expected.length, keyValues.results.size());
     assertFalse(keyValues.more);
 
     for (int i = 0; i < keyValues.results.size(); i++) {
@@ -1793,71 +2037,138 @@ public abstract class SimpleProxyBase extends SharedMiniClusterIT {
       fail("conditional writer not closed");
     } catch (UnknownWriter uk) {}
 
-    // run test with colvis
-    client.createLocalUser(creds, "cwuser", s2bb("bestpasswordever"));
-    client.changeUserAuthorizations(creds, "cwuser", Collections.singleton(s2bb("A")));
-    client.grantTablePermission(creds, "cwuser", table, TablePermission.WRITE);
-    client.grantTablePermission(creds, "cwuser", table, TablePermission.READ);
+    String principal;
+    ClusterUser cwuser = null;
+    if (isKerberosEnabled()) {
+      cwuser = getKdc().getClientPrincipal(1);
+      principal = cwuser.getPrincipal();
+      client.createLocalUser(creds, principal, s2bb("unused"));
+
+    } else {
+      principal = "cwuser";
+      // run test with colvis
+      client.createLocalUser(creds, principal, s2bb("bestpasswordever"));
+    }
 
-    ByteBuffer cwuCreds = client.login("cwuser", Collections.singletonMap("password", "bestpasswordever"));
+    client.changeUserAuthorizations(creds, principal, Collections.singleton(s2bb("A")));
+    client.grantTablePermission(creds, principal, table, TablePermission.WRITE);
+    client.grantTablePermission(creds, principal, table, TablePermission.READ);
+
+    TestProxyClient cwuserProxyClient = null;
+    Client origClient = null;
+    Map<String,String> cwProperties;
+    if (isKerberosEnabled()) {
+      UserGroupInformation.loginUserFromKeytab(cwuser.getPrincipal(), cwuser.getKeytab().getAbsolutePath());
+      final UserGroupInformation cwuserUgi = UserGroupInformation.getCurrentUser();
+      // Re-login in and make a new connection. Can't use the previous one
+      cwuserProxyClient = new TestProxyClient(hostname, proxyPort, factory, proxyPrimary, cwuserUgi);
+      origClient = client;
+      client = cwuserProxyClient.proxy();
+      cwProperties = Collections.emptyMap();
+    } else {
+      cwProperties = Collections.singletonMap("password", "bestpasswordever");
+    }
 
-    cwid = client.createConditionalWriter(cwuCreds, table, new ConditionalWriterOptions().setAuthorizations(Collections.singleton(s2bb("A"))));
+    try {
+      ByteBuffer cwCreds = client.login(principal, cwProperties);
 
-    updates.clear();
-    updates.put(
-        s2bb("00348"),
-        new ConditionalUpdates(Arrays.asList(new Condition(new Column(s2bb("data"), s2bb("c"), s2bb("A")))), Arrays.asList(newColUpdate("data", "seq", "1"),
-            newColUpdate("data", "c", "1").setColVisibility(s2bb("A")))));
-    updates.put(s2bb("00349"),
-        new ConditionalUpdates(Arrays.asList(new Condition(new Column(s2bb("data"), s2bb("c"), s2bb("B")))), Arrays.asList(newColUpdate("data", "seq", "1"))));
+      cwid = client.createConditionalWriter(cwCreds, table, new ConditionalWriterOptions().setAuthorizations(Collections.singleton(s2bb("A"))));
 
-    results = client.updateRowsConditionally(cwid, updates);
+      updates.clear();
+      updates.put(
+          s2bb("00348"),
+          new ConditionalUpdates(Arrays.asList(new Condition(new Column(s2bb("data"), s2bb("c"), s2bb("A")))), Arrays.asList(newColUpdate("data", "seq", "1"),
+              newColUpdate("data", "c", "1").setColVisibility(s2bb("A")))));
+      updates
+          .put(
+              s2bb("00349"),
+              new ConditionalUpdates(Arrays.asList(new Condition(new Column(s2bb("data"), s2bb("c"), s2bb("B")))), Arrays.asList(newColUpdate("data", "seq",
+                  "1"))));
 
-    assertEquals(2, results.size());
-    assertEquals(ConditionalStatus.ACCEPTED, results.get(s2bb("00348")));
-    assertEquals(ConditionalStatus.INVISIBLE_VISIBILITY, results.get(s2bb("00349")));
+      results = client.updateRowsConditionally(cwid, updates);
 
-    assertScan(new String[][] { {"00345", "data", "img", "1234567890"}, {"00345", "meta", "seq", "3"}, {"00346", "meta", "seq", "1"},
-        {"00347", "data", "count", "3"}, {"00347", "data", "img", "0987654321"}, {"00348", "data", "seq", "1"}}, table);
+      assertEquals(2, results.size());
+      assertEquals(ConditionalStatus.ACCEPTED, results.get(s2bb("00348")));
+      assertEquals(ConditionalStatus.INVISIBLE_VISIBILITY, results.get(s2bb("00349")));
 
-    updates.clear();
+      if (isKerberosEnabled()) {
+        UserGroupInformation.loginUserFromKeytab(clientPrincipal, clientKeytab.getAbsolutePath());
+        client = origClient;
+      }
+      // Verify that the original user can't see the updates with visibilities set
+      assertScan(new String[][] { {"00345", "data", "img", "1234567890"}, {"00345", "meta", "seq", "3"}, {"00346", "meta", "seq", "1"},
+          {"00347", "data", "count", "3"}, {"00347", "data", "img", "0987654321"}, {"00348", "data", "seq", "1"}}, table);
 
-    updates.clear();
-    updates.put(
-        s2bb("00348"),
-        new ConditionalUpdates(Arrays.asList(new Condition(new Column(s2bb("data"), s2bb("c"), s2bb("A"))).setValue(s2bb("0"))), Arrays.asList(
-            newColUpdate("data", "seq", "2"), newColUpdate("data", "c", "2").setColVisibility(s2bb("A")))));
+      if (isKerberosEnabled()) {
+        UserGroupInformation.loginUserFromKeytab(cwuser.getPrincipal(), cwuser.getKeytab().getAbsolutePath());
+        client = cwuserProxyClient.proxy();
+      }
 
-    results = client.updateRowsConditionally(cwid, updates);
+      updates.clear();
 
-    assertEquals(1, results.size());
-    assertEquals(ConditionalStatus.REJECTED, results.get(s2bb("00348")));
+      updates.clear();
+      updates.put(s2bb("00348"), new ConditionalUpdates(Arrays.asList(new Condition(new Column(s2bb("data"), s2bb("c"), s2bb("A"))).setValue(s2bb("0"))),
+          Arrays.asList(newColUpdate("data", "seq", "2"), newColUpdate("data", "c", "2").setColVisibility(s2bb("A")))));
 
-    assertScan(new String[][] { {"00345", "data", "img", "1234567890"}, {"00345", "meta", "seq", "3"}, {"00346", "meta", "seq", "1"},
-        {"00347", "data", "count", "3"}, {"00347", "data", "img", "0987654321"}, {"00348", "data", "seq", "1"}}, table);
+      results = client.updateRowsConditionally(cwid, updates);
 
-    updates.clear();
-    updates.put(
-        s2bb("00348"),
-        new ConditionalUpdates(Arrays.asList(new Condition(new Column(s2bb("data"), s2bb("c"), s2bb("A"))).setValue(s2bb("1"))), Arrays.asList(
-            newColUpdate("data", "seq", "2"), newColUpdate("data", "c", "2").setColVisibility(s2bb("A")))));
+      assertEquals(1, results.size());
+      assertEquals(ConditionalStatus.REJECTED, results.get(s2bb("00348")));
 
-    results = client.updateRowsConditionally(cwid, updates);
+      if (isKerberosEnabled()) {
+        UserGroupInformation.loginUserFromKeytab(clientPrincipal, clientKeytab.getAbsolutePath());
+        client = origClient;
+      }
 
-    assertEquals(1, results.size());
-    assertEquals(ConditionalStatus.ACCEPTED, results.get(s2bb("00348")));
+      // Same results as the original user
+      assertScan(new String[][] { {"00345", "data", "img", "1234567890"}, {"00345", "meta", "seq", "3"}, {"00346", "meta", "seq", "1"},
+          {"00347", "data", "count", "3"}, {"00347", "data", "img", "0987654321"}, {"00348", "data", "seq", "1"}}, table);
 
-    assertScan(new String[][] { {"00345", "data", "img", "1234567890"}, {"00345", "meta", "seq", "3"}, {"00346", "meta", "seq", "1"},
-        {"00347", "data", "count", "3"}, {"00347", "data", "img", "0987654321"}, {"00348", "data", "seq", "2"}}, table);
+      if (isKerberosEnabled()) {
+        UserGroupInformation.loginUserFromKeytab(cwuser.getPrincipal(), cwuser.getKeytab().getAbsolutePath());
+        client = cwuserProxyClient.proxy();
+      }
 
-    client.closeConditionalWriter(cwid);
-    try {
-      client.updateRowsConditionally(cwid, updates);
-      fail("conditional writer not closed");
-    } catch (UnknownWriter uk) {}
+      updates.clear();
+      updates.put(s2bb("00348"), new ConditionalUpdates(Arrays.asList(new Condition(new Column(s2bb("data"), s2bb("c"), s2bb("A"))).setValue(s2bb("1"))),
+          Arrays.asList(newColUpdate("data", "seq", "2"), newColUpdate("data", "c", "2").setColVisibility(s2bb("A")))));
 
-    client.dropLocalUser(creds, "cwuser");
+      results = client.updateRowsConditionally(cwid, updates);
 
+      assertEquals(1, results.size());
+      assertEquals(ConditionalStatus.ACCEPTED, results.get(s2bb("00348")));
+
+      if (isKerberosEnabled()) {
+        UserGroupInformation.loginUserFromKeytab(clientPrincipal, clientKeytab.getAbsolutePath());
+        client = origClient;
+      }
+
+      assertScan(new String[][] { {"00345", "data", "img", "1234567890"}, {"00345", "meta", "seq", "3"}, {"00346", "meta", "seq", "1"},
+          {"00347", "data", "count", "3"}, {"00347", "data", "img", "0987654321"}, {"00348", "data", "seq", "2"}}, table);
+
+      if (isKerberosEnabled()) {
+        UserGroupInformation.loginUserFromKeytab(cwuser.getPrincipal(), cwuser.getKeytab().getAbsolutePath());
+        client = cwuserProxyClient.proxy();
+      }
+
+      client.closeConditionalWriter(cwid);
+      try {
+        client.updateRowsConditionally(cwid, updates);
+        fail("conditional writer not closed");
+      } catch (UnknownWriter uk) {}
+    } finally {
+      if (isKerberosEnabled()) {
+        // Close the other client
+        if (null != cwuserProxyClient) {
+          cwuserProxyClient.close();
+        }
+
+        UserGroupInformation.loginUserFromKeytab(clientPrincipal, clientKeytab.getAbsolutePath());
+        // Re-login and restore the original client
+        client = origClient;
+      }
+      client.dropLocalUser(creds, principal);
+    }
   }
 
   private void checkKey(String row, String cf, String cq, String val, KeyValue keyValue) {