You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@drill.apache.org by ar...@apache.org on 2017/12/09 15:39:26 UTC

[5/5] drill git commit: DRILL-6019: Only admin should be able to access shutdown resources and information about process and admin users

DRILL-6019: Only admin should be able to access shutdown resources and information about process and admin users

1. Only admin should be able to access shutdown resources via REST API.
2. Modified ClusterInfo to show information about process and admin users only when user is logged in and is admin.
3. Added drillbits comparison based on thier adress and ports to check if drillbits are the same (DRILL-6006)

closes #1065


Project: http://git-wip-us.apache.org/repos/asf/drill/repo
Commit: http://git-wip-us.apache.org/repos/asf/drill/commit/0e5ad4e1
Tree: http://git-wip-us.apache.org/repos/asf/drill/tree/0e5ad4e1
Diff: http://git-wip-us.apache.org/repos/asf/drill/diff/0e5ad4e1

Branch: refs/heads/master
Commit: 0e5ad4e1b549f37eb878758409b5afda1deece9d
Parents: aa6666e
Author: Arina Ielchiieva <ar...@gmail.com>
Authored: Fri Dec 8 13:19:40 2017 +0200
Committer: Arina Ielchiieva <ar...@gmail.com>
Committed: Sat Dec 9 15:51:11 2017 +0200

----------------------------------------------------------------------
 .../drill/exec/server/rest/DrillRoot.java       | 117 ++++++++++++-------
 1 file changed, 73 insertions(+), 44 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/drill/blob/0e5ad4e1/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/DrillRoot.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/DrillRoot.java b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/DrillRoot.java
index 02f2731..ca6d748 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/DrillRoot.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/server/rest/DrillRoot.java
@@ -21,6 +21,7 @@ import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
 import javax.annotation.security.PermitAll;
+import javax.annotation.security.RolesAllowed;
 import javax.inject.Inject;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
@@ -31,6 +32,7 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.SecurityContext;
 import javax.xml.bind.annotation.XmlRootElement;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
 import com.google.common.base.Joiner;
 import com.google.common.base.Strings;
 import com.google.common.collect.Sets;
@@ -55,6 +57,8 @@ import org.glassfish.jersey.server.mvc.Viewable;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
 
+import static org.apache.drill.exec.server.rest.auth.DrillUserPrincipal.ADMIN_ROLE;
+
 @Path("/")
 @PermitAll
 public class DrillRoot {
@@ -69,10 +73,6 @@ public class DrillRoot {
   @Inject
   Drillbit drillbit;
 
-  public enum ShutdownMode {
-    forcefulShutdown, gracefulShutdown, quiescent
-  }
-
   @GET
   @Produces(MediaType.TEXT_HTML)
   public Viewable getClusterInfo() {
@@ -90,8 +90,7 @@ public class DrillRoot {
     for (DrillbitInfo drillbit : drillbits) {
       drillStatusMap.put(drillbit.getAddress() + "-" + drillbit.getUserPort(), drillbit.getState());
     }
-    Response response = setResponse(drillStatusMap);
-    return response;
+    return setResponse(drillStatusMap);
   }
 
   @SuppressWarnings("resource")
@@ -99,7 +98,6 @@ public class DrillRoot {
   @Path("/gracePeriod")
   @Produces(MediaType.APPLICATION_JSON)
   public Map<String, Integer> getGracePeriod() {
-
     final DrillConfig config = work.getContext().getConfig();
     final int gracePeriod = config.getInt(ExecConstants.GRACE_PERIOD);
     Map<String, Integer> gracePeriodMap = new HashMap<String, Integer>();
@@ -125,44 +123,42 @@ public class DrillRoot {
   @Path("/queriesCount")
   @Produces(MediaType.APPLICATION_JSON)
   public Response getRemainingQueries() {
-    Map<String, Integer> queriesInfo = new HashMap<String, Integer>();
-    queriesInfo = work.getRemainingQueries();
-    Response response = setResponse(queriesInfo);
-    return response;
+    Map<String, Integer> queriesInfo = work.getRemainingQueries();
+    return setResponse(queriesInfo);
   }
 
   @SuppressWarnings("resource")
   @POST
   @Path("/gracefulShutdown")
   @Produces(MediaType.APPLICATION_JSON)
+  @RolesAllowed(ADMIN_ROLE)
   public Response shutdownDrillbit() throws Exception {
     String resp = "Graceful Shutdown request is triggered";
     return shutdown(resp);
-
   }
 
   @SuppressWarnings("resource")
   @POST
   @Path("/shutdown")
   @Produces(MediaType.APPLICATION_JSON)
-  public Response ShutdownForcefully() throws Exception {
+  @RolesAllowed(ADMIN_ROLE)
+  public Response shutdownForcefully() throws Exception {
     drillbit.setForcefulShutdown(true);
     String resp = "Forceful shutdown request is triggered";
     return shutdown(resp);
-
   }
 
   @SuppressWarnings("resource")
   @POST
   @Path("/quiescent")
   @Produces(MediaType.APPLICATION_JSON)
+  @RolesAllowed(ADMIN_ROLE)
   public Response drillbitToQuiescentMode() throws Exception {
     drillbit.setQuiescentMode(true);
     String resp = "Request to put drillbit in Quiescent mode is triggered";
     return shutdown(resp);
   }
 
-
   @SuppressWarnings("resource")
   @GET
   @Path("/cluster.json")
@@ -180,36 +176,58 @@ public class DrillRoot {
             config.getBoolean(ExecConstants.USER_ENCRYPTION_SASL_ENABLED) ||
                     config .getBoolean(ExecConstants.USER_SSL_ENABLED);
     final boolean bitEncryptionEnabled = config.getBoolean(ExecConstants.BIT_ENCRYPTION_SASL_ENABLED);
-    // If the user is logged in and is admin user then show the admin user info
-    // For all other cases the user info need-not or should-not be displayed
+
     OptionManager optionManager = work.getContext().getOptionManager();
     final boolean isUserLoggedIn = AuthDynamicFeature.isUserLoggedIn(sc);
-    final String processUser = ImpersonationUtil.getProcessUserName();
-    final String processUserGroups = Joiner.on(", ").join(ImpersonationUtil.getProcessUserGroupNames());
-    String adminUsers = ExecConstants.ADMIN_USERS_VALIDATOR.getAdminUsers(optionManager);
-    String adminUserGroups = ExecConstants.ADMIN_USER_GROUPS_VALIDATOR.getAdminUserGroups(optionManager);
-
-    final boolean shouldShowAdminInfo = isUserLoggedIn &&
-            ((DrillUserPrincipal)sc.getUserPrincipal()).isAdminUser();
+    final boolean shouldShowAdminInfo = isUserLoggedIn && ((DrillUserPrincipal)sc.getUserPrincipal()).isAdminUser();
 
     for (DrillbitEndpoint endpoint : work.getContext().getAvailableBits()) {
       final DrillbitInfo drillbit = new DrillbitInfo(endpoint,
-              currentDrillbit.equals(endpoint),
+              isDrillbitsTheSame(currentDrillbit, endpoint),
               currentVersion.equals(endpoint.getVersion()));
       if (!drillbit.isVersionMatch()) {
         mismatchedVersions.add(drillbit.getVersion());
       }
       drillbits.add(drillbit);
     }
-    logger.debug("Admin info: user: "  + adminUsers +  " user group: " + adminUserGroups +
-            " userLoggedIn "  + isUserLoggedIn + " shouldShowAdminInfo: " + shouldShowAdminInfo );
+
+    // If the user is logged in and is admin user then show the admin user info
+    // For all other cases the user info need-not or should-not be displayed
+    if (shouldShowAdminInfo) {
+      final String processUser = ImpersonationUtil.getProcessUserName();
+      final String processUserGroups = Joiner.on(", ").join(ImpersonationUtil.getProcessUserGroupNames());
+      String adminUsers = ExecConstants.ADMIN_USERS_VALIDATOR.getAdminUsers(optionManager);
+      String adminUserGroups = ExecConstants.ADMIN_USER_GROUPS_VALIDATOR.getAdminUserGroups(optionManager);
+
+      logger.debug("Admin info: user: "  + adminUsers +  " user group: " + adminUserGroups +
+          " userLoggedIn "  + isUserLoggedIn + " shouldShowAdminInfo: " + shouldShowAdminInfo);
+
+      return new ClusterInfo(drillbits, currentVersion, mismatchedVersions,
+          userEncryptionEnabled, bitEncryptionEnabled, shouldShowAdminInfo,
+          QueueInfo.build(dbContext.getResourceManager()),
+          processUser, processUserGroups, adminUsers, adminUserGroups);
+    }
 
     return new ClusterInfo(drillbits, currentVersion, mismatchedVersions,
-            userEncryptionEnabled, bitEncryptionEnabled, processUser, processUserGroups, adminUsers,
-            adminUserGroups, shouldShowAdminInfo, QueueInfo.build(dbContext.getResourceManager()));
+        userEncryptionEnabled, bitEncryptionEnabled, shouldShowAdminInfo,
+        QueueInfo.build(dbContext.getResourceManager()));
+  }
+
+  /**
+   * Compares two drillbits based on their address and ports (control, data, user).
+   *
+   * @param endpoint1 first drillbit to compare
+   * @param endpoint2 second drillbit to compare
+   * @return true if drillbit are the same
+   */
+  private boolean isDrillbitsTheSame(DrillbitEndpoint endpoint1, DrillbitEndpoint endpoint2) {
+    return endpoint1.getAddress().equals(endpoint2.getAddress()) &&
+        endpoint1.getControlPort() == endpoint2.getControlPort() &&
+        endpoint1.getDataPort() == endpoint2.getDataPort() &&
+        endpoint1.getUserPort() == endpoint2.getUserPort();
   }
 
-  public Response setResponse(Map entity) {
+  private Response setResponse(Map entity) {
     return Response.ok()
             .entity(entity)
             .header("Access-Control-Allow-Origin", "*")
@@ -218,7 +236,7 @@ public class DrillRoot {
             .allow("OPTIONS").build();
   }
 
-  public Response shutdown(String resp) throws Exception {
+  private Response shutdown(String resp) throws Exception {
     Map<String, String> shutdownInfo = new HashMap<String, String>();
     new Thread(new Runnable() {
         public void run() {
@@ -230,11 +248,9 @@ public class DrillRoot {
         }
       }).start();
     shutdownInfo.put("response",resp);
-    Response response = setResponse(shutdownInfo);
-    return response;
+    return setResponse(shutdownInfo);
   }
 
-
 /**
  * Pretty-printing wrapper class around the ZK-based queue summary.
  */
@@ -317,29 +333,27 @@ public static class QueueInfo {
 }
 
 @XmlRootElement
+@JsonInclude(JsonInclude.Include.NON_ABSENT)
 public static class ClusterInfo {
   private final Collection<DrillbitInfo> drillbits;
   private final String currentVersion;
   private final Collection<String> mismatchedVersions;
   private final boolean userEncryptionEnabled;
   private final boolean bitEncryptionEnabled;
-  private final String adminUsers;
-  private final String adminUserGroups;
-  private final String processUser;
-  private final String processUserGroups;
   private final boolean shouldShowAdminInfo;
   private final QueueInfo queueInfo;
 
+  private String adminUsers;
+  private String adminUserGroups;
+  private String processUser;
+  private String processUserGroups;
+
   @JsonCreator
   public ClusterInfo(Collection<DrillbitInfo> drillbits,
                      String currentVersion,
                      Collection<String> mismatchedVersions,
                      boolean userEncryption,
                      boolean bitEncryption,
-                     String processUser,
-                     String processUserGroups,
-                     String adminUsers,
-                     String adminUserGroups,
                      boolean shouldShowAdminInfo,
                      QueueInfo queueInfo) {
     this.drillbits = Sets.newTreeSet(drillbits);
@@ -347,12 +361,27 @@ public static class ClusterInfo {
     this.mismatchedVersions = Sets.newTreeSet(mismatchedVersions);
     this.userEncryptionEnabled = userEncryption;
     this.bitEncryptionEnabled = bitEncryption;
+    this.shouldShowAdminInfo = shouldShowAdminInfo;
+    this.queueInfo = queueInfo;
+  }
+
+  @JsonCreator
+  public ClusterInfo(Collection<DrillbitInfo> drillbits,
+                     String currentVersion,
+                     Collection<String> mismatchedVersions,
+                     boolean userEncryption,
+                     boolean bitEncryption,
+                     boolean shouldShowAdminInfo,
+                     QueueInfo queueInfo,
+                     String processUser,
+                     String processUserGroups,
+                     String adminUsers,
+                     String adminUserGroups) {
+    this(drillbits, currentVersion, mismatchedVersions, userEncryption, bitEncryption, shouldShowAdminInfo, queueInfo);
     this.processUser = processUser;
     this.processUserGroups = processUserGroups;
     this.adminUsers = adminUsers;
     this.adminUserGroups = adminUserGroups;
-    this.shouldShowAdminInfo = shouldShowAdminInfo;
-    this.queueInfo = queueInfo;
   }
 
   public Collection<DrillbitInfo> getDrillbits() {