Spring Security 4 - Hello World example

Posted on October 2, 2017


Spring Security framework is a powerful and highly customizable authentication and authorization (access-control) framework for Java EE based applications.

Authentication is the process of verifying the user identity. Whereas authorization is the process of verifying that user has access to resources.

In this post, I will show you how to integrate a spring MVC application with Spring Security framework for securing the URLs access with authentication.

Tools and technologies used for this application are-

  • Spring Security 4.2.3.RELEASE
  • Spring MVC 4.3.10.RELEASE
  • Java SE 1.8
  • Maven 3.3.9
  • Eclipse Neon.3
  • Apache Tomcat 7.0.47

Let’s begin step by step and see how to secure Spring web application with Spring Security.

Step 1 - Create maven project

Create a maven project for our Spring MVC + Spring Security application in Eclipse IDE.

You can refer this article to learn - How to create a web project using maven build tool in eclipse IDE.

Step 2 - Add jar dependencies

To integrate the Spring security in Spring MVC application, you need to add the spring-security-web, spring-security-config and spring-security-taglibs jar dependencies in your pom.xml file.

Open pom.xml file and write the following code in it.

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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.boraji.tutorial.spring</groupId>
  <artifactId>spring-security-hello-world-example</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  <properties>
    <failOnMissingWebXml>false</failOnMissingWebXml>
  </properties>

  <dependencies>
    <!-- Spring MVC Dependency -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>4.3.10.RELEASE</version>
    </dependency>
    <!-- Spring Security Dependency -->
    <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-web</artifactId>
      <version>4.2.3.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-config</artifactId>
      <version>4.2.3.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-taglibs</artifactId>
      <version>4.2.3.RELEASE</version>
    </dependency>
    <!-- Servlet Dependency -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>
    <!-- JSP Dependency -->
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>javax.servlet.jsp-api</artifactId>
      <version>2.3.1</version>
      <scope>provided</scope>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.5.1</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>

      <!-- Embedded Apache Tomcat required for testing web application -->
      <plugin>
        <groupId>org.apache.tomcat.maven</groupId>
        <artifactId>tomcat7-maven-plugin</artifactId>
        <version>2.2</version>
        <configuration>
          <path>/</path>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

Step 3 - Create controller class

Create a simple @Controller class inside com.boraji.tutorial.spring.controller package as follows.

UserController.java

package com.boraji.tutorial.spring.controller;

import java.security.Principal;
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.GetMapping;

@Controller
public class UserController {

   @GetMapping("/")
   public String index() {
      return "index";
   }

   @GetMapping("/user")
   public String user(Principal principal) {
      // Get authenticated user name from Principal
      System.out.println(principal.getName());
      return "user";
   }

   @GetMapping("/admin")
   public String admin() {
      // Get authenticated user name from SecurityContext
      SecurityContext context = SecurityContextHolder.getContext();
      System.out.println(context.getAuthentication().getName());
      return "admin";
   }
}

Step 4 - Create JSP views

Create index.jsp, user.jsp and admin.jsp files under src\main\webapp\WEB-INF\views folder.

index.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
  pageEncoding="ISO-8859-1"%>
<%@ taglib uri="http://www.springframework.org/security/tags"
  prefix="security"%>
<!DOCTYPE html >
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>BORAJI.COM</title>
</head>
<body>
  <h2>Spring Security 4 - Hello World Example</h2>
  <hr />
  <h3>
    Welcome !
    <security:authorize access="isAnonymous()">
         Guest
     </security:authorize>
    <!-- Print the logged in user name -->
    <security:authorize access="isAuthenticated()">
      <security:authentication property="principal.username" />
    </security:authorize>
  </h3>
  <security:authorize access="isAnonymous()">
    Login as <a href="user">User</a> or <a href="/admin">Admin</a>
  </security:authorize>
  <security:authorize access="isAuthenticated()">
    <security:authorize access="hasRole('USER')">
      <a href="user">My Profile</a>
    </security:authorize>
    <security:authorize access="hasRole('ADMIN')">
      <a href="admin">My Profile</a>
    </security:authorize>
    <a href="logout">Logout</a>
  </security:authorize>
</body>
</html>

user.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib uri="http://www.springframework.org/security/tags" prefix="security" %>
<!DOCTYPE html >
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>BORAJI.COM</title>
</head>
<body>
  <h2>Spring Security 4 - Hello World Example</h2>
  <hr />
  <h3>User dashboard  </h3>
  <security:authorize access="isAuthenticated()">
     <b>Welcome! <security:authentication property="principal.username" /></b>
  </security:authorize>
  <br />
  <security:authorize access="isAuthenticated()">
    <a href="/">Home</a> | <a href="logout">Logout</a>
  </security:authorize>
</body>
</html>

admin.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
  pageEncoding="ISO-8859-1"%>
<%@ taglib uri="http://www.springframework.org/security/tags"
  prefix="security"%>
<!DOCTYPE html >
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>BORAJI.COM</title>
</head>
<body>
  <h2>Spring Security 4 - Hello World Example</h2>
  <hr />
  <h3>Admin dashboard</h3>
  <security:authorize access="isAuthenticated()">
    <b>Welcome! <security:authentication property="principal.username" /></b>
  </security:authorize>
  <br />
  <security:authorize access="isAuthenticated()">
    <a href="/">Home</a> | <a href="logout">Logout</a>
  </security:authorize>
</body>
</html>

<security:authorize/> tag evaluates the access expression, specified in the access attribute, to true for authenticate user. View Common Built-In Expressions which can be used in access attribute of  the <security:authorize/> tag.

<security:authentication> tag is use to access the current Authentication object stored in the security context.

 

Step 5 - Create spring security configuration class

The first step is to create a @Configuration class by extending the WebSecurityConfigurerAdapter class as follows.

WebSecurityConfig.java

package com.boraji.tutorial.security.config;

import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

   @Override
   protected void configure(AuthenticationManagerBuilder auth) throws Exception {
      auth.inMemoryAuthentication()
         .withUser("sunil").password("pass123").roles("USER")
         .and()
         .withUser("admin").password("pass123").roles("ADMIN");
   }

   @Override
   protected void configure(HttpSecurity http) throws Exception {
      http.authorizeRequests().antMatchers("/").permitAll()
      .and()
      .authorizeRequests().antMatchers("/user**").hasRole("USER")
      .and()
      .authorizeRequests().antMatchers("/admin**").hasRole("ADMIN")
      .and()
      .formLogin()
      .and()
      .logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"));
   }
}

This Java configuration class creates a Servlet Filter known as the springSecurityFilterChain, which is responsible for all security (protecting the application URLs, validating submitted username and passwords, redirecting to the log in form, etc) within your application.

The overridden method configure(AuthenticationManagerBuilder auth) configure the in memory authentication with user credentials and roles. You can configure the other authentications too such as JDBC, LDAP etc.

The overridden method configure(HttpSecurity http) configure the web based security for all HTTP request. By default it will be applied to all requests, but can be restricted using the requestMatcher() or other similar methods.

From the above configuration class, it is clear that –

  • URL '/'  is not secured and  accessible by everyone.
  • Any URLs that starts with '/user' are secured and only accessible by users who have the role 'USER'.
  • Any URLs that starts with '/admin' are secured and only accessible by users who have the role 'ADMIN'.

Step 6 - Register springSecurityFilterChain Filter

In Java configuration, you can register the spring springSecurityFilterChain using the base class AbstractSecurityWebApplicationInitializer as follows.

SecurityWebApplicationInitializer.java

package com.boraji.tutorial.security.config;

import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;

public class SecurityWebApplicationInitializer 
      extends AbstractSecurityWebApplicationInitializer {

}

This configuration only registers the springSecurityFilterChain Filter for every URL in your application.

Here is the equivalent XML configuration for registering the spring springSecurityFilterChain -

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

Step 7 - Create spring web configuration class

Create a web @Configuration class annotated with @EnableWebMvc and @ComponentScan as follows.

WebConfig.java

package com.boraji.tutorial.security.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = { "com.boraji.tutorial.spring.controller" })
public class WebConfig extends WebMvcConfigurerAdapter {
   @Override
   public void configureViewResolvers(ViewResolverRegistry registry) {
      registry.jsp().prefix("/WEB-INF/views/").suffix(".jsp");
   }
}

Step 8 - Create application initializer class

Create a MvcWebApplicationInitializer class, which will replace our traditional web.xml, to initialize the Servlet container.

Load the WebSecurityConfig and WebConfig classes using the getRootConfigClasses() and getServletConfigClasses() methods as follows.

MvcWebApplicationInitializer.java

package com.boraji.tutorial.security.config;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class MvcWebApplicationInitializer 
         extends AbstractAnnotationConfigDispatcherServletInitializer {

   @Override
   protected Class<?>[] getRootConfigClasses() {
      return new Class[] { WebSecurityConfig.class };
   }

   @Override
   protected Class<?>[] getServletConfigClasses() {
      return new Class[] { WebConfig.class };
   }

   @Override
   protected String[] getServletMappings() {
      return new String[] { "/" };
   }
}

Step 9 - Review the final project structure

Here is the final project structure of our Spring MVC + Spring Security application.

spring-security-hello-world.png

 

Build + Deploy + Run application

Use the following maven commands to build, deploy and run Tomcat server.

mvn clean install  (This command triggers war packaging)

mvn tomcat7:run (This command run embedded tomcat and deploy war file automatically)

You can refer this link to learn how to run the above commands in Eclipse IDE.

 

Type the following URL in browser's address bar to test our application.

http://localhost:8080/

spring-security-hello-world-01.png

Now click on the User link or enter URL http://localhost:8080/user  in browser's address bar.

Since, any URL that start with '/user' are restricted to users who have the role 'USER'. So spring security will generate a login page asking for credentials.

spring-security-hello-world-02.png

On successful login, you will see the user dashboard page as follows.

spring-security-hello-world-03.png

On providing invalid credentials, you see the failure message on login page as follows.

spring-security-hello-world-04.png

Similarly, click on the Admin link in home page or enter URL http://localhost:8080/admin in browser's address bar.

Since, any URL that start with '/admin' are restricted to users who have the role 'ADMIN'. So spring security will generate a login page asking for credentials.

spring-security-hello-world-05.png

On successful login, you will see the admin dashboard page as follows.

spring-security-hello-world-06.png