You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by ja...@apache.org on 2018/09/24 15:28:36 UTC

[31/50] [abbrv] phoenix git commit: PHOENIX-4755 Provide an option to plugin custom avatica server config in PQS

PHOENIX-4755 Provide an option to plugin custom avatica server config in PQS


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

Branch: refs/heads/omid2
Commit: 0639a7426558cf298288e05c193eea438c2f07e5
Parents: 7a2edb8
Author: Karan Mehta <ka...@gmail.com>
Authored: Mon Aug 20 16:52:22 2018 -0700
Committer: Karan Mehta <ka...@gmail.com>
Committed: Tue Aug 21 10:15:49 2018 -0700

----------------------------------------------------------------------
 .../org/apache/phoenix/query/QueryServices.java |   3 +-
 .../phoenix/query/QueryServicesOptions.java     |   1 +
 .../phoenix/end2end/ServerCustomizersIT.java    |   4 +-
 .../AvaticaServerConfigurationFactory.java      |  20 +++
 .../phoenix/queryserver/server/QueryServer.java | 167 ++++++++++++-------
 .../server/ServerCustomizersFactory.java        |   7 +-
 .../CustomAvaticaServerConfigurationTest.java   |  20 +++
 .../server/QueryServerConfigurationTest.java    |  26 ++-
 .../server/ServerCustomizersTest.java           |  13 +-
 9 files changed, 194 insertions(+), 67 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/phoenix/blob/0639a742/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java
index d290174..d681a13 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java
@@ -250,8 +250,9 @@ public interface QueryServices extends SQLCloseable {
     public static final String QUERY_SERVER_KERBEROS_ALLOWED_REALMS = "phoenix.queryserver.kerberos.allowed.realms";
     public static final String QUERY_SERVER_SPNEGO_AUTH_DISABLED_ATTRIB = "phoenix.queryserver.spnego.auth.disabled";
     public static final String QUERY_SERVER_WITH_REMOTEUSEREXTRACTOR_ATTRIB = "phoenix.queryserver.withRemoteUserExtractor";
-    public static final String QUERY_SERVER_REMOTEUSEREXTRACTOR_PARAM = "phoenix.queryserver.remoteUserExtractor.param";
     public static final String QUERY_SERVER_CUSTOMIZERS_ENABLED = "phoenix.queryserver.customizers.enabled";
+    public static final String QUERY_SERVER_CUSTOM_AUTH_ENABLED = "phoenix.queryserver.custom.auth.enabled";
+    public static final String QUERY_SERVER_REMOTEUSEREXTRACTOR_PARAM = "phoenix.queryserver.remoteUserExtractor.param";
     public static final String QUERY_SERVER_DISABLE_KERBEROS_LOGIN = "phoenix.queryserver.disable.kerberos.login";
 
     // metadata configs

http://git-wip-us.apache.org/repos/asf/phoenix/blob/0639a742/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java
index c68e793..76e79fa 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java
@@ -299,6 +299,7 @@ public class QueryServicesOptions {
     public static final int DEFAULT_QUERY_SERVER_UGI_CACHE_CONCURRENCY = 10;
     public static final boolean DEFAULT_QUERY_SERVER_SPNEGO_AUTH_DISABLED = false;
     public static final boolean DEFAULT_QUERY_SERVER_WITH_REMOTEUSEREXTRACTOR = false;
+    public static final boolean DEFAULT_QUERY_SERVER_CUSTOM_AUTH_ENABLED = false;
     public static final String DEFAULT_QUERY_SERVER_REMOTEUSEREXTRACTOR_PARAM = "doAs";
     public static final boolean DEFAULT_QUERY_SERVER_DISABLE_KERBEROS_LOGIN = false;
     public static final boolean DEFAULT_QUERY_SERVER_CUSTOMIZERS_ENABLED = false;

http://git-wip-us.apache.org/repos/asf/phoenix/blob/0639a742/phoenix-queryserver/src/it/java/org/apache/phoenix/end2end/ServerCustomizersIT.java
----------------------------------------------------------------------
diff --git a/phoenix-queryserver/src/it/java/org/apache/phoenix/end2end/ServerCustomizersIT.java b/phoenix-queryserver/src/it/java/org/apache/phoenix/end2end/ServerCustomizersIT.java
index d990adb..db08908 100644
--- a/phoenix-queryserver/src/it/java/org/apache/phoenix/end2end/ServerCustomizersIT.java
+++ b/phoenix-queryserver/src/it/java/org/apache/phoenix/end2end/ServerCustomizersIT.java
@@ -24,6 +24,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.calcite.avatica.server.AvaticaServerConfiguration;
 import org.apache.calcite.avatica.server.ServerCustomizer;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.phoenix.query.QueryServices;
@@ -66,7 +67,8 @@ public class ServerCustomizersIT extends BaseHBaseManagedTimeIT {
         InstanceResolver.clearSingletons();
         InstanceResolver.getSingleton(ServerCustomizersFactory.class, new ServerCustomizersFactory() {
             @Override
-            public List<ServerCustomizer<Server>> createServerCustomizers(Configuration conf) {
+            public List<ServerCustomizer<Server>> createServerCustomizers(Configuration conf,
+                                                                          AvaticaServerConfiguration avaticaServerConfiguration) {
                 return Collections.<ServerCustomizer<Server>>singletonList(new TestServerCustomizer());
             }
         });

http://git-wip-us.apache.org/repos/asf/phoenix/blob/0639a742/phoenix-queryserver/src/main/java/org/apache/phoenix/queryserver/server/AvaticaServerConfigurationFactory.java
----------------------------------------------------------------------
diff --git a/phoenix-queryserver/src/main/java/org/apache/phoenix/queryserver/server/AvaticaServerConfigurationFactory.java b/phoenix-queryserver/src/main/java/org/apache/phoenix/queryserver/server/AvaticaServerConfigurationFactory.java
new file mode 100644
index 0000000..87a72ea
--- /dev/null
+++ b/phoenix-queryserver/src/main/java/org/apache/phoenix/queryserver/server/AvaticaServerConfigurationFactory.java
@@ -0,0 +1,20 @@
+package org.apache.phoenix.queryserver.server;
+
+import org.apache.calcite.avatica.server.AvaticaServerConfiguration;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.security.UserGroupInformation;
+
+
+public interface AvaticaServerConfigurationFactory {
+
+    AvaticaServerConfiguration getAvaticaServerConfiguration(Configuration conf, UserGroupInformation ugi);
+
+    class AvaticaServerConfigurationFactoryImpl implements AvaticaServerConfigurationFactory {
+
+        @Override
+        public AvaticaServerConfiguration getAvaticaServerConfiguration(Configuration conf, UserGroupInformation ugi) {
+            return null;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/phoenix/blob/0639a742/phoenix-queryserver/src/main/java/org/apache/phoenix/queryserver/server/QueryServer.java
----------------------------------------------------------------------
diff --git a/phoenix-queryserver/src/main/java/org/apache/phoenix/queryserver/server/QueryServer.java b/phoenix-queryserver/src/main/java/org/apache/phoenix/queryserver/server/QueryServer.java
index 47466c8..4766394 100644
--- a/phoenix-queryserver/src/main/java/org/apache/phoenix/queryserver/server/QueryServer.java
+++ b/phoenix-queryserver/src/main/java/org/apache/phoenix/queryserver/server/QueryServer.java
@@ -27,6 +27,7 @@ import org.apache.calcite.avatica.Meta;
 import org.apache.calcite.avatica.remote.Driver;
 import org.apache.calcite.avatica.remote.LocalService;
 import org.apache.calcite.avatica.remote.Service;
+import org.apache.calcite.avatica.server.AvaticaServerConfiguration;
 import org.apache.calcite.avatica.server.DoAsRemoteUserCallback;
 import org.apache.calcite.avatica.server.HttpServer;
 import org.apache.calcite.avatica.server.RemoteUserExtractor;
@@ -76,6 +77,8 @@ import java.util.concurrent.TimeUnit;
 
 import javax.servlet.http.HttpServletRequest;
 
+import static org.apache.phoenix.query.QueryServicesOptions.DEFAULT_QUERY_SERVER_CUSTOM_AUTH_ENABLED;
+
 /**
  * A query server for Phoenix over Calcite's Avatica.
  */
@@ -219,27 +222,38 @@ public final class QueryServer extends Configured implements Tool, Runnable {
         LOG.info(" Kerberos is off and hostname is : "+hostname);
       }
 
-      Class<? extends PhoenixMetaFactory> factoryClass = getConf().getClass(
-          QueryServices.QUERY_SERVER_META_FACTORY_ATTRIB, PhoenixMetaFactoryImpl.class,
-          PhoenixMetaFactory.class);
       int port = getConf().getInt(QueryServices.QUERY_SERVER_HTTP_PORT_ATTRIB,
           QueryServicesOptions.DEFAULT_QUERY_SERVER_HTTP_PORT);
       LOG.debug("Listening on port " + port);
-      PhoenixMetaFactory factory =
-          factoryClass.getDeclaredConstructor(Configuration.class).newInstance(getConf());
-      Meta meta = factory.create(Arrays.asList(args));
-      Service service = new LocalService(meta);
+
+      // Update proxyuser configuration for impersonation
+      ProxyUsers.refreshSuperUserGroupsConfiguration(getConf());
 
       // Start building the Avatica HttpServer
-      final HttpServer.Builder<Server> builder = HttpServer.Builder.<Server> newBuilder()
-          .withPort(port).withHandler(service, getSerialization(getConf()));
+      final HttpServer.Builder<Server>
+              builder =
+              HttpServer.Builder.<Server>newBuilder().withPort(port);
+
+      UserGroupInformation ugi = getUserGroupInformation();
 
-      // Enable client auth when using Kerberos auth for HBase
-      if (isKerberos) {
-        configureClientAuthentication(builder, disableSpnego);
+      AvaticaServerConfiguration avaticaServerConfiguration = null;
+
+      // RemoteUserCallbacks and RemoteUserExtractor are part of AvaticaServerConfiguration
+      // Hence they should be customizable when using QUERY_SERVER_CUSTOM_AUTH_ENABLED
+      // Handlers should be customized via ServerCustomizers
+      if (getConf().getBoolean(QueryServices.QUERY_SERVER_CUSTOM_AUTH_ENABLED,
+              DEFAULT_QUERY_SERVER_CUSTOM_AUTH_ENABLED)) {
+        avaticaServerConfiguration = enableCustomAuth(builder, getConf(), ugi);
+      } else {
+        if (isKerberos) {
+          // Enable client auth when using Kerberos auth for HBase
+          configureClientAuthentication(builder, disableSpnego, ugi);
+        }
+        setRemoteUserExtractorIfNecessary(builder, getConf());
+        setHandler(args, builder);
       }
-      setRemoteUserExtractorIfNecessary(builder, getConf());
-      enableServerCustomizersIfNecessary(builder, getConf());
+
+      enableServerCustomizersIfNecessary(builder, getConf(), avaticaServerConfiguration);
 
       // Build and start the HttpServer
       server = builder.build();
@@ -262,48 +276,71 @@ public final class QueryServer extends Configured implements Tool, Runnable {
   }
 
   @VisibleForTesting
-  void configureClientAuthentication(final HttpServer.Builder builder, boolean disableSpnego) throws IOException {
+  void configureClientAuthentication(final HttpServer.Builder builder, boolean disableSpnego, UserGroupInformation ugi) throws IOException {
+
+    // Enable SPNEGO for client authentication unless it's explicitly disabled
+    if (!disableSpnego) {
+      configureSpnegoAuthentication(builder, ugi);
+    }
+    configureCallBack(builder, ugi);
+  }
+
+  @VisibleForTesting
+  void configureSpnegoAuthentication(HttpServer.Builder builder, UserGroupInformation ugi) {
+    String keytabPath = getConf().get(QueryServices.QUERY_SERVER_KEYTAB_FILENAME_ATTRIB);
+    File keytab = new File(keytabPath);
+    String httpKeytabPath =
+            getConf().get(QueryServices.QUERY_SERVER_HTTP_KEYTAB_FILENAME_ATTRIB, null);
+    String httpPrincipal =
+            getConf().get(QueryServices.QUERY_SERVER_KERBEROS_HTTP_PRINCIPAL_ATTRIB, null);
+    // Backwards compat for a configuration key change
+    if (httpPrincipal == null) {
+      httpPrincipal =
+              getConf().get(QueryServices.QUERY_SERVER_KERBEROS_HTTP_PRINCIPAL_ATTRIB_LEGACY, null);
+    }
+    File httpKeytab = null;
+    if (null != httpKeytabPath) {
+        httpKeytab = new File(httpKeytabPath);
+    }
+
+    String realmsString = getConf().get(QueryServices.QUERY_SERVER_KERBEROS_ALLOWED_REALMS, null);
+    String[] additionalAllowedRealms = null;
+    if (null != realmsString) {
+      additionalAllowedRealms = StringUtils.split(realmsString, ',');
+    }
+    if (null != httpKeytabPath && null != httpPrincipal) {
+      builder.withSpnego(httpPrincipal, additionalAllowedRealms).withAutomaticLogin(httpKeytab);
+    } else {
+      builder.withSpnego(ugi.getUserName(), additionalAllowedRealms)
+              .withAutomaticLogin(keytab);
+    }
+  }
+
+  @VisibleForTesting
+  UserGroupInformation getUserGroupInformation() throws IOException {
     UserGroupInformation ugi = UserGroupInformation.getCurrentUser();
     LOG.debug("Current user is " + ugi);
     if (!ugi.hasKerberosCredentials()) {
       ugi = UserGroupInformation.getLoginUser();
       LOG.debug("Current user does not have Kerberos credentials, using instead " + ugi);
     }
+    return ugi;
+  }
 
-    // Make sure the proxyuser configuration is up to date
-    ProxyUsers.refreshSuperUserGroupsConfiguration(getConf());
-
-    // Always enable impersonation for the proxy user (through standard Hadoop configuration means)
+  @VisibleForTesting
+  void configureCallBack(HttpServer.Builder<Server> builder, UserGroupInformation ugi) {
     builder.withImpersonation(new PhoenixDoAsCallback(ugi, getConf()));
+  }
 
-    // Enable SPNEGO for client authentication unless it's explicitly disabled
-    if (!disableSpnego) {
-      String keytabPath = getConf().get(QueryServices.QUERY_SERVER_KEYTAB_FILENAME_ATTRIB);
-      File keytab = new File(keytabPath);
-      String httpKeytabPath =
-          getConf().get(QueryServices.QUERY_SERVER_HTTP_KEYTAB_FILENAME_ATTRIB, null);
-      String httpPrincipal =
-          getConf().get(QueryServices.QUERY_SERVER_KERBEROS_HTTP_PRINCIPAL_ATTRIB, null);
-      // Backwards compat for a configuration key change
-      if (httpPrincipal == null) {
-        httpPrincipal =
-            getConf().get(QueryServices.QUERY_SERVER_KERBEROS_HTTP_PRINCIPAL_ATTRIB_LEGACY, null);
-      }
-      File httpKeytab = null;
-      if (null != httpKeytabPath) httpKeytab = new File(httpKeytabPath);
-
-      String realmsString = getConf().get(QueryServices.QUERY_SERVER_KERBEROS_ALLOWED_REALMS, null);
-      String[] additionalAllowedRealms = null;
-      if (null != realmsString) {
-        additionalAllowedRealms = StringUtils.split(realmsString, ',');
-      }
-      if ((null != httpKeytabPath) && (null != httpPrincipal)) {
-        builder.withSpnego(httpPrincipal, additionalAllowedRealms).withAutomaticLogin(httpKeytab);
-      } else {
-        builder.withSpnego(ugi.getUserName(), additionalAllowedRealms)
-            .withAutomaticLogin(keytab);
-      }
-    }
+  private void setHandler(String[] args, HttpServer.Builder<Server> builder) throws Exception {
+    Class<? extends PhoenixMetaFactory> factoryClass = getConf().getClass(
+            QueryServices.QUERY_SERVER_META_FACTORY_ATTRIB, PhoenixMetaFactoryImpl.class,
+            PhoenixMetaFactory.class);
+    PhoenixMetaFactory factory =
+            factoryClass.getDeclaredConstructor(Configuration.class).newInstance(getConf());
+    Meta meta = factory.create(Arrays.asList(args));
+    Service service = new LocalService(meta);
+    builder.withHandler(service, getSerialization(getConf()));
   }
 
   public synchronized void stop() {
@@ -405,20 +442,32 @@ public final class QueryServer extends Configured implements Tool, Runnable {
     }
   }
 
-  private static final RemoteUserExtractorFactory DEFAULT_USER_EXTRACTOR =
-    new RemoteUserExtractorFactory.RemoteUserExtractorFactoryImpl();
-
   @VisibleForTesting
-  public void enableServerCustomizersIfNecessary(HttpServer.Builder<Server> builder, Configuration conf) {
+  public void enableServerCustomizersIfNecessary(HttpServer.Builder<Server> builder,
+                                                 Configuration conf, AvaticaServerConfiguration avaticaServerConfiguration) {
     if (conf.getBoolean(QueryServices.QUERY_SERVER_CUSTOMIZERS_ENABLED,
             QueryServicesOptions.DEFAULT_QUERY_SERVER_CUSTOMIZERS_ENABLED)) {
-      builder.withServerCustomizers(createServerCustomizers(conf), Server.class);
+      builder.withServerCustomizers(createServerCustomizers(conf, avaticaServerConfiguration), Server.class);
     }
   }
 
+  @VisibleForTesting
+  public AvaticaServerConfiguration enableCustomAuth(HttpServer.Builder<Server> builder,
+                                                     Configuration conf, UserGroupInformation ugi) {
+    AvaticaServerConfiguration avaticaServerConfiguration = createAvaticaServerConfig(conf, ugi);
+    builder.withCustomAuthentication(avaticaServerConfiguration);
+    return avaticaServerConfiguration;
+  }
+
+  private static final RemoteUserExtractorFactory DEFAULT_USER_EXTRACTOR =
+    new RemoteUserExtractorFactory.RemoteUserExtractorFactoryImpl();
+
   private static final ServerCustomizersFactory DEFAULT_SERVER_CUSTOMIZERS =
     new ServerCustomizersFactory.ServerCustomizersFactoryImpl();
 
+  private static final AvaticaServerConfigurationFactory DEFAULT_SERVER_CONFIG =
+    new AvaticaServerConfigurationFactory.AvaticaServerConfigurationFactoryImpl();
+
   @VisibleForTesting
   RemoteUserExtractor createRemoteUserExtractor(Configuration conf) {
     RemoteUserExtractorFactory factory =
@@ -427,16 +476,22 @@ public final class QueryServer extends Configured implements Tool, Runnable {
   }
 
   @VisibleForTesting
-  List<ServerCustomizer<Server>> createServerCustomizers(Configuration conf) {
+  List<ServerCustomizer<Server>> createServerCustomizers(Configuration conf, AvaticaServerConfiguration avaticaServerConfiguration) {
     ServerCustomizersFactory factory =
       InstanceResolver.getSingleton(ServerCustomizersFactory.class, DEFAULT_SERVER_CUSTOMIZERS);
-    return factory.createServerCustomizers(conf);
+    return factory.createServerCustomizers(conf, avaticaServerConfiguration);
+  }
+
+  @VisibleForTesting
+  AvaticaServerConfiguration createAvaticaServerConfig(Configuration conf, UserGroupInformation ugi) {
+    AvaticaServerConfigurationFactory factory =
+            InstanceResolver.getSingleton(AvaticaServerConfigurationFactory.class, DEFAULT_SERVER_CONFIG);
+    return factory.getAvaticaServerConfiguration(conf, ugi);
   }
 
   /**
    * Use the correctly way to extract end user.
    */
-
   static class PhoenixRemoteUserExtractor implements RemoteUserExtractor{
     private final HttpQueryStringParameterRemoteUserExtractor paramRemoteUserExtractor;
     private final HttpRequestRemoteUserExtractor requestRemoteUserExtractor;
@@ -477,7 +532,7 @@ public final class QueryServer extends Configured implements Tool, Runnable {
   /**
    * Callback to run the Avatica server action as the remote (proxy) user instead of the server.
    */
-  static class PhoenixDoAsCallback implements DoAsRemoteUserCallback {
+  public static class PhoenixDoAsCallback implements DoAsRemoteUserCallback {
     private final UserGroupInformation serverUgi;
     private final LoadingCache<String,UserGroupInformation> ugiCache;
 

http://git-wip-us.apache.org/repos/asf/phoenix/blob/0639a742/phoenix-queryserver/src/main/java/org/apache/phoenix/queryserver/server/ServerCustomizersFactory.java
----------------------------------------------------------------------
diff --git a/phoenix-queryserver/src/main/java/org/apache/phoenix/queryserver/server/ServerCustomizersFactory.java b/phoenix-queryserver/src/main/java/org/apache/phoenix/queryserver/server/ServerCustomizersFactory.java
index 462cd5d..942660a 100644
--- a/phoenix-queryserver/src/main/java/org/apache/phoenix/queryserver/server/ServerCustomizersFactory.java
+++ b/phoenix-queryserver/src/main/java/org/apache/phoenix/queryserver/server/ServerCustomizersFactory.java
@@ -20,6 +20,7 @@ package org.apache.phoenix.queryserver.server;
 import java.util.Collections;
 import java.util.List;
 
+import org.apache.calcite.avatica.server.AvaticaServerConfiguration;
 import org.apache.calcite.avatica.server.ServerCustomizer;
 import org.apache.hadoop.conf.Configuration;
 import org.eclipse.jetty.server.Server;
@@ -32,9 +33,10 @@ public interface ServerCustomizersFactory {
     /**
      * Creates a list of customizers that will customize the server.
      * @param conf Configuration to use
+     * @param avaticaServerConfiguration to use in case custom-auth is enabled
      * @return List of server suctomizers
      */
-    List<ServerCustomizer<Server>> createServerCustomizers(Configuration conf);
+    List<ServerCustomizer<Server>> createServerCustomizers(Configuration conf, AvaticaServerConfiguration avaticaServerConfiguration);
 
     /**
      * Factory that creates an empty list of customizers.
@@ -42,7 +44,8 @@ public interface ServerCustomizersFactory {
     class ServerCustomizersFactoryImpl implements ServerCustomizersFactory {
         private static final List<ServerCustomizer<Server>> EMPTY_LIST = Collections.emptyList();
         @Override
-        public List<ServerCustomizer<Server>> createServerCustomizers(Configuration conf) {
+        public List<ServerCustomizer<Server>> createServerCustomizers(Configuration conf,
+                                                                      AvaticaServerConfiguration avaticaServerConfiguration) {
             return EMPTY_LIST;
         }
     }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/0639a742/phoenix-queryserver/src/test/java/org/apache/phoenix/queryserver/server/CustomAvaticaServerConfigurationTest.java
----------------------------------------------------------------------
diff --git a/phoenix-queryserver/src/test/java/org/apache/phoenix/queryserver/server/CustomAvaticaServerConfigurationTest.java b/phoenix-queryserver/src/test/java/org/apache/phoenix/queryserver/server/CustomAvaticaServerConfigurationTest.java
new file mode 100644
index 0000000..20bc868
--- /dev/null
+++ b/phoenix-queryserver/src/test/java/org/apache/phoenix/queryserver/server/CustomAvaticaServerConfigurationTest.java
@@ -0,0 +1,20 @@
+package org.apache.phoenix.queryserver.server;
+
+import org.apache.calcite.avatica.server.AvaticaServerConfiguration;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.IOException;
+
+public class CustomAvaticaServerConfigurationTest {
+    @Test
+    public void testDefaultFactory() throws IOException {
+        QueryServer queryServer = new QueryServer();
+        UserGroupInformation ugi = queryServer.getUserGroupInformation();
+        // the default factory creates null object
+        AvaticaServerConfiguration avaticaServerConfiguration = queryServer.createAvaticaServerConfig(new Configuration(), ugi);
+        Assert.assertNull(avaticaServerConfiguration);
+    }
+}

http://git-wip-us.apache.org/repos/asf/phoenix/blob/0639a742/phoenix-queryserver/src/test/java/org/apache/phoenix/queryserver/server/QueryServerConfigurationTest.java
----------------------------------------------------------------------
diff --git a/phoenix-queryserver/src/test/java/org/apache/phoenix/queryserver/server/QueryServerConfigurationTest.java b/phoenix-queryserver/src/test/java/org/apache/phoenix/queryserver/server/QueryServerConfigurationTest.java
index f2a1022..d01d2ea 100644
--- a/phoenix-queryserver/src/test/java/org/apache/phoenix/queryserver/server/QueryServerConfigurationTest.java
+++ b/phoenix-queryserver/src/test/java/org/apache/phoenix/queryserver/server/QueryServerConfigurationTest.java
@@ -20,10 +20,12 @@ package org.apache.phoenix.queryserver.server;
 import java.io.File;
 import java.io.IOException;
 
+import org.apache.calcite.avatica.server.AvaticaServerConfiguration;
 import org.apache.calcite.avatica.server.DoAsRemoteUserCallback;
 import org.apache.calcite.avatica.server.HttpServer;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hbase.HBaseConfiguration;
+import org.apache.hadoop.security.UserGroupInformation;
 import org.apache.phoenix.query.QueryServices;
 import org.junit.Before;
 import org.junit.Rule;
@@ -39,34 +41,52 @@ public class QueryServerConfigurationTest {
 
   private HttpServer.Builder builder;
   private QueryServer queryServer;
+  private UserGroupInformation ugi;
 
   @Before
   public void setup() throws IOException {
-    File keytabFile = testFolder.newFile("test.keytab");
-    CONF.set(QueryServices.QUERY_SERVER_KEYTAB_FILENAME_ATTRIB, keytabFile.getAbsolutePath());
     builder = mock(HttpServer.Builder.class);
     queryServer = new QueryServer(new String[0], CONF);
+    ugi = queryServer.getUserGroupInformation();
   }
 
   @Test
   public void testSpnegoEnabled() throws IOException {
+    setupKeytabForSpnego();
     // SPENEGO settings will be provided to the builder when enabled
     doReturn(builder).when(builder).withSpnego(anyString(), any(String[].class));
     configureAndVerifyImpersonation(builder, false);
     // A keytab file will also be provided for automatic login
     verify(builder).withAutomaticLogin(any(File.class));
+    verify(builder, never()).withCustomAuthentication(any(AvaticaServerConfiguration.class));
   }
 
   @Test
   public void testSpnegoDisabled() throws IOException {
+    setupKeytabForSpnego();
     configureAndVerifyImpersonation(builder, true);
     verify(builder, never()).withSpnego(anyString(), any(String[].class));
     verify(builder, never()).withAutomaticLogin(any(File.class));
+    verify(builder, never()).withCustomAuthentication(any(AvaticaServerConfiguration.class));
+  }
+
+  @Test
+  public void testCustomServerConfiguration() {
+    queryServer.enableCustomAuth(builder, CONF, ugi);
+    verify(builder).withCustomAuthentication(any(AvaticaServerConfiguration.class));
+    verify(builder, never()).withSpnego(anyString(), any(String[].class));
+    verify(builder, never()).withAutomaticLogin(any(File.class));
+    verify(builder, never()).withImpersonation(any(DoAsRemoteUserCallback.class));
+  }
+
+  private void setupKeytabForSpnego() throws IOException {
+    File keytabFile = testFolder.newFile("test.keytab");
+    CONF.set(QueryServices.QUERY_SERVER_KEYTAB_FILENAME_ATTRIB, keytabFile.getAbsolutePath());
   }
 
   private void configureAndVerifyImpersonation(HttpServer.Builder builder, boolean disableSpnego)
       throws IOException {
-    queryServer.configureClientAuthentication(builder, disableSpnego);
+    queryServer.configureClientAuthentication(builder, disableSpnego, ugi);
     verify(builder).withImpersonation(any(DoAsRemoteUserCallback.class));
   }
 }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/0639a742/phoenix-queryserver/src/test/java/org/apache/phoenix/queryserver/server/ServerCustomizersTest.java
----------------------------------------------------------------------
diff --git a/phoenix-queryserver/src/test/java/org/apache/phoenix/queryserver/server/ServerCustomizersTest.java b/phoenix-queryserver/src/test/java/org/apache/phoenix/queryserver/server/ServerCustomizersTest.java
index 45fec37..93e1e37 100644
--- a/phoenix-queryserver/src/test/java/org/apache/phoenix/queryserver/server/ServerCustomizersTest.java
+++ b/phoenix-queryserver/src/test/java/org/apache/phoenix/queryserver/server/ServerCustomizersTest.java
@@ -21,6 +21,7 @@ import java.util.Collections;
 import java.util.List;
 
 import org.apache.calcite.avatica.server.HttpServer;
+import org.apache.calcite.avatica.server.AvaticaServerConfiguration;
 import org.apache.calcite.avatica.server.ServerCustomizer;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.phoenix.query.QueryServices;
@@ -45,14 +46,16 @@ public class ServerCustomizersTest {
     @Test
     public void testDefaultFactory() {
         QueryServer queryServer = new QueryServer();
+        AvaticaServerConfiguration avaticaServerConfiguration = null;
         // the default factory creates an empty list of server customizers
         List<ServerCustomizer<Server>> customizers =
-            queryServer.createServerCustomizers(new Configuration());
+                queryServer.createServerCustomizers(new Configuration(), avaticaServerConfiguration);
         Assert.assertEquals(0, customizers.size());
     }
 
     @Test
     public void testUseProvidedCustomizers() {
+        AvaticaServerConfiguration avaticaServerConfiguration = null;
         final List<ServerCustomizer<Server>> expected =
             Collections.<ServerCustomizer<Server>> singletonList(new ServerCustomizer<Server>() {
               @Override
@@ -63,25 +66,27 @@ public class ServerCustomizersTest {
         // Register the server customizer list
         InstanceResolver.getSingleton(ServerCustomizersFactory.class, new ServerCustomizersFactory() {
             @Override
-            public List<ServerCustomizer<Server>> createServerCustomizers(Configuration conf) {
+            public List<ServerCustomizer<Server>> createServerCustomizers(Configuration conf,
+                                                                          AvaticaServerConfiguration avaticaServerConfiguration) {
                 return expected;
             }
         });
         Configuration conf = new Configuration(false);
         conf.set(QueryServices.QUERY_SERVER_CUSTOMIZERS_ENABLED, "true");
         QueryServer queryServer = new QueryServer();
-        List<ServerCustomizer<Server>> actual = queryServer.createServerCustomizers(conf);
+        List<ServerCustomizer<Server>> actual = queryServer.createServerCustomizers(conf, avaticaServerConfiguration);
         Assert.assertEquals("Customizers are different", expected, actual);
     }
 
     @Test
     @SuppressWarnings("unchecked")
     public void testEnableCustomizers() {
+        AvaticaServerConfiguration avaticaServerConfiguration = null;
         HttpServer.Builder builder = mock(HttpServer.Builder.class);
         Configuration conf = new Configuration(false);
         conf.set(QueryServices.QUERY_SERVER_CUSTOMIZERS_ENABLED, "true");
         QueryServer queryServer = new QueryServer();
-        queryServer.enableServerCustomizersIfNecessary(builder, conf);
+        queryServer.enableServerCustomizersIfNecessary(builder, conf, avaticaServerConfiguration);
         verify(builder).withServerCustomizers(anyList(), any(Class.class));
     }
 }
\ No newline at end of file