SEC-2025: SecurityContextLogoutHandler removes Authentication from SecurityContext
Previously there was a race condition could occur when the user attempts to access a slow resource and then logs out which would result in the user not being logged out. SecurityContextLogoutHandler will now remove the Authentication from the SecurityContext to protect against this scenario.
This commit is contained in:
parent
f38df99730
commit
d3339a1e32
|
@ -16,28 +16,34 @@
|
|||
package org.springframework.security.web.authentication.logout;
|
||||
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Performs a logout by modifying the {@link org.springframework.security.core.context.SecurityContextHolder}.
|
||||
* <p>
|
||||
* Will also invalidate the {@link HttpSession} if {@link #isInvalidateHttpSession()} is {@code true} and the
|
||||
* session is not {@code null}.
|
||||
* <p>
|
||||
* Will also remove the {@link Authentication} from the current {@link SecurityContext} if {@link #clearAuthentication}
|
||||
* is set to true (default).
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public class SecurityContextLogoutHandler implements LogoutHandler {
|
||||
protected final Log logger = LogFactory.getLog(this.getClass());
|
||||
|
||||
private boolean invalidateHttpSession = true;
|
||||
private boolean clearAuthentication = true;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
|
@ -58,6 +64,11 @@ public class SecurityContextLogoutHandler implements LogoutHandler {
|
|||
}
|
||||
}
|
||||
|
||||
if(clearAuthentication) {
|
||||
SecurityContext context = SecurityContextHolder.getContext();
|
||||
context.setAuthentication(null);
|
||||
}
|
||||
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
|
@ -75,4 +86,14 @@ public class SecurityContextLogoutHandler implements LogoutHandler {
|
|||
this.invalidateHttpSession = invalidateHttpSession;
|
||||
}
|
||||
|
||||
/**
|
||||
* If true, removes the {@link Authentication} from the {@link SecurityContext} to prevent issues with concurrent
|
||||
* requests.
|
||||
*
|
||||
* @param clearAuthentication true if you wish to clear the {@link Authentication} from the {@link SecurityContext}
|
||||
* (default) or false if the {@link Authentication} should not be removed.
|
||||
*/
|
||||
public void setClearAuthentication(boolean clearAuthentication) {
|
||||
this.clearAuthentication = clearAuthentication;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright 2002-2012 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.web.authentication.logout;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
public class SecurityContextLogoutHandlerTests {
|
||||
private MockHttpServletRequest request;
|
||||
private MockHttpServletResponse response;
|
||||
private SecurityContextLogoutHandler handler;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
request = new MockHttpServletRequest();
|
||||
response = new MockHttpServletResponse();
|
||||
|
||||
handler = new SecurityContextLogoutHandler();
|
||||
|
||||
SecurityContext context = SecurityContextHolder.createEmptyContext();
|
||||
context.setAuthentication(new TestingAuthenticationToken("user", "password", AuthorityUtils.createAuthorityList("ROLE_USER")));
|
||||
SecurityContextHolder.setContext(context);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
// SEC-2025
|
||||
@Test
|
||||
public void clearsAuthentication() {
|
||||
SecurityContext beforeContext = SecurityContextHolder.getContext();
|
||||
handler.logout(request, response, SecurityContextHolder.getContext().getAuthentication());
|
||||
assertNull(beforeContext.getAuthentication());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void disableClearsAuthentication() {
|
||||
handler.setClearAuthentication(false);
|
||||
SecurityContext beforeContext = SecurityContextHolder.getContext();
|
||||
Authentication beforeAuthentication = beforeContext.getAuthentication();
|
||||
handler.logout(request, response, SecurityContextHolder.getContext().getAuthentication());
|
||||
|
||||
assertNotNull(beforeContext.getAuthentication());
|
||||
assertSame(beforeAuthentication, beforeContext.getAuthentication());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue