DRILL-7562: Support HTTP Basic authentication for REST API calls

This can greatly simplify the development of HTTP clients, as well as
use from the command line using curl/wget, since you don't have to
deal with storing the session cookie.

closes #1972
diff --git a/distribution/src/main/resources/drill-override-example.conf b/distribution/src/main/resources/drill-override-example.conf
index e72396c..0c04175 100644
--- a/distribution/src/main/resources/drill-override-example.conf
+++ b/distribution/src/main/resources/drill-override-example.conf
@@ -103,8 +103,8 @@
     },
     auth: {
         # Http Auth mechanisms to configure. If not provided but user.auth is enabled
-        # then default value is FORM.
-        mechanisms: ["FORM", "SPNEGO"],
+        # then default value is ["FORM"].
+        mechanisms: ["BASIC", "FORM", "SPNEGO"],
         # Spnego principal to be used by WebServer when Spnego authentication is enabled.
         spnego.principal: "HTTP://<localhost>"
         # Location to keytab file for above spnego principal
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/auth/DrillHttpConstraintSecurityHandler.java b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/auth/DrillHttpConstraintSecurityHandler.java
index 8ba6ddf..99ca966 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/auth/DrillHttpConstraintSecurityHandler.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/auth/DrillHttpConstraintSecurityHandler.java
@@ -17,6 +17,7 @@
  */
 package org.apache.drill.exec.server.rest.auth;
 
+import org.apache.drill.exec.rpc.security.plain.PlainFactory;
 import org.apache.drill.shaded.guava.com.google.common.collect.ImmutableSet;
 import org.apache.drill.common.exceptions.DrillException;
 import org.apache.drill.exec.server.DrillbitContext;
@@ -38,24 +39,33 @@
  **/
 public abstract class DrillHttpConstraintSecurityHandler extends ConstraintSecurityHandler {
 
-    @Override
-    public void doStart() throws Exception {
-        super.doStart();
+  @Override
+  public void doStart() throws Exception {
+    super.doStart();
+  }
+
+  @Override
+  public void doStop() throws Exception {
+    super.doStop();
+  }
+
+  public abstract void doSetup(DrillbitContext dbContext) throws DrillException;
+
+  public void setup(LoginAuthenticator authenticator, LoginService loginService) {
+    final Set<String> knownRoles = ImmutableSet.of(AUTHENTICATED_ROLE, ADMIN_ROLE);
+    setConstraintMappings(Collections.<ConstraintMapping>emptyList(), knownRoles);
+    setAuthenticator(authenticator);
+    setLoginService(loginService);
+  }
+
+  protected void requireAuthProvider(DrillbitContext dbContext, String name) throws DrillException {
+    // Check if PAMAuthenticator is available or not which is required for FORM authentication
+    if (!dbContext.getAuthProvider().containsFactory(PlainFactory.SIMPLE_NAME)) {
+      throw new DrillException(String.format("%1$s auth mechanism was configured but %2$s mechanism is not enabled to provide an " +
+        "authenticator. Please configure user authentication with %2$s mechanism and authenticator to use " +
+        "%1$s authentication", getImplName(), name));
     }
+  }
 
-    @Override
-    public void doStop() throws Exception {
-        super.doStop();
-    }
-
-    public abstract void doSetup(DrillbitContext dbContext) throws DrillException;
-
-    public void setup(LoginAuthenticator authenticator, LoginService loginService) {
-      final Set<String> knownRoles = ImmutableSet.of(AUTHENTICATED_ROLE, ADMIN_ROLE);
-      setConstraintMappings(Collections.<ConstraintMapping>emptyList(), knownRoles);
-      setAuthenticator(authenticator);
-      setLoginService(loginService);
-    }
-
-    public abstract String getImplName();
+  public abstract String getImplName();
 }
\ No newline at end of file
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/auth/DrillHttpSecurityHandlerProvider.java b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/auth/DrillHttpSecurityHandlerProvider.java
index e95a057..e3087ca 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/auth/DrillHttpSecurityHandlerProvider.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/auth/DrillHttpSecurityHandlerProvider.java
@@ -27,6 +27,7 @@
 import org.apache.drill.exec.rpc.security.AuthStringUtil;
 import org.apache.drill.exec.server.DrillbitContext;
 import org.apache.drill.exec.server.rest.WebServerConstants;
+import org.eclipse.jetty.http.HttpHeader;
 import org.eclipse.jetty.security.ConstraintSecurityHandler;
 import org.eclipse.jetty.security.authentication.SessionAuthentication;
 import org.eclipse.jetty.server.Handler;
@@ -139,10 +140,14 @@
       if (isSpnegoEnabled() && (!isFormEnabled() || uri.equals(WebServerConstants.SPENGO_LOGIN_RESOURCE_PATH))) {
         securityHandler = securityHandlers.get(Constraint.__SPNEGO_AUTH);
         securityHandler.handle(target, baseRequest, request, response);
+      } else if(isBasicEnabled() && request.getHeader(HttpHeader.AUTHORIZATION.asString()) != null) {
+        securityHandler = securityHandlers.get(Constraint.__BASIC_AUTH);
+        securityHandler.handle(target, baseRequest, request, response);
       } else if (isFormEnabled()) {
         securityHandler = securityHandlers.get(Constraint.__FORM_AUTH);
         securityHandler.handle(target, baseRequest, request, response);
       }
+
     }
     // If user has logged in, use the corresponding handler to handle the request
     else {
@@ -175,6 +180,10 @@
     return securityHandlers.containsKey(Constraint.__FORM_AUTH);
   }
 
+  public boolean isBasicEnabled() {
+    return securityHandlers.containsKey(Constraint.__BASIC_AUTH);
+  }
+
   /**
    * Return's list of configured mechanisms for HTTP authentication. For backward
    * compatibility if authentication is enabled it will include FORM mechanism by default.
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/auth/FormSecurityHandler.java b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/auth/FormSecurityHandler.java
index 2c19d41..8169a40 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/auth/FormSecurityHandler.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/auth/FormSecurityHandler.java
@@ -33,15 +33,10 @@
   @Override
   public void doSetup(DrillbitContext dbContext) throws DrillException {
 
-    // Check if PAMAuthenticator is available or not which is required for FORM authentication
-    if (!dbContext.getAuthProvider().containsFactory(PlainFactory.SIMPLE_NAME)) {
-      throw new DrillException("FORM mechanism was configured but PLAIN mechanism is not enabled to provide an " +
-          "authenticator. Please configure user authentication with PLAIN mechanism and authenticator to use " +
-          "FORM authentication");
-    }
+    requireAuthProvider(dbContext, PlainFactory.SIMPLE_NAME);
 
     setup(new FormAuthenticator(WebServerConstants.FORM_LOGIN_RESOURCE_PATH,
-        WebServerConstants.FORM_LOGIN_RESOURCE_PATH, true), new DrillRestLoginService(dbContext));
+      WebServerConstants.FORM_LOGIN_RESOURCE_PATH, true), new DrillRestLoginService(dbContext));
   }
 
 }
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/auth/HttpBasicAuthSecurityHandler.java b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/auth/HttpBasicAuthSecurityHandler.java
new file mode 100644
index 0000000..2657186
--- /dev/null
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/auth/HttpBasicAuthSecurityHandler.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.exec.server.rest.auth;
+
+import org.apache.drill.common.exceptions.DrillException;
+import org.apache.drill.exec.rpc.security.plain.PlainFactory;
+import org.apache.drill.exec.server.DrillbitContext;
+import org.eclipse.jetty.security.authentication.BasicAuthenticator;
+import org.eclipse.jetty.util.security.Constraint;
+
+/**
+ * Implement HTTP Basic authentication for REST API access
+ */
+public class HttpBasicAuthSecurityHandler extends DrillHttpConstraintSecurityHandler {
+  @Override
+  public String getImplName() {
+    return Constraint.__BASIC_AUTH;
+  }
+
+  @Override
+  public void doSetup(DrillbitContext dbContext) throws DrillException {
+
+    requireAuthProvider(dbContext, PlainFactory.SIMPLE_NAME);
+
+    setup(new BasicAuthenticator(), new DrillRestLoginService(dbContext));
+  }
+
+}