Showing posts with label Spring Security. Show all posts
Showing posts with label Spring Security. Show all posts

Spring Boot + Spring Security + Serve static resources from different locations

In Spring we can configure static resources such as  images, js, and, css files from specific locations under web application root, the classpath, and other locations. Even we can configure multiple locations to server different type of file.
An implementation of WebMvcConfigurer interface in WebMvcConfigurerAdapter abstract class with empty methods allowing sub-classes to override only the methods they're interested in. To achieve and serve static resources from different locations we need to extend WebMvcConfigurerAdapter class and need to @Override addResourceHandlers() method in our Application class.
Lets simple example to serve static resources like images and text files from different locations.
Here in this example we are loading images and text files from different locations like

  • images from C://images 
  • text files from C://txtfiles

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>

 <groupId>com.app</groupId>
 <artifactId>staticresourceloader</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>war</packaging>

 <name>staticresourceloader</name>
 <description>staticresourceloader project</description>

 <parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>1.2.5.RELEASE</version>
  <relativePath/> <!-- lookup parent from repository -->
 </parent>

  <dependencies>
  
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-security</artifactId>
  </dependency>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-ws</artifactId>
  </dependency>
  
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-tomcat</artifactId>
   <scope>provided</scope>
  </dependency>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-test</artifactId>
   <scope>test</scope>
  </dependency>
 </dependencies>
 
 <build>
  <plugins>
   <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
   </plugin>
  </plugins>
 </build>

</project>


application.properties

security.user.password=Efhj34tGVW

staticresourceloader.imageFileLocation.path:file:C:\\images\\

staticresourceloader.txtFileLocation.path:file:C:\\txtfiles\\


Application.java

package com.app.staticresourceloader;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@ComponentScan
@EnableAutoConfiguration
@SpringBootApplication
public class Application extends WebMvcConfigurerAdapter  {

 @Value("${staticresourceloader.imageFileLocation.path}")
    private String staticImageFilePath;
 
 @Value("${staticresourceloader.txtFileLocation.path}")
    private String staticTxtFilePath;
 
 public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
    
 @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/api/image/**").addResourceLocations(staticImageFilePath);
        registry.addResourceHandler("/api/txt/**").addResourceLocations(staticTxtFilePath);
    }    
}


ServletInitializer.java

package com.app.staticresourceloader;

import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;

public class ServletInitializer extends SpringBootServletInitializer {

 @Override
 protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
  return application.sources(Application.class);
 } 
}


MyController.java

package com.app.staticresourceloader;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;


@Controller
public class MyController {

 @Value("${staticresourceloader.imageFileLocation.path}")
    private String staticImageFilePath;
 
 @Value("${staticresourceloader.txtFileLocation.path}")
    private String staticTxtFilePath;
 
 
 @RequestMapping(value="/api/getImageList", method=RequestMethod.GET, headers="Accept=application/json")
 public ResponseEntity<Collection<String>> getImageList(){
  
  Collection<String> fileList = fileList(staticImageFilePath, "image");
  
  return new ResponseEntity<Collection<String>>(fileList, HttpStatus.OK);
 } 
 
 


        @RequestMapping(value="/api/getTxtList", method=RequestMethod.GET, headers="Accept=application/json")
 public ResponseEntity<Collection<String>> getTxtFileList(){
  
  Collection<String> fileList = fileList(staticTxtFilePath, "txt");
  
  return new ResponseEntity<Collection<String>>(fileList, HttpStatus.OK);
 } 
 
 


        public Collection<String> fileList(String folderPath, String type) {
  
  File directory = new File(folderPath.replace("file:", ""));
  File[] fList = directory.listFiles();
  
  Collection<String> list = new ArrayList<String>();
  
  for (File file : fList) {
   
   list.add("http://localhost:8080/api/"+type+"/"+file.getName());
  }  
  return list;
 } 
}


Spring Boot + Spring Security + Serve static resources from different locations



OUTPUT:

Spring Boot + Spring Security + Serve static resources from different locations

Spring Boot + Spring Security + Serve static resources from different locations

Spring Boot + Spring Security + Serve static resources from different locations

Spring Boot + Spring Security + Serve static resources from different locations

Spring Boot + Spring Security + Serve static resources from different locations




Spring Security - Pre-Authentication using Header

In our earlier tutorial we have seen about Spring Security Pre-Authentication using request parameters. In this tutorial we will see about Pre-Authentication by setting header value. For more docs please refer to Spring Docs link.

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>springsecurity</artifactId>
 <packaging>war</packaging>
 <version>1.0-SNAPSHOT</version>
 <name>Spring Security</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>springsecurity</finalName>
 </build>
</project>


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</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>

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


</web-app>


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 use-expressions="true" auto-config="true" 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.app.service.CustomUserDetailsService"></bean>
    <bean id="http403EntryPoint" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint"></bean>
    
</beans>


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="empid")
 private String empId;
 
 @XmlElement(name="firstname")
 private String firstName;
 
 @XmlElement(name="lastname")
 private String lastName;
 
 @XmlElement(name="designation")
 private String designation;
 
 public String getEmpId() {
  return empId;
 }
 public void setEmpId(String empId) {
  this.empId = empId;
 }
 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 getDesignation() {
  return designation;
 }
 public void setDesignation(String designation) {
  this.designation = designation;
 } 
}


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="employees")
 private Collection<Employee> employees;

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

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


CustomUserDetailsService.java


package com.app.service;

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

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
    {
  System.out.println("Username::: "+userName);
  UserDetails user = null;
  if(userName.equalsIgnoreCase("admin")){
   user = getAdminUser(userName);
  }else if(userName.equalsIgnoreCase("dba")){
   user = getDBAUser(userName);
  }else if(userName.equalsIgnoreCase("user")){
   user = getUserUser(userName);
  }
  
  if (user == null) {
         throw new UsernameNotFoundException("Invalid user : "+userName);
     }
  
  return user;
    }
 
 private UserDetails getAdminUser(String username) {
     Collection<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>();
     //Don't change the order
     grantedAuthorities.add(new GrantedAuthorityImpl("ROLE_ADMIN"));
     grantedAuthorities.add(new GrantedAuthorityImpl("ROLE_DBA"));
     grantedAuthorities.add(new GrantedAuthorityImpl("ROLE_USER"));
     
     return new User(username, "adminpassword", true, true, true, true,
             grantedAuthorities);
 }

 private UserDetails getDBAUser(String username) {
     Collection<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>();
     //Don't change the order
     grantedAuthorities.add(new GrantedAuthorityImpl("ROLE_DBA"));
     grantedAuthorities.add(new GrantedAuthorityImpl("ROLE_USER"));
     return new User(username, "dbapassword", 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, "userpassword", true, true, true, true,
             grantedAuthorities);
 }
}


EmployeeController.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 EmployeeController 
{
 @RequestMapping(method = RequestMethod.GET,  headers="Accept=application/xml")
 public @ResponseBody Employees getAllUsers() 
 {
  
  String userRole = getUserRole();
  
  System.out.println("User Role : "+userRole);
        
  Employee emp1 = new Employee();
  
  if(userRole.equals("admin")){
   emp1.setEmpId("101");
   emp1.setFirstName("Steve");
   emp1.setLastName("Smith");
   emp1.setDesignation("ADMIN");
  
  }else if(userRole.equals("dba")){
   emp1.setEmpId("301");
   emp1.setFirstName("Bill");
   emp1.setLastName("Rock");
   emp1.setDesignation("DBA");
  
  }else if(userRole.equals("user")){
   emp1.setEmpId("163");
   emp1.setFirstName("Tim");
   emp1.setLastName("Jack");
   emp1.setDesignation("USER");
  } 
  
  Employees users = new Employees();
  users.setUsers(new ArrayList<Employee>());
  users.getUsers().add(emp1);
  
  return users;
 }
 
 
 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";
                return userRole;
            }
            if ("ROLE_DBA".equals(auth.getAuthority())){
                userRole = "dba";
                return userRole;
            }
            if ("ROLE_USER".equals(auth.getAuthority())){
                userRole = "user";
                return userRole;
            }
        }
        
        return userRole;
 }
}



OUTPUT:

Request without header value - Error page


spring_security_pre_auth_error









Request with SM_USER header - Success page

spring_security_pre_auth_success