118 lines
6.9 KiB
XML
118 lines
6.9 KiB
XML
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="remember-me"><info><title>Remember-Me Authentication</title></info>
|
|
|
|
|
|
<section xml:id="remember-me-overview">
|
|
<info><title>Overview</title></info>
|
|
|
|
|
|
<para>Remember-me authentication refers to web sites being able to
|
|
remember the identity of a principal between sessions. This is
|
|
typically accomplished by sending a cookie to the browser, with the
|
|
cookie being detected during future sessions and causing automated
|
|
login to take place. Spring Security provides the necessary hooks so
|
|
that such operations can take place, along with providing a concrete
|
|
implementation that uses hashing to preserve the security of
|
|
cookie-based tokens.</para>
|
|
</section>
|
|
|
|
<section xml:id="remember-me-config"><info><title>Configuration</title></info>
|
|
|
|
|
|
<para>Remember-me authentication is not used with basic
|
|
authentication, given it is often not used with
|
|
<literal>HttpSession</literal>s. Remember-me is used with
|
|
<literal>AuthenticationProcessingFilter</literal>, and is implemented
|
|
via hooks in the <literal>AbstractProcessingFilter</literal>
|
|
superclass. The hooks will invoke a concrete
|
|
<literal>RememberMeServices</literal> at the appropriate times. The
|
|
interface looks like this:</para>
|
|
|
|
<para><programlisting>public Authentication autoLogin(HttpServletRequest request, HttpServletResponse response);
|
|
public void loginFail(HttpServletRequest request, HttpServletResponse response);
|
|
public void loginSuccess(HttpServletRequest request, HttpServletResponse response, Authentication successfulAuthentication);</programlisting></para>
|
|
|
|
<para>Please refer to JavaDocs for a fuller discussion on what the
|
|
methods do, although note at this stage
|
|
<literal>AbstractProcessingFilter</literal> only calls the
|
|
<literal>loginFail()</literal> and <literal>loginSuccess()</literal>
|
|
methods. The <literal>autoLogin()</literal> method is called by
|
|
<literal>RememberMeProcessingFilter</literal> whenever the
|
|
<literal>SecurityContextHolder</literal> does not contain an
|
|
<literal>Authentication</literal>. This interface therefore provides
|
|
the underlaying remember-me implementation with sufficient
|
|
notification of authentication-related events, and delegates to the
|
|
implementation whenever a candidate web request might contain a cookie
|
|
and wish to be remembered.</para>
|
|
|
|
<para>This design allows any number of remember-me implementation
|
|
strategies. In the interests of simplicity and avoiding the need for
|
|
DAO implementations that specify write and create methods, Acegi
|
|
Security's only concrete implementation,
|
|
<literal>TokenBasedRememberMeServices</literal>, uses hashing to
|
|
achieve a useful remember-me strategy. In essence a cookie is sent to
|
|
the browser upon successful interactive authentication, with that
|
|
cookie being composed as follows:</para>
|
|
|
|
<para><programlisting>base64(username + ":" + expirationTime + ":" + md5Hex(username + ":" + expirationTime + ":" password + ":" + key))
|
|
|
|
username: As identifiable to TokenBasedRememberMeServices.getUserDetailsService()
|
|
password: That matches the relevant UserDetails retrieved from TokenBasedRememberMeServices.getUserDetailsService()
|
|
expirationTime: The date and time when the remember-me token expires, expressed in milliseconds
|
|
key: A private key to prevent modification of the remember-me token
|
|
</programlisting></para>
|
|
|
|
<para>As such the remember-me token is valid only for the period
|
|
specified, and provided that the username, password and key does not
|
|
change. Notably, this has a potential security issue in that a
|
|
captured remember-me token will be usable from any user agent until
|
|
such time as the token expires. This is the same issue as with digest
|
|
authentication. If a principal is aware a token has been captured,
|
|
they can easily change their password and immediately invalidate all
|
|
remember-me tokens on issue. However, if more significant security is
|
|
needed a rolling token approach should be used (this would require a
|
|
database) or remember-me services should simply not be used.</para>
|
|
|
|
<para><literal>TokenBasedRememberMeServices</literal> generates a
|
|
<literal>RememberMeAuthenticationToken</literal>, which is processed
|
|
by <literal>RememberMeAuthenticationProvider</literal>. A
|
|
<literal>key</literal> is shared between this authentication provider
|
|
and the <literal>TokenBasedRememberMeServices</literal>. In addition,
|
|
<literal>TokenBasedRememberMeServices</literal> requires A
|
|
UserDetailsService from which it can retrieve the username and
|
|
password for signature comparison purposes, and generate the
|
|
<literal>RememberMeAuthenticationToken</literal> to contain the
|
|
correct <literal>GrantedAuthority</literal>[]s. Some sort of logout
|
|
command should be provided by the application (typically via a JSP)
|
|
that invalidates the cookie upon user request. See the Contacts Sample
|
|
application's <literal>logout.jsp</literal> for an example.</para>
|
|
|
|
<para>The beans required in an application context to enable
|
|
remember-me services are as follows:</para>
|
|
|
|
<para><programlisting>
|
|
<bean id="rememberMeProcessingFilter"
|
|
class="org.springframework.security.ui.rememberme.RememberMeProcessingFilter">
|
|
<property name="rememberMeServices"><ref local="rememberMeServices"/></property>
|
|
</bean>
|
|
|
|
<bean id="rememberMeServices" class="org.springframework.security.ui.rememberme.TokenBasedRememberMeServices">
|
|
<property name="userDetailsService"><ref local="jdbcDaoImpl"/></property>
|
|
<property name="key"><value>springRocks</value></property>
|
|
</bean>
|
|
|
|
<bean id="rememberMeAuthenticationProvider"
|
|
class="org.springframework.security.providers.rememberme.RememberMeAuthenticationProvider">
|
|
<property name="key"><value>springRocks</value></property>
|
|
</bean>
|
|
|
|
</programlisting>Don't forget to add your
|
|
<literal>RememberMeServices</literal> implementation to your
|
|
<literal>AuthenticationProcessingFilter.setRememberMeServices()</literal>
|
|
property, include the
|
|
<literal>RememberMeAuthenticationProvider</literal> in your
|
|
<literal>AuthenticationManager.setProviders()</literal> list, and add
|
|
a call to <literal>RememberMeProcessingFilter</literal> into your
|
|
<literal>FilterChainProxy</literal> (typically immediately after your
|
|
<literal>AuthenticationProcessingFilter</literal>)</para>
|
|
</section>
|
|
</chapter> |