http://git-wip-us.apache.org/repos/asf/ambari/blob/b0f1e340/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/authenticate/LogsearchLogoutSuccessHandler.java ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/authenticate/LogsearchLogoutSuccessHandler.java b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/authenticate/LogsearchLogoutSuccessHandler.java new file mode 100644 index 0000000..c20e383 --- /dev/null +++ b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/authenticate/LogsearchLogoutSuccessHandler.java @@ -0,0 +1,41 @@ +/* + * 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.authenticate; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.log4j.Logger; +import org.springframework.security.core.Authentication; +import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; +import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler; + +public class LogsearchLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler implements LogoutSuccessHandler { + private static final Logger logger = Logger.getLogger(LogsearchLogoutSuccessHandler.class); + + @Override + public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) + throws IOException, ServletException { + logger.debug("LogsearchLogoutSuccessHandler ::: onLogoutSuccess"); + response.sendRedirect("/index.html"); + } +}
http://git-wip-us.apache.org/repos/asf/ambari/blob/b0f1e340/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/AbstractLogsearchGlobalStateFilter.java ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/AbstractLogsearchGlobalStateFilter.java b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/AbstractLogsearchGlobalStateFilter.java new file mode 100644 index 0000000..4d529fb --- /dev/null +++ b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/AbstractLogsearchGlobalStateFilter.java @@ -0,0 +1,100 @@ +/* + * 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.filters; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.ambari.logsearch.common.MessageEnums; +import org.apache.ambari.logsearch.common.VResponse; +import org.apache.ambari.logsearch.conf.SolrPropsConfig; +import org.apache.ambari.logsearch.conf.global.SolrCollectionState; +import org.apache.ambari.logsearch.util.RESTErrorUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.web.util.matcher.RequestMatcher; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +abstract public class AbstractLogsearchGlobalStateFilter implements Filter { + + private static final Logger LOG = LoggerFactory.getLogger(AbstractLogsearchGlobalStateFilter.class); + + protected static final String ZNODE_NOT_READY_MSG = "ZNode is not available for %s. (connection string: %s, endpoint: %s)"; + protected static final String ZK_CONFIG_NOT_READY_MSG = "Collection configuration has not uploaded yet for %s. (configuration name: %s, collection name: %s, endpoint: %s)"; + protected static final String SOLR_COLLECTION_NOT_READY_MSG = "Solr has not accessible yet for %s collection. (endpoint: %s)"; + + private SolrCollectionState solrCollectionState; + private RequestMatcher requestMatcher; + private SolrPropsConfig solrPropsConfig; + + public AbstractLogsearchGlobalStateFilter(RequestMatcher requestMatcher, SolrCollectionState state, SolrPropsConfig solrPropsConfig) { + this.requestMatcher = requestMatcher; + this.solrCollectionState = state; + this.solrPropsConfig = solrPropsConfig; + } + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { + HttpServletRequest request = (HttpServletRequest) servletRequest; + if (requestMatcher.matches(request)) { + VResponse errorResponse = getErrorResponse(solrCollectionState, solrPropsConfig, request); + if (errorResponse != null) { + LOG.info("{} request is filtered out: {}", request.getRequestURL(), errorResponse.getMsgDesc()); + HttpServletResponse resp = (HttpServletResponse) servletResponse; + resp.setStatus(500); + resp.setContentType("application/json"); + resp.getWriter().print(createStringFromErrorMessageObject(errorResponse)); + return; + } + } + filterChain.doFilter(servletRequest, servletResponse); + } + + @Override + public void destroy() { + } + + /** + * Fill the error message with data in case of any condition based on collection state. + * If return value is null, that means there were no any errors + * @param solrCollectionState object to store solr state (e.g. : zookeeper/solr collection availability) + * @param solrPropsConfig object to store details for solr collection (e.g. : collection name, connection string) + */ + public abstract VResponse getErrorResponse(SolrCollectionState solrCollectionState, SolrPropsConfig solrPropsConfig, HttpServletRequest request); + + private String createStringFromErrorMessageObject(VResponse responseObject) { + try { + ObjectMapper mapper = new ObjectMapper(); + return mapper.writeValueAsString(responseObject); + } catch (Exception e) { + throw RESTErrorUtil.createRESTException("Cannot parse response object on backend", MessageEnums.ERROR_CREATING_OBJECT); + } + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/b0f1e340/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchAuditLogsStateFilter.java ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchAuditLogsStateFilter.java b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchAuditLogsStateFilter.java new file mode 100644 index 0000000..117fdd4 --- /dev/null +++ b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchAuditLogsStateFilter.java @@ -0,0 +1,51 @@ +/* + * 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.filters; + +import org.apache.ambari.logsearch.common.MessageEnums; +import org.apache.ambari.logsearch.common.VResponse; +import org.apache.ambari.logsearch.conf.SolrPropsConfig; +import org.apache.ambari.logsearch.conf.global.SolrCollectionState; +import org.apache.ambari.logsearch.util.RESTErrorUtil; +import org.springframework.security.web.util.matcher.RequestMatcher; + +import javax.servlet.http.HttpServletRequest; + +public class LogsearchAuditLogsStateFilter extends AbstractLogsearchGlobalStateFilter { + + public LogsearchAuditLogsStateFilter(RequestMatcher requestMatcher, SolrCollectionState state, SolrPropsConfig solrPropsConfig) { + super(requestMatcher, state, solrPropsConfig); + } + + @Override + public VResponse getErrorResponse(SolrCollectionState solrCollectionState, SolrPropsConfig solrPropsConfig, HttpServletRequest request) { + String requestUri = request.getRequestURI(); + if (!solrCollectionState.isZnodeReady()) { + return RESTErrorUtil.createMessageResponse(String.format(ZNODE_NOT_READY_MSG, + "audit logs", solrPropsConfig.getZkConnectString(), requestUri), MessageEnums.ZNODE_NOT_READY); + } else if (!solrCollectionState.isConfigurationUploaded()) { + return RESTErrorUtil.createMessageResponse(String.format(ZK_CONFIG_NOT_READY_MSG, "audit logs", + solrPropsConfig.getConfigName(), solrPropsConfig.getCollection(), requestUri), MessageEnums.ZK_CONFIG_NOT_READY); + } else if (!solrCollectionState.isSolrCollectionReady()) { + return RESTErrorUtil.createMessageResponse(String.format(SOLR_COLLECTION_NOT_READY_MSG, + solrPropsConfig.getCollection(), requestUri), MessageEnums.SOLR_COLLECTION_NOT_READY); + } + return null; + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/b0f1e340/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchAuthenticationEntryPoint.java ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchAuthenticationEntryPoint.java b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchAuthenticationEntryPoint.java new file mode 100644 index 0000000..1831697 --- /dev/null +++ b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchAuthenticationEntryPoint.java @@ -0,0 +1,50 @@ +/* + * 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.filters; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.log4j.Logger; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; + +public class LogsearchAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint { + private static final Logger logger = Logger.getLogger(LogsearchAuthenticationEntryPoint.class); + + public LogsearchAuthenticationEntryPoint(String loginFormUrl) { + super(loginFormUrl); + } + + @Override + public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) + throws IOException, ServletException { + String ajaxRequestHeader = request.getHeader("X-Requested-With"); + if (ajaxRequestHeader != null && ajaxRequestHeader.equalsIgnoreCase("XMLHttpRequest")) { + logger.debug("AJAX request. Authentication required. Returning URL=" + request.getRequestURI()); + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Session Timeout"); + } else { + logger.debug("Redirecting to login page :" + this.getLoginFormUrl()); + response.sendRedirect(this.getLoginFormUrl() + ((request.getQueryString() != null) ? "?" + request.getQueryString() : "")); + } + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/b0f1e340/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchCorsFilter.java ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchCorsFilter.java b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchCorsFilter.java new file mode 100644 index 0000000..f5e7bca --- /dev/null +++ b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchCorsFilter.java @@ -0,0 +1,59 @@ +/* + * 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.filters; + +import org.apache.ambari.logsearch.conf.LogSearchHttpHeaderConfig; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +public class LogsearchCorsFilter implements Filter { + + private LogSearchHttpHeaderConfig logSearchHttpHeaderConfig; + + public LogsearchCorsFilter(LogSearchHttpHeaderConfig logSearchHttpHeaderConfig) { + this.logSearchHttpHeaderConfig = logSearchHttpHeaderConfig; + } + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) + throws IOException, ServletException { + HttpServletResponse response = (HttpServletResponse) servletResponse; + response.setHeader("Access-Control-Allow-Origin", logSearchHttpHeaderConfig.getAccessControlAllowOrigin()); + response.setHeader("Access-Control-Allow-Headers", logSearchHttpHeaderConfig.getAccessControlAllowHeaders()); + response.setHeader("Access-Control-Allow-Credentials", logSearchHttpHeaderConfig.getAccessControlAllowCredentials()); + response.setHeader("Access-Control-Allow-Methods", logSearchHttpHeaderConfig.getAccessControlAllowMethods()); + filterChain.doFilter(servletRequest, servletResponse); + } + + @Override + public void destroy() { + + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/b0f1e340/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchJWTFilter.java ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchJWTFilter.java b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchJWTFilter.java new file mode 100644 index 0000000..1bc7231 --- /dev/null +++ b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchJWTFilter.java @@ -0,0 +1,181 @@ +/* + * 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.filters; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.ExpiredJwtException; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.MalformedJwtException; +import io.jsonwebtoken.SignatureException; +import org.apache.ambari.logsearch.conf.AuthPropsConfig; +import org.apache.ambari.logsearch.web.model.JWTAuthenticationToken; +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.authentication.AnonymousAuthenticationToken; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; +import org.springframework.security.web.util.matcher.NegatedRequestMatcher; +import org.springframework.security.web.util.matcher.RequestMatcher; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPublicKey; + +public class LogsearchJWTFilter extends AbstractAuthenticationProcessingFilter { + + private static final Logger LOG = LoggerFactory.getLogger(LogsearchJWTFilter.class); + + private static final String PEM_HEADER = "-----BEGIN CERTIFICATE-----\n"; + private static final String PEM_FOOTER = "\n-----END CERTIFICATE-----"; + + private AuthPropsConfig authPropsConfig; + + public LogsearchJWTFilter(RequestMatcher requestMatcher, AuthPropsConfig authPropsConfig) { + super(new NegatedRequestMatcher(requestMatcher)); + this.authPropsConfig = authPropsConfig; + } + + @Override + public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException { + if (StringUtils.isEmpty(authPropsConfig.getProvidedUrl())) { + throw new BadCredentialsException("Authentication provider URL must not be null or empty."); + } + if (StringUtils.isEmpty(authPropsConfig.getPublicKey())) { + throw new BadCredentialsException("Public key for signature validation must be provisioned."); + } + + try { + Claims claims = Jwts + .parser() + .setSigningKey(parseRSAPublicKey(authPropsConfig.getPublicKey())) + .parseClaimsJws(getJWTFromCookie(request)) + .getBody(); + + String userName = claims.getSubject(); + LOG.info("USERNAME: " + userName); + LOG.info("URL = " + request.getRequestURL()); + if (StringUtils.isNotEmpty(claims.getAudience()) && !authPropsConfig.getAudiences().contains(claims.getAudience())) { + throw new IllegalArgumentException(String.format("Audience validation failed. (Not found: %s)", claims.getAudience())); + } + Authentication authentication = new JWTAuthenticationToken(userName, authPropsConfig.getPublicKey()); + authentication.setAuthenticated(true); + SecurityContextHolder.getContext().setAuthentication(authentication); + return authentication; + } catch (ExpiredJwtException | MalformedJwtException | SignatureException | IllegalArgumentException e) { + LOG.info("URL = " + request.getRequestURL()); + LOG.warn("Error during JWT authentication: ", e.getMessage()); + throw new BadCredentialsException(e.getMessage(), e); + } + } + + @Override + public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (!authPropsConfig.isAuthJwtEnabled() || isAuthenticated(authentication)) { + chain.doFilter(req, res); + return; + } + super.doFilter(req, res, chain); + } + + @Override + protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException { + super.successfulAuthentication(request, response, chain, authResult); + response.sendRedirect(request.getRequestURL().toString() + getOriginalQueryString(request)); + } + + @Override + protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException { + super.unsuccessfulAuthentication(request, response, failed); + String loginUrl = constructLoginURL(request); + response.sendRedirect(loginUrl); + } + + private String getJWTFromCookie(HttpServletRequest req) { + String serializedJWT = null; + Cookie[] cookies = req.getCookies(); + if (cookies != null) { + for (Cookie cookie : cookies) { + if (authPropsConfig.getCookieName().equals(cookie.getName())) { + LOG.info(authPropsConfig.getCookieName() + " cookie has been found and is being processed"); + serializedJWT = cookie.getValue(); + break; + } + } + } + return serializedJWT; + } + + private RSAPublicKey parseRSAPublicKey(String pem) throws ServletException { + String fullPem = PEM_HEADER + pem + PEM_FOOTER; + try { + CertificateFactory fact = CertificateFactory.getInstance("X.509"); + ByteArrayInputStream is = new ByteArrayInputStream(fullPem.getBytes("UTF8")); + + X509Certificate cer = (X509Certificate) fact.generateCertificate(is); + return (RSAPublicKey) cer.getPublicKey(); + } catch (CertificateException ce) { + String message; + if (pem.startsWith(PEM_HEADER)) { + message = "CertificateException - be sure not to include PEM header " + + "and footer in the PEM configuration element."; + } else { + message = "CertificateException - PEM may be corrupt"; + } + throw new ServletException(message, ce); + } catch (UnsupportedEncodingException uee) { + throw new ServletException(uee); + } + } + + private String constructLoginURL(HttpServletRequest request) { + String delimiter = "?"; + if (authPropsConfig.getProvidedUrl().contains("?")) { + delimiter = "&"; + } + return authPropsConfig.getProvidedUrl() + delimiter + + authPropsConfig.getOriginalUrlQueryParam() + "=" + + request.getRequestURL().toString() + getOriginalQueryString(request); + } + + private String getOriginalQueryString(HttpServletRequest request) { + String originalQueryString = request.getQueryString(); + return (originalQueryString == null) ? "" : "?" + originalQueryString; + } + + private boolean isAuthenticated(Authentication authentication) { + return authentication != null && !(authentication instanceof AnonymousAuthenticationToken) && authentication.isAuthenticated(); + } + +} http://git-wip-us.apache.org/repos/asf/ambari/blob/b0f1e340/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchKRBAuthenticationFilter.java ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchKRBAuthenticationFilter.java b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchKRBAuthenticationFilter.java new file mode 100644 index 0000000..1b77753 --- /dev/null +++ b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchKRBAuthenticationFilter.java @@ -0,0 +1,338 @@ +/* + * 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.filters; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.security.authentication.AbstractAuthenticationToken; +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.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.context.SecurityContextImpl; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.apache.ambari.logsearch.common.PropertiesHelper; +import org.apache.commons.collections.iterators.IteratorEnumeration; +import org.apache.commons.lang.StringEscapeUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.hadoop.security.authentication.server.KerberosAuthenticationHandler; +import org.apache.hadoop.security.authentication.server.PseudoAuthenticationHandler; +import org.apache.hadoop.security.authentication.util.KerberosName; +import org.springframework.security.web.authentication.WebAuthenticationDetails; + +public class LogsearchKRBAuthenticationFilter extends LogsearchKrbFilter { + private static final Logger logger = LoggerFactory.getLogger(LogsearchKRBAuthenticationFilter.class); + + private static final String NAME_RULES = "hadoop.security.auth_to_local"; + private static final String TOKEN_VALID = "logsearch.admin.kerberos.token.valid.seconds"; + private static final String COOKIE_DOMAIN = "logsearch.admin.kerberos.cookie.domain"; + private static final String COOKIE_PATH = "logsearch.admin.kerberos.cookie.path"; + private static final String PRINCIPAL = "logsearch.spnego.kerberos.principal"; + private static final String KEYTAB = "logsearch.spnego.kerberos.keytab"; + private static final String HOST_NAME = "logsearch.spnego.kerberos.host"; + private static final String KERBEROS_ENABLED = "logsearch.spnego.kerberos.enabled"; + + private static final String NAME_RULES_PARAM = "kerberos.name.rules"; + private static final String TOKEN_VALID_PARAM = "token.validity"; + private static final String COOKIE_DOMAIN_PARAM = "cookie.domain"; + private static final String COOKIE_PATH_PARAM = "cookie.path"; + private static final String PRINCIPAL_PARAM = "kerberos.principal"; + private static final String KEYTAB_PARAM = "kerberos.keytab"; + private static final String AUTH_TYPE = "type"; + private static final String AUTH_COOKIE_NAME = "hadoop.auth"; + private static final String DEFAULT_USER_ROLE = "ROLE_USER"; + + private static final NoServletContext NO_SERVLET_CONTEXT = new NoServletContext(); + private static final Pattern usernamePattern = Pattern.compile("(?<=u=)(.*?)(?=&)|(?<=u=)(.*)"); + + private String authType = PseudoAuthenticationHandler.TYPE; + private static boolean spnegoEnable = false; + + public LogsearchKRBAuthenticationFilter() { + try { + isSpnegoEnable(); + init(null); + } catch (ServletException e) { + logger.error("Error while initializing Filter : " + e.getMessage()); + } + } + + @Override + public void init(FilterConfig conf) throws ServletException { + final FilterConfig globalConf = conf; + String hostName = PropertiesHelper.getProperty(HOST_NAME, "localhost"); + final Map<String, String> params = new HashMap<String, String>(); + if (spnegoEnable) { + authType = KerberosAuthenticationHandler.TYPE; + } + params.put(AUTH_TYPE,authType); + params.put(NAME_RULES_PARAM,PropertiesHelper.getProperty(NAME_RULES, "DEFAULT")); + params.put(TOKEN_VALID_PARAM, PropertiesHelper.getProperty(TOKEN_VALID, "30")); + params.put(COOKIE_DOMAIN_PARAM, PropertiesHelper.getProperty(COOKIE_DOMAIN, hostName)); + params.put(COOKIE_PATH_PARAM, PropertiesHelper.getProperty(COOKIE_PATH, "/")); + params.put(PRINCIPAL_PARAM,PropertiesHelper.getProperty(PRINCIPAL,"")); + params.put(KEYTAB_PARAM,PropertiesHelper.getProperty(KEYTAB,"")); + FilterConfig myConf = new FilterConfig() { + @Override + public ServletContext getServletContext() { + if (globalConf != null) { + return globalConf.getServletContext(); + } else { + return NO_SERVLET_CONTEXT; + } + } + + @SuppressWarnings("unchecked") + @Override + public Enumeration<String> getInitParameterNames() { + return new IteratorEnumeration(params.keySet().iterator()); + } + + @Override + public String getInitParameter(String param) { + return params.get(param); + } + + @Override + public String getFilterName() { + return "KerberosFilter"; + } + }; + super.init(myConf); + } + + @Override + protected void doFilter(FilterChain filterChain, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + logger.debug("LogsearchKRBAuthenticationFilter private filter"); + String userName = getUsernameFromResponse(response); + if (StringUtils.isNotEmpty(userName)) { + Authentication existingAuth = SecurityContextHolder.getContext() + .getAuthentication(); + if (existingAuth == null || !existingAuth.isAuthenticated()) { + // --------------------------- To Create Logsearch Session-------------------------------------- + // if we get the userName from the token then log into Logsearch using the same user + final List<GrantedAuthority> grantedAuths = new ArrayList<>(); + grantedAuths.add(new SimpleGrantedAuthority(DEFAULT_USER_ROLE)); + final UserDetails principal = new User(userName, "", grantedAuths); + final Authentication finalAuthentication = new UsernamePasswordAuthenticationToken( + principal, "", grantedAuths); + WebAuthenticationDetails webDetails = new WebAuthenticationDetails( + request); + ((AbstractAuthenticationToken) finalAuthentication) + .setDetails(webDetails); + Authentication authentication = this + .authenticate(finalAuthentication); + authentication = getGrantedAuthority(authentication); + SecurityContextHolder.getContext().setAuthentication(authentication); + request.getSession(true).setAttribute("SPRING_SECURITY_CONTEXT", + SecurityContextHolder.getContext()); + request.setAttribute("spnegoEnabled", true); + logger.info("Logged into Logsearch as = " + userName); + filterChain.doFilter(request, response); + } else { + try { + super.doFilter(filterChain, request, response); + } catch (Exception e) { + logger.error("Error LogsearchKRBAuthenticationFilter : " + e.getMessage()); + } + } + } else { + filterChain.doFilter(request, response); + } + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, + FilterChain filterChain) throws IOException, ServletException { + HttpServletRequest httpRequest = (HttpServletRequest) request; + logger.debug("LogsearchKRBAuthenticationFilter public filter path >>>>" +httpRequest.getPathInfo()); + SecurityContextImpl securityContextImpl=(SecurityContextImpl) httpRequest.getSession(true).getAttribute("SPRING_SECURITY_CONTEXT"); + Authentication existingAuth = null; + if(securityContextImpl!=null){ + existingAuth= securityContextImpl.getAuthentication(); + } + if (!isLoginRequest(httpRequest) && spnegoEnable + && (existingAuth == null || !existingAuth.isAuthenticated())) { + KerberosName.setRules(PropertiesHelper.getProperty(NAME_RULES, "DEFAULT")); + String userName = getUsernameFromRequest(httpRequest); + if ((existingAuth == null || !existingAuth.isAuthenticated()) + && (StringUtils.isNotEmpty(userName))) { + // --------------------------- To Create Logsearch Session-------------------------------------- + // if we get the userName from the token then log into logsearch using the same user + final List<GrantedAuthority> grantedAuths = new ArrayList<>(); + grantedAuths.add(new SimpleGrantedAuthority(DEFAULT_USER_ROLE)); + final UserDetails principal = new User(userName, "", grantedAuths); + final Authentication finalAuthentication = new UsernamePasswordAuthenticationToken( + principal, "", grantedAuths); + WebAuthenticationDetails webDetails = new WebAuthenticationDetails( + httpRequest); + ((AbstractAuthenticationToken) finalAuthentication) + .setDetails(webDetails); + Authentication authentication = this + .authenticate(finalAuthentication); + authentication = getGrantedAuthority(authentication); + SecurityContextHolder.getContext().setAuthentication(authentication); + request.setAttribute("spnegoEnabled", true); + logger.info("Logged into Logsearch as = " + userName); + }else { + try { + super.doFilter(request, response, filterChain); + } catch (Exception e) { + logger.error("Error LogsearchKRBAuthenticationFilter : " + e.getMessage()); + } + } + } else { + filterChain.doFilter(request, response); + } + } + + private void isSpnegoEnable() { + spnegoEnable = PropertiesHelper.getBooleanProperty(KERBEROS_ENABLED, false); + if (spnegoEnable) { + spnegoEnable = false; + String keytab = PropertiesHelper.getProperty(KEYTAB); + String principal = PropertiesHelper.getProperty(PRINCIPAL); + String hostname = PropertiesHelper.getProperty(HOST_NAME); + if (StringUtils.isNotEmpty(keytab) && StringUtils.isNotEmpty(principal) + && StringUtils.isNotEmpty(hostname)) { + spnegoEnable = true; + } + } + } + + private Authentication getGrantedAuthority(Authentication authentication) { + UsernamePasswordAuthenticationToken result = null; + if (authentication != null && authentication.isAuthenticated()) { + final List<GrantedAuthority> grantedAuths = getAuthorities(); + 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; + } + + private List<GrantedAuthority> getAuthorities() { + final List<GrantedAuthority> grantedAuths = new ArrayList<>(); + grantedAuths.add(new SimpleGrantedAuthority(DEFAULT_USER_ROLE)); + return grantedAuths; + } + + private Authentication authenticate(Authentication authentication) + throws AuthenticationException { + String username = authentication.getName(); + String password = (String) authentication.getCredentials(); + username = StringEscapeUtils.unescapeHtml(username); + if (StringUtils.isEmpty(username)) { + throw new BadCredentialsException("Username can't be null or empty."); + } + org.apache.ambari.logsearch.web.model.User user = new org.apache.ambari.logsearch.web.model.User(); + user.setUsername(username); + authentication = new UsernamePasswordAuthenticationToken(username, + password, getAuthorities()); + return authentication; + } + + private String getUsernameFromRequest(HttpServletRequest httpRequest) { + String userName = null; + Cookie[] cookie = httpRequest.getCookies(); + if (cookie != null) { + for (Cookie c : cookie) { + if (c.getName().equalsIgnoreCase(AUTH_COOKIE_NAME)) { + String cookieStr = c.getName() + "=" + c.getValue(); + Matcher m = usernamePattern.matcher(cookieStr); + if (m.find()) { + userName = m.group(1); + } + } + } + } + logger.debug("kerberos username from request >>>>>>>>" + userName); + return userName; + } + + private String getUsernameFromResponse(HttpServletResponse response) { + String userName = null; + boolean checkCookie = response.containsHeader("Set-Cookie"); + if (checkCookie) { + Collection<String> cookiesCollection = response.getHeaders("Set-Cookie"); + if (cookiesCollection != null) { + Iterator<String> iterator = cookiesCollection.iterator(); + while (iterator.hasNext()) { + String cookie = iterator.next(); + if (StringUtils.isNotEmpty(cookie)) { + if (cookie.toLowerCase().startsWith(AUTH_COOKIE_NAME.toLowerCase())) { + Matcher m = usernamePattern.matcher(cookie); + if (m.find()) { + userName = m.group(1); + } + } + } + if (StringUtils.isNotEmpty(userName)) { + break; + } + } + } + } + logger.debug("kerberos username from response >>>>>>>>" + userName); + return userName; + } + + + + private boolean isLoginRequest(HttpServletRequest httpServletRequest) { + boolean isLoginRequest = false; + if ("POST".equalsIgnoreCase(httpServletRequest.getMethod())) { + String url = httpServletRequest.getRequestURI().toString(); + if ("/login".equalsIgnoreCase(url)) { + isLoginRequest = true; + } + } + return isLoginRequest; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/b0f1e340/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchKrbFilter.java ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchKrbFilter.java b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchKrbFilter.java new file mode 100644 index 0000000..f4e70d7 --- /dev/null +++ b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchKrbFilter.java @@ -0,0 +1,581 @@ +/* + * 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.filters; + +import org.apache.commons.lang.StringUtils; +import org.apache.hadoop.security.authentication.client.AuthenticatedURL; +import org.apache.hadoop.security.authentication.client.AuthenticationException; +import org.apache.hadoop.security.authentication.client.KerberosAuthenticator; +import org.apache.hadoop.security.authentication.server.AuthenticationHandler; +import org.apache.hadoop.security.authentication.server.AuthenticationToken; +import org.apache.hadoop.security.authentication.server.KerberosAuthenticationHandler; +import org.apache.hadoop.security.authentication.server.PseudoAuthenticationHandler; +import org.apache.hadoop.security.authentication.util.*; +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.classification.InterfaceStability; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import javax.servlet.http.HttpServletResponse; + +import java.io.IOException; +import java.security.Principal; +import java.text.SimpleDateFormat; +import java.util.*; + +import static org.apache.ambari.logsearch.common.LogSearchConstants.LOGSEARCH_SESSION_ID; + +@InterfaceAudience.Private +@InterfaceStability.Unstable +public class LogsearchKrbFilter implements Filter { + + private static Logger logger = LoggerFactory.getLogger(LogsearchKrbFilter.class); + + /** + * Constant for the property that specifies the configuration prefix. + */ + public static final String CONFIG_PREFIX = "config.prefix"; + + /** + * Constant for the property that specifies the authentication handler to use. + */ + public static final String AUTH_TYPE = "type"; + + /** + * Constant for the property that specifies the secret to use for signing the HTTP Cookies. + */ + public static final String SIGNATURE_SECRET = "signature.secret"; + + public static final String SIGNATURE_SECRET_FILE = SIGNATURE_SECRET + ".file"; + + /** + * Constant for the configuration property that indicates the validity of the generated token. + */ + public static final String AUTH_TOKEN_VALIDITY = "token.validity"; + + /** + * Constant for the configuration property that indicates the domain to use in the HTTP cookie. + */ + public static final String COOKIE_DOMAIN = "cookie.domain"; + + /** + * Constant for the configuration property that indicates the path to use in the HTTP cookie. + */ + public static final String COOKIE_PATH = "cookie.path"; + + /** + * Constant for the configuration property that indicates the name of the + * SignerSecretProvider class to use. + * Possible values are: "string", "random", "zookeeper", or a classname. + * If not specified, the "string" implementation will be used with + * SIGNATURE_SECRET; and if that's not specified, the "random" implementation + * will be used. + */ + public static final String SIGNER_SECRET_PROVIDER = + "signer.secret.provider"; + + /** + * Constant for the ServletContext attribute that can be used for providing a + * custom implementation of the SignerSecretProvider. Note that the class + * should already be initialized. If not specified, SIGNER_SECRET_PROVIDER + * will be used. + */ + public static final String SIGNER_SECRET_PROVIDER_ATTRIBUTE = + "signer.secret.provider.object"; + + private Properties config; + private Signer signer; + private SignerSecretProvider secretProvider; + private AuthenticationHandler authHandler; + private long validity; + private String cookieDomain; + private String cookiePath; + + /** + * <p>Initializes the authentication filter and signer secret provider.</p> + * It instantiates and initializes the specified {@link + * AuthenticationHandler}. + * + * @param filterConfig filter configuration. + * + * @throws ServletException thrown if the filter or the authentication handler could not be initialized properly. + */ + @Override + public void init(FilterConfig filterConfig) throws ServletException { + String configPrefix = filterConfig.getInitParameter(CONFIG_PREFIX); + configPrefix = (configPrefix != null) ? configPrefix + "." : ""; + config = getConfiguration(configPrefix, filterConfig); + String authHandlerName = config.getProperty(AUTH_TYPE, null); + String authHandlerClassName; + if (authHandlerName == null) { + throw new ServletException("Authentication type must be specified: " + + PseudoAuthenticationHandler.TYPE + "|" + + KerberosAuthenticationHandler.TYPE + "|<class>"); + } + if(StringUtils.equalsIgnoreCase(authHandlerName, PseudoAuthenticationHandler.TYPE)){ + authHandlerClassName = PseudoAuthenticationHandler.class.getName(); + }else if(StringUtils.equalsIgnoreCase(authHandlerName, KerberosAuthenticationHandler.TYPE)){ + authHandlerClassName = KerberosAuthenticationHandler.class.getName(); + } else { + authHandlerClassName = authHandlerName; + } + + validity = Long.parseLong(config.getProperty(AUTH_TOKEN_VALIDITY, "36000")) + * 1000; //10 hours + initializeSecretProvider(filterConfig); + + initializeAuthHandler(authHandlerClassName, filterConfig); + + cookieDomain = config.getProperty(COOKIE_DOMAIN, null); + cookiePath = config.getProperty(COOKIE_PATH, null); + } + + protected void initializeAuthHandler(String authHandlerClassName, FilterConfig filterConfig) + throws ServletException { + try { + Class<?> klass = Thread.currentThread().getContextClassLoader().loadClass(authHandlerClassName); + authHandler = (AuthenticationHandler) klass.newInstance(); + authHandler.init(config); + } catch (ClassNotFoundException | InstantiationException | + IllegalAccessException ex) { + throw new ServletException(ex); + } + } + + protected void initializeSecretProvider(FilterConfig filterConfig) + throws ServletException { + secretProvider = (SignerSecretProvider) filterConfig.getServletContext(). + getAttribute(SIGNER_SECRET_PROVIDER_ATTRIBUTE); + if (secretProvider == null) { + try { + secretProvider = constructSecretProvider( + filterConfig.getServletContext(), + config, false); + } catch (Exception ex) { + throw new ServletException(ex); + } + } + signer = new Signer(secretProvider); + } + + public static SignerSecretProvider constructSecretProvider( + ServletContext ctx, Properties config, + boolean disallowFallbackToRandomSecretProvider) throws Exception { + long validity = Long.parseLong(config.getProperty(AUTH_TOKEN_VALIDITY, + "36000")) * 1000; + + String name = config.getProperty(SIGNER_SECRET_PROVIDER); + if (StringUtils.isEmpty(name)) { + if (!disallowFallbackToRandomSecretProvider) { + name = "random"; + } else { + name = "file"; + } + } + + SignerSecretProvider provider; + if ("file".equals(name)) { + provider = new FileSignerSecretProvider(); + try { + provider.init(config, ctx, validity); + } catch (Exception e) { + if (!disallowFallbackToRandomSecretProvider) { + logger.info("Unable to initialize FileSignerSecretProvider, " + + "falling back to use random secrets."); + provider = new RandomSignerSecretProvider(); + provider.init(config, ctx, validity); + } else { + throw e; + } + } + } else if ("random".equals(name)) { + provider = new RandomSignerSecretProvider(); + provider.init(config, ctx, validity); + } else if ("zookeeper".equals(name)) { + provider = new ZKSignerSecretProvider(); + provider.init(config, ctx, validity); + } else { + provider = (SignerSecretProvider) Thread.currentThread(). + getContextClassLoader().loadClass(name).newInstance(); + provider.init(config, ctx, validity); + } + return provider; + } + + /** + * Returns the configuration properties of the {@link LogsearchKrbFilter} + * without the prefix. The returned properties are the same that the + * {@link #getConfiguration(String, FilterConfig)} method returned. + * + * @return the configuration properties. + */ + protected Properties getConfiguration() { + return config; + } + + /** + * Returns the authentication handler being used. + * + * @return the authentication handler being used. + */ + protected AuthenticationHandler getAuthenticationHandler() { + return authHandler; + } + + /** + * Returns if a random secret is being used. + * + * @return if a random secret is being used. + */ + protected boolean isRandomSecret() { + return secretProvider != null && secretProvider.getClass() == RandomSignerSecretProvider.class; + } + + /** + * Returns if a custom implementation of a SignerSecretProvider is being used. + * + * @return if a custom implementation of a SignerSecretProvider is being used. + */ + protected boolean isCustomSignerSecretProvider() { + Class<?> clazz = secretProvider != null ? secretProvider.getClass() : null; + return clazz != FileSignerSecretProvider.class && clazz != + RandomSignerSecretProvider.class && clazz != ZKSignerSecretProvider + .class; + } + + /** + * Returns the validity time of the generated tokens. + * + * @return the validity time of the generated tokens, in seconds. + */ + protected long getValidity() { + return validity / 1000; + } + + /** + * Returns the cookie domain to use for the HTTP cookie. + * + * @return the cookie domain to use for the HTTP cookie. + */ + protected String getCookieDomain() { + return cookieDomain; + } + + /** + * Returns the cookie path to use for the HTTP cookie. + * + * @return the cookie path to use for the HTTP cookie. + */ + protected String getCookiePath() { + return cookiePath; + } + + /** + * Destroys the filter. + * <p> + * It invokes the {@link AuthenticationHandler#destroy()} method to release any resources it may hold. + */ + @Override + public void destroy() { + if (authHandler != null) { + authHandler.destroy(); + authHandler = null; + } + } + + /** + * Returns the filtered configuration (only properties starting with the specified prefix). The property keys + * are also trimmed from the prefix. The returned {@link Properties} object is used to initialized the + * {@link AuthenticationHandler}. + * <p> + * This method can be overriden by subclasses to obtain the configuration from other configuration source than + * the web.xml file. + * + * @param configPrefix configuration prefix to use for extracting configuration properties. + * @param filterConfig filter configuration object + * + * @return the configuration to be used with the {@link AuthenticationHandler} instance. + * + * @throws ServletException thrown if the configuration could not be created. + */ + protected Properties getConfiguration(String configPrefix, FilterConfig filterConfig) throws ServletException { + Properties props = new Properties(); + if(filterConfig != null){ + Enumeration<?> names = filterConfig.getInitParameterNames(); + if(names != null){ + while (names.hasMoreElements()) { + String name = (String) names.nextElement(); + if (name != null && configPrefix != null && name.startsWith(configPrefix)) { + String value = filterConfig.getInitParameter(name); + props.put(name.substring(configPrefix.length()), value); + } + } + } + } + return props; + } + + /** + * Returns the full URL of the request including the query string. + * <p> + * Used as a convenience method for logging purposes. + * + * @param request the request object. + * + * @return the full URL of the request including the query string. + */ + protected String getRequestURL(HttpServletRequest request) { + StringBuffer sb = request.getRequestURL(); + if (request.getQueryString() != null) { + sb.append("?").append(request.getQueryString()); + } + return sb.toString(); + } + + /** + * Returns the {@link AuthenticationToken} for the request. + * <p> + * It looks at the received HTTP cookies and extracts the value of the {@link AuthenticatedURL#AUTH_COOKIE} + * if present. It verifies the signature and if correct it creates the {@link AuthenticationToken} and returns + * it. + * <p> + * If this method returns <code>null</code> the filter will invoke the configured {@link AuthenticationHandler} + * to perform user authentication. + * + * @param request request object. + * + * @return the Authentication token if the request is authenticated, <code>null</code> otherwise. + * + * @throws IOException thrown if an IO error occurred. + * @throws AuthenticationException thrown if the token is invalid or if it has expired. + */ + protected AuthenticationToken getToken(HttpServletRequest request) throws IOException, AuthenticationException { + AuthenticationToken token = null; + String tokenStr = null; + Cookie[] cookies = request.getCookies(); + if (cookies != null) { + for (Cookie cookie : cookies) { + if (AuthenticatedURL.AUTH_COOKIE.equals(cookie.getName())) { + tokenStr = cookie.getValue(); + try { + tokenStr = signer.verifyAndExtract(tokenStr); + } catch (SignerException ex) { + throw new AuthenticationException(ex); + } + break; + } + } + } + if (tokenStr != null) { + token = AuthenticationToken.parse(tokenStr); + if(token != null){ + if (!token.getType().equals(authHandler.getType())) { + throw new AuthenticationException("Invalid AuthenticationToken type"); + } + if (token.isExpired()) { + throw new AuthenticationException("AuthenticationToken expired"); + } + } + } + return token; + } + + /** + * If the request has a valid authentication token it allows the request to continue to the target resource, + * otherwise it triggers an authentication sequence using the configured {@link AuthenticationHandler}. + * + * @param request the request object. + * @param response the response object. + * @param filterChain the filter chain object. + * + * @throws IOException thrown if an IO error occurred. + * @throws ServletException thrown if a processing error occurred. + */ + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) + throws IOException, ServletException { + HttpServletRequest httpRequest = (HttpServletRequest) request; + logger.debug("LogsearchKrbFilter public filter path >>>>" +httpRequest.getPathInfo()); + boolean unauthorizedResponse = true; + int errCode = HttpServletResponse.SC_UNAUTHORIZED; + AuthenticationException authenticationEx = null; + HttpServletResponse httpResponse = (HttpServletResponse) response; + boolean isHttps = "https".equals(httpRequest.getScheme()); + try { + boolean newToken = false; + AuthenticationToken token; + try { + token = getToken(httpRequest); + } + catch (AuthenticationException ex) { + ex.printStackTrace(); + logger.warn("AuthenticationToken ignored: " + ex.getMessage()); + // will be sent back in a 401 unless filter authenticates + authenticationEx = ex; + token = null; + } + if (authHandler.managementOperation(token, httpRequest, httpResponse)) { + if (token == null) { + if (logger.isDebugEnabled()) { + logger.debug("Request [{}] triggering authentication", getRequestURL(httpRequest)); + } + token = authHandler.authenticate(httpRequest, httpResponse); + if (token != null && token.getExpires() != 0 && + token != AuthenticationToken.ANONYMOUS) { + token.setExpires(System.currentTimeMillis() + getValidity() * 1000); + } + newToken = true; + } + if (token != null) { + unauthorizedResponse = false; + if (logger.isDebugEnabled()) { + logger.debug("Request [{}] user [{}] authenticated", getRequestURL(httpRequest), token.getUserName()); + } + final AuthenticationToken authToken = token; + httpRequest = new HttpServletRequestWrapper(httpRequest) { + + @Override + public String getAuthType() { + return authToken.getType(); + } + + @Override + public String getRemoteUser() { + return authToken.getUserName(); + } + + @Override + public Principal getUserPrincipal() { + return (authToken != AuthenticationToken.ANONYMOUS) ? authToken : null; + } + }; + if (newToken && !token.isExpired() && token != AuthenticationToken.ANONYMOUS) { + String signedToken = signer.sign(token.toString()); + createAuthCookie(httpResponse, signedToken, getCookieDomain(), + getCookiePath(), token.getExpires(), isHttps); + } + doFilter(filterChain, httpRequest, httpResponse); + } + } else { + unauthorizedResponse = false; + } + } catch (AuthenticationException ex) { + // exception from the filter itself is fatal + ex.printStackTrace(); + errCode = HttpServletResponse.SC_FORBIDDEN; + authenticationEx = ex; + logger.warn("Authentication exception: " + ex.getMessage(), ex); + } + if (unauthorizedResponse) { + if (!httpResponse.isCommitted()) { + createAuthCookie(httpResponse, "", getCookieDomain(), + getCookiePath(), 0, isHttps); + // If response code is 401. Then WWW-Authenticate Header should be + // present.. reset to 403 if not found.. + if ((errCode == HttpServletResponse.SC_UNAUTHORIZED) + && (!httpResponse.containsHeader( + KerberosAuthenticator.WWW_AUTHENTICATE))) { + errCode = HttpServletResponse.SC_FORBIDDEN; + } + if (authenticationEx == null) { + boolean chk = true; + Collection<String> headerNames = httpResponse.getHeaderNames(); + for(String headerName : headerNames){ + String value = httpResponse.getHeader(headerName); + if(headerName.equalsIgnoreCase("Set-Cookie") && value.startsWith(LOGSEARCH_SESSION_ID)){ + chk = false; + break; + } + } + String authHeader = httpRequest.getHeader("Authorization"); + if(authHeader == null && chk){ + filterChain.doFilter(request, response); + }else if(authHeader != null && authHeader.startsWith("Basic")){ + filterChain.doFilter(request, response); + } + } else { + httpResponse.sendError(errCode, authenticationEx.getMessage()); + } + } + } + } + + /** + * Delegates call to the servlet filter chain. Sub-classes my override this + * method to perform pre and post tasks. + */ + protected void doFilter(FilterChain filterChain, HttpServletRequest request, + HttpServletResponse response) throws IOException, ServletException { + filterChain.doFilter(request, response); + } + + /** + * Creates the Hadoop authentication HTTP cookie. + * + * @param token authentication token for the cookie. + * @param expires UNIX timestamp that indicates the expire date of the + * cookie. It has no effect if its value < 0. + * + * XXX the following code duplicate some logic in Jetty / Servlet API, + * because of the fact that Hadoop is stuck at servlet 2.5 and jetty 6 + * right now. + */ + public static void createAuthCookie(HttpServletResponse resp, String token, + String domain, String path, long expires, + boolean isSecure) { + StringBuilder sb = new StringBuilder(AuthenticatedURL.AUTH_COOKIE) + .append("="); + if (token != null && token.length() > 0) { + sb.append("\"").append(token).append("\""); + } + + if (path != null) { + sb.append("; Path=").append(path); + } + + if (domain != null) { + sb.append("; Domain=").append(domain); + } + + if (expires >= 0) { + Date date = new Date(expires); + SimpleDateFormat df = new SimpleDateFormat("EEE, " + + "dd-MMM-yyyy HH:mm:ss zzz"); + df.setTimeZone(TimeZone.getTimeZone("GMT")); + sb.append("; Expires=").append(df.format(date)); + } + + if (isSecure) { + sb.append("; Secure"); + } + + sb.append("; HttpOnly"); + resp.addHeader("Set-Cookie", sb.toString()); + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/b0f1e340/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchSecurityContextFormationFilter.java ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchSecurityContextFormationFilter.java b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchSecurityContextFormationFilter.java new file mode 100644 index 0000000..fed86e8 --- /dev/null +++ b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchSecurityContextFormationFilter.java @@ -0,0 +1,106 @@ +/* + * 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.filters; + +import java.io.IOException; + +import javax.inject.Inject; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.apache.ambari.logsearch.common.LogSearchContext; +import org.apache.ambari.logsearch.manager.SessionManager; +import org.apache.ambari.logsearch.util.CommonUtil; +import org.apache.ambari.logsearch.web.model.User; +import org.apache.log4j.Logger; +import org.springframework.security.authentication.AnonymousAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.filter.GenericFilterBean; + +public class LogsearchSecurityContextFormationFilter extends GenericFilterBean { + + static Logger logger = Logger.getLogger(LogsearchSecurityContextFormationFilter.class); + + public static final String LOGSEARCH_SC_SESSION_KEY = "LOGSEARCH_SECURITY_CONTEXT"; + public static final String USER_AGENT = "User-Agent"; + + @Inject + SessionManager sessionManager; + + public LogsearchSecurityContextFormationFilter() { + } + + /* + * (non-Javadoc) + * + * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, + * javax.servlet.ServletResponse, javax.servlet.FilterChain) + */ + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, + ServletException { + + try { + Authentication auth = SecurityContextHolder.getContext().getAuthentication(); + + if (auth instanceof AnonymousAuthenticationToken) { + // ignore + } else { + HttpServletRequest httpRequest = (HttpServletRequest) request; + HttpSession httpSession = httpRequest.getSession(false); + Cookie[] cookieList = httpRequest.getCookies(); + String msaCookie = null; + for (int i = 0; cookieList != null && i < cookieList.length; i++) { + if (cookieList[i].getName().equalsIgnoreCase("msa")) { + msaCookie = cookieList[i].getValue(); + } + } + if (msaCookie == null) { + HttpServletResponse httpResponse = (HttpServletResponse) response; + msaCookie = CommonUtil.genGUI(); + Cookie cookie = new Cookie("msa", msaCookie); + // TODO: Need to revisit this + cookie.setMaxAge(Integer.MAX_VALUE); + httpResponse.addCookie(cookie); + } + // [1]get the context from session + LogSearchContext context = (LogSearchContext) httpSession.getAttribute(LOGSEARCH_SC_SESSION_KEY); + if (context == null) { + context = new LogSearchContext(); + httpSession.setAttribute(LOGSEARCH_SC_SESSION_KEY, context); + } + LogSearchContext.setContext(context); + User user = sessionManager.processSuccessLogin(); + context.setUser(user); + } + chain.doFilter(request, response); + + } finally { + // [4]remove context from thread-local + LogSearchContext.resetContext(); + } + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/b0f1e340/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchServiceLogsStateFilter.java ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchServiceLogsStateFilter.java b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchServiceLogsStateFilter.java new file mode 100644 index 0000000..74b30e1 --- /dev/null +++ b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchServiceLogsStateFilter.java @@ -0,0 +1,51 @@ +/* + * 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.filters; + +import org.apache.ambari.logsearch.common.MessageEnums; +import org.apache.ambari.logsearch.common.VResponse; +import org.apache.ambari.logsearch.conf.SolrPropsConfig; +import org.apache.ambari.logsearch.conf.global.SolrCollectionState; +import org.apache.ambari.logsearch.util.RESTErrorUtil; +import org.springframework.security.web.util.matcher.RequestMatcher; + +import javax.servlet.http.HttpServletRequest; + +public class LogsearchServiceLogsStateFilter extends AbstractLogsearchGlobalStateFilter { + + public LogsearchServiceLogsStateFilter(RequestMatcher requestMatcher, SolrCollectionState state, SolrPropsConfig solrPropsConfig) { + super(requestMatcher, state, solrPropsConfig); + } + + @Override + public VResponse getErrorResponse(SolrCollectionState solrCollectionState, SolrPropsConfig solrPropsConfig, HttpServletRequest request) { + String requestUri = request.getRequestURI(); + if (!solrCollectionState.isZnodeReady()) { + return RESTErrorUtil.createMessageResponse(String.format(ZNODE_NOT_READY_MSG, + "service logs", solrPropsConfig.getZkConnectString(), requestUri), MessageEnums.ZNODE_NOT_READY); + } else if (!solrCollectionState.isConfigurationUploaded()) { + return RESTErrorUtil.createMessageResponse(String.format(ZK_CONFIG_NOT_READY_MSG, "service logs", + solrPropsConfig.getConfigName(), solrPropsConfig.getCollection(), requestUri), MessageEnums.ZK_CONFIG_NOT_READY); + } else if (!solrCollectionState.isSolrCollectionReady()) { + return RESTErrorUtil.createMessageResponse(String.format(SOLR_COLLECTION_NOT_READY_MSG, + solrPropsConfig.getCollection(), requestUri), MessageEnums.SOLR_COLLECTION_NOT_READY); + } + return null; + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/b0f1e340/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchUserConfigStateFilter.java ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchUserConfigStateFilter.java b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchUserConfigStateFilter.java new file mode 100644 index 0000000..037bed0 --- /dev/null +++ b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchUserConfigStateFilter.java @@ -0,0 +1,52 @@ +/* + * 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.filters; + +import org.apache.ambari.logsearch.common.MessageEnums; +import org.apache.ambari.logsearch.common.VResponse; +import org.apache.ambari.logsearch.conf.SolrPropsConfig; +import org.apache.ambari.logsearch.conf.global.SolrCollectionState; +import org.apache.ambari.logsearch.util.RESTErrorUtil; +import org.springframework.security.web.util.matcher.RequestMatcher; + +import javax.servlet.http.HttpServletRequest; + +public class LogsearchUserConfigStateFilter extends AbstractLogsearchGlobalStateFilter { + + + public LogsearchUserConfigStateFilter(RequestMatcher requestMatcher, SolrCollectionState state, SolrPropsConfig solrPropsConfig) { + super(requestMatcher, state, solrPropsConfig); + } + + @Override + public VResponse getErrorResponse(SolrCollectionState solrCollectionState, SolrPropsConfig solrPropsConfig, HttpServletRequest request) { + String requestUri = request.getRequestURI(); + if (!solrCollectionState.isZnodeReady()) { + return RESTErrorUtil.createMessageResponse(String.format(ZNODE_NOT_READY_MSG, + "userconfig", solrPropsConfig.getZkConnectString(), requestUri), MessageEnums.ZNODE_NOT_READY); + } else if (!solrCollectionState.isConfigurationUploaded()) { + return RESTErrorUtil.createMessageResponse(String.format(ZK_CONFIG_NOT_READY_MSG, "userconfig", + solrPropsConfig.getConfigName(), solrPropsConfig.getCollection(), requestUri), MessageEnums.ZK_CONFIG_NOT_READY); + } else if (!solrCollectionState.isSolrCollectionReady()) { + return RESTErrorUtil.createMessageResponse(String.format(SOLR_COLLECTION_NOT_READY_MSG, + solrPropsConfig.getCollection(), requestUri), MessageEnums.SOLR_COLLECTION_NOT_READY); + } + return null; + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/b0f1e340/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchUsernamePasswordAuthenticationFilter.java ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchUsernamePasswordAuthenticationFilter.java b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchUsernamePasswordAuthenticationFilter.java new file mode 100644 index 0000000..e20c0fa --- /dev/null +++ b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/LogsearchUsernamePasswordAuthenticationFilter.java @@ -0,0 +1,45 @@ +/* + * 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.filters; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.log4j.Logger; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.authentication.RememberMeServices; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +public class LogsearchUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter { + private static final Logger logger = Logger.getLogger(LogsearchUsernamePasswordAuthenticationFilter.class); + + public void setRememberMeServices(RememberMeServices rememberMeServices) { + super.setRememberMeServices(rememberMeServices); + } + + @Override + protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, + AuthenticationException failed) throws IOException, ServletException { + logger.info("login failed :::::" + failed.getMessage()); + super.unsuccessfulAuthentication(request, response, failed); + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/b0f1e340/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/NoServletContext.java ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/NoServletContext.java b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/NoServletContext.java new file mode 100644 index 0000000..f1663bc --- /dev/null +++ b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/filters/NoServletContext.java @@ -0,0 +1,300 @@ +/* + * 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.filters; + +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Enumeration; +import java.util.EventListener; +import java.util.Map; +import java.util.Set; + +import javax.servlet.Filter; +import javax.servlet.FilterRegistration; +import javax.servlet.RequestDispatcher; +import javax.servlet.Servlet; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRegistration; +import javax.servlet.SessionCookieConfig; +import javax.servlet.SessionTrackingMode; +import javax.servlet.FilterRegistration.Dynamic; +import javax.servlet.descriptor.JspConfigDescriptor; + +public class NoServletContext implements ServletContext { + + @Override + public void setSessionTrackingModes( + Set<SessionTrackingMode> sessionTrackingModes) { + } + + @Override + public boolean setInitParameter(String name, String value) { + return false; + } + + @Override + public void setAttribute(String name, Object object) { + } + + @Override + public void removeAttribute(String name) { + } + + @Override + public void log(String message, Throwable throwable) { + } + + @Override + public void log(Exception exception, String msg) { + } + + @Override + public void log(String msg) { + } + + @Override + public String getVirtualServerName() { + return null; + } + + @Override + public SessionCookieConfig getSessionCookieConfig() { + return null; + } + + @Override + public Enumeration<Servlet> getServlets() { + return null; + } + + @Override + public Map<String, ? extends ServletRegistration> getServletRegistrations() { + return null; + } + + @Override + public ServletRegistration getServletRegistration(String servletName) { + return null; + } + + @Override + public Enumeration<String> getServletNames() { + return null; + } + + @Override + public String getServletContextName() { + return null; + } + + @Override + public Servlet getServlet(String name) throws ServletException { + return null; + } + + @Override + public String getServerInfo() { + return null; + } + + @Override + public Set<String> getResourcePaths(String path) { + return null; + } + + @Override + public InputStream getResourceAsStream(String path) { + return null; + } + + @Override + public URL getResource(String path) throws MalformedURLException { + return null; + } + + @Override + public RequestDispatcher getRequestDispatcher(String path) { + return null; + } + + @Override + public String getRealPath(String path) { + return null; + } + + @Override + public RequestDispatcher getNamedDispatcher(String name) { + return null; + } + + @Override + public int getMinorVersion() { + return 0; + } + + @Override + public String getMimeType(String file) { + return null; + } + + @Override + public int getMajorVersion() { + return 0; + } + + @Override + public JspConfigDescriptor getJspConfigDescriptor() { + return null; + } + + @Override + public Enumeration<String> getInitParameterNames() { + return null; + } + + @Override + public String getInitParameter(String name) { + return null; + } + + @Override + public Map<String, ? extends FilterRegistration> getFilterRegistrations() { + return null; + } + + @Override + public FilterRegistration getFilterRegistration(String filterName) { + return null; + } + + @Override + public Set<SessionTrackingMode> getEffectiveSessionTrackingModes() { + return null; + } + + @Override + public int getEffectiveMinorVersion() { + return 0; + } + + @Override + public int getEffectiveMajorVersion() { + return 0; + } + + @Override + public Set<SessionTrackingMode> getDefaultSessionTrackingModes() { + return null; + } + + @Override + public String getContextPath() { + return null; + } + + @Override + public ServletContext getContext(String uripath) { + return null; + } + + @Override + public ClassLoader getClassLoader() { + return null; + } + + @Override + public Enumeration<String> getAttributeNames() { + return null; + } + + @Override + public Object getAttribute(String name) { + return null; + } + + @Override + public void declareRoles(String... roleNames) { + } + + @Override + public <T extends Servlet> T createServlet(Class<T> clazz) + throws ServletException { + return null; + } + + @Override + public <T extends EventListener> T createListener(Class<T> clazz) + throws ServletException { + return null; + } + + @Override + public <T extends Filter> T createFilter(Class<T> clazz) + throws ServletException { + return null; + } + + @Override + public javax.servlet.ServletRegistration.Dynamic addServlet( + String servletName, Class<? extends Servlet> servletClass) { + return null; + } + + @Override + public javax.servlet.ServletRegistration.Dynamic addServlet( + String servletName, Servlet servlet) { + return null; + } + + @Override + public javax.servlet.ServletRegistration.Dynamic addServlet( + String servletName, String className) { + return null; + } + + @Override + public void addListener(Class<? extends EventListener> listenerClass) { + } + + @Override + public <T extends EventListener> void addListener(T t) { + } + + @Override + public void addListener(String className) { + } + + @Override + public Dynamic addFilter(String filterName, + Class<? extends Filter> filterClass) { + return null; + } + + @Override + public Dynamic addFilter(String filterName, Filter filter) { + return null; + } + + @Override + public Dynamic addFilter(String filterName, String className) { + return null; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/b0f1e340/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/listener/LogSearchSessionListener.java ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/listener/LogSearchSessionListener.java b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/listener/LogSearchSessionListener.java new file mode 100644 index 0000000..9fa5c80 --- /dev/null +++ b/ambari-logsearch/ambari-logsearch-server/src/main/java/org/apache/ambari/logsearch/web/listener/LogSearchSessionListener.java @@ -0,0 +1,48 @@ +/* + * 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.listener; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.http.HttpSessionEvent; +import javax.servlet.http.HttpSessionListener; + +public class LogSearchSessionListener implements HttpSessionListener { + + private Logger LOG = LoggerFactory.getLogger(LogSearchSessionListener.class); + + private int numberOfSessions = 0; + + @Override + public void sessionCreated(HttpSessionEvent event) { + synchronized (this) { + numberOfSessions++; + } + LOG.debug(String.format("New session is created (Id: %s). Number of sessions: %d", event.getSession().getId(), numberOfSessions)); + } + + @Override + public void sessionDestroyed(HttpSessionEvent event) { + synchronized (this) { + numberOfSessions--; + } + LOG.debug(String.format("Session destroyed (Id: %s). Number of sessions: %d", event.getSession().getId(), numberOfSessions)); + } +}