Showing posts with label Basic Authentication. Show all posts
Showing posts with label Basic Authentication. Show all posts

Tuesday, July 20, 2010

Basic Authentication with Spring Security (Part 3)

Basic authentication with Spring Security works great in my application until a web site is trying to access my application by pass in Authorization information through parameter instead of request header.  I have to create a CustomBasicProcessingFilter to handle the special case, which leads to my new application context configuration:
<security:http auto-config="false"
    access-denied-page="/noaccess.jsp"
    session-fixation-protection="none"
    entry-point-ref="authenticationEntryPoint">
    <security:intercept-url pattern="/helper*" filters="none" />
    <security:intercept-url pattern="/index.jsp*"
        access="ROLE_ANONYMOUS" />
    <security:intercept-url pattern="/logout.*"
        access="ROLE_ANONYMOUS" />
    <security:intercept-url pattern="/401.jsp*"
        access="ROLE_ANONYMOUS" />
    <security:intercept-url pattern="/noaccess.jsp*"
        access="ROLE_ANONYMOUS" />
    <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"/>

<security:authentication-manager
    alias="authenticationManager"/>

<bean id="authenticationEntryPoint" class="org.springframework.security.ui.basicauth.BasicProcessingFilterEntryPoint">
    <property name="realmName" value="My Realm"/>
</bean>


<bean id="customFilter" class="com.my.company.web.CustomBasicProcessingFilter">
     <security:custom-filter after="BASIC_PROCESSING_FILTER"/>
</bean>
As you can see from above, Spring Security's Basic Authentication is still in use.  However, when this failed, CustomBasicProcessingFilter will be called to retry authentication.

entry-point-ref in security:http is a must for custom filters.  Without it, the application won't work at all.

One more think you'll need to watch out when adding custom filter.  If you have more than one servlet defined in web.xml but not all of them requires authentication, you might need to add them to the configuration for exclusion even if it was working without the configuration before the custom filter.

Wednesday, March 31, 2010

Basic Authentication with Spring Security (Part 2)

So I double checked my configuration, nothing seems to be wrong.  In the end, I managed to get it to work for the first time with following added configuration:
In web.xml
<login-config>
    <auth-method>BASIC</auth-method>
</login-config>
<error-page>
    <error-code>401</error-code>
    <location>/WEB-INF/jsp/errors/401.jsp</location>
</error-page>
401.jsp
<%
  response.setHeader("WWW-Authenticate", "BASIC realm=\"My Realm\"");
%>
<html>
    <head>
        <meta http-equiv="refresh" content="1;url=https://www.mysite.com/subscribe/">
    </head>
    <body>
        <h1>HTTP Status 401</h1><br>
        Unauthorized Access.  Redirecting to registration page...
    </body>
</html>

Update: I was able to get the application running without above configuration.  All I need is moving the response.setHeader code to my welcome-file specified in the web.xml file, in my case, index.jsp.
<%
  response.setHeader("WWW-Authenticate",
      "BASIC realm=\"My Realm\"");
%>
<%@ page language="java"
    contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:redirect url="/home.do" />

Although I specified a logout in Spring Security configuration, it doesn't work very well.  Unless I close down all browsers opened at the same time, I'll be logged right back in by the browser's memory cache.  So I ended up adding a "You are now logged out!  Please close the main window to clean up browser cache!" message in the logout.html page.  And finally, Business decided to remove the logout link on the page.  Looks like a form-based authentication is a better choice.

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).