В моем приложении добавлен пользовательский фильтр в расширение WebSecurityConfigurerAdapter:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private static final RequestMatcher PROTECTED_URLS = new AntPathRequestMatcher("/v1/**");
@Override
public void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(authenticationFilter(), AnonymousAuthenticationFilter.class)
.authorizeRequests()
.requestMatchers(PROTECTED_URLS)
.authenticated()
.and()
.csrf().disable()
.formLogin().disable()
.httpBasic().disable()
.logout().disable();
}
@Bean
AuthenticationFilter authenticationFilter() throws Exception {
final AuthenticationFilter filter = new AuthenticationFilter(PROTECTED_URLS);
// filter setup...
filter.setAuthenticationManager(authenticationManager());
return filter;
}
}
Сам фильтр, который отвечает за проверку токена доступа путем вызова внешнего сервера авторизации, определяется как:
public class AuthenticationFilter extends AbstractAuthenticationProcessingFilter {
AuthenticationFilter(final RequestMatcher requiresAuth) {
super(requiresAuth);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse)
throws AuthenticationException, IOException, OAuth2Exception {
try {
// Get Authorization header.
String token = httpServletRequest.getHeader(AUTHORIZATION);
// Check if the token is valid by calling an external authorization server.
// Returns some Authentication if successful.
} catch (OAuth2Exception exception) {
// Return 401
} catch (Exception exception) {
// All other errors are 500s
}
}
@Override
protected void successfulAuthentication(final HttpServletRequest request,
final HttpServletResponse response,
final FilterChain chain,
final Authentication authResult)
throws IOException, ServletException {
SecurityContextHolder.getContext().setAuthentication(authResult);
chain.doFilter(request, response);
}
}
Я пытаюсь выполнить интеграционное тестирование на контроллере, определенном как:
@RestController
@RequestMapping(value = "/v1", produces = "application/json")
public class SomeController {
@Autowired
private SomeService someService;
@ResponseStatus(OK)
@PostMapping(value = "/a/path")
public SomeSuccessResponse pathHandlerMethod() {
return someService.someServiceMethod();
}
}
Наконец, моя настройка теста выглядит следующим образом:
@RunWith(SpringRunner.class)
@WebMvcTest(SomeController.class)
@Import(SecurityConfig.class)
@ContextConfiguration
@WebAppConfiguration
public class SomeControllerTest {
private MockMvc mockMvc;
@Autowired
private ObjectMapper objectMapper;
@Autowired
private WebApplicationContext context;
@MockBean
private SomeService someService;
@Before
public void setup() {
mockMvc = MockMvcBuilders
.webAppContextSetup(context)
.apply(springSecurity()) // When I comment out this line I'm getting 404 errors instead.
.build();
}
@Test
@WithMockUser
public void performIntegrationTest() throws Exception {
mockMvc.perform(post("/v1/a/path")).andExpect(status().isOk());
}
}
Я бы хотел, чтобы аутентификация была отключена или каким-то образом отключена для этого сценария - реальный код в AuthenticationFilter
не должен вызываться вообще. Чтобы достичь этого, в классе SomeControllerTest
я пробовал:
- аннотировать методы испытаний с помощью
@WithMockUser
- с настройкой
mockMvc
с помощью MockMvcBuilders
(см. setup()
метод выше) с .apply(springSecurity())
и без него - с аннотацией класса
SomeControllerTest
с @AutoConfigureMockMvc
(для параметров secure
и addFilters
установлено false
) - аннотируя класс
SomeControllerTest
с помощью @ContextConfiguration
и @WebAppConfiguration
(я не знаю, меняет ли это что-либо)
Ни один из этих подходов не отключает аутентификацию. Когда я запускаю тест, метод AuthenticationFilter
attemptAuthentication()
, вызывающий внешнюю службу, все еще вызывается, чего я не хочу.