Tuesday, March 30, 2010

Basic Authentication with Spring Security (Part 1)

About two years back, I learned to authenticate a user using CAS.  Back then, we were using a business customized framework integrated with Spring and Struts.  And there are a lot Java coding in the default jsp page to make the authentication work.

This year, I'm working on migrating an old project to Spring framework.  For the web application, I decide to use Spring Security to replace the custom Basic Authentication machanism implemented by the previous developer.

On my first tryout, I have following added to existing configuration:
In web.xml
<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>
      org.springframework.web.filter.DelegatingFilterProxy
    </filter-class>
</filter>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
    <listener-class>
org.springframework.security.ui.session.HttpSessionEventPublisher
    </listener-class>
</listener>

In application context file, first add schema delaration:
<beans default-autowire="byName" default-lazy-init="true"
xmlns:security="http://www.springframework.org/schema/security"
xmlns="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-2.5.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-2.0.4.xsd">

Then add security configuration:
<security:http auto-config="false"
    access-denied-page="/noaccess.jsp"
    session-fixation-protection="none">
<security:intercept-url pattern="/index.jsp*"
    access="ROLE_ANONYMOUS" />
<security:intercept-url pattern="/logout.*" filters="none" />
<security:intercept-url pattern="/noaccess.jsp*" filters="none" />
<security:intercept-url pattern="/*.do*" access="ROLE_USER"/>
<security:http-basic />
<security:anonymous />
<security:logout logout-url="/logout.do"
    logout-success-url="/logout.html" />
<security:concurrent-session-control max-sessions="1"
    exception-if-maximum-exceeded="true" />
</security:http>

<security:authentication-provider
    user-service-ref="authenticationProvider" />

<bean name="authenticationProvider"
    class="com.my.company.web.CustomUserDetailsService" />
So far, everything is by Spring Security's documentation.

I need to use a CustomUserDetailsService which creates a CustomUserDetails object upon authentication process.  Besides authenticate a user, I also need a Customer object from CustomUserDetails to determin whether a user has certain authority to access certain area in the same page.  And in the Java code, I can get the Customer object by following code:
public static Customer getCustomer() {
    Object obj = SecurityContextHolder.getContext()
                                     .getAuthentication().getPrincipal();
    if (obj != null && obj instanceof CustomUserDetails)
        return ((CustomUserDetails) obj).getCustomer();
    return null;
}

At this point, everything seems to be in place except that when I run the application, it always gives me a HTTP Status 401 (Unauthorized Access).