Spring security with site minder integration

SSO : Single sign on system which means “sign in once for multiple secured applications”

Site Minder : single sign on system which will authenticate the user for one of the application where the site minder is integrated and all other applications just allows the user inside without any authentication.

Now if the user tries to access any other application within that group of application designed for SSO, it will just pass the request header with user id and the application will just do the authorization of roles and provide appropriate access inside the application.

Example:
If the organization has 5 applications to use for SSO and one of those is integrated with third party SSO.
Then rest 4 of the applications will be just reading the request header from the SSO system and skip the authentication but continues with the authorization.

Let’s see how our application can use request header from site minder and do the SSO process using spring security.

Tools and Technologies used
1)Eclipse IDE Mars Release (4.5.0)
2)Java 8
3)Spring framework 3
4)Spring security 3.2
5)Tomcat 8
6)Mod Header plugin

Create maven project using link

Modify the pom.xml as below

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>SpringSecurityUsingSiteMinder</groupId>
  <artifactId>SpringSecurityUsingSiteMinder</artifactId>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>
  <name>SpringSecurityUsingSiteMinder Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <properties>
        <org.springframework.version>4.2.0.RELEASE</org.springframework.version>
        <spring-security.version>3.2.7.RELEASE</spring-security.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
        <!-- Spring MVC depends on these modules spring-core, spring-beans, spring-context, 
            spring-web -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>
 
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>
        
         <!-- Spring Security Dependencies -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-core</artifactId>
            <version>${spring-security.version}</version>
         </dependency> 
         <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>${spring-security.version}</version>
          </dependency> 
          <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>${spring-security.version}</version>
          </dependency>
          
    </dependencies>
    <build>
           <finalName>SpringSecurityUsingSiteMinder</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.5.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>SpringSecurityUsingSiteMinder</groupId>
  <artifactId>SpringSecurityUsingSiteMinder</artifactId>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>
  <name>SpringSecurityUsingSiteMinder Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <properties>
		<org.springframework.version>4.2.0.RELEASE</org.springframework.version>
		<spring-security.version>3.2.7.RELEASE</spring-security.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>3.8.1</version>
			<scope>test</scope>
		</dependency>
		<!-- Spring MVC depends on these modules spring-core, spring-beans, spring-context, 
			spring-web -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>${org.springframework.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${org.springframework.version}</version>
		</dependency>
		
		 <!-- Spring Security Dependencies -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-core</artifactId>
            <version>${spring-security.version}</version>
         </dependency> 
         <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>${spring-security.version}</version>
          </dependency> 
          <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>${spring-security.version}</version>
          </dependency>
          
	</dependencies>
	<build>
		   <finalName>SpringSecurityUsingSiteMinder</finalName>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.5.1</version>
				<configuration>
					<source>1.8</source>
					<target>1.8</target>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

Modify the web.xml as below

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
    version="3.1">
 
    <display-name>Spring security site minder Application</display-name>
 
    <!-- Spring MVC dispatcher servlet -->
    <servlet>
        <servlet-name>mvc-dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>
            /WEB-INF/spring-mvc.xml,
            /WEB-INF/spring-security.xml
        </param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>mvc-dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
 
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
 
    <!-- Loads Spring Security configuration file -->
     <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/spring-mvc.xml,
            /WEB-INF/spring-security.xml
        </param-value>
    </context-param>
    
    <!-- Spring Security filter -->
    <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>
 
</web-app>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
	version="3.1">

	<display-name>Spring security site minder Application</display-name>

	<!-- Spring MVC dispatcher servlet -->
	<servlet>
		<servlet-name>mvc-dispatcher</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>
			/WEB-INF/spring-mvc.xml,
			/WEB-INF/spring-security.xml
		</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>mvc-dispatcher</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<!-- Loads Spring Security configuration file -->
	 <context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			/WEB-INF/spring-mvc.xml,
			/WEB-INF/spring-security.xml
		</param-value>
	</context-param>
	
	<!-- Spring Security filter -->
	<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>

</web-app>

Modify the spring-mvc.xml as below

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
 
    <context:component-scan base-package="com.kb.*" />
    <mvc:annotation-driven />
     
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/" />
        <property name="suffix" value=".jsp" />
    </bean>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
 
    <context:component-scan base-package="com.kb.*" />
    <mvc:annotation-driven />
     
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/" />
        <property name="suffix" value=".jsp" />
    </bean>
</beans>

Create the spring-security.xml as below

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<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.2.xsd
          http://www.springframework.org/schema/security
          http://www.springframework.org/schema/security/spring-security-3.2.xsd">
           
    <http auto-config='true'>
      <intercept-url pattern="/**" access="ROLE_USER" />
      <custom-filter ref="siteMinderFilter" position="PRE_AUTH_FILTER"/>
    </http>
     <beans:bean id="siteMinderFilter" class="org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter">
        <beans:property name="principalRequestHeader" value="SM_USER"/>
        <beans:property name="authenticationManager" ref="authenticationManager" />
  </beans:bean>
    <authentication-manager alias="authenticationManager">
    <authentication-provider ref="preAuthenticationProvider"/>
    </authentication-manager>
    
      <beans:bean id="preAuthenticationProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
        <beans:property name="preAuthenticatedUserDetailsService">
            <beans:bean id="userDetailsServiceWrapper"  class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
                <beans:property name="userDetailsService" ref="customUserService"/>
            </beans:bean>
        </beans:property>
    </beans:bean> 
    <beans:bean id="customUserService" class="com.kb.service.CustomUserService"/>
           
</beans:beans>
<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.2.xsd
          http://www.springframework.org/schema/security
          http://www.springframework.org/schema/security/spring-security-3.2.xsd">
           
    <http auto-config='true'>
      <intercept-url pattern="/**" access="ROLE_USER" />
      <custom-filter ref="siteMinderFilter" position="PRE_AUTH_FILTER"/>
    </http>
     <beans:bean id="siteMinderFilter" class="org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter">
        <beans:property name="principalRequestHeader" value="SM_USER"/>
        <beans:property name="authenticationManager" ref="authenticationManager" />
  </beans:bean>
    <authentication-manager alias="authenticationManager">
    <authentication-provider ref="preAuthenticationProvider"/>
    </authentication-manager>
    
      <beans:bean id="preAuthenticationProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
        <beans:property name="preAuthenticatedUserDetailsService">
            <beans:bean id="userDetailsServiceWrapper"  class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
                <beans:property name="userDetailsService" ref="customUserService"/>
            </beans:bean>
        </beans:property>
    </beans:bean> 
    <beans:bean id="customUserService" class="com.kb.service.CustomUserService"/>
           
</beans:beans>

Create a custom user service class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package com.kb.service;
 
import java.util.ArrayList;
import java.util.List;
 
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
 
import com.kb.model.CustomUser;
import com.kb.model.Role;
 
public class CustomUserService implements UserDetailsService {
 
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // Write your DB call code to get the user details(user and roles) from
        // DB ,But I am just hard coding it.
        CustomUser user = new CustomUser();
        user.setFirstName("kb");
        user.setLastName("gc");
        user.setUsername("kb");
        user.setPassword("1234");
        Role r = new Role();
        r.setName("ROLE_USER");
        List<Role> roles = new ArrayList<Role>();
        roles.add(r);
        user.setAuthorities(roles);
        return user;
    }
 
}
package com.kb.service;

import java.util.ArrayList;
import java.util.List;

import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import com.kb.model.CustomUser;
import com.kb.model.Role;

public class CustomUserService implements UserDetailsService {

	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		// Write your DB call code to get the user details(user and roles) from
		// DB ,But I am just hard coding it.
		CustomUser user = new CustomUser();
		user.setFirstName("kb");
		user.setLastName("gc");
		user.setUsername("kb");
		user.setPassword("1234");
		Role r = new Role();
		r.setName("ROLE_USER");
		List<Role> roles = new ArrayList<Role>();
		roles.add(r);
		user.setAuthorities(roles);
		return user;
	}

}

Create a home controller class as below

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.kb.controller;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
 
import com.kb.model.CustomUser;
 
 
@Controller
public class HomeController {
    
    @RequestMapping(value="/secured/home", method = RequestMethod.GET)
    public String securedHome(ModelMap model) {
        Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        CustomUser user=null;
        if (principal instanceof CustomUser) {
        user = ((CustomUser)principal);
        String name = user.getUsername();
        model.addAttribute("username", name);
        }
     
    model.addAttribute("message", "Welcome to the secured page through site minder");
    return "home";
     
    }
    
}
package com.kb.controller;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.kb.model.CustomUser;


@Controller
public class HomeController {
	
	@RequestMapping(value="/secured/home", method = RequestMethod.GET)
	public String securedHome(ModelMap model) {
		Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
		CustomUser user=null;
		if (principal instanceof CustomUser) {
		user = ((CustomUser)principal);
		String name = user.getUsername();
		model.addAttribute("username", name);
		}
	 
	model.addAttribute("message", "Welcome to the secured page through site minder");
	return "home";
	 
	}
	
}

Create home.jsp as below

1
2
3
4
5
6
7
8
9
10
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
 
</head>
<body>
<h3>Hello World!</h3>
<h4>Hi ${username}, ${message}</h4>
</body>
</html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">

</head>
<body>
<h3>Hello World!</h3>
<h4>Hi ${username}, ${message}</h4>
</body>
</html>

Now right click on the project and do run as -> maven-install

Copy the war file from project target folder to server’s webapps folder

Restart the server

Now lets access the secured url without passing the user name in the header

http://localhost:8080/SpringSecurityUsingSiteMinder/secured/home

and see the below exception

Now let’s set the header with username as ‘kb’ using ‘Mod Header’ plugin as below

Now lets access the secured url by passing the user name in the header

http://localhost:8080/SpringSecurityUsingSiteMinder/secured/home

Now we are able to access the secured url without any login prompt.

Download this project SpringSecurityUsingSiteMinder.zip

About the Author

Karibasappa G C (KB)
Founder of javainsimpleway.com
I love Java and open source technologies and very much passionate about software development.
I like to share my knowledge with others especially on technology 🙂
I have given all the examples as simple as possible to understand for the beginners.
All the code posted on my blog is developed,compiled and tested in my development environment.
If you find any mistakes or bugs, Please drop an email to kb.knowledge.sharing@gmail.com

Connect with me on Facebook for more updates

Share this article on