/* (c) 2014 Open Source Geospatial Foundation - all rights reserved * (c) 2001 - 2013 OpenPlans * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.security.filter; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.SortedSet; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.geoserver.security.GeoServerSecurityFilterChain; import org.geoserver.security.RequestFilterChain; import org.geoserver.security.config.LogoutFilterConfig; import org.geoserver.security.config.SecurityNamedServiceConfig; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.authentication.RememberMeServices; import org.springframework.security.web.authentication.logout.LogoutHandler; import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler; import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler; import org.springframework.util.StringUtils; /** * Logout filter * * * @author christian * */ public class GeoServerLogoutFilter extends GeoServerSecurityFilter { public static final String URL_AFTER_LOGOUT="/web/"; public static final String LOGOUT_REDIRECT_ATTR="_logout_redirect"; private String redirectUrl; SecurityContextLogoutHandler logoutHandler; SimpleUrlLogoutSuccessHandler logoutSuccessHandler; String[] pathInfos; @Override public void initializeFromConfig(SecurityNamedServiceConfig config) throws IOException { super.initializeFromConfig(config); logoutHandler = new SecurityContextLogoutHandler(); redirectUrl= ((LogoutFilterConfig) config).getRedirectURL(); logoutSuccessHandler=new SimpleUrlLogoutSuccessHandler(); if (StringUtils.hasLength(redirectUrl)) logoutSuccessHandler.setDefaultTargetUrl(redirectUrl); String formLogoutChain = (((LogoutFilterConfig) config).getFormLogoutChain() != null ? ((LogoutFilterConfig) config).getFormLogoutChain() : GeoServerSecurityFilterChain.FORM_LOGOUT_CHAIN); pathInfos=formLogoutChain.split(","); } @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; boolean doLogout = false; for (String pathInfo:pathInfos) { if (getRequestPath(request).startsWith(pathInfo)) { doLogout=true; break; } } if (doLogout) doLogout(request, response); return; } public void doLogout(HttpServletRequest request,HttpServletResponse response,String... skipHandlerName) throws IOException, ServletException{ Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication!=null) { List<LogoutHandler> logoutHandlers = calculateActiveLogoutHandlers(skipHandlerName); for (LogoutHandler h : logoutHandlers) { h.logout(request, response, authentication); } RememberMeServices rms = securityManager.getRememberMeService(); ((LogoutHandler) rms).logout(request, response, authentication); logoutHandler.logout(request, response, authentication); } String redirectUrl = (String) request.getAttribute(LOGOUT_REDIRECT_ATTR); if (StringUtils.hasLength(redirectUrl)) { SimpleUrlLogoutSuccessHandler h = new SimpleUrlLogoutSuccessHandler(); h.setDefaultTargetUrl(redirectUrl); h.onLogoutSuccess(request, response, authentication); return; } logoutSuccessHandler.onLogoutSuccess(request, response, authentication); } /** * Search for filters implementing {@link LogoutHandler}. If such * a filter is on an active filter chain and is not enlisted in * the parameter skipHandlerName, add it to the result * * The skipHandlerName parameter gives other LogoutHandler the chance * to trigger a using {@link #doLogout(HttpServletRequest, HttpServletResponse, String...)} * without receiving an unnecessary callback. * * @param skipHandlerName * * @throws IOException */ List<LogoutHandler> calculateActiveLogoutHandlers(String... skipHandlerName) throws IOException { List<LogoutHandler> result = new ArrayList<LogoutHandler>(); SortedSet<String> logoutFilterNames = getSecurityManager().listFilters(LogoutHandler.class); logoutFilterNames.removeAll(Arrays.asList(skipHandlerName)); Set<String> handlerNames = new HashSet<String>(); GeoServerSecurityFilterChain chain = getSecurityManager().getSecurityConfig().getFilterChain(); for (RequestFilterChain requestChain : chain.getRequestChains()) { for (String filterName : requestChain.getFilterNames()) { if (logoutFilterNames.contains(filterName)) handlerNames.add(filterName); } } for (String handlerName : handlerNames) { result.add((LogoutHandler)getSecurityManager().loadFilter(handlerName)); } return result; } }