Reputation: 1817
I'm trying to test my controller with Spring boot @WebMvcTest. I also have implemented SPring OAuth security (resource and authorization server), so to reach endpoint you need to be authorized.
For this reason I cannot test my controller like this:
@WebMvcTest(MyController.class)
public class MyControllerTest {
@Autowired
private MockMvc mvc;
@Autowired
private ObjectMapper objectMapper;
@MockBean
private MyService service;
@Test
public void myTest() throws Exception {
//Arrange request
//Act
mvc.perform
(MockMvcRequestBuilders
.post("/v1/my-controller/type", type.name())
.characterEncoding(StandardCharsets.UTF_8.name())
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(requestDTO)))
//Assert
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().json(objectMapper.writeValueAsString("")));
}
Because it requires resource server. But the problem is that when I'm running this test I got next error:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in com.danfoss.cloud.prosa.restapi.security.WebSecurityConfig$OAuthResourceServer required a bean of type 'org.springframework.security.oauth2.provider.token.TokenStore' that could not be found.
Action:
Consider defining a bean of type 'org.springframework.security.oauth2.provider.token.TokenStore' in your configuration.
My Resource server looks like
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Configuration
@EnableResourceServer
public static class OAuthResourceServer extends ResourceServerConfigurerAdapter {
private final TokenStore tokenStore;
////CANNOT INJECT DURING WEB CONTEXT START
@Autowired
public OAuthResourceServer(TokenStore tokenStore) {
this.tokenStore = tokenStore;
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources
.resourceId("resource")
.tokenStore(tokenStore);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/status")
.permitAll()
.anyRequest()
.access("isAuthenticated()");
}
private String createAuthorizationExpression(String ipWhitelist) {
return null;
}
}
}
One important thing that application works fine and it injects TokenStore fine during run.
How to overcome this issue?
Upvotes: 0
Views: 473
Reputation: 1817
Resolved this issue by decoupling configurations like this:
@Configuration
public class Config {
@Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(mainDataSource());
}
....
other beans
}
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
@Configuration
@EnableWebSecurity
@EnableResourceServer
public class OAuthResourceServer extends ResourceServerConfigurerAdapter {
private final TokenStore tokenStore;
@Autowired
public OAuthResourceServer(TokenStore tokenStore) {
this.tokenStore = tokenStore;
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources
.resourceId("resource")
.tokenStore(tokenStore);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(
"/status",
"/")
.permitAll()
.anyRequest()
.access(
...
);
}
}
@Configuration
@EnableAuthorizationServer
public class OAuthAuthorizationServer extends AuthorizationServerConfigurerAdapter {
...
private final AuthenticationManager authenticationManager;
...
private final TokenStore tokenStore;
...
@Autowired
public OAuthAuthorizationServer(
....
AuthenticationManager authenticationManager,
TokenStore tokenStore,
...
) {
this.restUserDetailsService = restUserDetailsService;
this.oAuthRestAuthenticationProvider = oAuthRestAuthenticationProvider;
this.authenticationManager = authenticationManager;
this.jdbcClientDetailsService = jdbcClientDetailsService;
this.tokenStore = tokenStore;
this.authorizationCodeServices = authorizationCodeServices;
}
@Bean
public AuthorizationServerTokenServices tokenServices() {
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setAccessTokenValiditySeconds(accessTokenValiditySeconds);
tokenServices.setRefreshTokenValiditySeconds(refreshTokenValiditySeconds);
tokenServices.setSupportRefreshToken(true);
tokenServices.setReuseRefreshToken(true);
tokenServices.setTokenStore(tokenStore);
tokenServices.setClientDetailsService(jdbcClientDetailsService);
tokenServices.setSupportRefreshToken(true);
tokenServices.setAuthenticationManager(authenticationManager);
return tokenServices;
}
@Autowired
public void configure(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(oAuthRestAuthenticationProvider);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(jdbcClientDetailsService);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints
.approvalStoreDisabled()
.authorizationCodeServices(authorizationCodeServices)
.tokenStore(tokenStore)
.tokenServices(tokenServices())
.authenticationManager(authenticationManager)
.userDetailsService(restUserDetailsService);
}
}
Then to disable security in controller test you need to do next
@WebMvcTest(MyController.class)
@AutoConfigureMockMvc(addFilters = false)
Upvotes: 1