Spring Security – Remember Me

Yesterday I implemented my login form using Spring Security. One thing I added was the ability to check a checkbox so a user would stay logged in for a certain period even if he closes his browser. You’re probably familiar with the idea.

In Spring this is done using the RememberMeAuthenticationFilter. And when you use the basic implementation, like I did, it’s based on a cookie and an in memory ‘cache’ for holding the key value in the cookie that’s linked to the user. For now, that suites my needs.

My applicationContext-security.xml looks like this (btw, I’m using Spring 3.0.0.RELEASE):

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
             xmlns:beans="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="
             http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
             http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">

    <http>
        <intercept-url pattern="/static/**" filters="none"/>
        <intercept-url pattern="/favicon.ico" filters="none"/>
        <intercept-url pattern="/" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
        <intercept-url pattern="/**" access="ROLE_USER"/>
        <form-login always-use-default-target='false' login-processing-url="/login" default-target-url="/" authentication-failure-url="/" />
        <remember-me/>
        <logout logout-url="/logout"/>
    </http>

    <authentication-manager>
        <authentication-provider>
            <user-service>
                <user name="admin" password="admin" authorities="ROLE_USER, ROLE_ADMIN"/>
                <user name="user" password="user" authorities="ROLE_USER"/>
            </user-service>
        </authentication-provider>
    </authentication-manager>

    <global-method-security secured-annotations="enabled" jsr250-annotations="enabled"/>

</beans:beans>

As you can see, I didn’t yet setup my authentication provide as it should, but that’s OK for now. The important thing is the <remember-me> tag. That’s all it takes to implement a basic Remember Me implementation. Additionally, as one can stay logged in even after closing his browser, you need to provide some way to logout. So I putted the <logout> tag in as well.

Now, I’m using Velocity as my render engine. When a user is logged in, I don’t want to show any longer the login form, but some message like ‘welcome user x – log out’. I started using the variables that are exposed on the session in my velocity templates. To be able to do that, I had to expose my session variables to my model:

    <bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
        <property name="cache" value="true"/>
        <property name="prefix" value=""/>
        <property name="suffix" value=".vm"/>
        <property name="exposeSessionAttributes" value="true"/>
    </bean>

So, that lets me write this in my velocity template:

<span>#springMessage('welcome')&nbsp;$SPRING_SECURITY_CONTEXT.authentication.getName().</span>

The problem with that is that we can’t rely on the session as we don’t know their is actually a session created and secondly, if the SecurityContext is set on the session. Logging in into the application using the Remember Me logic, this looks not be the case. The reasoning behind it is that the session is only used for holding status between different requests, not for rendering data to the view. The user info will off course be put on the session, but in our case, it happens too late in the process.

So, how do we solve this ?
Well, the solution appears to be easy (once you know it :-) ). We adapt our view resolver like this:

    <bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
        <property name="cache" value="true"/>
        <property name="prefix" value=""/>
        <property name="suffix" value=".vm"/>
        <property name="exposeSessionAttributes" value="true"/>
        <property name="attributes">
            <map>
                <entry key="authentication">
                    <bean class="com.idevelop.kizhi.web.util.AuthenticatedUserDetails"/>
                </entry>
            </map>
        </property>
    </bean>

Meaning that we add a bean AuthenticatedUserDetails to our model and it will be accessible with the key authentication. The AuthenticatedUserDetails class is nothing more than a class that accesses info from the SecurityContext in a nice manner for our velocity template. It looks like this:

public class AuthenticatedUserDetails {
    /**
     * Get the user name of the logged in user.
     *
     * @return the user name of the user
     */
    public static String getPrincipal() {
        Object obj = SecurityContextHolder.getContext().getAuthentication().getPrincipal();

        if (obj instanceof UserDetails) {
            return ((UserDetails) obj).getUsername();
        } else {
            return null;
        }
    }
}

And now in our velocity template, we can write the following as we exposed our bean to our model:

<span>#springMessage('welcome')&nbsp;$authentication.principal.</span>

For completeness, this is how the login form looks like:

#* @vtlvariable name="authentication" type="com.idevelop.kizhi.web.util.AuthenticatedUserDetails" *#
#* @vtlvariable name="SPRING_SECURITY_LAST_EXCEPTION" type="org.springframework.security.authentication.BadCredentialsException" *#
#* @vtlvariable name="SPRING_SECURITY_LAST_USERNAME" type="java.lang.String" *#
<div class="login">
    #if(!$authentication.principal)
        <form id="logInForm" method="POST" action="/login">
            <div class="header"><p>#springMessage('loginHeader').</p></div>

            #if ($SPRING_SECURITY_LAST_EXCEPTION)
                <div class="error"><p>#springMessage($SPRING_SECURITY_LAST_EXCEPTION.message)</p></div>
            #end

            <div class="fields">
                <p>
                    <label for="j_username" class="formLabel">
                        #springMessage('userName'):
                    </label>
                    <input class="text medium-field" type="text" id="j_username" name="j_username" tabindex="1"
                           value="$!SPRING_SECURITY_LAST_USERNAME" size="30"/>
                    <br/>
                </p>

                <p>
                    <label for="j_password" class="formLabel">
                        #springMessage('password'):
                    </label>
                    <input type="password" name="j_password" id="j_password" tabindex="2" size="30"/>
                    <br/>
                </p>

                <p>
                    <label for="_spring_security_remember_me" class="checkboxLabel">
                        <input type='checkbox' name='_spring_security_remember_me' id="_spring_security_remember_me"
                               tabindex="3" value="true"/>
                        #springMessage('rememberMe')
                    </label>
                    <br/>
                </p>
            </div>
            <div class="buttons">
                <p>
                    <input id="login" class="button" type="submit" value="#springMessage('login')" tabindex="4"/>
                </p>
            </div>
        </form>
        <div class="forgotPassword">
            <a href="#" target="_parent">#springMessage('forgotPassword')</a>
        </div>
    #end
</div>

And that’s how it’s done. Once you know it, it’s peanuts, but it took me quite some googling before finding this out. I hope this post wins you some time.

Tags: , ,

8 Responses to “Spring Security – Remember Me”

  1. kiran says:

    i want to develope the login form using spring tags

    using

    Please help me
    how to devlop that

  2. Make sure the things in your home are insured before you plan any
    repairs. In evaluating the contractors in your area, keep in mind the
    following tips:. How to Plan for life as a Government Contractor in A War Zone – Damaged Tank,
    photo by Charles Buchanan – Things you’ll need to have prior to deploying:· Passport and several photo copies of the identification page.

  3. Generally loans will include extra fees in addition with
    interest charged. If you meet the criteria of the underwriter and lender, you are
    good as gold to get the loan. This will help you choose your preferred
    apartment before others do.

  4. Ask the contractor to provide at least three referees and
    check them out. Surprisingly, you can actually save money
    from hiring contractors as you are ensured that the roof is professionally taken
    care of. These so-called cowboy contractors are the people who rip off
    their clients by taking more money than necessary then botching up
    the job they were paid to do.

  5. Do not settle with one hardwood flooring installation contractor.
    Surprisingly, you can actually save money from hiring contractors as you are ensured that the roof is professionally taken care of.
    Specialists have good liability insurance just in case
    anything happens.

  6. If a client is unsatisfied with the quality
    of my performance, product or service, what are the ramifications.

    We don’t brand our website or products to look like a government site because we don’t want to mislead our customers.

    Discuss these scenarios with your agent and
    make sure you understand clearly who is covered and what is covered.

  7. Roboform says:

    There are many paid surveys that have inferior payouts, from $1 to $5, but you should not disregard them.
    In this traffic generating strategy quantity is a head of quality.
    The mid to long term traffic comes from the search engines and the articles.

  8. This text is priceless. When can I find out more?

    Also visit my weblog … good plumbers (wordpress.com)

Leave a Reply