Spring 4 Security JUnit Test with @WithMockUser and @WithUserDetails Annotation Example using @WebAppConfiguration

By Arvind Rai, May 12, 2015
On this page we will provide Spring 4 security JUnit test with @WithMockUser and @WithUserDetails annotation example using @WebAppConfiguration. @WithMockUser provides a mock user, password and role to test any spring security method annotated with @PreAuthorize and @PostAuthorize etc. The mock user is not necessary to be present. The default user is user, password is password and role is USER. We need not to append ROLE_ with role as it is automatically appended by @WithMockUser. If we are using UserDetailsService bean in our java configuration, then we can take the advantages of @WithUserDetails which is more flexible than @WithMockUser. The default user for @WithUserDetails is user but we can provide custom user which needs to be configured in UserDetailsService. Our test class needs to be annotated with @WebAppConfiguration to declare ApplicationContext.

Gradle File for Spring Security

To resolve @WithMockUser and @WithUserDetails, we need to provide spring-security-test JAR. Find the gradle file.
build.gradle
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'war'
archivesBaseName = 'Spring4'
version = '1' 
repositories {
    maven { url "https://repo.spring.io/libs-release" }
    mavenLocal()
    mavenCentral()
}
dependencies {
    compile 'org.springframework.boot:spring-boot-starter-web:1.2.2.RELEASE'
    compile 'org.springframework.boot:spring-boot-starter-security:1.2.2.RELEASE'
    compile 'org.springframework.ldap:spring-ldap-core:2.0.2.RELEASE'
    compile 'org.springframework.security:spring-security-ldap:4.0.1.RELEASE'
    compile 'org.springframework.boot:spring-boot-starter-test:1.2.2.RELEASE'
    compile 'org.springframework.security:spring-security-test:4.0.1.RELEASE'
} 

Java Configuration Class for Spring Security

Find the java configuration classes for spring security, we are using in our demo.
SecurityConfig.java
package com.concretepage.config;  
import java.util.Arrays;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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.provisioning.InMemoryUserDetailsManager;
@Configuration
@ComponentScan("com.concretepage")
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled=true, prePostEnabled=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.authorizeRequests().
		antMatchers("/app/admin/**").hasRole("ADMIN").
		antMatchers("/app/user/**").hasRole("USER").
		and().formLogin();
	}
	@Configuration
	protected static class AuthenticationConfiguration extends
			GlobalAuthenticationConfigurerAdapter {

		@Override
		public void init(AuthenticationManagerBuilder auth) throws Exception {
			  auth.inMemoryAuthentication().withUser("ravan").password("ravan123").roles("USER");
			  auth.inMemoryAuthentication().withUser("ram").password("ram123").roles("ADMIN");

		}
	} 
	@Bean
	public UserDetailsService userDetailsService(){
		GrantedAuthority authority = new SimpleGrantedAuthority("ADMIN");
		UserDetails userDetails = (UserDetails)new User("ram", "ram123", Arrays.asList(authority));
		return new InMemoryUserDetailsManager(Arrays.asList(userDetails));
	}
}   

AppConfig.java
package com.concretepage.config;  
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@Configuration 
@ComponentScan("com.concretepage") 
@EnableWebMvc   
@Import({ SecurityConfig.class })
public class AppConfig {  
}  

Demo Service Class

Find the service interface and its implementation used in our demo.
IUserService.java
package com.concretepage.service;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PreAuthorize;
import com.concretepage.User;
public interface IUserService {
	@Secured("authenticated")
	public void methodOne();
	
	@PreAuthorize("hasRole('ADMIN')")
	public void methodTwo(String msg);
	
	@PreAuthorize ("#user.userName == authentication.name")
	public void methodThree(User user);

	@PostAuthorize ("returnObject.userName == authentication.name")
	public User methodFour();
} 

UserService.java
package com.concretepage.service;
import org.springframework.stereotype.Service;
import com.concretepage.User;
@Service
public class UserService implements IUserService {
	@Override
	public void methodOne() {
		System.out.println("--Method One--");
	}
	@Override
	public void methodTwo(String msg) {
		System.out.println("MSG:"+msg);
	}
	@Override
	public void methodThree(User user) {
		System.out.println("User Name:"+user.getUserName());
	}
	@Override
	public User methodFour() {
		User user = new User();
		user.setUserName("ram");
		return user;
	}
} 

User.java
package com.concretepage;
public class User {
	private String userName;
	private String location;
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getLocation() {
		return location;
	}
	public void setLocation(String location) {
		this.location = location;
	}
} 

@WithMockUser

Spring 4 has introduced @WithMockUser annotation to test spring security with mock user at server side. The attributes of this annotation are given below.
username: Assign any username, not necessary that user exits. Default is user.
roles: Assign the role to test. Default is USER. ROLE_ is automatically added.
password: Assign any password to test. Default is password.

Find the code below.
@Test
@WithMockUser
public void testTwo() {
	userService.methodTwo("This is  User");
} 
Here we have not assigned any user, password and role. So the default is considered. If we want to assign any role and user, we can do as following.
@Test
@WithMockUser(username = "ram", roles={"ADMIN"})
public void testTwo() {
   userService.methodTwo("This is admin");
} 
We can do same as class level too.
@WithMockUser(username = "ram", roles={"ADMIN"})
public class SpringSecurityTest {} 

@WithUserDetails

Spring 4 has introduced @WithUserDetails annotation to test spring security with custom UserDetailsService. In our demo, we have created it in security configuration file as following.
@Bean
public UserDetailsService userDetailsService(){
	GrantedAuthority authority = new SimpleGrantedAuthority("ADMIN");
	UserDetails userDetails = (UserDetails)new User("ram", "ram123", Arrays.asList(authority));
	return new InMemoryUserDetailsManager(Arrays.asList(userDetails));
} 
The default user for @WithUserDetails is user. We can use custom user too but that should be defined with UserDetailsService.
@Test
@WithUserDetails("ram") 
public void testFour() {
	userService.methodFour();
} 

Spring Test for @Secured

To test @Secured , suppose we have a service method.
@Secured("authenticated")
public void methodOne(); 
Now find the test code.
@Test(expected = AuthenticationCredentialsNotFoundException.class)
public void testOne() {
	userService.methodOne();
}  

Spring Test for @PreAuthorize

Suppose we have a method in our service annotated with @PreAuthorize
@PreAuthorize("hasRole('ADMIN')")
public void methodTwo(String msg); 
The test code can be written as following.
@Test
@WithMockUser(roles={"ADMIN"})
public void testTwo() {
    userService.methodTwo("This is Admin");
} 

Spring Test for @PostAuthorize

To test @PostAuthorize , suppose we have a method as given below.
@PostAuthorize ("returnObject.userName == authentication.name")
public User methodFour();  
The test code will be written as
@Test
@WithMockUser(username = "ram")
public void testFour1() {
    userService.methodFour();
} 

Setup Spring JUnit Test class: Use @WebAppConfiguration to load ApplicationContext

To run the test cases, we need to setup our test class.
@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(classes = AppConfig.class)
@WebAppConfiguration
public class SpringSecurityTest {}  
@WebAppConfiguration annotation is used at class level to integrate test that declares ApplicationContext. Our java configuration class is annotated with @EnableWebMvc. So we need to resolve the loading of DelegatingWebMvcConfiguration in demo test class by annotating @WebAppConfiguration

Demo Class for Spring Security JUnit Test

Now find the demo test class.
SpringSecurityTest.java
package com.concretepage;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.security.test.context.support.WithUserDetails;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import com.concretepage.config.AppConfig;
import com.concretepage.service.IUserService;
@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(classes = AppConfig.class)
@WebAppConfiguration
public class SpringSecurityTest {
	@Autowired
	public IUserService userService;
	@Autowired
	public UserDetailsService userDetailsService;
	
	@Test(expected = AuthenticationCredentialsNotFoundException.class)
	public void testOne() {
		userService.methodOne();
	}
	@Test
	@WithMockUser(roles={"ADMIN"})
	public void testTwo() {
		userService.methodTwo("This is Admin");
	}
	@Test
	@WithMockUser(username = "ravan")
	public void testThree() {
		User user = new User();
		user.setUserName("ravan");
		userService.methodThree(user);
	}
	@Test
	@WithUserDetails("ram") 
	public void testFour() {
		userService.methodFour();
	}
} 
Run it as JUnit test case. The output will be that all the test cases will run successfully. Find the print screen.
Spring 4 Security JUnit Test with @WithMockUser and @WithUserDetails Annotation Example using @WebAppConfiguration


Now I am done with Spring 4 Security Test example.

Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI
LEARN MORE








©2024 concretepage.com | Privacy Policy | Contact Us