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.
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 security configuration
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:
- “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.
- “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.
- “security:custom-filter” specifies definition of a custom filter which will be invoked to verify user’s validity.
- 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.
- “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.
- “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) Demo
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)

Case 2 :: With “SM_USER
” request header
This time user will be able to access the resource.

To download the sourcecode of above tutorial, please follow below download link.
Sourcecode Download[/download]Happy Learning !!