Browse Source

SEC-1229: Refactored authentication.concurrent in core, moving classes into core.session

Luke Taylor 16 năm trước cách đây
mục cha
commit
acf13c74ca
23 tập tin đã thay đổi với 119 bổ sung150 xóa
  1. 3 3
      config/src/main/java/org/springframework/security/config/http/HttpConfigurationBuilder.java
  2. 1 1
      config/src/test/java/org/springframework/security/config/http/HttpSecurityBeanDefinitionParserTests.java
  3. 0 55
      core/src/main/java/org/springframework/security/authentication/concurrent/ConcurrentSessionController.java
  4. 0 6
      core/src/main/java/org/springframework/security/authentication/concurrent/package.html
  5. 1 1
      core/src/main/java/org/springframework/security/core/session/SessionIdentifierAware.java
  6. 1 1
      core/src/main/java/org/springframework/security/core/session/SessionInformation.java
  7. 1 1
      core/src/main/java/org/springframework/security/core/session/SessionRegistry.java
  8. 2 3
      core/src/main/java/org/springframework/security/core/session/SessionRegistryImpl.java
  9. 6 0
      core/src/main/java/org/springframework/security/core/session/package.html
  10. 2 2
      core/src/test/java/org/springframework/security/core/session/SessionInformationTests.java
  11. 3 1
      core/src/test/java/org/springframework/security/core/session/SessionRegistryImplTests.java
  12. 9 10
      docs/manual/src/docbook/appendix-namespace.xml
  13. 39 43
      docs/manual/src/docbook/concurrent-sessions.xml
  14. 1 1
      itest/context/src/test/java/org/springframework/security/integration/SEC936ApplicationContextTests.java
  15. 2 2
      itest/context/src/test/resources/sec-936-app-context.xml
  16. 1 1
      web/src/main/java/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilter.java
  17. 1 1
      web/src/main/java/org/springframework/security/web/authentication/WebAuthenticationDetails.java
  18. 4 4
      web/src/main/java/org/springframework/security/web/authentication/concurrent/ConcurrentSessionFilter.java
  19. 32 4
      web/src/main/java/org/springframework/security/web/session/ConcurrentSessionControlStrategy.java
  20. 1 1
      web/src/main/java/org/springframework/security/web/session/SessionFixationProtectionStrategy.java
  21. 2 2
      web/src/main/java/org/springframework/security/web/session/SessionManagementFilter.java
  22. 3 3
      web/src/test/java/org/springframework/security/web/concurrent/ConcurrentSessionFilterTests.java
  23. 4 4
      web/src/test/java/org/springframework/security/web/session/DefaultSessionAuthenticationStrategyTests.java

+ 3 - 3
config/src/main/java/org/springframework/security/config/http/HttpConfigurationBuilder.java

@@ -24,8 +24,8 @@ import org.springframework.beans.factory.xml.ParserContext;
 import org.springframework.security.access.vote.AffirmativeBased;
 import org.springframework.security.access.vote.AuthenticatedVoter;
 import org.springframework.security.access.vote.RoleVoter;
-import org.springframework.security.authentication.concurrent.SessionRegistryImpl;
 import org.springframework.security.config.Elements;
+import org.springframework.security.core.session.SessionRegistryImpl;
 import org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator;
 import org.springframework.security.web.access.channel.ChannelDecisionManagerImpl;
 import org.springframework.security.web.access.channel.ChannelProcessingFilter;
@@ -42,7 +42,7 @@ import org.springframework.security.web.authentication.concurrent.ConcurrentSess
 import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
 import org.springframework.security.web.context.SecurityContextPersistenceFilter;
 import org.springframework.security.web.session.ConcurrentSessionControlStrategy;
-import org.springframework.security.web.session.DefaultSessionAuthenticationStrategy;
+import org.springframework.security.web.session.SessionFixationProtectionStrategy;
 import org.springframework.security.web.session.SessionManagementFilter;
 import org.springframework.security.web.util.AntUrlPathMatcher;
 import org.springframework.security.web.util.UrlMatcher;
@@ -248,7 +248,7 @@ class HttpConfigurationBuilder {
             }
         } else if (sessionFixationProtectionRequired || StringUtils.hasText(invalidSessionUrl)
                 || StringUtils.hasText(sessionAuthStratRef)) {
-            sessionStrategy = BeanDefinitionBuilder.rootBeanDefinition(DefaultSessionAuthenticationStrategy.class);
+            sessionStrategy = BeanDefinitionBuilder.rootBeanDefinition(SessionFixationProtectionStrategy.class);
         } else {
             sfpf = null;
             return;

+ 1 - 1
config/src/test/java/org/springframework/security/config/http/HttpSecurityBeanDefinitionParserTests.java

@@ -27,11 +27,11 @@ import org.springframework.security.access.ConfigAttribute;
 import org.springframework.security.access.SecurityConfig;
 import org.springframework.security.authentication.TestingAuthenticationToken;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.security.authentication.concurrent.SessionRegistryImpl;
 import org.springframework.security.config.BeanIds;
 import org.springframework.security.config.PostProcessedMockUserDetailsService;
 import org.springframework.security.config.util.InMemoryXmlApplicationContext;
 import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.session.SessionRegistryImpl;
 import org.springframework.security.openid.OpenID4JavaConsumer;
 import org.springframework.security.openid.OpenIDAttribute;
 import org.springframework.security.openid.OpenIDAuthenticationProcessingFilter;

+ 0 - 55
core/src/main/java/org/springframework/security/authentication/concurrent/ConcurrentSessionController.java

@@ -1,55 +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.Authentication;
-import org.springframework.security.core.AuthenticationException;
-
-
-/**
- * Provides two methods that can be called by an {@link
- * org.springframework.security.authentication.AuthenticationManager} to integrate with the
- * concurrent session handling infrastructure.
- *
- * @author Ben Alex
- * @version $Id$
- */
-public interface ConcurrentSessionController {
-    //~ Methods ========================================================================================================
-
-    /**
-     * Called by any class that wishes to know whether the current authentication request should be permitted.
-     * Generally callers will be <code>AuthenticationManager</code>s before they authenticate, but could equally
-     * include <code>Filter</code>s or other interceptors that wish to confirm the ongoing validity of a previously
-     * authenticated <code>Authentication</code>.<p>The implementation should throw a suitable exception if the
-     * user has exceeded their maximum allowed concurrent sessions.</p>
-     *
-     * @param request the authentication request (never <code>null</code>)
-     *
-     * @throws AuthenticationException if the user has exceeded their maximum allowed current sessions
-     */
-    void checkAuthenticationAllowed(Authentication request)
-        throws AuthenticationException;
-
-    /**
-     * Called by an <code>AuthenticationManager</code> when the authentication was successful. An
-     * implementation is expected to register the authenticated user in some sort of registry, for future concurrent
-     * tracking via the {@link #checkAuthenticationAllowed(Authentication)} method.
-     *
-     * @param authentication the successfully authenticated user (never <code>null</code>)
-     */
-    void registerSuccessfulAuthentication(Authentication authentication);
-}

+ 0 - 6
core/src/main/java/org/springframework/security/authentication/concurrent/package.html

@@ -1,6 +0,0 @@
-<html>
-<body>
-Concurrent session control and registration classes.
-</body>
-</html>
-

+ 1 - 1
core/src/main/java/org/springframework/security/authentication/concurrent/SessionIdentifierAware.java → core/src/main/java/org/springframework/security/core/session/SessionIdentifierAware.java

@@ -13,7 +13,7 @@
  * limitations under the License.
  */
 
-package org.springframework.security.authentication.concurrent;
+package org.springframework.security.core.session;
 
 /**
  * Implemented by {@link org.springframework.security.core.Authentication#getDetails()}

+ 1 - 1
core/src/main/java/org/springframework/security/authentication/concurrent/SessionInformation.java → core/src/main/java/org/springframework/security/core/session/SessionInformation.java

@@ -13,7 +13,7 @@
  * limitations under the License.
  */
 
-package org.springframework.security.authentication.concurrent;
+package org.springframework.security.core.session;
 
 import org.springframework.util.Assert;
 

+ 1 - 1
core/src/main/java/org/springframework/security/authentication/concurrent/SessionRegistry.java → core/src/main/java/org/springframework/security/core/session/SessionRegistry.java

@@ -13,7 +13,7 @@
  * limitations under the License.
  */
 
-package org.springframework.security.authentication.concurrent;
+package org.springframework.security.core.session;
 
 import java.util.List;
 

+ 2 - 3
core/src/main/java/org/springframework/security/authentication/concurrent/SessionRegistryImpl.java → core/src/main/java/org/springframework/security/core/session/SessionRegistryImpl.java

@@ -13,7 +13,7 @@
  * limitations under the License.
  */
 
-package org.springframework.security.authentication.concurrent;
+package org.springframework.security.core.session;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -28,11 +28,10 @@ import java.util.Set;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.springframework.context.ApplicationListener;
-import org.springframework.security.core.session.SessionDestroyedEvent;
 import org.springframework.util.Assert;
 
 /**
- * Base implementation of {@link org.springframework.security.authentication.concurrent.SessionRegistry}
+ * Base implementation of {@link org.springframework.security.core.session.SessionRegistry}
  * which also listens for {@link org.springframework.security.web.session.HttpSessionDestroyedEvent}s
  * published in the Spring application context.
  *

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

@@ -0,0 +1,6 @@
+<html>
+<body>
+Session registry and other related classes.
+</body>
+</html>
+

+ 2 - 2
core/src/test/java/org/springframework/security/authentication/concurrent/SessionInformationTests.java → core/src/test/java/org/springframework/security/core/session/SessionInformationTests.java

@@ -13,13 +13,13 @@
  * limitations under the License.
  */
 
-package org.springframework.security.authentication.concurrent;
+package org.springframework.security.core.session;
 
 import junit.framework.TestCase;
 
 import java.util.Date;
 
-import org.springframework.security.authentication.concurrent.SessionInformation;
+import org.springframework.security.core.session.SessionInformation;
 
 
 /**

+ 3 - 1
core/src/test/java/org/springframework/security/authentication/concurrent/SessionRegistryImplTests.java → core/src/test/java/org/springframework/security/core/session/SessionRegistryImplTests.java

@@ -13,7 +13,7 @@
  * limitations under the License.
  */
 
-package org.springframework.security.authentication.concurrent;
+package org.springframework.security.core.session;
 
 import static org.junit.Assert.*;
 
@@ -24,6 +24,8 @@ import org.junit.Before;
 import org.junit.Test;
 import org.springframework.security.core.context.SecurityContext;
 import org.springframework.security.core.session.SessionDestroyedEvent;
+import org.springframework.security.core.session.SessionInformation;
+import org.springframework.security.core.session.SessionRegistryImpl;
 
 /**
  * Tests {@link SessionRegistryImpl}.

+ 9 - 10
docs/manual/src/docbook/appendix-namespace.xml

@@ -298,18 +298,17 @@
     <section xml:id="nsa-session-mgmt">
       <title>The <literal>&lt;session-management&gt;</literal> Element</title>
       <para>Session-management related functionality is implemented by the addition of a
-        <classname>SessionManagementFilter</classname> to the filter stack.</para>
+          <classname>SessionManagementFilter</classname> to the filter stack.</para>
       <section xml:id="session-fixation-protection">
         <title><literal>session-fixation-protection</literal></title>
         <para> Indicates whether an existing session should be invalidated when a user authenticates
           and a new session started. If set to "none" no change will be made. "newSession" will
           create a new empty session. "migrateSession" will create a new session and copy the
           session attributes to the new session. Defaults to "migrateSession".</para>
-        <para>
-          If session fixation protection is enabled, the <classname>SessionManagementFilter</classname>
-          is inected with a appropriately configured <classname>DefaultSessionAuthenticationStrategy</classname>.
-          See the Javadoc for this class for more details.
-        </para>
+        <para> If session fixation protection is enabled, the
+            <classname>SessionManagementFilter</classname> is inected with a appropriately
+          configured <classname>DefaultSessionAuthenticationStrategy</classname>. See the Javadoc
+          for this class for more details. </para>
       </section>
     </section>
     <section xml:id="nsa-concurrent-session-control">
@@ -317,15 +316,15 @@
       <para> Adds support for concurrent session control, allowing limits to be placed on the number
         of active sessions a user can have. A <classname>ConcurrentSessionFilter</classname> will be
         created, and a <classname>ConcurrentSessionControlStrategy</classname> will be used with the
-          <classname>SessionManagementFilter</classname>.  If a <literal>form-login</literal>
-        element has been declared, the strategy object will also be injected into the created
-        authentication filter. An instance of <interfacename>SessionRegistry</interfacename> (a
+          <classname>SessionManagementFilter</classname>. If a <literal>form-login</literal> element
+        has been declared, the strategy object will also be injected into the created authentication
+        filter. An instance of <interfacename>SessionRegistry</interfacename> (a
           <classname>SessionRegistryImpl</classname> instance unless the user wishes to use a custom
         bean) will be created for use by the strategy.</para>
       <section>
         <title>The <literal>max-sessions</literal> attribute</title>
         <para>Maps to the <literal>maximumSessions</literal> property of
-            <classname>ConcurrentSessionControllerImpl</classname>.</para>
+            <classname>ConcurrentSessionControlStrategy</classname>.</para>
       </section>
       <section>
         <title>The <literal>expired-url</literal> attribute</title>

+ 39 - 43
docs/manual/src/docbook/concurrent-sessions.xml

@@ -14,14 +14,13 @@
     <para>The <classname>SessionManagementFilter</classname> checks the contents of the
         <interfacename>SecurityContextRepository</interfacename> against the current contents of the
         <classname>SecurityContextHolder</classname> to deterine whether a user has been
-      authenticated during the current request, typically by a non-interactive authentication mechanism, such
-      as pre-authentication or remember-me <footnote><para>Authentication by mechanisms which perform a redirect
-        after authenticating (such as form-login) will not be detected by <classname>SessionManagementFilter</classname>,
-        as the filter will not be invoked during the authenticating request. Session-management functionality has to be 
-        handled separately in these cases.
-      </para></footnote>. 
-      If the repository contains a security context, the
-      filter does nothing. If it doesn't, and the thread-local
+      authenticated during the current request, typically by a non-interactive authentication
+      mechanism, such as pre-authentication or remember-me <footnote><para>Authentication by
+          mechanisms which perform a redirect after authenticating (such as form-login) will not be
+          detected by <classname>SessionManagementFilter</classname>, as the filter will not be
+          invoked during the authenticating request. Session-management functionality has to be
+          handled separately in these cases. </para></footnote>. If the repository contains a
+      security context, the filter does nothing. If it doesn't, and the thread-local
         <interfacename>SecurityContext</interfacename> contains a (non-anonymous)
         <interfacename>Authentication</interfacename> object, the filter assumes they have been
       authenticated by a previous filter in the stack. It will then invoke the configured
@@ -34,10 +33,11 @@
   <section>
     <title><interfacename>SessionAuthenticationStrategy</interfacename></title>
     <para>
-      <interfacename>SessionAuthenticationStrategy</interfacename> is used by both <classname>SessionManagementFilter</classname>
-      and <classname>AbstractAutheticationProcessingFilter</classname>, so if you are using a customized form-login class, for example, you will need to inject 
-      it into both of these. In this case, a typical configuration, combining the namespace and custom beans might look like
-      <programlisting><![CDATA[
+      <interfacename>SessionAuthenticationStrategy</interfacename> is used by both
+        <classname>SessionManagementFilter</classname> and
+        <classname>AbstractAutheticationProcessingFilter</classname>, so if you are using a
+      customized form-login class, for example, you will need to inject it into both of these. In
+      this case, a typical configuration, combining the namespace and custom beans might look like this:<programlisting><![CDATA[
   <http>  
     <custom-filter position="AUTHENTICATION_PROCESSING_FILTER" ref="myAuthFilter" />     
     <session-management session-authentication-strategy-ref="sas"/>      
@@ -55,9 +55,7 @@
     <beans:property name="maximumSessions" value="1" />
   </beans:bean>
 ]]>       
-      </programlisting>      
-      
-    </para>
+      </programlisting></para>
   </section>
   <section xml:id="concurrent-sessions">
     <title>Concurrency Control</title>
@@ -70,15 +68,15 @@
       for the simplest configuration. Sometimes you need to customize things though. </para>
     <para>The implementation uses a specialized version of
         <interfacename>SessionAuthenticationStrategy</interfacename>, called
-      <classname>ConcurrentSessionControlStrategy</classname>.
-        <note><para>Previously the concurrent authentication check was made by the
-          <classname>ProviderManager</classname>, which could be injected with a
-          <literal>ConcurrentSessionController</literal> which would check if the user was
-        attempting to exceed the number of sessions permitted. However, this approach required that
-        an HTTP session be created in advance, which is undesirable. In Spring Security 3, the user
-        is first authenticated by the <interfacename>AuthenticationManager</interfacename> and once
-        they are successfully authenticated, a session is created and the check is made whether they
-        are allowed to have another session open.</para></note></para>
+        <classname>ConcurrentSessionControlStrategy</classname>. <note><para>Previously the
+          concurrent authentication check was made by the <classname>ProviderManager</classname>,
+          which could be injected with a <literal>ConcurrentSessionController</literal>. The latter
+          would check if the user was attempting to exceed the number of permitted sessions.
+          However, this approach required that an HTTP session be created in advance, which is
+          undesirable. In Spring Security 3, the user is first authenticated by the
+            <interfacename>AuthenticationManager</interfacename> and once they are successfully
+          authenticated, a session is created and the check is made whether they are allowed to have
+          another session open.</para></note></para>
     <para>To use concurrent session support, you'll need to add the following to
         <literal>web.xml</literal>: <programlisting><![CDATA[
   <listener>
@@ -87,15 +85,13 @@
     </listener-class>
   </listener> ]]>       
         </programlisting></para>
-    <para>In addition, you will need to add the
-        <literal>org.springframework.security.web.authentication.concurrent.ConcurrentSessionFilter</literal>
-      to your <classname>FilterChainProxy</classname>. The
-        <classname>ConcurrentSessionFilter</classname> requires two properties,
-        <literal>sessionRegistry</literal>, which generally points to an instance of
-        <literal>SessionRegistryImpl</literal>, and <literal>expiredUrl</literal>, which points to
-      the page to display when a session has expired. A configuration using the namespace to create the 
-      <classname>FilterChainProxy</classname> and other default beans might look like this:
-    <programlisting><![CDATA[
+    <para>In addition, you will need to add the <literal>ConcurrentSessionFilter</literal> to your
+        <classname>FilterChainProxy</classname>. The <classname>ConcurrentSessionFilter</classname>
+      requires two properties, <literal>sessionRegistry</literal>, which generally points to an
+      instance of <literal>SessionRegistryImpl</literal>, and <literal>expiredUrl</literal>, which
+      points to the page to display when a session has expired. A configuration using the namespace
+      to create the <classname>FilterChainProxy</classname> and other default beans might look like
+      this: <programlisting><![CDATA[
   <http>
     <custom-filter position="CONCURRENT_SESSION_FILTER" ref="concurrencyFilter" />  
     <custom-filter position="AUTHENTICATION_PROCESSING_FILTER" ref="myAuthFilter" />     
@@ -104,7 +100,7 @@
   </http>
   
   <beans:bean id="concurrencyFilter" 
-      class="org.springframework.security.web.authentication.concurrent.ConcurrentSessionFilter">
+      class="org.springframework.security.web.session.ConcurrentSessionFilter">
     <beans:property name="sessionRegistry" ref="sessionRegistry" />
     <beans:property name="expiredUrl" value="/session-expired.htm" />
   </beans:bean>
@@ -121,15 +117,15 @@
     <beans:property name="maximumSessions" value="1" />
   </beans:bean>
   
-  <beans:bean id="sessionRegistry" class="org.springframework.security.authentication.concurrent.SessionRegistryImpl" />
+  <beans:bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl" />
 ]]>       
-    </programlisting>
-    </para>
-    <para>Adding the listener to <filename>web.xml</filename> causes an <literal>ApplicationEvent</literal> to
-      be published to the Spring <literal>ApplicationContext</literal> every time a
-      <literal>HttpSession</literal> commences or terminates. This is critical, as it allows the
-      <classname>SessionRegistryImpl</classname> to be notified when a session ends. Without it, a user
-    will never be able to log back in again once they have exceeded their session allowance, even if they log out
-    of another session or it times out.</para>    
+    </programlisting></para>
+    <para>Adding the listener to <filename>web.xml</filename> causes an
+        <literal>ApplicationEvent</literal> to be published to the Spring
+        <literal>ApplicationContext</literal> every time a <literal>HttpSession</literal> commences
+      or terminates. This is critical, as it allows the <classname>SessionRegistryImpl</classname>
+      to be notified when a session ends. Without it, a user will never be able to log back in again
+      once they have exceeded their session allowance, even if they log out of another session or it
+      times out.</para>
   </section>
 </chapter>

+ 1 - 1
itest/context/src/test/java/org/springframework/security/integration/SEC936ApplicationContextTests.java

@@ -5,8 +5,8 @@ import org.junit.runner.RunWith;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.AccessDeniedException;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
-import org.springframework.security.authentication.concurrent.SessionRegistry;
 import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.session.SessionRegistry;
 import org.springframework.test.context.ContextConfiguration;
 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 

+ 2 - 2
itest/context/src/test/resources/sec-936-app-context.xml

@@ -31,12 +31,12 @@
         <property name="authenticationManager" ref="authenticationManager"/>
         <property name="accessDecisionManager" ref="accessDecisionManager"/>
         <property name="securityMetadataSource"><value>
-            org.springframework.security.authentication.concurrent.SessionRegistry.get*=ROLE_C
+            org.springframework.security.core.session.SessionRegistry.get*=ROLE_C
         </value></property>
     </bean>
 
     <bean id="httpRemoteService" class="org.springframework.aop.framework.ProxyFactoryBean">
-        <property name="proxyInterfaces" value="org.springframework.security.authentication.concurrent.SessionRegistry"/>
+        <property name="proxyInterfaces" value="org.springframework.security.core.session.SessionRegistry"/>
         <property name="interceptorNames">
             <list>
                 <value>securityInterceptor</value>

+ 1 - 1
web/src/main/java/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilter.java

@@ -37,8 +37,8 @@ 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.SessionAuthenticationStrategy;
 import org.springframework.security.web.session.NullAuthenticatedSessionStrategy;
+import org.springframework.security.web.session.SessionAuthenticationStrategy;
 import org.springframework.security.web.util.UrlUtils;
 import org.springframework.util.Assert;
 import org.springframework.web.filter.GenericFilterBean;

+ 1 - 1
web/src/main/java/org/springframework/security/web/authentication/WebAuthenticationDetails.java

@@ -15,7 +15,7 @@
 
 package org.springframework.security.web.authentication;
 
-import org.springframework.security.authentication.concurrent.SessionIdentifierAware;
+import org.springframework.security.core.session.SessionIdentifierAware;
 
 import java.io.Serializable;
 

+ 4 - 4
web/src/main/java/org/springframework/security/web/authentication/concurrent/ConcurrentSessionFilter.java

@@ -25,10 +25,10 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
 
-import org.springframework.security.authentication.concurrent.SessionInformation;
-import org.springframework.security.authentication.concurrent.SessionRegistry;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.session.SessionInformation;
+import org.springframework.security.core.session.SessionRegistry;
 import org.springframework.security.web.DefaultRedirectStrategy;
 import org.springframework.security.web.RedirectStrategy;
 import org.springframework.security.web.authentication.logout.LogoutHandler;
@@ -42,9 +42,9 @@ import org.springframework.web.filter.GenericFilterBean;
  * Filter required by concurrent session handling package.
  * <p>
  * This filter performs two functions. First, it calls
- * {@link org.springframework.security.authentication.concurrent.SessionRegistry#refreshLastRequest(String)} for each request
+ * {@link org.springframework.security.core.session.SessionRegistry#refreshLastRequest(String)} for each request
  * so that registered sessions always have a correct "last update" date/time. Second, it retrieves a
- * {@link org.springframework.security.authentication.concurrent.SessionInformation} from the <code>SessionRegistry</code>
+ * {@link org.springframework.security.core.session.SessionInformation} from the <code>SessionRegistry</code>
  * for each request and checks if the session has been marked as expired.
  * If it has been marked as expired, the configured logout handlers will be called (as happens with
  * {@link org.springframework.security.web.authentication.logout.LogoutFilter}), typically to invalidate the session.

+ 32 - 4
web/src/main/java/org/springframework/security/web/session/ConcurrentSessionControlStrategy.java

@@ -9,20 +9,36 @@ import javax.servlet.http.HttpSession;
 import org.springframework.context.MessageSource;
 import org.springframework.context.MessageSourceAware;
 import org.springframework.context.support.MessageSourceAccessor;
-import org.springframework.security.authentication.concurrent.SessionInformation;
-import org.springframework.security.authentication.concurrent.SessionRegistry;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.AuthenticationException;
 import org.springframework.security.core.SpringSecurityMessageSource;
+import org.springframework.security.core.session.SessionInformation;
+import org.springframework.security.core.session.SessionRegistry;
+import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationProcessingFilter;
+import org.springframework.security.web.authentication.concurrent.ConcurrentSessionFilter;
 import org.springframework.util.Assert;
 
 /**
+ * Strategy which handles concurrent session-control, in addition to the functionality provided by the base class.
+ *
+ * When invoked following an authentication, it will check whether the user in question should be allowed to proceed,
+ * by comparing the number of sessions they already have active with the configured <tt>maximumSessions</tt> value.
+ * The {@link SessionRegistry} is used as the source of data on authenticated users and session data.
+ * <p>
+ * If a user has reached the maximum number of permitted sessions, the behaviour depends on the
+ * <tt>exceptionIfMaxExceeded</tt> property. The default behaviour is to expired the least recently used session, which
+ * will be invalidated by the {@link ConcurrentSessionFilter} if accessed again. If <tt>exceptionIfMaxExceeded</tt> is
+ * set to <tt>true</tt>, however, the user will be prevented from starting a new authenticated session.
+ * <p>
+ * This strategy can be injected into both the {@link SessionManagementFilter} and instances of
+ * {@link AbstractAuthenticationProcessingFilter} (typically {@link UsernamePasswordAuthenticationProcessingFilter}).
  *
  * @author Luke Taylor
  * @version $Id$
  * @since 3.0
  */
-public class ConcurrentSessionControlStrategy extends DefaultSessionAuthenticationStrategy
+public class ConcurrentSessionControlStrategy extends SessionFixationProtectionStrategy
         implements MessageSourceAware {
     protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
     private final SessionRegistry sessionRegistry;
@@ -106,7 +122,7 @@ public class ConcurrentSessionControlStrategy extends DefaultSessionAuthenticati
      *
      */
     protected void allowableSessionsExceeded(List<SessionInformation> sessions, int allowableSessions,
-            SessionRegistry registry) {
+            SessionRegistry registry) throws SessionAuthenticationException {
         if (exceptionIfMaximumExceeded || (sessions == null)) {
             throw new SessionAuthenticationException(messages.getMessage("ConcurrentSessionControllerImpl.exceededAllowed",
                     new Object[] {new Integer(allowableSessions)},
@@ -133,10 +149,22 @@ public class ConcurrentSessionControlStrategy extends DefaultSessionAuthenticati
         sessionRegistry.registerNewSession(newSession.getId(), auth.getPrincipal());
     }
 
+    /**
+     * Sets the <tt>exceptionIfMaximumExceeded</tt> property, which determines whether the user should be prevented
+     * from opening more sessions than allowed. If set to <tt>true</tt>, a <tt>SessionAuthenticationException</tt>
+     * will be raised.
+     *
+     * @param exceptionIfMaximumExceeded defaults to <tt>false</tt>.
+     */
     public void setExceptionIfMaximumExceeded(boolean exceptionIfMaximumExceeded) {
         this.exceptionIfMaximumExceeded = exceptionIfMaximumExceeded;
     }
 
+    /**
+     * Sets the <tt>maxSessions</tt> property. The default value is 1. Use -1 for unlimited sessions.
+     *
+     * @param maximumSessions the maximimum number of permitted sessions a user can have open simultaneously.
+     */
     public void setMaximumSessions(int maximumSessions) {
         Assert.isTrue(maximumSessions != 0,
             "MaximumLogins must be either -1 to allow unlimited logins, or a positive integer to specify a maximum");

+ 1 - 1
web/src/main/java/org/springframework/security/web/session/DefaultSessionAuthenticationStrategy.java → web/src/main/java/org/springframework/security/web/session/SessionFixationProtectionStrategy.java

@@ -32,7 +32,7 @@ import org.springframework.security.web.savedrequest.DefaultSavedRequest;
  * @version $Id$
  * @since 3.0
  */
-public class DefaultSessionAuthenticationStrategy implements SessionAuthenticationStrategy {
+public class SessionFixationProtectionStrategy implements SessionAuthenticationStrategy {
     protected final Log logger = LogFactory.getLog(this.getClass());
 
     /**

+ 2 - 2
web/src/main/java/org/springframework/security/web/session/SessionManagementFilter.java

@@ -39,7 +39,7 @@ public class SessionManagementFilter extends GenericFilterBean {
     //~ Instance fields ================================================================================================
 
     private final SecurityContextRepository securityContextRepository;
-    private SessionAuthenticationStrategy sessionStrategy = new DefaultSessionAuthenticationStrategy();
+    private SessionAuthenticationStrategy sessionStrategy = new SessionFixationProtectionStrategy();
     private AuthenticationTrustResolver authenticationTrustResolver = new AuthenticationTrustResolverImpl();
     private String invalidSessionUrl;
     private AuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler();
@@ -96,7 +96,7 @@ 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 DefaultSessionAuthenticationStrategy} is used.
+     * @param sessionStrategy the strategy object. If not set, a {@link SessionFixationProtectionStrategy} is used.
      */
     public void setSessionAuthenticationStrategy(SessionAuthenticationStrategy sessionStrategy) {
         Assert.notNull(sessionStrategy, "authenticatedSessionStratedy must not be null");

+ 3 - 3
web/src/test/java/org/springframework/security/web/authentication/ConcurrentSessionFilterTests.java → web/src/test/java/org/springframework/security/web/concurrent/ConcurrentSessionFilterTests.java

@@ -13,15 +13,15 @@
  * limitations under the License.
  */
 
-package org.springframework.security.web.authentication;
+package org.springframework.security.web.concurrent;
 
 import junit.framework.TestCase;
 import org.springframework.mock.web.MockFilterConfig;
 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.core.session.SessionRegistry;
+import org.springframework.security.core.session.SessionRegistryImpl;
 import org.springframework.security.web.authentication.concurrent.ConcurrentSessionFilter;
 
 import javax.servlet.Filter;

+ 4 - 4
web/src/test/java/org/springframework/security/web/session/DefaultSessionAuthenticationStrategyTests.java

@@ -21,7 +21,7 @@ public class DefaultSessionAuthenticationStrategyTests {
 
     @Test
     public void newSessionShouldNotBeCreatedIfNoSessionExistsAndAlwaysCreateIsFalse() throws Exception {
-        DefaultSessionAuthenticationStrategy strategy = new DefaultSessionAuthenticationStrategy();
+        SessionFixationProtectionStrategy strategy = new SessionFixationProtectionStrategy();
         HttpServletRequest request = new MockHttpServletRequest();
 
         strategy.onAuthentication(mock(Authentication.class), request, new MockHttpServletResponse());
@@ -31,7 +31,7 @@ public class DefaultSessionAuthenticationStrategyTests {
 
     @Test
     public void newSessionIsCreatedIfSessionAlreadyExists() throws Exception {
-        DefaultSessionAuthenticationStrategy strategy = new DefaultSessionAuthenticationStrategy();
+        SessionFixationProtectionStrategy strategy = new SessionFixationProtectionStrategy();
         HttpServletRequest request = new MockHttpServletRequest();
         String sessionId = request.getSession().getId();
 
@@ -43,7 +43,7 @@ public class DefaultSessionAuthenticationStrategyTests {
     // See SEC-1077
     @Test
     public void onlySavedRequestAttributeIsMigratedIfMigrateAttributesIsFalse() throws Exception {
-        DefaultSessionAuthenticationStrategy strategy = new DefaultSessionAuthenticationStrategy();
+        SessionFixationProtectionStrategy strategy = new SessionFixationProtectionStrategy();
         strategy.setMigrateSessionAttributes(false);
         HttpServletRequest request = new MockHttpServletRequest();
         HttpSession session = request.getSession();
@@ -58,7 +58,7 @@ public class DefaultSessionAuthenticationStrategyTests {
 
     @Test
     public void sessionIsCreatedIfAlwaysCreateTrue() throws Exception {
-        DefaultSessionAuthenticationStrategy strategy = new DefaultSessionAuthenticationStrategy();
+        SessionFixationProtectionStrategy strategy = new SessionFixationProtectionStrategy();
         strategy.setAlwaysCreateSession(true);
         HttpServletRequest request = new MockHttpServletRequest();
         strategy.onAuthentication(mock(Authentication.class), request, new MockHttpServletResponse());