Set HttpMessageConverter by DSL

Closes gh-16369

Signed-off-by: DingHao <dh.hiekn@gmail.com>
This commit is contained in:
DingHao
2025-01-12 14:47:56 +08:00
committed by Rob Winch
parent 4fc99aa9e1
commit 8181cec06c
3 changed files with 117 additions and 6 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2024 the original author or authors.
* Copyright 2002-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
package org.springframework.security.config.annotation.web.configurers;
import java.io.IOException;
import java.util.List;
import org.junit.jupiter.api.Test;
@@ -24,21 +25,37 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.test.SpringTestContext;
import org.springframework.security.config.test.SpringTestContextExtension;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.ui.DefaultResourcesFilter;
import org.springframework.security.web.webauthn.api.PublicKeyCredentialCreationOptions;
import org.springframework.security.web.webauthn.api.TestPublicKeyCredentialCreationOptions;
import org.springframework.security.web.webauthn.management.WebAuthnRelyingPartyOperations;
import org.springframework.test.web.servlet.MockMvc;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@@ -126,6 +143,66 @@ public class WebAuthnConfigurerTests {
this.mvc.perform(get("/login/webauthn.js")).andExpect(status().isNotFound());
}
@Test
public void webauthnWhenConfiguredMessageConverter() throws Exception {
TestingAuthenticationToken user = new TestingAuthenticationToken("user", "password", "ROLE_USER");
SecurityContextHolder.setContext(new SecurityContextImpl(user));
PublicKeyCredentialCreationOptions options = TestPublicKeyCredentialCreationOptions
.createPublicKeyCredentialCreationOptions()
.build();
WebAuthnRelyingPartyOperations rpOperations = mock(WebAuthnRelyingPartyOperations.class);
ConfigMessageConverter.rpOperations = rpOperations;
given(rpOperations.createPublicKeyCredentialCreationOptions(any())).willReturn(options);
HttpMessageConverter<Object> converter = new AbstractHttpMessageConverter<>() {
@Override
protected boolean supports(Class<?> clazz) {
return true;
}
@Override
protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
return null;
}
@Override
protected void writeInternal(Object o, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
outputMessage.getBody().write("123".getBytes());
}
};
ConfigMessageConverter.converter = converter;
this.spring.register(ConfigMessageConverter.class).autowire();
this.mvc.perform(post("/webauthn/register/options"))
.andExpect(status().isOk())
.andExpect(content().string("123"));
}
@Configuration
@EnableWebSecurity
static class ConfigMessageConverter {
private static HttpMessageConverter<Object> converter;
private static WebAuthnRelyingPartyOperations rpOperations;
@Bean
WebAuthnRelyingPartyOperations webAuthnRelyingPartyOperations() {
return ConfigMessageConverter.rpOperations;
}
@Bean
UserDetailsService userDetailsService() {
return new InMemoryUserDetailsManager();
}
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http.csrf(AbstractHttpConfigurer::disable).webAuthn((c) -> c.messageConverter(converter)).build();
}
}
@Configuration
@EnableWebSecurity
static class DefaultWebauthnConfiguration {