In REST controller I have several methods on which I need to create contract test and I don't know how to provide Principal for passing tests.
One of the method in Controller which has Principal in parameters:
@PreAuthorize("hasRole('USER')")
@GetMapping("/current")
public Details getCurrent(Principal principal) {
return houseManager.getById(Principals.getCurrentUserId(principal));
}
I've created base class for tests:
@RunWith(SpringRunner.class)
@WebMvcTest(controllers = {Controller.class})
@ContextConfiguration(classes = {TestConfig.class, ControllerTestConfig.class})
@ComponentScan(basePackageClasses = {Controller.class})
@AutoConfigureStubRunner
public class ControllersWithSecurityBase {
@Autowired
privet Service service;
@Autowired
WebApplicationContext context;
@Mock
private Principal mockedPrincipal;
RestAssuredMockMvc.standaloneSetup(new Controller(service));
RequestBuilder requestBuilder = MockMvcRequestBuilders
.get("/")
.with(user("user")
.password("password")
.roles("USER"))
.principal(mockedPrincipal)
.accept(MediaType.APPLICATION_JSON);
MockMvc mockMvc = MockMvcBuilders
.webAppContextSetup(context)
.defaultRequest(requestBuilder)
.apply(springSecurity())
.build();
RestAssuredMockMvc.mockMvc(mockMvc);
}
Contract:
Contract.make {
name("Should find current by principal")
request {
method(GET)
urlPath(".../current")
}
response {
status(200)
}
}
As result of mvn clean install I've got next exception:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.ClassCastException: org.springframework.security.authentication.UsernamePasswordAuthenticationToken cannot be cast to java.util.Map
What I need to do for correct mocking Principal and passing tests?
My project use Oauth2 security.
So for mocking Principal object in contract tests I've created bean of OAuth2AuthenticationDetails (this class implements Principal interface).
Class configuration with bean OAuth2AuthenticationDetails is:
package com.example.config.fakesecurityconfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.OAuth2Request;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
import java.util.*;
@Configuration
public class OAuth2TestConfig {
@Bean
public OAuth2Authentication oAuth2Authentication() {
return new OAuth2Authentication(getStoredRequest(), getUserAuthentication());
}
@Bean
public OAuth2AuthenticationDetails oAuth2AuthenticationDetails() {
MockHttpServletRequest request = new MockHttpServletRequest();
return new OAuth2AuthenticationDetails(request);
}
private OAuth2Request getStoredRequest() {
Set<String> scope = new HashSet<>();
scope.add("read");
scope.add("write");
return new OAuth2Request(
Collections.EMPTY_MAP,
"clientId",
getGrantedAuthorityCollection(),
true,
scope,
Collections.EMPTY_SET,
null,
Collections.EMPTY_SET,
Collections.EMPTY_MAP);
}
private Authentication getUserAuthentication() {
String credentials = "PROTECTED";
Authentication authentication = new TestingAuthenticationToken(getPrincipalMap(), credentials, getGrantedAuthorityAsList());
return new OAuth2Authentication(getStoredRequest(), authentication);
}
private Map<String, String> getPrincipalMap() {
Map<String, String> principalMap = new LinkedHashMap<>();
principalMap.put("id", "5c49c98d3a0f3a23cd39a720");
principalMap.put("username", "TestUserName");
principalMap.put("password", "TestPassword");
principalMap.put("createdAt", "2018-06-14 10:35:05");
principalMap.put("userType", "USER");
principalMap.put("authorities", getGrantedAuthorityCollectionAsMap().toString());
principalMap.put("accountNonExpired", "true");
principalMap.put("accountNonLocked", "true");
principalMap.put("credentialsNonExpired", "true");
principalMap.put("enabled", "true");
principalMap.put("uniqueId", "null");
principalMap.put("uniqueLink", "fc3552f4-0cdf-494d-bc46-9d1e6305400a");
principalMap.put("uniqueLinkCreatedAt", "2019-09-06 10:44:36");
principalMap.put("someId", "59b5a82c410df8000a83a1ff");
principalMap.put("otherId", "59b5a82c410df8000a83a1ff");
principalMap.put("name", "TestName");
return principalMap;
}
private Collection<GrantedAuthority> getGrantedAuthorityCollection() {
return Arrays.asList(
new SimpleGrantedAuthority("ROLE_ADMIN"),
new SimpleGrantedAuthority("ROLE_USER")
);
}
private List<GrantedAuthority> getGrantedAuthorityAsList() {
return new ArrayList<>(getGrantedAuthorityCollection());
}
private LinkedHashMap<String, GrantedAuthority> getGrantedAuthorityCollectionAsMap() {
LinkedHashMap<String, GrantedAuthority> map = new LinkedHashMap<>();
for (GrantedAuthority authority : getGrantedAuthorityCollection()) {
map.put("authority", authority);
}
return map;
}
}
As result my base class for contract tests is:
@RunWith(SpringRunner.class)
@WebMvcTest(controllers = {Controller.class})
@ContextConfiguration(classes = {TestConfig.class, OAuth2TestConfig.class})
@ComponentScan(basePackageClasses = {Controller.class})
@AutoConfigureStubRunner
@WebAppConfiguration
public abstract class HousesControllersSecuredBase {
@Autowired
private Service service;
@Autowired
private WebApplicationContext context;
@Autowired
private OAuth2Authentication oAuth2Authentication;
@Autowired
private OAuth2AuthenticationDetails oAuth2AuthenticationDetails;
@Autowired
private MockMvc mockMvc;
@Before
public void settingUpTests() {
RestAssuredMockMvc.standaloneSetup(Controller(houseService));
mockMvc = MockMvcBuilders
.webAppContextSetup(context)
.build();
RestAssuredMockMvc.mockMvc(mockMvc);
oAuth2Authentication.setDetails(oAuth2AuthenticationDetails);
RestAssuredMockMvc.authentication =
RestAssuredMockMvc.principal(oAuth2Authentication);
}
@After
public void ShuttingDownTests() {
RestAssuredMockMvc.reset();
}
}