/* * 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.server.security.authentication; import java.io.IOException; import java.util.Collection; import java.util.Collections; 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 org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * The AmbariDelegatingAuthenticationFilter is an authentication filter that holds zero or more * {@link org.apache.ambari.server.security.authorization.AmbariAuthorizationFilter}s. * <p> * This container iterates though the contained Filters to delegate {@link Filter} operations. * For {@link Filter#init(FilterConfig)} and {@link Filter#destroy()} operations, all contained filters * will be called. For {@link Filter#doFilter(ServletRequest, ServletResponse, FilterChain)}, each * filter will be accessed in order to test whether is should be used or skipped. Once a filter * claims it is to be used for the operation, interation stops ensuring at most only one of the contained * filters is invoked. */ public class AmbariDelegatingAuthenticationFilter implements Filter { private static final Logger LOG = LoggerFactory.getLogger(AmbariDelegatingAuthenticationFilter.class); /** * The ordered collections of {@link org.apache.ambari.server.security.authorization.AmbariAuthorizationFilter}s */ private final Collection<AmbariAuthenticationFilter> filters; /** * Constructor. * * @param filters an ordered collections of {@link org.apache.ambari.server.security.authorization.AmbariAuthorizationFilter}s */ public AmbariDelegatingAuthenticationFilter(Collection<AmbariAuthenticationFilter> filters) { this.filters = (filters == null) ? Collections.<AmbariAuthenticationFilter>emptyList() : filters; if (this.filters.isEmpty()) { LOG.warn("The delegated filters list is empty. No authentication tests will be performed by this " + "authentication filter."); } else if (LOG.isDebugEnabled()) { StringBuffer filterNames = new StringBuffer(); for (AmbariAuthenticationFilter filter : this.filters) { filterNames.append("\n\t"); filterNames.append(filter.getClass().getName()); } LOG.debug("This authentication filter will attempt to authenticate a user using one of the " + "following delegated authentication filters: {}", filterNames); } } /** * Iterates over the contained {@link org.apache.ambari.server.security.authorization.AmbariAuthorizationFilter}s * to invoke each's init method. * * @param filterConfig a filter configuration * @throws ServletException */ @Override public void init(FilterConfig filterConfig) throws ServletException { for (AmbariAuthenticationFilter filter : filters) { filter.init(filterConfig); } } /** * Iterates over the contained {@link org.apache.ambari.server.security.authorization.AmbariAuthorizationFilter}s * to test each to see if they should be invoked. If one tests positive, its doFilter method will be * invoked and processing will stop ensuring only at most one of the contained filter is invoked. * * @param servletRequest the request * @param servletResponse the response * @param chain the Spring filter change * @throws IOException * @throws ServletException */ @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException { boolean handled = false; HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest; for (AmbariAuthenticationFilter filter : filters) { if (LOG.isTraceEnabled()) { LOG.trace("Attempting to apply authentication filter {}", filter.getClass().getName()); } if (filter.shouldApply(httpServletRequest)) { if (LOG.isDebugEnabled()) { LOG.debug("Using authentication filter {} since it applies", filter.getClass().getName()); } filter.doFilter(servletRequest, servletResponse, chain); handled = true; break; } else { if (LOG.isDebugEnabled()) { LOG.debug("Filter {} does not apply skipping", filter.getClass().getName()); } } } if (!handled) { LOG.debug("No delegated filters applied while attempting to authenticate a user, continuing with the filter chain."); chain.doFilter(servletRequest, servletResponse); } } /** * Iterates over the contained {@link org.apache.ambari.server.security.authorization.AmbariAuthorizationFilter}s * to invoke each's destroy method. */ @Override public void destroy() { for (AmbariAuthenticationFilter filter : filters) { filter.destroy(); } } }