Reputation: 217
I have added Http cookie Authentication using authentication manager to my Spring Boot REST API I have a controller that exposes a rest service allowing authentication to /api/auth/signin resource via Spring security cookies session.
Here is the the Controller and the security configuration This exemple.
After running the application, I noticed that it is important to carry out the unit test part, so I wanted to create mocks for the authenticateUser method (resource: /signin), but unfortunately I encountered problems.
Voici la classe AuthControllerTest:
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes=Application.class)
@WebMvcTest(AuthController.class)
public class AuthControllerTest {
@MockBean
UserRepository userRepository;
@MockBean
AuthenticationManager authenticationManager;
@MockBean
private UserDetailsServiceImpl userDetailsServiceImpl;
@Autowired
private MockMvc mockMvc;
private static UserDetailsImpl dummy;
@MockBean
private JwtUtils jwtUtil;
@Autowired
WebApplicationContext webApplicationContext ;
private ResponseCookie cookies;
@BeforeEach
public void setUp() {
dummy = new UserDetailsImpl(10L,"test1","[email protected]","123456",new ArrayList<>());
Authentication authentication = authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()));
SecurityContextHolder.getContext().setAuthentication(authentication);
UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();*/
cookies = jwtUtil.generateJwtCookie(dummy) ;
}
@Test
@DisplayName("POST /signin")
void authenticateUser() throws Exception
{
LoginRequest authenticationRequest = new LoginRequest("mod", "123456") ;
String jsonRequest = asJsonString(authenticationRequest);
RequestBuilder request = MockMvcRequestBuilders
.post("/api/auth/signin")
.content(jsonRequest)
.contentType(MediaType.APPLICATION_JSON_VALUE)
.accept(MediaType.APPLICATION_JSON);
Authentication auth = Mockito.mock(Authentication.class);
Mockito.when(auth.getName()).thenReturn("authName");
auth.setAuthenticated(true);
Mockito.when(auth.isAuthenticated()).thenReturn(true);
Mockito.when(authenticationManager.authenticate(auth)).thenReturn(auth); // Failing here
Mockito.when(jwtUtil.generateJwtCookie(dummy)).thenReturn(cookies);
Mockito.when(userDetailsServiceImpl.loadUserByUsername("test1")).thenReturn(dummy);
MvcResult mvcResult = mockMvc.perform(request)
.andExpect(status().is2xxSuccessful())
.andReturn();
}
public static String asJsonString(final Object obj) {
try {
return new ObjectMapper().writeValueAsString(obj);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Here is the encountered errors after running the class AuthControllerTest:
java.lang.AssertionError: Range for response status value 403 expected: but was:<CLIENT_ERROR> Expected :SUCCESSFUL Actual :CLIENT_ERROR
at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:59) at org.springframework.test.util.AssertionErrors.assertEquals(AssertionErrors.java:122) at org.springframework.test.web.servlet.result.StatusResultMatchers.lambda$is2xxSuccessful$3(StatusResultMatchers.java:78) at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:212) at AuthControllerTest.authenticateUser(AuthControllerTest.java:102) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725) at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149) at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140) at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84) at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115) at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105) at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Upvotes: 1
Views: 1431
Reputation: 352
If you willing to change your code, then do this and hopefully everything will work fine:
A. Create a package in your test main package, it should include both words test and integration
package com.<yourApplication>.test.integration;
B.This is how your test class should be like:
@AutoConfigureMockMvc
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Import({ ObjectMapper.class, <YourController>.class })
@TestMethodOrder(OrderAnnotation.class)
class YourTestClass {
@Autowired
private MockMvc mockMvc;
@Autowired
private ObjectMapper objectMapper;
// user authentication
private static String jwt; // can use this for your next test request
@Test
@Order(1)
@DisplayName("User Authentication token")
void authenticationTest() throws JsonProcessingException, Exception {
final String link = "/api/auth/signin";
AuthenticationRequest defaultAuth = new AuthenticationRequest("admin", "admin");
System.out.println(objectMapper.writeValueAsString(defaultAuth));
// perform the request
MvcResult result = this.mockMvc
.perform(MockMvcRequestBuilders.post(link)
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsBytes(defaultAuth)))
.andExpect(MockMvcResultMatchers.status().isOk())
.andReturn();
String response = result.getResponse().getContentAsString();
System.out.println("from response: " + response); //
JsonNode root = objectMapper.readTree(response);
JsonNode jwtvalue = root.get("jwt");
jwt = jwtvalue.textValue();
System.out.println("jwt deserlized: " + jwt);
}
}
C. If the request returned an error, then the problem is either in your controller or the way you setup the JWT authentication.
Upvotes: 1