Как проверить код состояния http 401 (без аутентификации) с помощью MockMVC и Spring Boot OAuth2 Resource Server?
В настоящее время я разрабатываю приложение Spring Boot 3 , которое предоставляет REST API. Чтобы использовать этот API, пользователи должны пройти аутентификацию с помощью рабочего процесса OAuth2 нашего keycloak поставщика удостоверений. Поэтому я использовал org.springframework.boot:spring-boot-starter-oauth2-resource-server. Когда я запускаю приложение, аутентификация и авторизация работают должным образом.
К сожалению, я не могу написать WebMvcTest для варианта использования, когда пользователь не предоставляет JWT для аутентификации . В этом случае я ожидаю ответа HTTP с кодом состояния 401 (без аутентификации), но получаю код состояния 403 (запрещено). Возможно ли это событие, потому что MockMvc имитирует части обработки ответа?
Я успешно написал тестовые примеры для следующих вариантов использования.
- Пользователь предоставляет JWT с ожидаемым требованием => Я ожидаю код состояния 200 ✔
- Пользователь предоставляет JWT без ожидаемого утверждения => Я ожидаю код состояния 403 ✔
Я пытался следовать всему из документации Spring Security: https://docs.spring.io/spring-security/reference/servlet/test/index.html .
Вот мой код.
@WebMvcTest(CustomerController.class)
@ImportAutoConfiguration(classes = {RequestInformationExtractor.class})
@ContextConfiguration(classes = SecurityConfiguration.class)
@Import({TestConfiguration.class, CustomerController.class})
public class PartnerControllerTest {
@Autowired
private WebApplicationContext context;
private MockMvc mockMvc;
@BeforeEach
public void setup() {
mockMvc = MockMvcBuilders
.webAppContextSetup(context)
.apply(springSecurity())
.build();
}
// runs successfully
@Test
void shouldReturnListOfCustomers() throws Exception {
mockMvc.perform(
post("/search")
.contentType(MediaType.APPLICATION_JSON)
.content("{" +
"\"searchKeyword\": \"Mustermann\"" +
"}")
.with(jwt()
.authorities(
new SimpleGrantedAuthority("basic")
)))
.andExpect(status().isOk());
}
// fails: expect 401 but got 403
@Test
void shouldReturn401WithoutJwt() throws Exception {
mockMvc.perform(
post("/search")
.contentType(MediaType.APPLICATION_JSON)
.content("{" +
"\"searchKeyword\": \"Mustermann\"" +
"}"))
.andExpect(status().isUnauthorized());
}
// runs successfully
@Test
void shouldReturn403() throws Exception {
mockMvc.perform(
post("/search")
.contentType(MediaType.APPLICATION_JSON)
.content("{" +
"\"searchKeyword\": \"Mustermann\"" +
"}")
.with(jwt()))
.andExpect(status().isForbidden());
}
}
@org.springframework.boot.test.context.TestConfiguration
public class TestConfiguration {
@Bean
public JwtDecoder jwtDecoder() {
SecretKey secretKey = new SecretKeySpec("dasdasdasdfgsg9423942342394239492349fsd9fsd9fsdfjkldasd".getBytes(), JWSAlgorithm.HS256.getName());
NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withSecretKey(secretKey).build();
return jwtDecoder;
}
}
@Configuration
@EnableWebSecurity
public class SecurityConfiguration {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.sessionManagement(sessionManagement -> sessionManagement.sessionCreationPolicy(STATELESS))
.authorizeHttpRequests((authz) -> authz
.requestMatchers("/actuator/**").permitAll()
.anyRequest().hasAuthority("Basic")
)
.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt);
return http.build();
}
@Bean
public JwtAuthenticationConverter jwtAuthenticationConverter() {
JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
grantedAuthoritiesConverter.setAuthoritiesClaimName("groups");
grantedAuthoritiesConverter.setAuthorityPrefix("");
JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter);
return jwtAuthenticationConverter;
}
}
1 ответ
Вероятно, у вас есть 403, потому что исключение выдается до оценки контроля доступа (CORS или CSRF или что-то в этом роде).
Например, в вашей конфигурации безопасности вы отключаете сеансы (политика создания сеансов для безгражданства), но не защиту CSRF. Либо отключите CSRF в вашей конфигурации (вы можете, потому что атаки CSRF используют сеансы), либо используйте MockMvccsrf()
постпроцессор в ваших тестах.
В моих примерах и туториалах есть много демонстраций серверов-ресурсов с конфигурацией безопасности и тестами (модульными и интеграционными) . В большинстве из них есть ссылки на мои тестовые аннотации и загрузчики (которые позволяют определить почти всю конфигурацию безопасности из свойств без конфигурации Java), но этот не использует ничего из моих расширений. Там вы должны найти полезные советы для вашей безопасности и тестов.