Spring 4 Security JUnit Test with @WithMockUser and @WithUserDetails Annotation Example using @WebAppConfiguration
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.
Contents
- Gradle File for Spring Security
- Java Configuration Class for Spring Security
- Demo Service Class
- @WithMockUser
- @WithUserDetails
- Spring Test for @Secured
- Spring Test for @PreAuthorize
- Spring Test for @PostAuthorize
- Set Up Spring JUnit Test class: Use @WebAppConfiguration to load ApplicationContext
- Demo Class for Spring Security JUnit Test
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"); }
@Test @WithMockUser(username = "ram", roles={"ADMIN"}) public void testTwo() { userService.methodTwo("This is admin"); }
@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)); }
@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();
@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);
@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();
@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(); } }

Now I am done with Spring 4 Security Test example.