瀏覽代碼

Refactored SessionRegistryImpl to remove servlet API deps and moved back into core, along with other concurrent authentication package classes.

Luke Taylor 16 年之前
父節點
當前提交
cac2bce382

+ 1 - 1
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;
 

+ 1 - 1
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;

+ 1 - 1
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;
 
 /**
  *

+ 0 - 34
core/src/main/java/org/springframework/security/authentication/concurrent/SessionAlreadyUsedException.java

@@ -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 <code>SessionRegistry</code> 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
- * <code>ConcurrentSessionRegistry</code>.
- *
- * @author Ben Alex
- */
-public class SessionAlreadyUsedException extends AuthenticationException {
-    //~ Constructors ===================================================================================================
-
-    public SessionAlreadyUsedException(String msg) {
-        super(msg);
-    }
-}

+ 1 - 4
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 <code>null</code>)
      * @param principal to associate with the session (should never be <code>null</code>)
-     *
-     * @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 <code>sessionId</code>. If the

+ 6 - 13
web/src/main/java/org/springframework/security/web/concurrent/SessionRegistryImpl.java → 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<SessionDestroyedEvent> {
     //~ 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) {

+ 6 - 0
core/src/main/java/org/springframework/security/core/session/SessionDestroyedEvent.java

@@ -23,4 +23,10 @@ public abstract class SessionDestroyedEvent extends ApplicationEvent {
      * @return the <tt>SecurityContext</tt> 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();
 }

+ 23 - 38
web/src/test/java/org/springframework/security/web/concurrent/ConcurrentSessionControllerImplTests.java → 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();
     }
 }

+ 1 - 1
web/src/test/java/org/springframework/security/web/concurrent/SessionInformationTests.java → 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;
 

+ 31 - 18
web/src/test/java/org/springframework/security/web/concurrent/SessionRegistryImplTests.java → 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++) {

+ 8 - 2
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();
     }
 }

+ 1 - 1
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;