Sfoglia il codice sorgente

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

Luke Taylor 16 anni fa
parent
commit
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;