SEC-1229: Redesign Concurrent Session Control implementation. Renamed session strategy interface and introduced SessionAuthenticationException for rejection of session/Authentication combination.
This commit is contained in:
+4
-4
@@ -37,7 +37,7 @@ import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.SpringSecurityMessageSource;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.web.session.AuthenticatedSessionStrategy;
|
||||
import org.springframework.security.web.session.SessionAuthenticationStrategy;
|
||||
import org.springframework.security.web.session.NullAuthenticatedSessionStrategy;
|
||||
import org.springframework.security.web.util.UrlUtils;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -130,7 +130,7 @@ public abstract class AbstractAuthenticationProcessingFilter extends GenericFilt
|
||||
|
||||
private boolean continueChainBeforeSuccessfulAuthentication = false;
|
||||
|
||||
private AuthenticatedSessionStrategy sessionStrategy = new NullAuthenticatedSessionStrategy();
|
||||
private SessionAuthenticationStrategy sessionStrategy = new NullAuthenticatedSessionStrategy();
|
||||
|
||||
private boolean allowSessionCreation = true;
|
||||
|
||||
@@ -273,7 +273,7 @@ public abstract class AbstractAuthenticationProcessingFilter extends GenericFilt
|
||||
* Default behaviour for successful authentication.
|
||||
* <ol>
|
||||
* <li>Sets the successful <tt>Authentication</tt> object on the {@link SecurityContextHolder}</li>
|
||||
* <li>Invokes the configured {@link AuthenticatedSessionStrategy} to handle any session-related behaviour
|
||||
* <li>Invokes the configured {@link SessionAuthenticationStrategy} to handle any session-related behaviour
|
||||
* (such as creating a new session to protect against session-fixation attacks).</li>
|
||||
* <li>Informs the configured <tt>RememberMeServices</tt> of the successful login</li>
|
||||
* <li>Fires an {@link InteractiveAuthenticationSuccessEvent} via the configured
|
||||
@@ -400,7 +400,7 @@ public abstract class AbstractAuthenticationProcessingFilter extends GenericFilt
|
||||
* @param sessionStrategy the implementation to use. If not set a null implementation is
|
||||
* used.
|
||||
*/
|
||||
public void setAuthenticatedSessionStrategy(AuthenticatedSessionStrategy sessionStrategy) {
|
||||
public void setAuthenticatedSessionStrategy(SessionAuthenticationStrategy sessionStrategy) {
|
||||
this.sessionStrategy = sessionStrategy;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ import org.springframework.util.Assert;
|
||||
* @version $Id$
|
||||
* @since 3.0
|
||||
*/
|
||||
public class ConcurrentSessionControlAuthenticatedSessionStrategy extends DefaultAuthenticatedSessionStrategy
|
||||
public class ConcurrentSessionControlAuthenticatedSessionStrategy extends DefaultSessionAuthenticationStrategy
|
||||
implements MessageSourceAware {
|
||||
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
||||
private final SessionRegistry sessionRegistry;
|
||||
|
||||
+2
-2
@@ -16,7 +16,7 @@ import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.savedrequest.SavedRequest;
|
||||
|
||||
/**
|
||||
* The default implementation of {@link AuthenticatedSessionStrategy}.
|
||||
* The default implementation of {@link SessionAuthenticationStrategy}.
|
||||
* <p>
|
||||
* Creates a new session for the newly authenticated user if they already have a session (as a defence against
|
||||
* session-fixation protection attacks), and copies their
|
||||
@@ -32,7 +32,7 @@ import org.springframework.security.web.savedrequest.SavedRequest;
|
||||
* @version $Id$
|
||||
* @since 3.0
|
||||
*/
|
||||
public class DefaultAuthenticatedSessionStrategy implements AuthenticatedSessionStrategy {
|
||||
public class DefaultSessionAuthenticationStrategy implements SessionAuthenticationStrategy {
|
||||
protected final Log logger = LogFactory.getLog(this.getClass());
|
||||
|
||||
/**
|
||||
+1
-1
@@ -11,7 +11,7 @@ import org.springframework.security.core.Authentication;
|
||||
* @version $Id$
|
||||
* @since 3.0
|
||||
*/
|
||||
public final class NullAuthenticatedSessionStrategy implements AuthenticatedSessionStrategy {
|
||||
public final class NullAuthenticatedSessionStrategy implements SessionAuthenticationStrategy {
|
||||
|
||||
public void onAuthentication(Authentication authentication, HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package org.springframework.security.web.session;
|
||||
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
|
||||
/**
|
||||
* Thrown by an <tt>SessionAuthenticationStrategy</tt> to indicate that an authentication object is not valid for
|
||||
* the current session, typically because the same user has exceeded the number of sessions they are allowed to have
|
||||
* concurrently.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
* @since 3.0
|
||||
*/
|
||||
public class SessionAuthenticationException extends AuthenticationException {
|
||||
|
||||
public SessionAuthenticationException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
}
|
||||
+5
-4
@@ -7,7 +7,7 @@ import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
|
||||
/**
|
||||
* Allows pluggable support for Http session-related behaviour when an authentication occurs.
|
||||
* Allows pluggable support for HttpSession-related behaviour when an authentication occurs.
|
||||
* <p>
|
||||
* Typical use would be to make sure a session exists or to change the session Id to guard against session-fixation
|
||||
* attacks.
|
||||
@@ -16,14 +16,15 @@ import org.springframework.security.core.AuthenticationException;
|
||||
* @version $Id$
|
||||
* @since
|
||||
*/
|
||||
public interface AuthenticatedSessionStrategy {
|
||||
public interface SessionAuthenticationStrategy {
|
||||
|
||||
/**
|
||||
* Performs Http session-related functionality when a new authentication occurs.
|
||||
*
|
||||
* @throws AuthenticationException if it is decided that the authentication is not allowed for the session.
|
||||
* @throws SessionAuthenticationException if it is decided that the authentication is not allowed for the session.
|
||||
* This will typically be because the user has too many sessions open at once.
|
||||
*/
|
||||
void onAuthentication(Authentication authentication, HttpServletRequest request, HttpServletResponse response)
|
||||
throws AuthenticationException;
|
||||
throws SessionAuthenticationException;
|
||||
|
||||
}
|
||||
+12
-8
@@ -21,10 +21,8 @@ import org.springframework.web.filter.GenericFilterBean;
|
||||
|
||||
/**
|
||||
* Detects that a user has been authenticated since the start of the request and, if they have, calls the
|
||||
* configured {@link AuthenticatedSessionStrategy} to perform any session-related activity (such as
|
||||
* activating session-fixation protection mechanisms).
|
||||
* <p>
|
||||
* This is essentially a generalization of the functionality that was implemented for SEC-399.
|
||||
* configured {@link SessionAuthenticationStrategy} to perform any session-related activity such as
|
||||
* activating session-fixation protection mechanisms or checking for multiple concurrent logins.
|
||||
*
|
||||
* @author Martin Algesten
|
||||
* @author Luke Taylor
|
||||
@@ -39,7 +37,7 @@ public class SessionManagementFilter extends GenericFilterBean {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private final SecurityContextRepository securityContextRepository;
|
||||
private AuthenticatedSessionStrategy sessionStrategy = new DefaultAuthenticatedSessionStrategy();
|
||||
private SessionAuthenticationStrategy sessionStrategy = new DefaultSessionAuthenticationStrategy();
|
||||
private AuthenticationTrustResolver authenticationTrustResolver = new AuthenticationTrustResolverImpl();
|
||||
private String invalidSessionUrl;
|
||||
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
|
||||
@@ -65,7 +63,13 @@ public class SessionManagementFilter extends GenericFilterBean {
|
||||
|
||||
if (authentication != null && !authenticationTrustResolver.isAnonymous(authentication)) {
|
||||
// The user has been authenticated during the current request, so call the session strategy
|
||||
sessionStrategy.onAuthentication(authentication, request, response);
|
||||
try {
|
||||
sessionStrategy.onAuthentication(authentication, request, response);
|
||||
} catch (SessionAuthenticationException e) {
|
||||
// The session strategy can reject the authentication
|
||||
logger.debug("SessionAuthenticationStrategy rejected the authentication object",e);
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
} else {
|
||||
// No security context or authentication present. Check for a session timeout
|
||||
if (request.getRequestedSessionId() != null && !request.isRequestedSessionIdValid()) {
|
||||
@@ -83,9 +87,9 @@ public class SessionManagementFilter extends GenericFilterBean {
|
||||
* Sets the strategy object which handles the session management behaviour when a
|
||||
* user has been authenticated during the current request.
|
||||
*
|
||||
* @param sessionStrategy the strategy object. If not set, a {@link DefaultAuthenticatedSessionStrategy} is used.
|
||||
* @param sessionStrategy the strategy object. If not set, a {@link DefaultSessionAuthenticationStrategy} is used.
|
||||
*/
|
||||
public void setAuthenticatedSessionStrategy(AuthenticatedSessionStrategy sessionStrategy) {
|
||||
public void setAuthenticatedSessionStrategy(SessionAuthenticationStrategy sessionStrategy) {
|
||||
Assert.notNull(sessionStrategy, "authenticatedSessionStratedy must not be null");
|
||||
this.sessionStrategy = sessionStrategy;
|
||||
}
|
||||
|
||||
+2
-2
@@ -50,7 +50,7 @@ import org.springframework.security.web.authentication.SavedRequestAwareAuthenti
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
|
||||
import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices;
|
||||
import org.springframework.security.web.savedrequest.SavedRequest;
|
||||
import org.springframework.security.web.session.AuthenticatedSessionStrategy;
|
||||
import org.springframework.security.web.session.SessionAuthenticationStrategy;
|
||||
|
||||
|
||||
/**
|
||||
@@ -240,7 +240,7 @@ public class AbstractProcessingFilterTests extends TestCase {
|
||||
MockAbstractProcessingFilter filter = new MockAbstractProcessingFilter(true);
|
||||
|
||||
filter.setFilterProcessesUrl("/j_mock_post");
|
||||
filter.setAuthenticatedSessionStrategy(mock(AuthenticatedSessionStrategy.class));
|
||||
filter.setAuthenticatedSessionStrategy(mock(SessionAuthenticationStrategy.class));
|
||||
filter.setAuthenticationSuccessHandler(successHandler);
|
||||
filter.setAuthenticationFailureHandler(failureHandler);
|
||||
filter.setAuthenticationManager(mock(AuthenticationManager.class));
|
||||
|
||||
+5
-5
@@ -18,11 +18,11 @@ import org.springframework.security.web.savedrequest.SavedRequest;
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class DefaultAuthenticatedSessionStrategyTests {
|
||||
public class DefaultSessionAuthenticationStrategyTests {
|
||||
|
||||
@Test
|
||||
public void newSessionShouldNotBeCreatedIfNoSessionExistsAndAlwaysCreateIsFalse() throws Exception {
|
||||
DefaultAuthenticatedSessionStrategy strategy = new DefaultAuthenticatedSessionStrategy();
|
||||
DefaultSessionAuthenticationStrategy strategy = new DefaultSessionAuthenticationStrategy();
|
||||
HttpServletRequest request = new MockHttpServletRequest();
|
||||
|
||||
strategy.onAuthentication(mock(Authentication.class), request, new MockHttpServletResponse());
|
||||
@@ -32,7 +32,7 @@ public class DefaultAuthenticatedSessionStrategyTests {
|
||||
|
||||
// @Test
|
||||
// public void newSessionIsCreatedIfSessionAlreadyExists() throws Exception {
|
||||
// DefaultAuthenticatedSessionStrategy strategy = new DefaultAuthenticatedSessionStrategy();
|
||||
// DefaultSessionAuthenticationStrategy strategy = new DefaultSessionAuthenticationStrategy();
|
||||
// strategy.setSessionRegistry(mock(SessionRegistry.class));
|
||||
// HttpServletRequest request = new MockHttpServletRequest();
|
||||
// String sessionId = request.getSession().getId();
|
||||
@@ -45,7 +45,7 @@ public class DefaultAuthenticatedSessionStrategyTests {
|
||||
// See SEC-1077
|
||||
@Test
|
||||
public void onlySavedRequestAttributeIsMigratedIfMigrateAttributesIsFalse() throws Exception {
|
||||
DefaultAuthenticatedSessionStrategy strategy = new DefaultAuthenticatedSessionStrategy();
|
||||
DefaultSessionAuthenticationStrategy strategy = new DefaultSessionAuthenticationStrategy();
|
||||
strategy.setMigrateSessionAttributes(false);
|
||||
HttpServletRequest request = new MockHttpServletRequest();
|
||||
HttpSession session = request.getSession();
|
||||
@@ -60,7 +60,7 @@ public class DefaultAuthenticatedSessionStrategyTests {
|
||||
|
||||
@Test
|
||||
public void sessionIsCreatedIfAlwaysCreateTrue() throws Exception {
|
||||
DefaultAuthenticatedSessionStrategy strategy = new DefaultAuthenticatedSessionStrategy();
|
||||
DefaultSessionAuthenticationStrategy strategy = new DefaultSessionAuthenticationStrategy();
|
||||
strategy.setAlwaysCreateSession(true);
|
||||
HttpServletRequest request = new MockHttpServletRequest();
|
||||
strategy.onAuthentication(mock(Authentication.class), request, new MockHttpServletResponse());
|
||||
+4
-4
@@ -44,7 +44,7 @@ public class SessionManagementFilterTests {
|
||||
@Test
|
||||
public void strategyIsNotInvokedIfSecurityContextAlreadyExistsForRequest() throws Exception {
|
||||
SecurityContextRepository repo = mock(SecurityContextRepository.class);
|
||||
AuthenticatedSessionStrategy strategy = mock(AuthenticatedSessionStrategy.class);
|
||||
SessionAuthenticationStrategy strategy = mock(SessionAuthenticationStrategy.class);
|
||||
// mock that repo contains a security context
|
||||
when(repo.containsContext(any(HttpServletRequest.class))).thenReturn(true);
|
||||
SessionManagementFilter filter = new SessionManagementFilter(repo);
|
||||
@@ -60,7 +60,7 @@ public class SessionManagementFilterTests {
|
||||
@Test
|
||||
public void strategyIsNotInvokedIfAuthenticationIsNull() throws Exception {
|
||||
SecurityContextRepository repo = mock(SecurityContextRepository.class);
|
||||
AuthenticatedSessionStrategy strategy = mock(AuthenticatedSessionStrategy.class);
|
||||
SessionAuthenticationStrategy strategy = mock(SessionAuthenticationStrategy.class);
|
||||
SessionManagementFilter filter = new SessionManagementFilter(repo);
|
||||
filter.setAuthenticatedSessionStrategy(strategy);
|
||||
HttpServletRequest request = new MockHttpServletRequest();
|
||||
@@ -74,7 +74,7 @@ public class SessionManagementFilterTests {
|
||||
public void strategyIsInvokedIfUserIsNewlyAuthenticated() throws Exception {
|
||||
SecurityContextRepository repo = mock(SecurityContextRepository.class);
|
||||
// repo will return false to containsContext()
|
||||
AuthenticatedSessionStrategy strategy = mock(AuthenticatedSessionStrategy.class);
|
||||
SessionAuthenticationStrategy strategy = mock(SessionAuthenticationStrategy.class);
|
||||
SessionManagementFilter filter = new SessionManagementFilter(repo);
|
||||
filter.setAuthenticatedSessionStrategy(strategy);
|
||||
HttpServletRequest request = new MockHttpServletRequest();
|
||||
@@ -92,7 +92,7 @@ public class SessionManagementFilterTests {
|
||||
public void responseIsRedirectedToTimeoutUrlIfSetAndSessionIsInvalid() throws Exception {
|
||||
SecurityContextRepository repo = mock(SecurityContextRepository.class);
|
||||
// repo will return false to containsContext()
|
||||
AuthenticatedSessionStrategy strategy = mock(AuthenticatedSessionStrategy.class);
|
||||
SessionAuthenticationStrategy strategy = mock(SessionAuthenticationStrategy.class);
|
||||
SessionManagementFilter filter = new SessionManagementFilter(repo);
|
||||
filter.setAuthenticatedSessionStrategy(strategy);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
|
||||
Reference in New Issue
Block a user