Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id CD2992007D0 for ; Tue, 10 May 2016 11:55:46 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id CBB7A1607AA; Tue, 10 May 2016 09:55:46 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 9C06A160A17 for ; Tue, 10 May 2016 11:55:45 +0200 (CEST) Received: (qmail 45986 invoked by uid 500); 10 May 2016 09:55:44 -0000 Mailing-List: contact commits-help@ambari.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: ambari-dev@ambari.apache.org Delivered-To: mailing list commits@ambari.apache.org Received: (qmail 45916 invoked by uid 99); 10 May 2016 09:55:44 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 10 May 2016 09:55:44 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 78E1AE02D3; Tue, 10 May 2016 09:55:44 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: oleewere@apache.org To: commits@ambari.apache.org Date: Tue, 10 May 2016 09:55:49 -0000 Message-Id: <85ee695b978647f7bcddf1fcb2f36209@git.apache.org> In-Reply-To: <6afffbe5ed024042bff723342bcea0ac@git.apache.org> References: <6afffbe5ed024042bff723342bcea0ac@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [6/6] ambari git commit: AMBARI-16153. Logsearch: Use Ambari Server as credential server (Dharmesh Makwana via oleewere) archived-at: Tue, 10 May 2016 09:55:46 -0000 AMBARI-16153. Logsearch: Use Ambari Server as credential server (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/24b2391e Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/24b2391e Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/24b2391e Branch: refs/heads/trunk Commit: 24b2391efab918ae86dce996912772dc9fbd673f Parents: bdbe7d9 Author: oleewere Authored: Tue May 10 01:06:47 2016 +0200 Committer: oleewere Committed: Tue May 10 11:34:51 2016 +0200 ---------------------------------------------------------------------- .../ambari-logsearch-portal/pom.xml | 8 +- .../logsearch/util/ExternalServerClient.java | 211 +++++++++++++++++++ ...LogsearchAbstractAuthenticationProvider.java | 42 ++-- .../LogsearchAuthenticationProvider.java | 5 + ...rchExternalServerAuthenticationProvider.java | 105 +++++++++ .../LogsearchSimpleAuthenticationProvider.java | 5 +- .../src/main/resources/logsearch.properties | 5 +- 7 files changed, 352 insertions(+), 29 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/24b2391e/ambari-logsearch/ambari-logsearch-portal/pom.xml ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-portal/pom.xml b/ambari-logsearch/ambari-logsearch-portal/pom.xml index 799e95e..b6dd40f 100755 --- a/ambari-logsearch/ambari-logsearch-portal/pom.xml +++ b/ambari-logsearch/ambari-logsearch-portal/pom.xml @@ -33,6 +33,7 @@ 4.2.5.RELEASE 4.0.4.RELEASE 2.0.4.RELEASE + 1.19 @@ -504,7 +505,7 @@ com.sun.jersey.contribs jersey-spring - 1.19 + ${jersey.version} org.springframework @@ -513,6 +514,11 @@ + com.sun.jersey.contribs + jersey-apache-client + ${jersey.version} + + javax.servlet javax.servlet-api 3.1.0 http://git-wip-us.apache.org/repos/asf/ambari/blob/24b2391e/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/util/ExternalServerClient.java ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/util/ExternalServerClient.java b/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/util/ExternalServerClient.java new file mode 100644 index 0000000..32e547e --- /dev/null +++ b/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/util/ExternalServerClient.java @@ -0,0 +1,211 @@ +/* + * 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.ambari.logsearch.util; + +import java.io.IOException; +import java.io.InputStream; +import java.net.UnknownHostException; +import java.util.List; +import java.util.Map.Entry; + +import javax.annotation.PostConstruct; +import javax.ws.rs.WebApplicationException; + +import org.apache.ambari.logsearch.web.security.LogsearchAbstractAuthenticationProvider; +import org.apache.commons.io.IOUtils; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import com.sun.jersey.api.client.Client; +import com.sun.jersey.api.client.ClientHandlerException; +import com.sun.jersey.api.client.ClientResponse; +import com.sun.jersey.api.client.UniformInterfaceException; +import com.sun.jersey.api.client.WebResource; +import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter; +import com.sun.jersey.api.client.filter.LoggingFilter; +import com.sun.jersey.client.apache.ApacheHttpClient; +import com.sun.jersey.client.apache.config.DefaultApacheHttpClientConfig; +import com.sun.jersey.core.util.MultivaluedMapImpl; + +/** + * Layer to send REST request to External server using jersey client + */ +@Component +public class ExternalServerClient { + private static Logger LOG = Logger.getLogger(ExternalServerClient.class); + private static final ThreadLocal localJerseyClient = new ThreadLocal(); + private DefaultApacheHttpClientConfig defaultConfig = new DefaultApacheHttpClientConfig(); + private String hostURL = "http://host:ip";// default + private boolean enableLog = false;// default + + @PostConstruct + public void initialization() { + hostURL = PropertiesUtil.getProperty( + LogsearchAbstractAuthenticationProvider.AUTH_METHOD_PROP_START_WITH + + "external_auth.host_url", hostURL); + } + + private Client getJerseyClient() { + Client jerseyClient = localJerseyClient.get(); + if (jerseyClient == null) { + jerseyClient = ApacheHttpClient.create(defaultConfig); + localJerseyClient.set(jerseyClient); + } + return jerseyClient; + } + + /** + * Send GET Request to External server + * @param url + * @param klass + * @param queryParam + * @param username + * @param password + * @return Response Object + * @throws UnknownHostException + * @throws Exception + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public Object sendGETRequest(String url, Class klass, + MultivaluedMapImpl queryParam, String username, String password) + throws UnknownHostException, Exception { + // add host url + url = hostURL + url; + String parameters = getQueryParameter(queryParam); + LOG.debug("URL: " + url + " query parameters are : " + parameters); + WebResource.Builder builder = buildWebResourceBuilder(url, queryParam, + username, password); + try { + return builder.get(klass); + } catch (WebApplicationException webApplicationException) { + String errMsg = webApplicationExceptionHandler(webApplicationException, + url); + throw new Exception(errMsg); + } catch (UniformInterfaceException uniformInterfaceException) { + String errMsg = uniformInterfaceExceptionHandler( + uniformInterfaceException, url); + throw new Exception(errMsg); + } catch (ClientHandlerException clientHandlerException) { + String errMsg = clientHandlerExceptionHandler(clientHandlerException, url); + throw new Exception(errMsg); + } catch (Exception e) { + Object response = builder.get(Object.class); + String errMsg = "URL: " + url + response.toString(); + LOG.error(errMsg); + throw new Exception(errMsg); + } finally { + cleanup(); + } + } + + private WebResource.Builder buildWebResourceBuilder(String url, + MultivaluedMapImpl queryParam, String username, String password) { + WebResource webResource = getJerseyClient().resource(url); + // add filter + if (enableLog) { + webResource.addFilter(new LoggingFilter()); + } + getJerseyClient().addFilter(new HTTPBasicAuthFilter(username, password)); + // add query param + if (queryParam != null) { + webResource = webResource.queryParams(queryParam); + } + WebResource.Builder builder = webResource.getRequestBuilder(); + return builder; + } + + private String webApplicationExceptionHandler( + WebApplicationException webApplicationException, String url) { + Object object = null; + try { + object = webApplicationException.getResponse().getEntity(); + } catch (Exception e) { + LOG.error(e.getLocalizedMessage()); + } + String errMsg = null; + if (object != null) { + errMsg = object.toString(); + } else { + errMsg = webApplicationException.getMessage(); + } + errMsg = "URL: " + url + errMsg; + LOG.error(errMsg); + return errMsg; + } + + private String uniformInterfaceExceptionHandler( + UniformInterfaceException uniformInterfaceException, String url) { + Object object = null; + String errMsg = null; + ClientResponse clientResponse = uniformInterfaceException.getResponse(); + try { + object = clientResponse.getEntity(Object.class); + if (object != null) { + errMsg = object.toString(); + } + } catch (Exception e) { + InputStream inputStream = clientResponse.getEntityInputStream(); + try { + errMsg = IOUtils.toString(inputStream); + } catch (IOException e1) { + LOG.error(e.getLocalizedMessage()); + } + } + if (errMsg == null) { + errMsg = uniformInterfaceException.getLocalizedMessage(); + } + LOG.error("url :" + url + " Response : " + errMsg); + return errMsg; + } + + private String clientHandlerExceptionHandler( + ClientHandlerException clientHandlerException, String url) { + String errMsg = clientHandlerException.getLocalizedMessage(); + errMsg = "URL: " + url + errMsg; + LOG.error(errMsg); + return errMsg; + } + + private String getQueryParameter(MultivaluedMapImpl queryParam) { + StringBuilder builder = new StringBuilder(); + if (queryParam != null) { + builder.append(" Query param :"); + for (Entry> entry : queryParam.entrySet()) { + String name = entry.getKey(); + builder.append(" name : " + name + " " + "values : ["); + List valuesList = entry.getValue(); + if (valuesList != null) { + for (int index = 0; index < valuesList.size(); index++) { + String value = valuesList.get(index); + if (index > 0) { + builder.append(","); + } + builder.append(value); + } + } + builder.append("]"); + } + } + return builder.toString(); + } + + private void cleanup() { + localJerseyClient.remove(); + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/24b2391e/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/security/LogsearchAbstractAuthenticationProvider.java ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/security/LogsearchAbstractAuthenticationProvider.java b/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/security/LogsearchAbstractAuthenticationProvider.java index 157fdfc..d82bf8e 100644 --- a/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/security/LogsearchAbstractAuthenticationProvider.java +++ b/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/security/LogsearchAbstractAuthenticationProvider.java @@ -24,46 +24,27 @@ import java.util.List; import org.apache.ambari.logsearch.util.PropertiesUtil; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.userdetails.User; -import org.springframework.security.core.userdetails.UserDetails; public abstract class LogsearchAbstractAuthenticationProvider implements AuthenticationProvider { - private static String AUTH_METHOD_PROP_START_WITH = "logsearch.auth."; + public final static String AUTH_METHOD_PROP_START_WITH = "logsearch.auth."; protected enum AUTH_METHOD { - LDAP, FILE, SIMPLE + LDAP, FILE, EXTERNAL_AUTH, SIMPLE }; - @Override public boolean supports(Class authentication) { return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication); } /** - * @param authentication - * @return - */ - public Authentication getAuthenticationWithGrantedAuthority(Authentication authentication) { - UsernamePasswordAuthenticationToken result = null; - if (authentication != null && authentication.isAuthenticated()) { - final List grantedAuths = getAuthorities(authentication.getName().toString()); - final UserDetails userDetails = new User(authentication.getName().toString(), authentication - .getCredentials().toString(), grantedAuths); - result = new UsernamePasswordAuthenticationToken(userDetails, authentication.getCredentials(), grantedAuths); - result.setDetails(authentication.getDetails()); - return result; - } - return authentication; - } - - /** + * GET Default GrantedAuthority + * * @param username - * @return + * @return List */ protected List getAuthorities(String username) { final List grantedAuths = new ArrayList<>(); @@ -71,6 +52,12 @@ public abstract class LogsearchAbstractAuthenticationProvider implements Authent return grantedAuths; } + /** + * Check authentication provider is enable or disable for specified method + * + * @param method + * @return boolean + */ public boolean isEnable(AUTH_METHOD method) { String methodName = method.name().toLowerCase(); String property = AUTH_METHOD_PROP_START_WITH + methodName + ".enable"; @@ -78,8 +65,13 @@ public abstract class LogsearchAbstractAuthenticationProvider implements Authent return isEnable; } + /** + * Check authentication provider is enable or disable + * + * @return boolean + */ public boolean isEnable() { - //default is disabled + // default is disabled return false; } http://git-wip-us.apache.org/repos/asf/ambari/blob/24b2391e/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/security/LogsearchAuthenticationProvider.java ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/security/LogsearchAuthenticationProvider.java b/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/security/LogsearchAuthenticationProvider.java index f29d08f..e17650a 100644 --- a/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/security/LogsearchAuthenticationProvider.java +++ b/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/security/LogsearchAuthenticationProvider.java @@ -50,6 +50,9 @@ public class LogsearchAuthenticationProvider extends @Autowired LogsearchSimpleAuthenticationProvider simpleAuthenticationProvider; + + @Autowired + LogsearchExternalServerAuthenticationProvider externalServerAuthenticationProvider; @Autowired JSONUtil jsonUtil; @@ -133,6 +136,8 @@ public class LogsearchAuthenticationProvider extends authentication = fileAuthenticationProvider.authenticate(authentication); } else if (authMethod.equals(AUTH_METHOD.SIMPLE)) { authentication = simpleAuthenticationProvider.authenticate(authentication); + }else if (authMethod.equals(AUTH_METHOD.EXTERNAL_AUTH)) { + authentication = externalServerAuthenticationProvider.authenticate(authentication); } else { logger.error("Invalid authentication method :" + authMethod.name()); } http://git-wip-us.apache.org/repos/asf/ambari/blob/24b2391e/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 new file mode 100644 index 0000000..79a414c --- /dev/null +++ b/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/security/LogsearchExternalServerAuthenticationProvider.java @@ -0,0 +1,105 @@ +/* + * 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.ambari.logsearch.web.security; + +import javax.annotation.PostConstruct; + +import org.apache.ambari.logsearch.util.ExternalServerClient; +import org.apache.ambari.logsearch.util.PropertiesUtil; +import org.apache.ambari.logsearch.util.StringUtil; +import org.apache.commons.lang.StringEscapeUtils; +import org.apache.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.stereotype.Component; + +/** + * + * Authentication provider to authenticate user from external-server using REST + * call + */ +@Component +public class LogsearchExternalServerAuthenticationProvider extends + LogsearchAbstractAuthenticationProvider { + + private static Logger LOG = Logger + .getLogger(LogsearchExternalServerAuthenticationProvider.class); + + @Autowired + ExternalServerClient externalServerClient; + + @Autowired + StringUtil stringUtil; + + private String loginAPIURL = "/api/v1/clusters";// default + + @PostConstruct + public void initialization() { + loginAPIURL = PropertiesUtil.getProperty(AUTH_METHOD_PROP_START_WITH + + "external_auth.login_url", loginAPIURL); + } + + /** + * 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. + */ + @Override + public Authentication authenticate(Authentication authentication) + throws AuthenticationException { + if (!this.isEnable()) { + LOG.debug("external server auth is disabled."); + return authentication; + } + String username = authentication.getName(); + String password = (String) authentication.getCredentials(); + if (stringUtil.isEmpty(username)) { + throw new BadCredentialsException("Username can't be null or empty."); + } + if (stringUtil.isEmpty(password)) { + throw new BadCredentialsException("Password can't be null or empty."); + } + // html unescape + password = StringEscapeUtils.unescapeHtml(password); + username = StringEscapeUtils.unescapeHtml(username); + try { + externalServerClient.sendGETRequest(loginAPIURL, String.class, null, + username, password); + } catch (Exception e) { + LOG.error("Login failed for username :" + username + " Error :"+ e.getLocalizedMessage()); + throw new BadCredentialsException("Bad credentials"); + } + authentication = new UsernamePasswordAuthenticationToken(username, + password, getAuthorities(username)); + return authentication; + } + + /** + * Return true/false based on EXTERNAL_AUTH authentication method is enabled/disabled + * return boolean + */ + @Override + public boolean isEnable() { + return isEnable(AUTH_METHOD.EXTERNAL_AUTH); + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/24b2391e/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/security/LogsearchSimpleAuthenticationProvider.java ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/security/LogsearchSimpleAuthenticationProvider.java b/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/security/LogsearchSimpleAuthenticationProvider.java index 4dfc30a..7e0546e 100644 --- a/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/security/LogsearchSimpleAuthenticationProvider.java +++ b/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/web/security/LogsearchSimpleAuthenticationProvider.java @@ -59,9 +59,10 @@ public class LogsearchSimpleAuthenticationProvider extends LogsearchAbstractAuth public boolean isEnable(AUTH_METHOD method) { boolean ldapEnabled = super.isEnable(AUTH_METHOD.LDAP); boolean fileEnabled = super.isEnable(AUTH_METHOD.FILE); + boolean externalAuthEnabled = super.isEnable(AUTH_METHOD.EXTERNAL_AUTH); boolean simpleEnabled = super.isEnable(method); - if (!ldapEnabled && !fileEnabled && simpleEnabled) { - // simple is enabled only when rest two are disabled and simple is enable + if (!ldapEnabled && !fileEnabled && simpleEnabled && !externalAuthEnabled) { + // simple is enabled only when rest three are disabled and simple is enable return true; } else { return false; http://git-wip-us.apache.org/repos/asf/ambari/blob/24b2391e/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 b5b0b23..315d736 100755 --- a/ambari-logsearch/ambari-logsearch-portal/src/main/resources/logsearch.properties +++ b/ambari-logsearch/ambari-logsearch-portal/src/main/resources/logsearch.properties @@ -38,7 +38,10 @@ solr.audit_logs.replication_factor=1 logfeeder.include.default.level=fatal,error,warn #Authentication settings -#Note: Simple will be supported only if both file and ldap is disabled. +#Note: Simple will be supported only if file ,ldap and external_auth all three are disabled. logsearch.auth.file.enable=true 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