Spring 3 security siteminder pre-authentication example

So far we have learned about securing spring application using login form based security, custom user details security and many more such security related concepts. In this post, I am giving an example of scenario where use is already authenticated via any third party application or tool e.g. site minder which is very common interface between multiple applications in a group.

In this scenario, user has been pre-authenticated in any other application and get into your web application using site minder. Site minder sends a request header about pre-authenticated user which you can utilize to further authorize the user inside your application. You do not need to further authenticate the user, just verify user roles from database and provide appropriate access inside application.

Note: Please keep in mind that site minder is only for example, in fact you can use any third party 
application to get pre-authenticated user. Only request header will change in each case.

Lets follow the tutorial step by step.

Step 1) Maven dependency

I am using maven for runtime dependencies so giving pom.xml. If you are using ANT then download respective JARs and add them in class path.

<properties>
	<spring.version>3.0.5.RELEASE</spring.version>
	<jackson-mapper-asl.version>1.9.9</jackson-mapper-asl.version>
    <jaxb-api.version>2.2.7</jaxb-api.version>
  </properties>
  <dependencies>
    <!-- Spring 3 dependencies -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-core</artifactId>
		<version>${spring.version}</version>
		<scope>runtime</scope>
	</dependency>
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-web</artifactId>
		<version>${spring.version}</version>
		<scope>runtime</scope>
	</dependency>
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-webmvc</artifactId>
		<version>${spring.version}</version>
		<scope>runtime</scope>
	</dependency>
	<!-- Spring Security -->
	<dependency>
	    <groupId>org.springframework.security</groupId>
	    <artifactId>spring-security-core</artifactId>
	    <version>${spring.version}</version>
	    <type>jar</type>
	    <scope>runtime</scope>
	</dependency>
	<dependency>
	    <groupId>org.springframework.security</groupId>
	    <artifactId>spring-security-web</artifactId>
	    <version>${spring.version}</version>
	    <type>jar</type>
	    <scope>runtime</scope>
	</dependency>
	<dependency>
	    <groupId>org.springframework.security</groupId>
	    <artifactId>spring-security-config</artifactId>
	    <version>${spring.version}</version>
	    <type>jar</type>
	    <scope>runtime</scope>
	</dependency>
	<dependency>
	    <groupId>org.springframework.security</groupId>
	    <artifactId>spring-security-taglibs</artifactId>
	    <version>${spring.version}</version>
	    <type>jar</type>
	    <scope>runtime</scope>
	</dependency>
  </dependencies>

Step 2) Update web.xml file

There is nothing much in web.xml file. Just add context config location and spring security related filter mappings.

<web-app>
  <display-name>www.howtodoinjava.com</display-name>
  
  	<servlet>
		<servlet-name>spring-mvc</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
 
	<servlet-mapping>
		<servlet-name>spring-mvc</servlet-name>
		<url-pattern>/*</url-pattern>
	</servlet-mapping>
 
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring-mvc-servlet.xml</param-value>
	</context-param>
	
	<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.web.context.ContextLoaderListener</listener-class>
	</listener>
</web-app>

Step 3) Spring configuration file

This is most important step because here we will configure the pre authentication security related mappings. Lets look at the file:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:security="http://www.springframework.org/schema/security"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.3.xsd">
     
     <!-- Annotation are configuring the application -->
     <mvc:annotation-driven/>
	
     <!-- Scan this package for all config annotations -->
	<context:component-scan base-package="com.howtodoinjava.web" />
	
	<security:http use-expressions="true" auto-config="false" entry-point-ref="http403EntryPoint">
    	<!-- Additional http configuration omitted -->
    	<security:intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
    	<security:custom-filter position="PRE_AUTH_FILTER" ref="siteminderFilter" />
  	</security:http>

    <bean id="siteminderFilter" class="org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter">
	    <property name="principalRequestHeader" value="SM_USER"/>
	    <property name="authenticationManager" ref="authenticationManager" />
	</bean>
	
  	<bean id="preauthAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
	    <property name="preAuthenticatedUserDetailsService">
	      	<bean id="userDetailsServiceWrapper"  class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
	        	<property name="userDetailsService" ref="customUserDetailsService"/>
	      	</bean>
	    </property>
    </bean>

    <security:authentication-manager alias="authenticationManager">
      	<security:authentication-provider ref="preauthAuthProvider" />
    </security:authentication-manager>	
    
    <bean id="customUserDetailsService" class="com.howtodoinjava.security.CustomUserDetailsService"></bean>
    <bean id="http403EntryPoint" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint"></bean>
    
</beans>

Lets understand this configuration:

  1. mvc:annotation-driven” is used to tell spring that it needs to scan the annotations in base package specified in “context:component-scan” for searching the resource mappings.
  2. security:http” configuration specifies security related configuration and options. “use-expressions” tells that while matching the “access” property in “security:intercept-url”, expressions are allowed and should be parsed.
  3. security:custom-filter” specifies definition of a custom filter which will be invoked to verify user’s validity.
  4. PRE_AUTH_FILTER assures that this filter will be invoked before other authentication/authorization handling. I have defined a siteminder filter for this. You can name it to another name.
  5. principalRequestHeader” is important because it is the request header attribute which will be checked once user come to application from another application. So, ask this header from third party provider to integrate here.
  6. authenticationManager” is ultimately using “customUserDetailsService” which I have written in “com.howtodoinjava.security.CustomUserDetailsService” class. This class implements UserDetailsService interface and have one method loadUserByUsername(). This method must return a authenticated user interface of type “org.springframework.security.core.userdetails.UserDetails“. This object will have other authorization details such as user role, which will be used in further security.

Step 4) Write custom UserDetailsService class

This class will get the username passed from third party application and username is passed as request header e.g. in our case “SM_USER“.

package com.howtodoinjava.security;

import org.springframework.dao.DataAccessException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

public class CustomUserDetailsService implements UserDetailsService
{
	public UserDetails loadUserByUsername(String username)
	        throws UsernameNotFoundException, DataAccessException
    {
		System.out.println("username recieved :: " + username);
		@SuppressWarnings("deprecation")
		
		//Get this user details from database and set its roles also here
		
		UserDetails user = new User(username, "password", true, true, true, true,
				new GrantedAuthority[]{ new GrantedAuthorityImpl("ROLE_USER") });
		return user;
    }
}

Step 5) Write secured resources to verify

I ave written two very basic classes for sake of simplicity. I will try to access them with and without request header “SM_USER”.

DemoController.java

package com.howtodoinjava.web;

@Controller
@RequestMapping("/users")
public class DemoController 
{
	@RequestMapping(method = RequestMethod.GET, value="/{id}", headers="Accept=application/xml")
	public @ResponseBody User getUserById(@PathVariable String id) 
	{
		User user = new User();
		user.setFirstName("john");
		user.setLastName("adward");
		return user;
	}
	
	@RequestMapping(method = RequestMethod.GET,  headers="Accept=application/xml")
	public @ResponseBody Users getAllUsers() 
	{
		User user1 = new User();
		user1.setFirstName("john");
		user1.setLastName("adward");
		
		User user2 = new User();
		user2.setFirstName("tom");
		user2.setLastName("hanks");
		
		Users users = new Users();
		users.setUsers(new ArrayList<User>());
		users.getUsers().add(user1);
		users.getUsers().add(user2);
		
		return users;
	}
}

Users.java

@XmlRootElement(name="users")
@XmlAccessorType(XmlAccessType.NONE)
public class Users 
{
	@XmlElement(name="user")
	private Collection<User> users;

	public Collection<User> getUsers() {
		return users;
	}

	public void setUsers(Collection<User> users) {
		this.users = users;
	}
}

User.java

@XmlRootElement(name="user")
@XmlAccessorType(XmlAccessType.NONE)
public class User {
	
	@XmlElement(name="first-name")
	private String firstName;
	
	@XmlElement(name="last-name")
	private String lastName;
	
	public String getFirstName() {
		return firstName;
	}
	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}
	public String getLastName() {
		return lastName;
	}
	public void setLastName(String lastName) {
		this.lastName = lastName;
	}
}

Step 6) Test the application

Lets deploy the application in tomcat server and test it.

Case 1 :: Without “SM_USER” request header

This will throw following exception:

org.springframework.security.web.authentication.preauth.PreAuthenticatedCredentialsNotFoundException: SM_USER header not found in request.
	at org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter.getPreAuthenticatedPrincipal(RequestHeaderAuthenticationFilter.java:43)
	at org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter.doAuthenticate(AbstractPreAuthenticatedProcessingFilter.java:98)
	at org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter.doFilter(AbstractPreAuthenticatedProcessingFilter.java:86)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
	at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
	at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:79)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
	at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:169)
	at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:237)
Spring security pre-authentication error

Spring security pre-authentication error

Case 2 :: With “SM_USER” request header

This time user will be able to access the resource.

Spring security pre-authentication success

Spring security pre-authentication success

To download the sourcecode of above tutorial, please follow below download link.

Sourcecode Download

Happy Learning !!

27 thoughts on “Spring 3 security siteminder pre-authentication example”

  1. Very Good Article. I have a question :
    What if the Siteminder is sending extra headers like FIRST_NAME, LAST_NAME, USER_GROUPS etc. ? and we want to store them in our custom UserDetails object. At what point can I get the headers ? Do I need to write a custom filter extending the RequestHeaderAuthFilter and grab the extra headers from HttpServletRequest and add it to credentials property in Authentication class ? Or is there a nifty way that I can do it inside loadUserByUserName method ?

  2. I may not have understood the complete context of above implementation, but if the user is pre-authenticated using Siteminder or SSO, why you still need to create a UserDetails object with username and password.

    I have a application where i just need to create roles based on request headers passed to the application from SSO enabled server and want to use those roles in JSP file using spring security tags. Is it possible?

  3. Hello Lokesh Nice Example, I want to implement SiteMinder Auth but there is already one application in tomcat container doing that,in similar fashion I want to do it for another app so what are the classes and process should be follow is it same or something different in Spring MVC .

  4. Thanks for this great tutorial. Just a quick note, you can use ‘new SimpleGrantedAuthority(“ROLE_USER”)’ instead of using the deprecated class ‘new GrantedAuthorityImpl(“ROLE_USER”)’.

  5. Lokesh, My application has already implemented form login and now, we are trying to add SSO through pre auth filter. I am not able to figure out the configuration syntax both form login filter and pre auth filter. Can you please guide me on this?

  6. Thank you for the great tutorial. I do have a foolish question but hopefully you can answer it. How is the SM_USER being set. I am able to generate the error when it is not set, but I do not see how you passed ‘demo’ to the the SM_USER. Could you please explain?

    1. If you see in the image after section “Case 2 :: With “SM_USER” request header”, I am passing the request header “SM_USER” and set it’s value to “demo”. It is just like you pass “accept” o “content-type” request headers in your request. Basically, in configured environment, it will be passed by your thirdparty application through siteminder.

      1. Hey Lokesh,
        Are you using any tool to do it or How are you setting up. Highly Appreciated if you can share the steps to do it. Thanks

  7. Thanks alot. All of your examples were very helpful for me. I have a Spring application where I load my jsps and then through ajax calls interact with rest services. I need to secure both of these, but with basic auth there is no logout/custom login for MVC. Now my configuration is follows – on the server I have two authentications defined in the xml basic for pattern /rest/** and form based for /**. How should I pass username and password for each request for REST services?

    1. For me, it’s very bad idea to send username and password in each request. Authenticate once and then use something else everytime (e.g. jsessionid or IP of authenticated user or any encrypted cookie stored in client system).

      But, if still you want to pass parameters, you can use something like this:

      $.ajax( {
      url : '/rest/user',
      dataType : 'json',
      beforeSend : function(xhr) {
      var bytes = Crypto.charenc.Binary.stringToBytes(username + ":" + password);
      var base64 = Crypto.util.bytesToBase64(bytes);
      xhr.setRequestHeader("Authorization", "Basic " + base64);
      },
      error : function(xhr, ajaxOptions, thrownError) {
      //handle error
      },
      success : function(model) {
      //
      }
      });

      Reference: http://code.google.com/p/crypto-js/

      1. Thanks alot. Yeah I know its a bad idea. I need the basic auth for REST services used by mobile apps, and form-based for web. Can u suggest me some good solution and point me to the right resources for that

          1. My project already has REST services. And they work perfectly. And the website too works fine. The web controllers only serve empty jsp pages. And after the jsp pages are loaded, they make call to REST api and interact with the DB and get the data (This was one of the requirements). So I need security for both of them.

  8. Thanks Lokesh, this is a good example.
    My application already has a spring security form-based login, my requirement is if SM_USER is not present in http headers or is invalid it must allow form based login.

    Currently, what happening is if SM_USER is not present it through a internal error “SM_USER header not found in request”, in that case can we show them the login form to accept username and password and do normal login process ?

      1. Thanks…I solved this by adding
        This way if SM_USER is missing, it will not through the error instead continue to show login page.

        But now the scenario is that in my loadUserByUsername, i need to set session timeout for the authenticated user manually. and secondly, i need to redirect based on role. Can you please help how to do this.

        1. Please help I need to have a approach where try SiteMinder first. if dont get then Use the login page /guest/login.htm to login. Appreciate if you can share the spring security config xml….. Thanks in advance

    1. Manjunath,

      I have been working on exact scenario you have described above. Could you please let me know, how you configured both form login filter and pre auth filter together in your application?

      Thanks

  9. Thanks for the example.
    How do we manage session? and How do we implement Hibernate cache (1st & 2nd level)? when using spring pre-authentication

    1. Have you ever done something when few resources are authenticated normally and some other resources are pre-authenticated?
      Let me know if you have done similar to this. Thanks!

Note:- In comment box, please put your code inside [java] ... [/java] OR [xml] ... [/xml] tags otherwise it may not appear as intended.

Leave a Reply

Your email address will not be published. Required fields are marked *


4 − one =

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>