/* * Copyright 2011 Federal Chancellery Austria and * Graz University of Technology * * Licensed 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 at.gv.util.filter.moaid; import java.io.IOException; import java.util.ArrayList; import java.util.StringTokenizer; import java.util.regex.Pattern; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.commons.lang.BooleanUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.time.DateFormatUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import at.gv.util.MiscUtil; import at.gv.util.ToStringUtil; import at.gv.util.WebAppUtil; /** * @author Arne Tauber * @author Thomas Knall */ public class MOAIDAuthenticationFilter implements Filter { private final Logger log = LoggerFactory.getLogger(MOAIDAuthenticationFilter.class); public static final String USER_AUTH_DATA_ID = "AnyAuthDataObject:authenticatedUser"; public static final String STORED_REQUEST_URL_ID = String.class.getName() + ":" + "storedRequestURL"; public static final String WEB_XML_INIT_PARAM_LOGIN_PAGE = "loginPage"; public static final String WEB_XML_INIT_PARAM_ENABLED = "enabled"; public static final String WEB_XML_INIT_PARAM_ERROR_PAGE = "errorPage"; public static final String WEB_XML_INIT_PARAM_AUTHENTICATED_PAGE = "authenticatedPage"; // optional public static final String WEB_XML_INIT_PARAM_SESSION_LOST_PAGE = "sessionLostPage"; // optional public static final String WEB_XML_INIT_PARAM_ALLOWED_LIST = "allowedList"; public static final String WEB_XML_INIT_PARAM_ALLOWED_REGEX = "allowed"; private static final String WEB_XML_INIT_PARAM_EXCLUDED_PAGES_DELIMITER = ","; private boolean enabled = true; private static String loginPage = null; private boolean loginPageForward = true; private static String errorPage = null; private static String authenticatedPage = null; private static String sessionLostPage = null; private static String[] excludedPages = null; private static Pattern excludedRegEx = null; private HttpServletRequest servletRequest = null; public void destroy() { log.trace("Shutting down " + this.getClass().getName() + "..."); } public static String getErrorPage() { return errorPage; } public static String getAuthenticatedPage() { return authenticatedPage; } public static String getLoginPage() { return loginPage; } public static String getSessionLostPage() { return sessionLostPage; } public HttpServletRequest getHttpServletRequest() { return this.servletRequest; } private boolean isExcluded(String url) { boolean excluded = false; if (MiscUtil.isNotEmpty(excludedPages)) { for (String candidate : excludedPages) { if (StringUtils.upperCase(url).endsWith(StringUtils.upperCase(candidate))) { excluded = true; break; } } } if (excludedRegEx != null && !excluded) { // log.debug("Trying to match regex \"{}\" with \"{}\".", // excludedRegEx.toString(), url); if (excludedRegEx.matcher(url).matches()) { excluded = true; } } log.debug("URL \"" + url + "\" is " + (excluded ? "" : "NOT ") + "excluded from filter."); return excluded; } public void doFilter(ServletRequest request, ServletResponse response, final FilterChain filterChain) throws IOException, ServletException { if (this.enabled) { log.debug("Applying " + this.getClass().getSimpleName() + "..."); HttpServletRequest httpServletRequest = (HttpServletRequest) request; servletRequest = httpServletRequest; HttpServletResponse httpServletResponse = (HttpServletResponse) response; HttpSession session = httpServletRequest.getSession(); log.debug("Using session " + session.getId() + ", created at " + DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.format(session.getCreationTime()) + "."); Object anyObject = session.getAttribute(USER_AUTH_DATA_ID); String requestURL = WebAppUtil.getRequestURLWithParameters(httpServletRequest, true); log.trace("Request URL: " + requestURL); if (anyObject == null && !this.isExcluded(requestURL)) { Object dummyAuthData = this.provideDummyAuthenticationData(); if (dummyAuthData != null) { log.warn("Unable to find regular authentication data but dummy authentication data is provided."); log.debug("Authentication data = " + dummyAuthData.toString()); log.warn("Putting dummy authentication data into session."); session.setAttribute(USER_AUTH_DATA_ID, dummyAuthData); if (MiscUtil.isNotEmpty(getAuthenticatedPage())) { if (loginPageForward) { log.debug("Authenticated page is set. Forwarding to \"" + getAuthenticatedPage() + "\"."); RequestDispatcher dispatcher = request.getRequestDispatcher(getAuthenticatedPage()); dispatcher.forward(httpServletRequest, httpServletResponse); } else { log.debug("Authenticated page is set. Redirecting to \"" + getAuthenticatedPage() + "\"."); httpServletResponse.sendRedirect(httpServletResponse.encodeRedirectURL(getAuthenticatedPage())); } return; } } else { if (MiscUtil.isNotEmpty(getAuthenticatedPage())) { log.debug("Unable to find authentication data. Authenticated page is given so there is no need to save original request url. " + (loginPageForward ? "Forwarding" : "Redirecting") + " to login page \"" + loginPage + "\"."); } else { log.debug("Unable to find authentication data. Storing request url and " + (loginPageForward ? "forwarding" : "redirecting") + " to login page \"" + loginPage + "\"."); // TODO: save HttpServletRequest // log.debug("new CustomHttpServletRequest(request).toString() = // {}", new // CustomHttpServletRequest(httpServletRequest).toString()); session.setAttribute(STORED_REQUEST_URL_ID, requestURL); } if (loginPageForward) { RequestDispatcher dispatcher = request.getRequestDispatcher(loginPage); dispatcher.forward(httpServletRequest, httpServletResponse); } else { httpServletResponse.sendRedirect(httpServletResponse.encodeRedirectURL(loginPage)); } return; } } } filterChain.doFilter(request, response); } public void init(FilterConfig filterConfig) throws ServletException { log.debug("Starting init of " + this.getClass().getName() + "."); // enabled? String enabledValue = StringUtils.trimToNull(filterConfig.getInitParameter(WEB_XML_INIT_PARAM_ENABLED)); this.enabled = BooleanUtils.isNotFalse(BooleanUtils.toBooleanObject(enabledValue)); // login page loginPage = StringUtils.trim(filterConfig.getInitParameter(WEB_XML_INIT_PARAM_LOGIN_PAGE)); if (MiscUtil.isEmpty(loginPage)) { throw new ServletException("ServletInitParameter \"" + WEB_XML_INIT_PARAM_LOGIN_PAGE + "\" must not be empty."); } loginPageForward = false; //!WebAppUtil.isFullQualifiedURL(loginPage); // error page errorPage = StringUtils.trim(filterConfig.getInitParameter(WEB_XML_INIT_PARAM_ERROR_PAGE)); if (MiscUtil.isEmpty(errorPage)) { throw new ServletException("ServletInitParameter \"" + WEB_XML_INIT_PARAM_ERROR_PAGE + "\" must not be empty."); } // session lost page sessionLostPage = StringUtils.trim(filterConfig.getInitParameter(WEB_XML_INIT_PARAM_SESSION_LOST_PAGE)); if (MiscUtil.isEmpty(sessionLostPage)) { log.warn("ServletInitParameter \"" + WEB_XML_INIT_PARAM_SESSION_LOST_PAGE + "\" is empty. This parameter defines a failsafe url the browser is redirected to if the original url has been lost due to session timeout."); } // authenticated page authenticatedPage = StringUtils.trim(filterConfig.getInitParameter(WEB_XML_INIT_PARAM_AUTHENTICATED_PAGE)); if (MiscUtil.isEmpty(authenticatedPage)) { log.debug("ServletInitParameter \"" + WEB_XML_INIT_PARAM_AUTHENTICATED_PAGE + "\" is empty. This parameter defines the url the user is redirected to (instead of the original url) on successful authentication."); } String excluded = filterConfig.getInitParameter(WEB_XML_INIT_PARAM_ALLOWED_LIST); ArrayList excludedList = new ArrayList(); if (MiscUtil.isNotEmpty(excluded)) { StringTokenizer tokenizer = new StringTokenizer(excluded, WEB_XML_INIT_PARAM_EXCLUDED_PAGES_DELIMITER); while (tokenizer.hasMoreTokens()) { String ex = StringUtils.trim(tokenizer.nextToken()); if (MiscUtil.isNotEmpty(ex)) { excludedList.add(ex); } } } excludedList.add(loginPage); excludedList.add(errorPage); excludedPages = new String[excludedList.size()]; excludedPages = excludedList.toArray(excludedPages); String excludedRegExString = StringUtils.trim(filterConfig.getInitParameter(WEB_XML_INIT_PARAM_ALLOWED_REGEX)); if (MiscUtil.isNotEmpty(excludedRegExString)) { excludedRegEx = Pattern.compile(excludedRegExString); } if (!this.enabled) { log.info(this.getClass().getName() + " is DISABLED"); } else { log.debug(WEB_XML_INIT_PARAM_ENABLED + " = \"" + this.enabled + "\""); } log.debug(WEB_XML_INIT_PARAM_LOGIN_PAGE + " [" + (loginPageForward ? "forward" : "redirect") + "] = \"" + loginPage + "\""); log.debug(WEB_XML_INIT_PARAM_AUTHENTICATED_PAGE + " = \"" + (MiscUtil.isNotEmpty(authenticatedPage) ? authenticatedPage : "") + "\""); log.debug(WEB_XML_INIT_PARAM_ERROR_PAGE + " = \"" + errorPage + "\""); log.debug(WEB_XML_INIT_PARAM_SESSION_LOST_PAGE + " = \"" + (MiscUtil.isNotEmpty(sessionLostPage) ? sessionLostPage : "") + "\""); log.debug(WEB_XML_INIT_PARAM_ALLOWED_LIST + " = " + ToStringUtil.toString(excludedPages, ", ", "\"")); log.debug(WEB_XML_INIT_PARAM_ALLOWED_REGEX + " = \"" + (excludedRegEx != null ? excludedRegEx.pattern() : "") + "\""); } /** * May be overwritten in order to provide static authentication data during * development process. * * @return some kind of dummy authentication data */ public Object provideDummyAuthenticationData() { return null; } }