123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- <chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="session-mgmt"
- xmlns:xlink="http://www.w3.org/1999/xlink">
- <info>
- <title>Session Management</title>
- </info>
- <para>HTTP session related functonality is handled by a combination of the
- <classname>SessionManagementFilter</classname> and the
- <interfacename>SessionAuthenticationStrategy</interfacename> interface, which the filter
- delegates to. Typical usage includes session-fixation protection attack prevention, detection of
- session timeouts and restrictions on how many sessions an authenticated user may have open
- concurrently.</para>
- <section>
- <title>SessionManagementFilter</title>
- <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
- <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
- <interfacename>SessionAuthenticationStrategy</interfacename>.</para>
- <para>If the user is not currently authenticated, the filter will check whether an invalid
- session ID has been requested (because of a timeout, for example) and will redirect to the
- configured <literal>invalidSessionUrl</literal> if set. The easiest way to configure this is
- through the namespace, <link xlink:href="#ns-session-mgmt">as described earlier</link>.</para>
- </section>
- <section>
- <title><interfacename>SessionAuthenticationStrategy</interfacename></title>
- <para>
- <interfacename>SessionAuthenticationStrategy</interfacename> is used by both
- <classname>SessionManagementFilter</classname> and
- <classname>AbstractAuthenticationProcessingFilter</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="FORM_LOGIN_FILTER" ref="myAuthFilter" />
- <session-management session-authentication-strategy-ref="sas"/>
- </http>
-
- <beans:bean id="myAuthFilter"
- class="org.springframework.security.web.authentcation.UsernamePasswordAuthenticationFilter">
- <beans:property name="sessionAuthenticationStrategy" ref="sas" />
- ...
- </beans:bean>
-
- <beans:bean id="sas"
- class="org.springframework.security.web.session.DefaultAuthenticatedSessionStrategy">
- <beans:property name="sessionRegistry" ref="sessionRegistry" />
- <beans:property name="maximumSessions" value="1" />
- </beans:bean>
- ]]>
- </programlisting></para>
- </section>
- <section xml:id="concurrent-sessions">
- <title>Concurrency Control</title>
- <para>Spring Security is able to prevent a principal from concurrently authenticating to the
- same application more than a specified number of times. Many ISVs take advantage of this to
- enforce licensing, whilst network administrators like this feature because it helps prevent
- people from sharing login names. You can, for example, stop user "Batman" from logging onto
- the web application from two different sessions.</para>
- <para>This feature is supported by the namespace, so please check the earlier namespace chapter
- 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>. 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>
- <listener-class>
- org.springframework.security.web.session.HttpSessionEventPublisher
- </listener-class>
- </listener> ]]>
- </programlisting></para>
- <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" />
-
- <session-management session-authentication-strategy-ref="sas"/>
- </http>
-
- <beans:bean id="concurrencyFilter"
- class="org.springframework.security.web.session.ConcurrentSessionFilter">
- <beans:property name="sessionRegistry" ref="sessionRegistry" />
- <beans:property name="expiredUrl" value="/session-expired.htm" />
- </beans:bean>
-
- <beans:bean id="myAuthFilter"
- class="org.springframework.security.web.authentcation.UsernamePasswordAuthenticationFilter">
- <beans:property name="sessionAuthenticationStrategy" ref="sas" />
- ...
- </beans:bean>
-
- <beans:bean id="sas"
- class="org.springframework.security.web.session.ConcurrentSessionControlStrategy">
- <beans:property name="sessionRegistry" ref="sessionRegistry" />
- <beans:property name="maximumSessions" value="1" />
- </beans:bean>
-
- <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>
- </section>
- </chapter>
|