Repository: ambari Updated Branches: refs/heads/branch-2.4 114819b0c -> b990a5030
AMBARI-16629. Logsearch: Authentication changes along with role integration and few minor fixes. (Dharmesh Makwana via oleewere) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/b990a503 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/b990a503 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/b990a503 Branch: refs/heads/branch-2.4 Commit: b990a503003fd23e02b756334e75ce7998a4f85f Parents: 114819b Author: oleewere <[email protected]> Authored: Fri May 13 18:18:51 2016 +0200 Committer: oleewere <[email protected]> Committed: Fri May 13 18:22:45 2016 +0200 ---------------------------------------------------------------------- .../ambari/logsearch/manager/LogsMgr.java | 32 ++-- .../ambari/logsearch/manager/UserConfigMgr.java | 2 - .../logsearch/query/QueryGenerationBase.java | 2 +- .../apache/ambari/logsearch/util/JSONUtil.java | 152 ++++++++++++++----- ...rchExternalServerAuthenticationProvider.java | 106 +++++++++++-- .../src/main/resources/logsearch.properties | 4 +- 6 files changed, 232 insertions(+), 66 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/b990a503/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/manager/LogsMgr.java ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/manager/LogsMgr.java b/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/manager/LogsMgr.java index 0442cf9..411b954 100644 --- a/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/manager/LogsMgr.java +++ b/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); http://git-wip-us.apache.org/repos/asf/ambari/blob/b990a503/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/manager/UserConfigMgr.java ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/manager/UserConfigMgr.java b/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/manager/UserConfigMgr.java index a60402e..7a6e3e9 100644 --- a/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/manager/UserConfigMgr.java +++ b/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); http://git-wip-us.apache.org/repos/asf/ambari/blob/b990a503/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/query/QueryGenerationBase.java ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/query/QueryGenerationBase.java b/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/query/QueryGenerationBase.java index cc61127..a49107d 100644 --- a/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/query/QueryGenerationBase.java +++ b/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: http://git-wip-us.apache.org/repos/asf/ambari/blob/b990a503/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/util/JSONUtil.java ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/util/JSONUtil.java b/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/util/JSONUtil.java index 8535039..4703c58 100644 --- a/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/util/JSONUtil.java +++ b/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; + } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/b990a503/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/security/LogsearchExternalServerAuthenticationProvider.java ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/security/LogsearchExternalServerAuthenticationProvider.java b/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/security/LogsearchExternalServerAuthenticationProvider.java index 79a414c..0fd3770 100644 --- a/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/security/LogsearchExternalServerAuthenticationProvider.java +++ b/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() { http://git-wip-us.apache.org/repos/asf/ambari/blob/b990a503/ambari-logsearch/ambari-logsearch-portal/src/main/resources/logsearch.properties ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-portal/src/main/resources/logsearch.properties b/ambari-logsearch/ambari-logsearch-portal/src/main/resources/logsearch.properties index 315d736..fa8451c 100755 --- a/ambari-logsearch/ambari-logsearch-portal/src/main/resources/logsearch.properties +++ b/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 \ No newline at end of file
