I am using Spring Boot 1.4.2 and I am new with Spring Boot. I have an Authentication Filter to set the current user information when the user log in. In an advice for the controller, I made the call to get the current userId as below:
public static String getCurrentUserToken(){
return ((AuthenticatedUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUserId();
}
Here is my custom AuthenticatedUser:
public class AuthenticatedUser implements Serializable {
private final String userName;
private final String userId;
private final String sessionId;
public AuthenticatedUser(String userName, String userId, String sessionId) {
super();
this.userName = userName;
this.userId = userId;
this.sessionId = sessionId;
}
public String getUserName() {
return userName;
}
public String getUserId() {
return userId;
}
public String getSessionId() {
return sessionId;
}
}
Everything works fine. However, the filter does not work in integration testing and I need to mock a current user. I searched a lot on how to mock a user but none of them help me. I finally found out this guide which is likely close to what I wanted: https://aggarwalarpit.wordpress.com/2017/05/17/mocking-spring-security-context-for-unit-testing/ Below is my testing class following that guideline:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT)
public class PersonalLoanPreApprovalTest {
@Before
public void initDB() throws Exception {
MockitoAnnotations.initMocks(this);
}
@Test
public void testRequestPersonalLoanPreApproval_Me() {
AuthenticatedUser applicationUser = new
AuthenticatedUser("test@abc.com", "2d1b5ae3", "123");
UsernamePasswordAuthenticationToken authentication = new ApiKeyAuthentication(applicationUser);
SecurityContext securityContext = mock(SecurityContext.class);
when(securityContext.getAuthentication()).thenReturn(authentication);
SecurityContextHolder.setContext(securityContext);
// error at this line
when(securityContext.getAuthentication().getPrincipal()) .thenReturn(applicationUser);
// The controller for this api has the advice to get the userId
MyResponse response = restTemplate.getForObject(url.toString(), MyResponse.class);
}
}
I got this error:
org.mockito.exceptions.misusing.WrongTypeOfReturnValue:
AuthenticatedUser cannot be returned by getAuthentication()
getAuthentication() should return Authentication
I spent couple days on this already, tried a lot of suggestions I found but still failed. I also tried to remove the line that cause error, but when the error gone, I still could not get the current user information in my controller advice.
Any suggestion is highly appreciated.
UPDATE1: Just wanted to have my results with some modification in the code.
With @glitch suggestion, I changed the code to mock the authentication and user in my test method as below:
@Test
public void testRequestPersonalLoanPreApproval_Me() {
AuthenticatedUser applicationUser = new AuthenticatedUser("testtu_free@cs.com", "2d1b5ae3-cf04-44f5-9493-f0518cab4554", "123");
Authentication authentication = Mockito.mock(Authentication.class);
SecurityContext securityContext = Mockito.mock(SecurityContext.class);
Mockito.when(securityContext.getAuthentication()).thenReturn(authentication);
SecurityContextHolder.setContext(securityContext);
Mockito.when(authentication.getPrincipal()).thenReturn(applicationUser);
// The controller for this api has the advice to get the userId
MyResponse response = restTemplate.getForObject(url.toString(), MyResponse.class);
}
}
I now can get rid of the error in the testing class. I debugged into the code, see that the securityContext has value when I am in the testing class. But when I jump to the code inside the controller advice, the below get returns null:
SecurityContextHolder.getContext().getAuthentication().getPrincipal()