/* * Copyright 2002-2013 the original author or authors. * * 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 org.springframework.security.config.annotation.web.configurers; import java.util.ArrayList; import java.util.List; import javax.servlet.http.HttpSession; import org.springframework.security.config.annotation.SecurityConfigurer; import org.springframework.security.config.annotation.web.HttpSecurityBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.web.authentication.logout.CookieClearingLogoutHandler; import org.springframework.security.web.authentication.logout.LogoutFilter; import org.springframework.security.web.authentication.logout.LogoutHandler; import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler; import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler; import org.springframework.security.web.authentication.ui.DefaultLoginPageViewFilter; /** * Adds logout support. Other {@link SecurityConfigurer} instances may invoke * {@link #addLogoutHandler(LogoutHandler)} in the * {@link #init(HttpSecurity)} phase. * * <h2>Security Filters</h2> * * The following Filters are populated * * <ul> * <li> * {@link LogoutFilter}</li> * </ul> * * <h2>Shared Objects Created</h2> * * No shared Objects are created * * <h2>Shared Objects Used</h2> * * No shared objects are used. * * @author Rob Winch * @since 3.2 * @see RememberMeConfigurer */ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractHttpConfigurer<H> { private List<LogoutHandler> logoutHandlers = new ArrayList<LogoutHandler>(); private SecurityContextLogoutHandler contextLogoutHandler = new SecurityContextLogoutHandler(); private String logoutSuccessUrl = "/login?logout"; private LogoutSuccessHandler logoutSuccessHandler; private String logoutUrl = "/logout"; private boolean permitAll; private boolean customLogoutSuccess; /** * Creates a new instance * @see HttpSecurity#logout() */ public LogoutConfigurer() { } /** * Adds a {@link LogoutHandler}. The {@link SecurityContextLogoutHandler} is * added as the last {@link LogoutHandler} by default. * * @param logoutHandler the {@link LogoutHandler} to add * @return the {@link LogoutConfigurer} for further customization */ public LogoutConfigurer<H> addLogoutHandler(LogoutHandler logoutHandler) { this.logoutHandlers.add(logoutHandler); return this; } /** * Configures {@link SecurityContextLogoutHandler} to invalidate the {@link HttpSession} at the time of logout. * @param invalidateHttpSession true if the {@link HttpSession} should be invalidated (default), or false otherwise. * @return the {@link LogoutConfigurer} for further customization */ public LogoutConfigurer<H> invalidateHttpSession(boolean invalidateHttpSession) { contextLogoutHandler.setInvalidateHttpSession(invalidateHttpSession); return this; } /** * The URL that triggers logout to occur. The default is "/logout" * @param logoutUrl the URL that will invoke logout. * @return the {@link LogoutConfigurer} for further customization */ public LogoutConfigurer<H> logoutUrl(String logoutUrl) { this.logoutUrl = logoutUrl; return this; } /** * The URL to redirect to after logout has occurred. The default is * "/login?logout". This is a shortcut for invoking * {@link #logoutSuccessHandler(LogoutSuccessHandler)} with a * {@link SimpleUrlLogoutSuccessHandler}. * * @param logoutSuccessUrl * the URL to redirect to after logout occurred * @return the {@link LogoutConfigurer} for further customization */ public LogoutConfigurer<H> logoutSuccessUrl(String logoutSuccessUrl) { this.customLogoutSuccess = true; this.logoutSuccessUrl = logoutSuccessUrl; return this; } /** * A shortcut for {@link #permitAll(boolean)} with <code>true</code> as an argument. * @return the {@link LogoutConfigurer} for further customizations */ public LogoutConfigurer<H> permitAll() { return permitAll(true); } /** * Allows specifying the names of cookies to be removed on logout success. * This is a shortcut to easily invoke * {@link #addLogoutHandler(LogoutHandler)} with a * {@link CookieClearingLogoutHandler}. * * @param cookieNamesToClear the names of cookies to be removed on logout success. * @return the {@link LogoutConfigurer} for further customization */ public LogoutConfigurer<H> deleteCookies(String... cookieNamesToClear) { return addLogoutHandler(new CookieClearingLogoutHandler(cookieNamesToClear)); } /** * Sets the {@link LogoutSuccessHandler} to use. If this is specified, * {@link #logoutSuccessUrl(String)} is ignored. * * @param logoutSuccessHandler * the {@link LogoutSuccessHandler} to use after a user has been * logged out. * @return the {@link LogoutConfigurer} for further customizations */ public LogoutConfigurer<H> logoutSuccessHandler(LogoutSuccessHandler logoutSuccessHandler) { this.logoutSuccessUrl = null; this.customLogoutSuccess = true; this.logoutSuccessHandler = logoutSuccessHandler; return this; } /** * Grants access to the {@link #logoutSuccessUrl(String)} and the {@link #logoutUrl(String)} for every user. * * @param permitAll if true grants access, else nothing is done * @return the {@link LogoutConfigurer} for further customization. */ public LogoutConfigurer<H> permitAll(boolean permitAll) { this.permitAll = permitAll; return this; } /** * Gets the {@link LogoutSuccessHandler} if not null, otherwise creates a * new {@link SimpleUrlLogoutSuccessHandler} using the * {@link #logoutSuccessUrl(String)}. * * @return the {@link LogoutSuccessHandler} to use */ private LogoutSuccessHandler getLogoutSuccessHandler() { if(logoutSuccessHandler != null) { return logoutSuccessHandler; } SimpleUrlLogoutSuccessHandler logoutSuccessHandler = new SimpleUrlLogoutSuccessHandler(); logoutSuccessHandler.setDefaultTargetUrl(logoutSuccessUrl); return logoutSuccessHandler; } @Override public void init(H http) throws Exception { if(permitAll) { PermitAllSupport.permitAll(http, this.logoutUrl, this.logoutSuccessUrl); } DefaultLoginPageViewFilter loginPageGeneratingFilter = http.getSharedObject(DefaultLoginPageViewFilter.class); if(loginPageGeneratingFilter != null && !isCustomLogoutSuccess()) { loginPageGeneratingFilter.setLogoutSuccessUrl(getLogoutSuccessUrl()); } } @Override public void configure(H http) throws Exception { LogoutFilter logoutFilter = createLogoutFilter(); http.addFilter(logoutFilter); } /** * Returns true if the logout success has been customized via * {@link #logoutSuccessUrl(String)} or * {@link #logoutSuccessHandler(LogoutSuccessHandler)}. * * @return true if logout success handling has been customized, else false */ private boolean isCustomLogoutSuccess() { return customLogoutSuccess; } /** * Gets the logoutSuccesUrl or null if a * {@link #logoutSuccessHandler(LogoutSuccessHandler)} was configured. * * @return the logoutSuccessUrl */ private String getLogoutSuccessUrl() { return logoutSuccessUrl; } /** * Creates the {@link LogoutFilter} using the {@link LogoutHandler} * instances, the {@link #logoutSuccessHandler(LogoutSuccessHandler)} and * the {@link #logoutUrl(String)}. * * @return the {@link LogoutFilter} to use. * @throws Exception */ private LogoutFilter createLogoutFilter() throws Exception { logoutHandlers.add(contextLogoutHandler); LogoutHandler[] handlers = logoutHandlers.toArray(new LogoutHandler[logoutHandlers.size()]); LogoutFilter result = new LogoutFilter(getLogoutSuccessHandler(), handlers); result.setFilterProcessesUrl(logoutUrl); result = postProcess(result); return result; } }