ソースを参照

AMBARI-16629. Logsearch: Authentication changes along with role integration and few minor fixes. (Dharmesh Makwana via oleewere)

oleewere 9 年 前
コミット
b990a50300

+ 17 - 15
ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/manager/LogsMgr.java

@@ -1534,11 +1534,13 @@ public class LogsMgr extends MgrBase {
           List<PivotField> levelList = singlePivotField.getPivot();
           List<VNameValue> levelCountList = new ArrayList<VNameValue>();
           comp.setLogLevelCount(levelCountList);
+          if(levelList != null){
           for (PivotField levelPivot : levelList) {
-            VNameValue level = new VNameValue();
-            level.setName(("" + levelPivot.getValue()).toUpperCase());
-            level.setValue("" + levelPivot.getCount());
-            levelCountList.add(level);
+		  VNameValue level = new VNameValue();
+		  level.setName(("" + levelPivot.getValue()).toUpperCase());
+		  level.setValue("" + levelPivot.getCount());
+		  levelCountList.add(level);
+		}
           }
           datatList.add(comp);
         }
@@ -1841,19 +1843,19 @@ public class LogsMgr extends MgrBase {
         sequenceId, maxRows).getList();
       SolrDocumentList after = whenScrollDown(searchCriteria, logTime,
         sequenceId, maxRows).getList();
-      if (before == null || before.isEmpty()){
-        return convertObjToString(vSolrLogList);
-      }
-      for (SolrDocument solrDoc : Lists.reverse(before)) {
-        initial.add(solrDoc);
-      }
+			if (before != null && !before.isEmpty()) {
+				for (SolrDocument solrDoc : Lists.reverse(before)) {
+					initial.add(solrDoc);
+				}
+			}
+
       initial.add(docList.get(0));
-      if (after == null || after.isEmpty()){
-        return convertObjToString(vSolrLogList);
-      }
-      for (SolrDocument solrDoc : after) {
-        initial.add(solrDoc);
+      if (after != null && !after.isEmpty()){
+        for (SolrDocument solrDoc : after) {
+          initial.add(solrDoc);
+	      }
       }
+
       vSolrLogList.setSolrDocuments(initial);
      
         return convertObjToString(vSolrLogList);

+ 0 - 2
ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/manager/UserConfigMgr.java

@@ -231,8 +231,6 @@ public class UserConfigMgr extends MgrBase {
       userConfigList.setPageSize((int) searchCriteria.getMaxRows());
 
       userConfigList.setTotalCount((long) solrList.getNumFound());
-      userConfigList.setResultSize((int) (configList.size() - searchCriteria
-          .getStartIndex()));
     } catch (SolrException | SolrServerException | IOException e) {
       // do nothing
       logger.error(e);

+ 1 - 1
ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/query/QueryGenerationBase.java

@@ -417,7 +417,7 @@ public abstract class QueryGenerationBase extends QueryBase {
       String[] values = paramValue.split(LogSearchConstants.LIST_SEPARATOR);
       switch (condition) {
       case OR:
-        return solrUtil.orList(solrFieldName, values,"*");
+        return solrUtil.orList(solrFieldName, values,"");
       case AND:
         return solrUtil.andList(solrFieldName, values, "");
       default:

+ 114 - 38
ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/util/JSONUtil.java

@@ -24,19 +24,20 @@ import java.io.FileWriter;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
 import org.apache.ambari.logsearch.common.MessageEnums;
 import org.apache.log4j.Logger;
+import org.codehaus.jackson.JsonGenerationException;
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.map.JsonMappingException;
 import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.type.TypeReference;
 import org.codehaus.jettison.json.JSONArray;
 import org.codehaus.jettison.json.JSONException;
 import org.codehaus.jettison.json.JSONObject;
-import org.codehaus.jackson.type.TypeReference;
-import org.codehaus.jackson.JsonGenerationException;
-import org.codehaus.jackson.JsonParseException;
-import org.codehaus.jackson.map.JsonMappingException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
@@ -58,8 +59,7 @@ public class JSONUtil {
   Gson gson = new GsonBuilder().setDateFormat(DATE_FORMAT).create();
 
   // Conversion from JSONArray to List<String>
-  public static List<String> JSONToList(JSONArray jarray)
-    throws JSONException {
+  public static List<String> JSONToList(JSONArray jarray) throws JSONException {
     ArrayList<String> list = new ArrayList<String>();
     JSONArray jsonArray = jarray;
     if (jsonArray != null) {
@@ -80,22 +80,22 @@ public class JSONUtil {
     ObjectMapper mapper = new ObjectMapper();
     try {
       Object tempObject = mapper.readValue(jsonStr,
-        new TypeReference<HashMap<String, String>>() {
-        });
+          new TypeReference<HashMap<String, String>>() {
+          });
       return (HashMap<String, String>) tempObject;
 
     } catch (JsonParseException e) {
       throw restErrorUtil.createRESTException(
-        "Invalid input data: " + e.getMessage(),
-        MessageEnums.INVALID_INPUT_DATA);
+          "Invalid input data: " + e.getMessage(),
+          MessageEnums.INVALID_INPUT_DATA);
     } catch (JsonMappingException e) {
       throw restErrorUtil.createRESTException(
-        "Invalid input data: " + e.getMessage(),
-        MessageEnums.INVALID_INPUT_DATA);
+          "Invalid input data: " + e.getMessage(),
+          MessageEnums.INVALID_INPUT_DATA);
     } catch (IOException e) {
       throw restErrorUtil.createRESTException(
-        "Invalid input data: " + e.getMessage(),
-        MessageEnums.INVALID_INPUT_DATA);
+          "Invalid input data: " + e.getMessage(),
+          MessageEnums.INVALID_INPUT_DATA);
     }
 
   }
@@ -109,22 +109,22 @@ public class JSONUtil {
     ObjectMapper mapper = new ObjectMapper();
     try {
       Object tempObject = mapper.readValue(jsonStr,
-        new TypeReference<HashMap<String, Object>>() {
-        });
+          new TypeReference<HashMap<String, Object>>() {
+          });
       return (HashMap<String, Object>) tempObject;
 
     } catch (JsonParseException e) {
       throw restErrorUtil.createRESTException(
-        "Invalid input data: " + e.getMessage(),
-        MessageEnums.INVALID_INPUT_DATA);
+          "Invalid input data: " + e.getMessage(),
+          MessageEnums.INVALID_INPUT_DATA);
     } catch (JsonMappingException e) {
       throw restErrorUtil.createRESTException(
-        "Invalid input data: " + e.getMessage(),
-        MessageEnums.INVALID_INPUT_DATA);
+          "Invalid input data: " + e.getMessage(),
+          MessageEnums.INVALID_INPUT_DATA);
     } catch (IOException e) {
       throw restErrorUtil.createRESTException(
-        "Invalid input data: " + e.getMessage(),
-        MessageEnums.INVALID_INPUT_DATA);
+          "Invalid input data: " + e.getMessage(),
+          MessageEnums.INVALID_INPUT_DATA);
     }
 
   }
@@ -137,22 +137,22 @@ public class JSONUtil {
     ObjectMapper mapper = new ObjectMapper();
     try {
       Object tempObject = mapper.readValue(jsonStr,
-        new TypeReference<List<HashMap<String, Object>>>() {
-        });
+          new TypeReference<List<HashMap<String, Object>>>() {
+          });
       return (List<HashMap<String, Object>>) tempObject;
 
     } catch (JsonParseException e) {
       throw restErrorUtil.createRESTException(
-        "Invalid input data: " + e.getMessage(),
-        MessageEnums.INVALID_INPUT_DATA);
+          "Invalid input data: " + e.getMessage(),
+          MessageEnums.INVALID_INPUT_DATA);
     } catch (JsonMappingException e) {
       throw restErrorUtil.createRESTException(
-        "Invalid input data: " + e.getMessage(),
-        MessageEnums.INVALID_INPUT_DATA);
+          "Invalid input data: " + e.getMessage(),
+          MessageEnums.INVALID_INPUT_DATA);
     } catch (IOException e) {
       throw restErrorUtil.createRESTException(
-        "Invalid input data: " + e.getMessage(),
-        MessageEnums.INVALID_INPUT_DATA);
+          "Invalid input data: " + e.getMessage(),
+          MessageEnums.INVALID_INPUT_DATA);
     }
 
   }
@@ -178,8 +178,8 @@ public class JSONUtil {
     ObjectMapper mapper = new ObjectMapper();
     try {
       HashMap<String, Object> jsonmap = mapper.readValue(jsonFile,
-        new TypeReference<HashMap<String, Object>>() {
-        });
+          new TypeReference<HashMap<String, Object>>() {
+          });
       return jsonmap;
     } catch (JsonParseException e) {
       logger.error(e, e.getCause());
@@ -209,13 +209,13 @@ public class JSONUtil {
 
   /**
    * WRITE JOSN IN FILE ( Delete existing file and create new file)
-   *
+   * 
    * @param jsonStr
    * @param outputFile
    * @param beautify
    */
   public synchronized void writeJSONInFile(String jsonStr, File outputFile,
-                              boolean beautify) {
+      boolean beautify) {
     FileWriter fileWriter = null;
     if (outputFile == null) {
       logger.error("user_pass json file can't be null.");
@@ -231,13 +231,14 @@ public class JSONUtil {
         if (beautify) {
           ObjectMapper mapper = new ObjectMapper();
           Object json = mapper.readValue(jsonStr, Object.class);
-          jsonStr = mapper.writerWithDefaultPrettyPrinter()
-            .writeValueAsString(json);
+          jsonStr = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(
+              json);
         }
         fileWriter.write(jsonStr);
       } else {
-        logger.error("Applcation does not have permission to update file to write enc_password. file="
-          + outputFile.getAbsolutePath());
+        logger
+            .error("Applcation does not have permission to update file to write enc_password. file="
+                + outputFile.getAbsolutePath());
       }
     } catch (IOException e) {
       logger.error("Error writing to password file.", e.getCause());
@@ -261,4 +262,79 @@ public class JSONUtil {
   public Object jsonToObj(String json, Class<?> klass) {
     return gson.fromJson(json, klass);
   }
+
+  /**
+   * GET VALUES FROM JSON BY GIVING KEY RECURSIVELY
+   * 
+   * @param jsonStr
+   * @param keyName
+   * @return
+   */
+  @SuppressWarnings("rawtypes")
+  public static String getValuesOfKey(String jsonStr, String keyName,
+      List<String> values) {
+    if (values == null) {
+      return null;
+    }
+    Object jsonObj = null;
+    try {
+      jsonObj = new JSONObject(jsonStr);
+    } catch (Exception e) {
+      // ignore
+    }
+    if (jsonObj == null) {
+      try {
+        JSONArray jsonArray = new JSONArray(jsonStr);
+        String str = null;
+        for (int i = 0; i < jsonArray.length(); i++) {
+
+          str = getValuesOfKey(jsonArray.getString(i), keyName, values);
+          if (str != null) {
+            return str;
+          }
+        }
+
+      } catch (Exception e) {
+        // ignore
+      }
+    }
+    if (jsonObj == null) {
+      return null;
+    }
+
+    Iterator iterator = ((JSONObject) jsonObj).keys();
+    if (iterator == null) {
+      return null;
+    }
+    while (iterator.hasNext()) {
+      String key = (String) iterator.next();
+
+      if (key != null && key.equals(keyName)) {
+
+        try {
+          String val = ((JSONObject) jsonObj).getString(key);
+          values.add(val);
+        } catch (Exception e) {
+          // ignore
+        }
+
+      } else if ((((JSONObject) jsonObj).optJSONArray(key) != null)
+          || (((JSONObject) jsonObj).optJSONObject(key) != null)) {
+
+        String str = null;
+        try {
+          str = getValuesOfKey("" + ((JSONObject) jsonObj).getString(key),
+              keyName, values);
+        } catch (Exception e) {
+          // ignore
+        }
+        if (str != null) {
+          return str;
+        }
+
+      }
+
+    }
+    return null;
+  }
 }

+ 97 - 9
ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/security/LogsearchExternalServerAuthenticationProvider.java

@@ -18,9 +18,13 @@
  */
 package org.apache.ambari.logsearch.web.security;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import javax.annotation.PostConstruct;
 
 import org.apache.ambari.logsearch.util.ExternalServerClient;
+import org.apache.ambari.logsearch.util.JSONUtil;
 import org.apache.ambari.logsearch.util.PropertiesUtil;
 import org.apache.ambari.logsearch.util.StringUtil;
 import org.apache.commons.lang.StringEscapeUtils;
@@ -44,13 +48,63 @@ public class LogsearchExternalServerAuthenticationProvider extends
   private static Logger LOG = Logger
       .getLogger(LogsearchExternalServerAuthenticationProvider.class);
 
+  public final static String ALLOWED_ROLE_PROP = "logsearch.roles.allowed";
+
+  public static enum PRIVILEGE_INFO {
+    PERMISSION_LABEL {
+      @Override
+      public String toString() {
+        return "permission_label";
+      }
+    },
+    PERMISSION_NAME {
+      @Override
+      public String toString() {
+        return "permission_name";
+      }
+    },
+    PRINCIPAL_NAME {
+      @Override
+      public String toString() {
+        return "principal_name";
+      }
+    },
+    PRINCIPAL_TYPE {
+      @Override
+      public String toString() {
+        return "principal_type";
+      }
+    },
+    PRIVILEGE_ID {
+      @Override
+      public String toString() {
+        return "privilege_id";
+      }
+    },
+    TYPE {
+      @Override
+      public String toString() {
+        return "type";
+      }
+    },
+    USER_NAME {
+      @Override
+      public String toString() {
+        return "user_name";
+      }
+    };
+  }
+
   @Autowired
   ExternalServerClient externalServerClient;
 
   @Autowired
   StringUtil stringUtil;
 
-  private String loginAPIURL = "/api/v1/clusters";// default
+  @Autowired
+  JSONUtil jsonUtil;
+
+  private String loginAPIURL = "/api/v1/users/$USERNAME/privileges?fields=*";// default
 
   @PostConstruct
   public void initialization() {
@@ -59,10 +113,13 @@ public class LogsearchExternalServerAuthenticationProvider extends
   }
 
   /**
-   * Authenticating user from external-server using REST call 
-   * @param authentication the authentication request object.
+   * Authenticating user from external-server using REST call
+   * 
+   * @param authentication
+   *          the authentication request object.
    * @return a fully authenticated object including credentials.
-   * @throws AuthenticationException if authentication fails.
+   * @throws AuthenticationException
+   *           if authentication fails.
    */
   @Override
   public Authentication authenticate(Authentication authentication)
@@ -83,10 +140,17 @@ public class LogsearchExternalServerAuthenticationProvider extends
     password = StringEscapeUtils.unescapeHtml(password);
     username = StringEscapeUtils.unescapeHtml(username);
     try {
-      externalServerClient.sendGETRequest(loginAPIURL, String.class, null,
-          username, password);
+      String finalLoginUrl = loginAPIURL.replace("$USERNAME", username);
+      String responseObj = (String) externalServerClient.sendGETRequest(
+          finalLoginUrl, String.class, null, username, password);
+      if (!isAllowedRole(responseObj)) {
+        LOG.error(username + " does'nt have permission");
+        throw new BadCredentialsException("Invalid User");
+      }
+
     } catch (Exception e) {
-      LOG.error("Login failed for username :" + username + " Error :"+ e.getLocalizedMessage());
+      LOG.error("Login failed for username :" + username + " Error :"
+          + e.getLocalizedMessage());
       throw new BadCredentialsException("Bad credentials");
     }
     authentication = new UsernamePasswordAuthenticationToken(username,
@@ -95,8 +159,32 @@ public class LogsearchExternalServerAuthenticationProvider extends
   }
 
   /**
-   * Return true/false based on EXTERNAL_AUTH authentication method is enabled/disabled
-   * return boolean
+   * Return true/false based on PEMISSION NAME return boolean
+   */
+  @SuppressWarnings("static-access")
+  private boolean isAllowedRole(String responseJson) {
+    String allowedRoleList[] = PropertiesUtil
+        .getPropertyStringList(ALLOWED_ROLE_PROP);
+
+    if (allowedRoleList.length > 0 && responseJson != null) {
+      List<String> values = new ArrayList<String>();
+      jsonUtil.getValuesOfKey(responseJson,
+          PRIVILEGE_INFO.PERMISSION_NAME.toString(), values);
+
+      for (String allowedRole : allowedRoleList) {
+        for (String role : values) {
+          if (role.equals(allowedRole)) {
+            return true;
+          }
+        }
+      }
+    }
+    return false;
+  }
+
+  /**
+   * Return true/false based on EXTERNAL_AUTH authentication method is
+   * enabled/disabled return boolean
    */
   @Override
   public boolean isEnable() {

+ 3 - 1
ambari-logsearch/ambari-logsearch-portal/src/main/resources/logsearch.properties

@@ -44,4 +44,6 @@ logsearch.auth.ldap.enable=false
 logsearch.auth.simple.enable=false
 logsearch.auth.external_auth.enable=false
 logsearch.auth.external_auth.host_url=http://ip:port
-logsearch.auth.external_auth.login_url=/api/v1/clusters
+logsearch.auth.external_auth.login_url=/api/v1/users/$USERNAME/privileges?fields=*
+#Note: Use comma(,) for separation of multiple roles
+logsearch.roles.allowed=AMBARI.ADMIN