diff --git a/config/src/main/java/org/springframework/security/config/ConcurrentSessionsBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/ConcurrentSessionsBeanDefinitionParser.java index 8696a0dab4..5333c1fc21 100644 --- a/config/src/main/java/org/springframework/security/config/ConcurrentSessionsBeanDefinitionParser.java +++ b/config/src/main/java/org/springframework/security/config/ConcurrentSessionsBeanDefinitionParser.java @@ -11,8 +11,8 @@ import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.security.authentication.ProviderManager; import org.springframework.security.authentication.concurrent.ConcurrentSessionControllerImpl; +import org.springframework.security.authentication.concurrent.SessionRegistryImpl; import org.springframework.security.web.concurrent.ConcurrentSessionFilter; -import org.springframework.security.web.concurrent.SessionRegistryImpl; import org.springframework.util.StringUtils; import org.w3c.dom.Element; diff --git a/config/src/test/java/org/springframework/security/config/HttpSecurityBeanDefinitionParserTests.java b/config/src/test/java/org/springframework/security/config/HttpSecurityBeanDefinitionParserTests.java index d2434ac101..749a2de8e0 100644 --- a/config/src/test/java/org/springframework/security/config/HttpSecurityBeanDefinitionParserTests.java +++ b/config/src/test/java/org/springframework/security/config/HttpSecurityBeanDefinitionParserTests.java @@ -27,6 +27,7 @@ import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.concurrent.ConcurrentLoginException; import org.springframework.security.authentication.concurrent.ConcurrentSessionControllerImpl; +import org.springframework.security.authentication.concurrent.SessionRegistryImpl; import org.springframework.security.config.util.InMemoryXmlApplicationContext; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.openid.OpenIDAuthenticationProcessingFilter; @@ -51,7 +52,6 @@ import org.springframework.security.web.authentication.rememberme.PersistentToke import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices; import org.springframework.security.web.authentication.www.BasicProcessingFilter; import org.springframework.security.web.concurrent.ConcurrentSessionFilter; -import org.springframework.security.web.concurrent.SessionRegistryImpl; import org.springframework.security.web.context.HttpSessionSecurityContextRepository; import org.springframework.security.web.context.SecurityContextPersistenceFilter; import org.springframework.security.web.expression.DefaultWebSecurityExpressionHandler; diff --git a/config/src/test/java/org/springframework/security/config/SessionRegistryInjectionBeanPostProcessorTests.java b/config/src/test/java/org/springframework/security/config/SessionRegistryInjectionBeanPostProcessorTests.java index bf1bd83d0a..9ca9df72df 100644 --- a/config/src/test/java/org/springframework/security/config/SessionRegistryInjectionBeanPostProcessorTests.java +++ b/config/src/test/java/org/springframework/security/config/SessionRegistryInjectionBeanPostProcessorTests.java @@ -7,11 +7,11 @@ import org.junit.Test; import org.springframework.context.support.AbstractXmlApplicationContext; import org.springframework.security.authentication.concurrent.ConcurrentSessionController; import org.springframework.security.authentication.concurrent.ConcurrentSessionControllerImpl; +import org.springframework.security.authentication.concurrent.SessionRegistryImpl; import org.springframework.security.config.util.InMemoryXmlApplicationContext; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.util.FieldUtils; -import org.springframework.security.web.concurrent.SessionRegistryImpl; /** * diff --git a/core/src/main/java/org/springframework/security/authentication/concurrent/SessionAlreadyUsedException.java b/core/src/main/java/org/springframework/security/authentication/concurrent/SessionAlreadyUsedException.java deleted file mode 100644 index b4df1c7a41..0000000000 --- a/core/src/main/java/org/springframework/security/authentication/concurrent/SessionAlreadyUsedException.java +++ /dev/null @@ -1,34 +0,0 @@ -/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited - * - * 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.authentication.concurrent; - -import org.springframework.security.core.AuthenticationException; - - -/** - * Thrown by a SessionRegistry implementation if an attempt is made to create new session information - * for an existing sessionId. The user should firstly clear the existing session from the - * ConcurrentSessionRegistry. - * - * @author Ben Alex - */ -public class SessionAlreadyUsedException extends AuthenticationException { - //~ Constructors =================================================================================================== - - public SessionAlreadyUsedException(String msg) { - super(msg); - } -} diff --git a/core/src/main/java/org/springframework/security/authentication/concurrent/SessionRegistry.java b/core/src/main/java/org/springframework/security/authentication/concurrent/SessionRegistry.java index f8a7236515..69b2ba66e3 100644 --- a/core/src/main/java/org/springframework/security/authentication/concurrent/SessionRegistry.java +++ b/core/src/main/java/org/springframework/security/authentication/concurrent/SessionRegistry.java @@ -67,11 +67,8 @@ public interface SessionRegistry { * * @param sessionId to associate with the principal (should never be null) * @param principal to associate with the session (should never be null) - * - * @throws SessionAlreadyUsedException DOCUMENT ME! */ - void registerNewSession(String sessionId, Object principal) - throws SessionAlreadyUsedException; + void registerNewSession(String sessionId, Object principal); /** * Deletes all the session information being maintained for the specified sessionId. If the diff --git a/web/src/main/java/org/springframework/security/web/concurrent/SessionRegistryImpl.java b/core/src/main/java/org/springframework/security/authentication/concurrent/SessionRegistryImpl.java similarity index 90% rename from web/src/main/java/org/springframework/security/web/concurrent/SessionRegistryImpl.java rename to core/src/main/java/org/springframework/security/authentication/concurrent/SessionRegistryImpl.java index ec61e15f91..be9bdbf75b 100644 --- a/web/src/main/java/org/springframework/security/web/concurrent/SessionRegistryImpl.java +++ b/core/src/main/java/org/springframework/security/authentication/concurrent/SessionRegistryImpl.java @@ -13,7 +13,7 @@ * limitations under the License. */ -package org.springframework.security.web.concurrent; +package org.springframework.security.authentication.concurrent; import java.util.ArrayList; import java.util.Collections; @@ -24,15 +24,10 @@ import java.util.List; import java.util.Map; import java.util.Set; -import javax.servlet.http.HttpSession; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationListener; -import org.springframework.security.authentication.concurrent.SessionInformation; -import org.springframework.security.authentication.concurrent.SessionRegistry; -import org.springframework.security.web.session.HttpSessionDestroyedEvent; +import org.springframework.security.core.session.SessionDestroyedEvent; import org.springframework.util.Assert; /** @@ -48,7 +43,7 @@ import org.springframework.util.Assert; * @author Ben Alex * @version $Id$ */ -public class SessionRegistryImpl implements SessionRegistry, ApplicationListener { +public class SessionRegistryImpl implements SessionRegistry, ApplicationListener { //~ Static fields/initializers ===================================================================================== protected static final Log logger = LogFactory.getLog(SessionRegistryImpl.class); @@ -98,11 +93,9 @@ public class SessionRegistryImpl implements SessionRegistry, ApplicationListener return (SessionInformation) sessionIds.get(sessionId); } - public void onApplicationEvent(ApplicationEvent event) { - if (event instanceof HttpSessionDestroyedEvent) { - String sessionId = ((HttpSession) event.getSource()).getId(); - removeSessionInformation(sessionId); - } + public void onApplicationEvent(SessionDestroyedEvent event) { + String sessionId = event.getId(); + removeSessionInformation(sessionId); } public void refreshLastRequest(String sessionId) { diff --git a/core/src/main/java/org/springframework/security/core/session/SessionDestroyedEvent.java b/core/src/main/java/org/springframework/security/core/session/SessionDestroyedEvent.java index b7f23064b7..c66b8f938c 100644 --- a/core/src/main/java/org/springframework/security/core/session/SessionDestroyedEvent.java +++ b/core/src/main/java/org/springframework/security/core/session/SessionDestroyedEvent.java @@ -23,4 +23,10 @@ public abstract class SessionDestroyedEvent extends ApplicationEvent { * @return the SecurityContext associated with the session, or null if there is no context. */ public abstract SecurityContext getSecurityContext(); + + /** + * The identifier associated with the destroyed session. + * @return + */ + public abstract String getId(); } diff --git a/web/src/test/java/org/springframework/security/web/concurrent/ConcurrentSessionControllerImplTests.java b/core/src/test/java/org/springframework/security/authentication/concurrent/ConcurrentSessionControllerImplTests.java similarity index 69% rename from web/src/test/java/org/springframework/security/web/concurrent/ConcurrentSessionControllerImplTests.java rename to core/src/test/java/org/springframework/security/authentication/concurrent/ConcurrentSessionControllerImplTests.java index 4a112601c4..51560b5acb 100644 --- a/web/src/test/java/org/springframework/security/web/concurrent/ConcurrentSessionControllerImplTests.java +++ b/core/src/test/java/org/springframework/security/authentication/concurrent/ConcurrentSessionControllerImplTests.java @@ -13,23 +13,19 @@ * limitations under the License. */ -package org.springframework.security.web.concurrent; - -import junit.framework.TestCase; +package org.springframework.security.authentication.concurrent; +import static org.junit.Assert.*; +import org.junit.Test; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.concurrent.ConcurrentLoginException; import org.springframework.security.authentication.concurrent.ConcurrentSessionControllerImpl; +import org.springframework.security.authentication.concurrent.SessionIdentifierAware; import org.springframework.security.authentication.concurrent.SessionRegistry; +import org.springframework.security.authentication.concurrent.SessionRegistryImpl; import org.springframework.security.core.Authentication; -import org.springframework.security.web.authentication.WebAuthenticationDetails; -import org.springframework.security.web.concurrent.SessionRegistryImpl; - -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.mock.web.MockHttpSession; - /** * Tests {@link ConcurrentSessionControllerImpl}. @@ -37,25 +33,24 @@ import org.springframework.mock.web.MockHttpSession; * @author Ben Alex * @version $Id$ */ -public class ConcurrentSessionControllerImplTests extends TestCase { +public class ConcurrentSessionControllerImplTests { //~ Methods ======================================================================================================== + private static int nextSessionId = 1000; + private Authentication createAuthentication(String user, String password) { UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(user, password); - auth.setDetails(createWebDetails(auth)); + auth.setDetails(new SessionIdentifierAware() { + private final String id = Integer.toString(nextSessionId++); + public String getSessionId() { + return id; + } + }); return auth; } - private WebAuthenticationDetails createWebDetails(Authentication auth) { - MockHttpSession session = new MockHttpSession(); - MockHttpServletRequest request = new MockHttpServletRequest(); - request.setSession(session); - request.setUserPrincipal(auth); - - return new WebAuthenticationDetails(request); - } - + @Test public void testLifecycle() throws Exception { // Build a test fixture ConcurrentSessionControllerImpl sc = new ConcurrentSessionControllerImpl(); @@ -67,7 +62,7 @@ public class ConcurrentSessionControllerImplTests extends TestCase { sc.checkAuthenticationAllowed(auth); sc.registerSuccessfulAuthentication(auth); - String sessionId1 = ((WebAuthenticationDetails) auth.getDetails()).getSessionId(); + String sessionId1 = ((SessionIdentifierAware) auth.getDetails()).getSessionId(); assertFalse(registry.getSessionInformation(sessionId1).isExpired()); // Attempt to authenticate again - it should still be successful @@ -94,34 +89,24 @@ public class ConcurrentSessionControllerImplTests extends TestCase { sc.checkAuthenticationAllowed(auth3); sc.registerSuccessfulAuthentication(auth3); - String sessionId3 = ((WebAuthenticationDetails) auth3.getDetails()).getSessionId(); + String sessionId3 = ((SessionIdentifierAware) auth3.getDetails()).getSessionId(); assertTrue(registry.getSessionInformation(sessionId1).isExpired()); assertFalse(registry.getSessionInformation(sessionId3).isExpired()); } - public void testStartupDetectsInvalidMaximumSessions() - throws Exception { + @Test(expected=IllegalArgumentException.class) + public void startupDetectsInvalidMaximumSessions() throws Exception { ConcurrentSessionControllerImpl sc = new ConcurrentSessionControllerImpl(); sc.setMaximumSessions(0); - try { - sc.afterPropertiesSet(); - fail("Should have thrown IAE"); - } catch (IllegalArgumentException expected) { - assertTrue(true); - } + sc.afterPropertiesSet(); } - public void testStartupDetectsInvalidSessionRegistry() - throws Exception { + @Test(expected=IllegalArgumentException.class) + public void startupDetectsInvalidSessionRegistry() throws Exception { ConcurrentSessionControllerImpl sc = new ConcurrentSessionControllerImpl(); sc.setSessionRegistry(null); - try { - sc.afterPropertiesSet(); - fail("Should have thrown IAE"); - } catch (IllegalArgumentException expected) { - assertTrue(true); - } + sc.afterPropertiesSet(); } } diff --git a/web/src/test/java/org/springframework/security/web/concurrent/SessionInformationTests.java b/core/src/test/java/org/springframework/security/authentication/concurrent/SessionInformationTests.java similarity index 96% rename from web/src/test/java/org/springframework/security/web/concurrent/SessionInformationTests.java rename to core/src/test/java/org/springframework/security/authentication/concurrent/SessionInformationTests.java index 3d33c2cda8..bd04fbefb1 100644 --- a/web/src/test/java/org/springframework/security/web/concurrent/SessionInformationTests.java +++ b/core/src/test/java/org/springframework/security/authentication/concurrent/SessionInformationTests.java @@ -13,7 +13,7 @@ * limitations under the License. */ -package org.springframework.security.web.concurrent; +package org.springframework.security.authentication.concurrent; import junit.framework.TestCase; diff --git a/web/src/test/java/org/springframework/security/web/concurrent/SessionRegistryImplTests.java b/core/src/test/java/org/springframework/security/authentication/concurrent/SessionRegistryImplTests.java similarity index 85% rename from web/src/test/java/org/springframework/security/web/concurrent/SessionRegistryImplTests.java rename to core/src/test/java/org/springframework/security/authentication/concurrent/SessionRegistryImplTests.java index f7df160183..c481887f8d 100644 --- a/web/src/test/java/org/springframework/security/web/concurrent/SessionRegistryImplTests.java +++ b/core/src/test/java/org/springframework/security/authentication/concurrent/SessionRegistryImplTests.java @@ -13,49 +13,59 @@ * limitations under the License. */ -package org.springframework.security.web.concurrent; +package org.springframework.security.authentication.concurrent; -import junit.framework.TestCase; - -import org.springframework.security.authentication.concurrent.SessionInformation; -import org.springframework.security.web.concurrent.SessionRegistryImpl; -import org.springframework.security.web.session.HttpSessionDestroyedEvent; - -import org.springframework.mock.web.MockHttpSession; +import static org.junit.Assert.*; import java.util.Date; +import org.junit.Before; +import org.junit.Test; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.session.SessionDestroyedEvent; + /** * Tests {@link SessionRegistryImpl}. * -* @author Ben Alex + * @author Ben Alex * @version $Id$ */ -public class SessionRegistryImplTests extends TestCase { +public class SessionRegistryImplTests { private SessionRegistryImpl sessionRegistry; //~ Methods ======================================================================================================== - protected void setUp() throws Exception { + @Before + public void setUp() throws Exception { sessionRegistry = new SessionRegistryImpl(); } - public void testEventPublishing() { - MockHttpSession httpSession = new MockHttpSession(); + @Test + public void sessionDestroyedEventRemovesSessionFromRegistry() { Object principal = "Some principal object"; - String sessionId = httpSession.getId(); - assertNotNull(sessionId); + final String sessionId = "zzzz"; // Register new Session sessionRegistry.registerNewSession(sessionId, principal); - // Deregister session via an ApplicationEvent - sessionRegistry.onApplicationEvent(new HttpSessionDestroyedEvent(httpSession)); + // De-register session via an ApplicationEvent + sessionRegistry.onApplicationEvent(new SessionDestroyedEvent("") { + @Override + public String getId() { + return sessionId; + } + + @Override + public SecurityContext getSecurityContext() { + return null; + } + }); // Check attempts to retrieve cleared session return null assertNull(sessionRegistry.getSessionInformation(sessionId)); } + @Test public void testMultiplePrincipals() throws Exception { Object principal1 = "principal_1"; Object principal2 = "principal_2"; @@ -71,6 +81,7 @@ public class SessionRegistryImplTests extends TestCase { assertEquals(principal2, sessionRegistry.getAllPrincipals()[1]); } + @Test public void testSessionInformationLifecycle() throws Exception { Object principal = "Some principal object"; String sessionId = "1234567890"; @@ -106,6 +117,7 @@ public class SessionRegistryImplTests extends TestCase { assertNull(sessionRegistry.getAllSessions(principal, false)); } + @Test public void testTwoSessionsOnePrincipalExpiring() throws Exception { Object principal = "Some principal object"; String sessionId1 = "1234567890"; @@ -130,6 +142,7 @@ public class SessionRegistryImplTests extends TestCase { assertFalse(sessionRegistry.getSessionInformation(sessionId1).isExpired()); } + @Test public void testTwoSessionsOnePrincipalHandling() throws Exception { Object principal = "Some principal object"; String sessionId1 = "1234567890"; @@ -155,7 +168,7 @@ public class SessionRegistryImplTests extends TestCase { assertNull(sessionRegistry.getAllSessions(principal, false)); } - boolean contains(String sessionId, Object principal) { + private boolean contains(String sessionId, Object principal) { SessionInformation[] info = sessionRegistry.getAllSessions(principal, false); for (int i = 0; i < info.length; i++) { diff --git a/web/src/main/java/org/springframework/security/web/session/HttpSessionDestroyedEvent.java b/web/src/main/java/org/springframework/security/web/session/HttpSessionDestroyedEvent.java index cd0a8b1e0c..cb7f219e51 100644 --- a/web/src/main/java/org/springframework/security/web/session/HttpSessionDestroyedEvent.java +++ b/web/src/main/java/org/springframework/security/web/session/HttpSessionDestroyedEvent.java @@ -35,11 +35,17 @@ public class HttpSessionDestroyedEvent extends SessionDestroyedEvent { super(session); } + public HttpSession getSession() { + return (HttpSession) getSource(); + } + + @Override public SecurityContext getSecurityContext() { return (SecurityContext) ((HttpSession)getSource()).getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY); } - public HttpSession getSession() { - return (HttpSession) getSource(); + @Override + public String getId() { + return getSession().getId(); } } diff --git a/web/src/test/java/org/springframework/security/web/concurrent/ConcurrentSessionFilterTests.java b/web/src/test/java/org/springframework/security/web/concurrent/ConcurrentSessionFilterTests.java index 45f0f2f7c8..fde20d7bdf 100644 --- a/web/src/test/java/org/springframework/security/web/concurrent/ConcurrentSessionFilterTests.java +++ b/web/src/test/java/org/springframework/security/web/concurrent/ConcurrentSessionFilterTests.java @@ -21,8 +21,8 @@ import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockHttpSession; import org.springframework.security.authentication.concurrent.SessionRegistry; +import org.springframework.security.authentication.concurrent.SessionRegistryImpl; import org.springframework.security.web.concurrent.ConcurrentSessionFilter; -import org.springframework.security.web.concurrent.SessionRegistryImpl; import javax.servlet.Filter; import javax.servlet.FilterChain;