dineshonjava

Spring Security Java Configuration Annotation Example

In this Spring Security tutorial, we’ll take a look at Spring Security Java Configuration. Spring Security provides authentication and access-control features for the web layer of an application. Spring Security is a very powerful and highly customizable authentication and access-control framework. Spring security provides support for authentication and access control via configuring lot of filters in a order to filter any request before accessing any secured resource.

Here we will describe how to configure Spring Security in the web application by java based configuration instead of XML namespace configuration. Spring Security provides support for Java Based Configuration from Spring Security 3.2. Java developers can easily configure Spring Security in the web application by Java based without the use of any XML.

Spring Security's web infrastructure is nothing but it is collection of standard servlet filters. There is no web components exists into Spring Security infrastructure as like Spring MVC, Struts etc. Spring Security only provides filter to the requests, doesn't matter whether requests are coming from any browser, device, AJAX, REST etc.


Even Spring Security provide application security but it is not a panacea which will solve all security issues. So we have also take care about the many potential vulnerabilities such as cross-site scripting, request-forgery when application designed. Let's see this java based configuration with an example. Before example let recall some spring security terms with meaning.

Spring Security Terms
  • Principal– User, device or system that performs an action
  • Authentication– Establishing that a principal’s credentials are valid
  • Authorization– Deciding if a principal is allowed to perform an action
  • Secured item– Resource that is being secured
Spring Security Flow in the Application
Let's take a look into flow of Spring Security in the Application with example. In this article we just setup Spring Security into a simple web application. After setup Spring Security will work as below picture.

Spring Security Java Based Configuration

According to the above picture one thread want to access one secured resource at web but security applied by the spring security interceptors so thread should be authenticated and also it have proper access-control to access this secured resource. That means Spring Security provides two main mechanisms one is Authentication and another is Authorization. Authentication provided by AuthenticationManager and access decision taken by AccessDecisionManager in the Spring Security. Irrespective of the authentication mechanism, Spring Security provides a deep set of authorization capabilities. There are three main areas of interest: authorizing web requests, authorizing whether methods can be invoked and authorizing access to individual domain object instances.

1. Setup Spring Security to Web Application
1.1 Setup of Spring Security Filter (DelegatingFilterProxy)
As I told you already that Spring Security provides lot of filters in the infrastructure. When using servlet filters, you obviously need to declare them in your web.xml, or they will be ignored by the servlet container. These filter classes are also Spring beans in Spring Security so we can define these filter beans in the application context and thus we can take advantage of Spring’s rich dependency-injection facilities and lifecycle interfaces.

But question is that how to apply these spring security filters to intercepting the requests if you configure these filters in your application context file instead of web.xml? Don't worry Spring Security also provides solution for this problem. It provides you a special DelegatingFilterProxy filter. Spring’s DelegatingFilterProxy provides the link between web.xml and the application context. So each filter in Spring Security has own corresponding delegating filter to provide the link between web.xml and the application context.  DelegatingFilterProxy delegates the Filter 's methods through to a bean which is obtained from the Spring application context.

<filter>
<filter-name>myFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

DelegatingFilterProxy delegates the filter's methods to a bean in the application context only when the bean must implement javax.servlet.Filter and it must have the same name as that in the filter-name element.

1.2 Setup Order of Spring Security Filters Chain (FilterChainProxy)
As we know Spring Security has lot of filters to be configured in a specific order in the web.xml by using corresponding delegating filter. But it would be cumbersome task to maintain web.xml in case of robust application, have a lot of filters. Spring Security provides us a FilterChainProxy bean to maintain the order filters as below.

<bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy">
<constructor-arg>
 <list>
 <sec:filter-chain pattern="/restful/**" filters="
  securityContextPersistenceFilterWithASCFalse,
  basicAuthenticationFilter,
  exceptionTranslationFilter,
  filterSecurityInterceptor" />
 <sec:filter-chain pattern="/**" filters="
  securityContextPersistenceFilterWithASCTrue,
  formLoginFilter,
  exceptionTranslationFilter,
  filterSecurityInterceptor" />
 </list>
</constructor-arg>
</bean>

Now add the delegating filter for FilterChainProxy to web.xml filter name should same as bean name in the application context "filterChainProxy" as below:

<filter>
<filter-name>filterChainProxy</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
<filter-name>filterChainProxy</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

FilterChainProxy add a single entry to web.xml and deal entirely with the application context file for managing our web security beans. It is wired using a DelegatingFilterProxy, just like in the example above, but with the filter-name set to the bean name "filterChainProxy". The filter chain is then declared in the application context with the same bean name.

Spring Security Filter Configuration

2. Java Based Spring Security Configuration Example
Java configuration creates a Servlet Filter known as the springSecurityFilterChain which is responsible for all the security (protecting the application URLs, validating submitted username and passwords, redirecting to the log in form, etc) within your application. Spring Security provides an abstract class AbstractSecurityWebApplicationInitializer to ensure register the springSecurityFilterChain with the war Filter for every URL in your application. It will be work only on Servlet 3.0+ environment.

2.1 Setup DelegatingFilterProxy and FilterChainProxy

2.1.1 Spring Security Configuration in the Application Context
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
  @Bean
  public UserDetailsService userDetailsService() {
 InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
 manager.createUser(User.withUsername("user").password("password").roles("USER").build());
 return manager;
  }
  @Override
  protected void configure(HttpSecurity http) throws Exception {

  }
  @Autowired
  public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {

  }
}

2.1.2 AbstractSecurityWebApplicationInitializer without Existing Spring
Suppose if you are using Spring Security in non Spring application then you will need to pass in the SecurityConfig into the superclass to ensure the configuration is picked up.
/**
 * 
 */
package com.doj.app.web;

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

/**
 * @author Dinesh.Rajput
 *
 */
public class SecurityWebApplicationInitializer extends
  AbstractSecurityWebApplicationInitializer {
   public SecurityWebApplicationInitializer() {
  super(SecurityConfig.class);
   }

}


SecurityWebApplicationInitializer class do automatically register the springSecurityFilterChain Filter for every URL in your application and also add a ContextLoaderListener that loads the SecurityConfig class.

2.1.3 AbstractSecurityWebApplicationInitializer with Spring MVC
Suppose if you are using Spring in your application then you can register Spring Security with the existing ApplicationContext.
/**
 * 
 */
package com.doj.app.web;

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

/**
 * @author Dinesh.Rajput
 *
 */
public class SecurityWebApplicationInitializer extends
  AbstractSecurityWebApplicationInitializer {

}

This would simply only register the springSecurityFilterChain Filter for every URL in your application. After that we would ensure that SecurityConfig was loaded in our existing ApplicationInitializer.

2.2 HttpSecurity (authorizeRequests())
Thus far our SecurityConfig file only contains default information about how to authenticate our users. In above our configuration file SecurityConfig extends WebSecurityConfigurerAdapter class for more control over the default configuration. WebSecurityConfigurerAdapter provides a default configuration in the configure(HttpSecurity http) method that is why all users require to be authenticated for accessing any URLs of web application. But we can override this method as below:

//1. Default
//Default configuration in WebSecurityConfigurerAdapter
protected void configure(HttpSecurity http) throws Exception {
 http
  .authorizeRequests()
   .anyRequest().authenticated()
   .and()
  .formLogin()
   .and()
  .httpBasic();
}
The default configuration above:

  • Ensures that any request to our application requires the user to be authenticated
  • Allows users to authenticate with form based login
  • Allows users to authenticate with HTTP Basic authentication


2.3 Custom Login Form Java Configuration
Spring Security generates login form automatically, based on the features that are enabled and using standard values for the URL which processes the submitted login, the default target URL the user will be sent to after logging in and so on.

//2. Custom Login Form
//Override Default configuration in WebSecurityConfigurerAdapter for custom login form instead auto generated login form by spring security
//The updated configuration specifies the location of the log in page.
//We must grant all users (i.e. unauthenticated users) access to our log in page
protected void configure(HttpSecurity http) throws Exception {
 http
  .authorizeRequests()
   .anyRequest().authenticated()
   .and()
  .formLogin()
   .loginPage("/login") //specifies the location of the log in page
   .permitAll(); //allows granting access to all users for all URLs
}

And login file as below login.jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:url value="/login" var="loginUrl"/>
<form action="${loginUrl}" method="post">       
 <c:if test="${param.error != null}">        
  <p>
   Invalid username and password.
  </p>
 </c:if>
 <c:if test="${param.logout != null}">       
  <p>
   You have been logged out.
  </p>
 </c:if>
 <p>
  <label for="username">Username</label>
  <input type="text" id="username" name="username"/> 
 </p>
 <p>
  <label for="password">Password</label>
  <input type="password" id="password" name="password"/> 
 </p>
 <input type="hidden"                        
  name="${_csrf.parameterName}"
  value="${_csrf.token}"/>
 <button type="submit" class="btn">Log in</button>
</form>

2.4. Authorize Requests

  • Adds specific authorization requirements to URLs
  • Evaluated in the order listed – first match is used, put specific matches first

//3. Customization to authorize request
//Override Default configuration in WebSecurityConfigurerAdapter for custom login form and authorize requests
//We specified multiple URL patterns that any user can access like "/resources/", "/scripts/", "/css/" etc.
http
.authorizeRequests()
.antMatchers("/css/**","/images/**","/scripts/**").permitAll()
.antMatchers("/accounts/edit*").hasRole("ADMIN")
.antMatchers("/accounts/account*").hasAnyRole("USER",”ADMIN”)
.anyRequest().authenticated()                                                   
.and()
.formLogin()
.loginPage("/login") 
.permitAll();
}
  • Any URL that starts with "/accounts/edit" will be restricted to users who have the role "ROLE_ADMIN".
  • Any URL that starts with "/accounts/account" requires the user to have both "ROLE_ADMIN" and "ROLE_USER".
  • Any URL that has not already been matched on only requires that the user be authenticated


2.5. Handling Logouts
When using the WebSecurityConfigurerAdapter, logout capabilities are automatically applied.
The default is that accessing the URL /logout will log the user out by:

  • Invalidating the HTTP Session
  • Cleaning up any RememberMe authentication that was configured
  • Clearing the SecurityContextHolder
  • Redirect to /login?logout


protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/aaa*").hasRole("ADMIN")
.and() // method chaining!
.formLogin() // setup form-based authentication
.loginPage("/login.jsp") // URL to use when login is needed
.permitAll() // any user can access
.and() // method chaining!
.logout() // configure logout
.permitAll(); // any user can access
}

2.5.1. LogoutHandler
Generally, LogoutHandler implementations indicate classes that are able to participate in logout handling. They are expected to be invoked to perform necessary clean-up.

2.5.2. LogoutSuccessHandler
The LogoutSuccessHandler is called after a successful logout by the LogoutFilter, to handle e.g. redirection or forwarding to the appropriate destination. Note that the interface is almost the same as the LogoutHandler but may raise an exception.

2.6. Configure Authentication
Thus far we have only taken a look at the most basic authentication configuration. Let’s take a look at a few slightly more advanced options for configuring authentication. Spring Security provides various Authentication Provider as below:
  • DAO Authentication provider is default
    • Expects a UserDetailsService implementation to provide credentials and authorities
      • Built-in: In-memory (properties), JDBC (database), LDAP
      • Custom
  • Or define your own Authentication provider
    • Example: to get pre-authenticated user details when using single sign-on
      • CAS, TAM, SiteMinder
2.6.1 Authentication provider: Use a UserDetailsManagerConfigurer
– Three built in options: LDAP, JDBC, in-memory (for quick testing)
– Or use your own UserDetailsService implementation

In-Memory Authentication Java Configuration
//In memory authentication java configuration
//Not web-specific
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication() //Adds a UserDetailsManagerConfigurer
//login, password and supported role
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("adminpassword").roles("ADMIN").and()
.withUser("dinesh").password("support").roles("SUPPORT");
}

JDBC Authentication Java Configuration
//JDBC Authentication
//Provides default queries
//– SELECT username, password, enabled FROM users WHERE username = ?
//– SELECT username, authority FROM authorities WHERE username = ?
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource);
}

We can customize the default queries by using following methods

  • usersByUsernameQuery()
  • authoritiesByUsernameQuery()
  • groupAuthoritiesByUsername()


//JDBC Authentication
//Provides default queries
//– SELECT username, password, enabled FROM users WHERE username = ?
//– SELECT username, authority FROM authorities WHERE username = ?
//We can customize the default queries by using following methods
//usersByUsernameQuery()
//authoritiesByUsernameQuery()
//groupAuthoritiesByUsername()
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
.usersByUsernameQuery("SELECT username, password, enabled FROM users WHERE username = ?")
.authoritiesByUsernameQuery("SELECT username, authority FROM authorities WHERE username = ?")
.dataSource(dataSource);
}

2.6.2 Password Encoder
You can also customize how passwords are encoded by exposing a PasswordEncoder as a bean. We can encode passwords using a hash – sha, md5, bcrypt etc.
//SHA-256 encoding
auth.jdbcAuthentication()
.dataSource(dataSource)
.passwordEncoder(new StandardPasswordEncoder());

2.6.3 Use Salting in Password Encoder
Secure passwords using a well-known string known as a 'salt', makes brute force attacks harder
//Encoding with salt
auth.jdbcAuthentication()
.dataSource(dataSource)
.passwordEncoder(new StandardPasswordEncoder("sodium-chloride"));

Note: Authorization is not affected by changes to Authentication!

2.7. Configure Multiple HttpSecurity
We can configure multiple HttpSecurity instances. The key is to extend the WebSecurityConfigurationAdapter multiple times.

2.8. Method Security
From Spring version 2.0 Spring Security provides support to adding security to your service layer methods. Spring Security uses AOP for security at the method level.
– annotations based on Spring annotations or JSR-250 annotations
– Java configuration to activate detection of annotations
- From 3.0 you can also make use of new expression-based annotations.
Typically secure your services
– Do not access repositories directly, bypasses security (and transactions)

2.8.1 EnableGlobalMethodSecurity
We can enable annotation-based security using the @EnableGlobalMethodSecurity annotation on any @Configuration instance.

2.8.2 Enable Method Security - JSR-250
@EnableGlobalMethodSecurity(jsr250Enabled = true)
public class MethodSecurityConfig {
// ...
}

import javax.annotation.security.RolesAllowed;

public class ItemManagerService {
@RolesAllowed({"ROLE_MEMBER", "ROLE_USER"})
public Item findItem(long itemNumber) {
...
}
}
Note: Only supports role-based security – hence the name

2.8.3 Enable Spring Security’s @Secured annotation
@EnableGlobalMethodSecurity(securedEnabled = true)
public class MethodSecurityConfig {
// ...
}

import org.springframework.security.annotation.Secured;

public class ItemManagerService {
@Secured("IS_AUTHENTICATED_FULLY")
public Item findItem(long itemNumber) {
...
}
}
We can also use

  • @Secured("ROLE_MEMBER")
  • @Secured({"ROLE_MEMBER", "ROLE_USER"})


Note: Spring 2.0 syntax, so not limited to roles. SpEL not supported.

2.8.4 Method Security with SpEL

@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig {
// ...
}

public interface ItemManagerService {

@PreAuthorize("isAnonymous()")
public Item findItem(Long itemNumber);

@PreAuthorize("isAnonymous()")
public Item[] findItems();

@PreAuthorize("hasAuthority('ROLE_USER')")
public Item post(Item item);
}

Download Java Based Configuration Example

Source Code of Example from Git.


Spring-Security-java-based-configuration-example

Summary

  • Spring Security secure URLs using a chain of Servlet filters and methods on Spring beans using AOP proxies
  • Out-of-the-box setup usually sufficient – you define:
    • – URL and/or method restrictions
    • – How to login (typically using an HTML form)
    • – Supports in-memory, database, LDAP credentials (and more)
    • – Password encryption using familiar hashing techniques
    • – Support for security tags in JSP views