I have a Spring Application and I am building JUnit
tests to test a certain Controller
.
The problem is that inside the Controller
I call this code:
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
final String userName = authentication.getName();
In other words, I need to authenticate before calling this Controller
. I wrote a JUnit
test with this code:
private MockMvc mockMvc;
@Test
public void getPageTest() throws Exception{
final ProcessFileController controller = new ProcessFileController();
mockMvc = standaloneSetup(controller).build();
mockMvc.perform(get(URI.create("/processFile.html")).sessionAttr("freeTrialEmailAddress", "")).andExpect(view().name("processFile"));
}
And when I run it gives me a NullPointerException
right on the final String userName = authentication.getName();
because my authentication
is null
since I did not login.
The question is: Is there a way to mock the authentication? All ideas are welcome.
Thank you.
Spring Security version 4 introduced some neat improvements regarding this.
First make sure you have the testing framework in the classpath for tests, with Maven it looks like:
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<version>4.0.4.RELEASE</version>
<scope>test</scope>
</dependency>
Useful imports:
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*;
Test setup:
mockMvc = webAppContextSetup(applicationContext).apply(springSecurity()).build();
(I think you need to the WebApplicationContext rather than a single controller.)
Then the test something like:
mockMvc.perform(get(...).with(user("username").roles("USER"))).andExpect(...);
Ideally you would use @AuthenticationPrincipal
but if that isn't an option you need to setup the SecurityContext
with an Authentication
instance that will then be available in the test.
You could you a static method in a helper class to do this.
public static void setupSecurityContext(String username, String password, String... groups)
{
List<GrantedAuthority> authorities = new ArrayList<>();
for (String group : groups)
{
authorities.add(new SimpleGrantedAuthority(group));
}
UserDetails user = new UserDetails(username, password, authorities);
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user, password);
SecurityContextHolder.getContext().setAuthentication(token);
}
Then in the test you can simply call
SecurityHelper.setupSecurityContext("user", "password", "g1", "g2");
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With