Spring Security - Pre-Authentication

 

Using spring security is a scenario where we need to check for users pre-authentication while accessing the application. For example valid user logged-in to ABC application, and inside ABC application there are XYZ services running which require user authentication, but users who access ABC application should not require to authenticate again by XYZ services when they access through ABC application, just need to pre-authenticate by earlier login details. 
Here Spring Security Pre-Authentication plays the role for us. For more details and methods and classes please refer to Spring docs link
Directly lets see simple example to authenticate user based on request param. Here all services and pages are filtered through security chain and only valid users can access like "admin", "dba" and "user".

pom.xml


<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>com.app.mvc</groupId>
 <artifactId>springsecuritybyurl</artifactId>
 <packaging>war</packaging>
 <version>1.0-SNAPSHOT</version>
 <name>Spring Security By URL</name>
 <url>http://maven.apache.org</url>
 <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>
  <dependency>
   <groupId>junit</groupId>
   <artifactId>junit</artifactId>
   <version>3.8.1</version>
   <scope>test</scope>
  </dependency>
  <!-- Spring 3 dependencies -->
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-core</artifactId>
   <version>${spring.version}</version>
   <scope>compile</scope>
  </dependency>

  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-web</artifactId>
   <version>${spring.version}</version>
   <scope>compile</scope>
  </dependency>

  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-webmvc</artifactId>
   <version>${spring.version}</version>
   <scope>compile</scope>
  </dependency>

  <!-- Spring Security -->
  <dependency>
   <groupId>org.springframework.security</groupId>
   <artifactId>spring-security-core</artifactId>
   <version>${spring.version}</version>
   <type>jar</type>
   <scope>compile</scope>
  </dependency>
  <dependency>
   <groupId>org.springframework.security</groupId>
   <artifactId>spring-security-web</artifactId>
   <version>${spring.version}</version>
   <type>jar</type>
   <scope>compile</scope>
  </dependency>
  <dependency>
   <groupId>org.springframework.security</groupId>
   <artifactId>spring-security-config</artifactId>
   <version>${spring.version}</version>
   <type>jar</type>
   <scope>compile</scope>
  </dependency>
  <dependency>
   <groupId>org.springframework.security</groupId>
   <artifactId>spring-security-taglibs</artifactId>
   <version>${spring.version}</version>
   <type>jar</type>
   <scope>compile</scope>
  </dependency>

  <dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>jstl</artifactId>
   <version>1.2</version>
   <scope>compile</scope>
  </dependency>

  <dependency>
   <groupId>taglibs</groupId>
   <artifactId>standard</artifactId>
   <version>1.1.2</version>
   <scope>compile</scope>
  </dependency>

  <dependency>
   <groupId>org.codehaus.jackson</groupId>
   <artifactId>jackson-mapper-asl</artifactId>
   <version>${jackson-mapper-asl.version}</version>
   <scope>compile</scope>
  </dependency>

  <dependency>
   <groupId>javax.xml.bind</groupId>
   <artifactId>jaxb-api</artifactId>
   <version>${jaxb-api.version}</version>
   <scope>compile</scope>
  </dependency>

  <dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>javax.servlet-api</artifactId>
   <version>3.0.1</version>
   <scope>provided</scope>
  </dependency>

 </dependencies>
 <build>
  <finalName>springsecuritybyurl</finalName>
 </build>
</project>


spring-mvc-servlet.xml


<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.app.controller" />

 <security:http create-session="never" use-expressions="true"
  auto-config="false" entry-point-ref="preAuthenticatedProcessingFilterEntryPoint">
  <security:intercept-url pattern="/jsp/access-denied.jsp"
   access="permitAll()" />
  <security:intercept-url pattern="/accessdenied.do"
   access="permitAll()" />
  <security:intercept-url pattern="/**"
   access="hasRole('ROLE_USER')" />
  <security:custom-filter position="PRE_AUTH_FILTER"
   ref="preAuthFilter" />
  <security:session-management
   session-fixation-protection="none" />
 </security:http>

 <bean id="preAuthFilter" class="com.app.filter.UrlParametersAuthenticationFilter">
  <property name="authenticationManager" ref="appControlAuthenticationManager" />
 </bean>

 <bean id="preAuthenticationProvider"
  class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
  <property name="preAuthenticatedUserDetailsService" ref="UserDetailsServiceImpl" />
 </bean>


 <security:authentication-manager alias="appControlAuthenticationManager">
  <security:authentication-provider
   ref="preAuthenticationProvider" />
 </security:authentication-manager>


 <bean id="UserDetailsServiceImpl" class="com.app.security.UserDetailsServiceImpl" />

 <bean id="preAuthenticatedProcessingFilterEntryPoint" class="com.app.security.AuthenticationEntryPointDenied" />


 <!-- <bean id="customUserDetailsService" class="com.app.security.CustomUserDetailsService"></bean> 
  <bean id="http403EntryPoint" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint"></bean> -->

</beans>


web.xml


<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
 <display-name>Spring Security By URL</display-name>
 <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>

 <listener>
  <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
 </listener>

 <servlet>
  <servlet-name>accessTest</servlet-name>
  <jsp-file>/WEB-INF/jsp/access-denied.jsp</jsp-file>
 </servlet>

 <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>accessTest</servlet-name>
  <url-pattern>/accessdenied.do</url-pattern>
 </servlet-mapping>

 <servlet-mapping>
  <servlet-name>spring-mvc</servlet-name>
  <url-pattern>/</url-pattern>
 </servlet-mapping>





</web-app>


access-denied.jsp


<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<%@ taglib prefix="x" uri="http://java.sun.com/jstl/xml" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt" %>
<%@ taglib prefix="sql" uri="http://java.sun.com/jstl/sql" %>

<html>
 <head>
  <title>Invalid user</title>
 </head>
 <body>
  <h1>Oops, Access denied....</h1> 
 </body>
</html>


UrlParametersAuthenticationFilter.java


package com.app.filter;

import javax.servlet.http.HttpServletRequest;

import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;

public class UrlParametersAuthenticationFilter  extends AbstractPreAuthenticatedProcessingFilter {

 @Override
 protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
  
  //Checking for no. of URL params
  if (request.getParameterMap().size() == 1) {
         return true;
     }
     return false;
 }

 @Override
 protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
  
  String[] credentials = new String[1];
     
  //Getting authentication credentials
  credentials[0] = request.getParameter("param1");
     
     return credentials;
 }

}


AuthenticationEntryPointDenied.java


package com.app.security;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;

public class AuthenticationEntryPointDenied implements AuthenticationEntryPoint {

 public void commence(HttpServletRequest request,
   HttpServletResponse response, AuthenticationException authException)
   throws IOException, ServletException {
  
  // Redirecting service to access denied page for invalid users
  RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
  redirectStrategy.sendRedirect(request, response, "/accessdenied.do");
  
 }

}


UserDetailsServiceImpl.java


package com.app.security;

import java.util.ArrayList;
import java.util.Collection;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

public class UserDetailsServiceImpl implements AuthenticationUserDetailsService {

 public UserDetails loadUserDetails(Authentication token)
   throws UsernameNotFoundException {
  UserDetails userDetails = null;

  String[] credentials = (String[]) token.getCredentials();
  boolean principal = Boolean.valueOf(token.getPrincipal().toString());

  if (credentials != null && principal == true) {
   String name = credentials[0];

   // Setting user Authorities
   if ("admin".equalsIgnoreCase(name)) {
    userDetails = getAdminUser(name);
   } else if ("dba".equalsIgnoreCase(name)) {
    userDetails = getDBAUser(name);
   } else if ("user".equalsIgnoreCase(name)) {
    userDetails = getUserUser(name);
   }
  }

  if (userDetails == null) {
   throw new UsernameNotFoundException("Invalid user - "
     + credentials[0]);
  }

  return userDetails;
 }

 private UserDetails getAdminUser(String username) {
  Collection<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>();
  grantedAuthorities.add(new GrantedAuthorityImpl("ROLE_USER"));
  grantedAuthorities.add(new GrantedAuthorityImpl("ROLE_DBA"));
  grantedAuthorities.add(new GrantedAuthorityImpl("ROLE_ADMIN"));
  return new User(username, "notused", true, true, true, true,
    grantedAuthorities);
 }

 private UserDetails getDBAUser(String username) {
  Collection<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>();
  grantedAuthorities.add(new GrantedAuthorityImpl("ROLE_USER"));
  grantedAuthorities.add(new GrantedAuthorityImpl("ROLE_DBA"));
  return new User(username, "notused", true, true, true, true,
    grantedAuthorities);
 }

 private UserDetails getUserUser(String username) {
  Collection<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>();
  grantedAuthorities.add(new GrantedAuthorityImpl("ROLE_USER"));
  return new User(username, "notused", true, true, true, true,
    grantedAuthorities);
 }
}


Employee.java


package com.app.model;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name="employee")
@XmlAccessorType(XmlAccessType.NONE)
public class Employee {
 
 @XmlElement(name="firstName")
 private String firstName;
 
 @XmlElement(name="lastName")
 private String lastName;
 
 @XmlElement(name="role")
 private String role;
 
 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;
 }
 public String getRole() {
  return role;
 }
 public void setRole(String role) {
  this.role = role;
 }
}


Employees.java


package com.app.model;

import java.util.Collection;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;


@XmlRootElement(name="employees")
@XmlAccessorType(XmlAccessType.NONE)
public class Employees 
{
 @XmlElement(name="employee")
 private Collection<Employee> employees;

 public Collection<Employee> getUsers() {
  return employees;
 }

 public void setUsers(Collection<Employee> employees) {
  this.employees = employees;
 }
}


DemoController.java


package com.app.controller;

import java.util.ArrayList;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.app.model.Employee;
import com.app.model.Employees;

@Controller
@RequestMapping("/employees")
public class DemoController 
{
 @RequestMapping(method = RequestMethod.GET,  headers="Accept=application/xml")
 public @ResponseBody Employees getEmployees() 
 {
  
  String userRole = getUserRole();
  
  System.out.println("User Role : "+userRole);
        
  Employee emp1 = new Employee();
  Employee emp2 = new Employee();
  
  if(userRole.equals("admin")){
  
   emp1.setFirstName("Bala");
   emp1.setLastName("Raj");
   emp1.setRole("ADMIN");
   emp2.setFirstName("Tim");
   emp2.setLastName("Rock");
   emp2.setRole("ADMIN");
  
  }else if(userRole.equals("dba")){
   
   emp1.setFirstName("Steve");
   emp1.setLastName("Jose");
   emp1.setRole("DBA");
   emp2.setFirstName("Bill");
   emp2.setLastName("Fish");
   emp2.setRole("DBA");
   
  }else if(userRole.equals("user")){
   
   emp1.setFirstName("Joy");
   emp1.setLastName("Tiger");
   emp1.setRole("USER");
   emp2.setFirstName("Wood");
   emp2.setLastName("Rich");
   emp2.setRole("USER");
   
  } 
  
  Employees emps = new Employees();
  emps.setUsers(new ArrayList<Employee>());
  emps.getUsers().add(emp1);
  emps.getUsers().add(emp2);
  
  return emps;
 }
 
 private String getUserRole(){
  
  String userRole = "";
  
  SecurityContext context = SecurityContextHolder.getContext();
        Authentication authentication = context.getAuthentication();
        
        for (GrantedAuthority auth : authentication.getAuthorities()) {
            if ("ROLE_ADMIN".equals(auth.getAuthority())){
                userRole = "admin";
                break;
            }
            if ("ROLE_DBA".equals(auth.getAuthority())){
                userRole = "dba";
                break;
            }
            if ("ROLE_USER".equals(auth.getAuthority())){
                userRole = "user";
                break;
            }
        }
        
        return userRole;
 }
}



OUTPUT:

URL : http://localhost:8080/springsecuritybyurl/employees?param1=bill


Invalid User


URL : http://localhost:8080/springsecuritybyurl/employees?param1=admin


Admin



Download complete sample project from below link.

Spring Security - Pre-Authentication.

No comments:
Write comments