Add support for JacksonJsonHttpMessageConverter
This commit introduces classpath checks and instantiation of JacksonJsonHttpMessageConverter (based on Jackson 3) leveraging a new GenericHttpMessageConverterAdapter which allows to adapt SmartHttpMessageConverter to GenericHttpMessageConverter. See gh-17832 Signed-off-by: Sébastien Deleuze <sdeleuze@users.noreply.github.com>
This commit is contained in:
committed by
Rob Winch
parent
702a177e25
commit
137f8fd670
+9
@@ -19,8 +19,10 @@ package org.springframework.security.config.web.server;
|
||||
import org.springframework.http.converter.GenericHttpMessageConverter;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.json.GsonHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.JsonbHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.security.oauth2.core.http.converter.GenericHttpMessageConverterAdapter;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
@@ -32,6 +34,8 @@ import org.springframework.util.ClassUtils;
|
||||
*/
|
||||
final class HttpMessageConverters {
|
||||
|
||||
private static final boolean jacksonPresent;
|
||||
|
||||
private static final boolean jackson2Present;
|
||||
|
||||
private static final boolean gsonPresent;
|
||||
@@ -40,6 +44,7 @@ final class HttpMessageConverters {
|
||||
|
||||
static {
|
||||
ClassLoader classLoader = HttpMessageConverters.class.getClassLoader();
|
||||
jacksonPresent = ClassUtils.isPresent("tools.jackson.databind.json.JsonMapper", classLoader);
|
||||
jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader)
|
||||
&& ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
|
||||
gsonPresent = ClassUtils.isPresent("com.google.gson.Gson", classLoader);
|
||||
@@ -49,7 +54,11 @@ final class HttpMessageConverters {
|
||||
private HttpMessageConverters() {
|
||||
}
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
static GenericHttpMessageConverter<Object> getJsonMessageConverter() {
|
||||
if (jacksonPresent) {
|
||||
return new GenericHttpMessageConverterAdapter<>(new JacksonJsonHttpMessageConverter());
|
||||
}
|
||||
if (jackson2Present) {
|
||||
return new MappingJackson2HttpMessageConverter();
|
||||
}
|
||||
|
||||
+9
@@ -19,8 +19,10 @@ package org.springframework.security.oauth2.server.authorization.http.converter;
|
||||
import org.springframework.http.converter.GenericHttpMessageConverter;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.json.GsonHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.JsonbHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.security.web.http.GenericHttpMessageConverterAdapter;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
@@ -32,6 +34,8 @@ import org.springframework.util.ClassUtils;
|
||||
*/
|
||||
final class HttpMessageConverters {
|
||||
|
||||
private static final boolean jacksonPresent;
|
||||
|
||||
private static final boolean jackson2Present;
|
||||
|
||||
private static final boolean gsonPresent;
|
||||
@@ -40,6 +44,7 @@ final class HttpMessageConverters {
|
||||
|
||||
static {
|
||||
ClassLoader classLoader = HttpMessageConverters.class.getClassLoader();
|
||||
jacksonPresent = ClassUtils.isPresent("tools.jackson.databind.json.JsonMapper", classLoader);
|
||||
jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader)
|
||||
&& ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
|
||||
gsonPresent = ClassUtils.isPresent("com.google.gson.Gson", classLoader);
|
||||
@@ -49,7 +54,11 @@ final class HttpMessageConverters {
|
||||
private HttpMessageConverters() {
|
||||
}
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
static GenericHttpMessageConverter<Object> getJsonMessageConverter() {
|
||||
if (jacksonPresent) {
|
||||
return new GenericHttpMessageConverterAdapter<>(new JacksonJsonHttpMessageConverter());
|
||||
}
|
||||
if (jackson2Present) {
|
||||
return new MappingJackson2HttpMessageConverter();
|
||||
}
|
||||
|
||||
+10
-1
@@ -19,19 +19,23 @@ package org.springframework.security.oauth2.server.authorization.oidc.http.conve
|
||||
import org.springframework.http.converter.GenericHttpMessageConverter;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.json.GsonHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.JsonbHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.security.web.http.GenericHttpMessageConverterAdapter;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Utility methods for {@link HttpMessageConverter}'s.
|
||||
*
|
||||
* @author Joe Grandja
|
||||
* @author l uamas
|
||||
* @author luamas
|
||||
* @since 7.0
|
||||
*/
|
||||
final class HttpMessageConverters {
|
||||
|
||||
private static final boolean jacksonPresent;
|
||||
|
||||
private static final boolean jackson2Present;
|
||||
|
||||
private static final boolean gsonPresent;
|
||||
@@ -40,6 +44,7 @@ final class HttpMessageConverters {
|
||||
|
||||
static {
|
||||
ClassLoader classLoader = HttpMessageConverters.class.getClassLoader();
|
||||
jacksonPresent = ClassUtils.isPresent("tools.jackson.databind.json.JsonMapper", classLoader);
|
||||
jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader)
|
||||
&& ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
|
||||
gsonPresent = ClassUtils.isPresent("com.google.gson.Gson", classLoader);
|
||||
@@ -49,7 +54,11 @@ final class HttpMessageConverters {
|
||||
private HttpMessageConverters() {
|
||||
}
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
static GenericHttpMessageConverter<Object> getJsonMessageConverter() {
|
||||
if (jacksonPresent) {
|
||||
return new GenericHttpMessageConverterAdapter<>(new JacksonJsonHttpMessageConverter());
|
||||
}
|
||||
if (jackson2Present) {
|
||||
return new MappingJackson2HttpMessageConverter();
|
||||
}
|
||||
|
||||
+9
@@ -19,8 +19,10 @@ package org.springframework.security.oauth2.server.authorization.web;
|
||||
import org.springframework.http.converter.GenericHttpMessageConverter;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.json.GsonHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.JsonbHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.security.web.http.GenericHttpMessageConverterAdapter;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
@@ -31,6 +33,8 @@ import org.springframework.util.ClassUtils;
|
||||
*/
|
||||
final class HttpMessageConverters {
|
||||
|
||||
private static final boolean jacksonPresent;
|
||||
|
||||
private static final boolean jackson2Present;
|
||||
|
||||
private static final boolean gsonPresent;
|
||||
@@ -39,6 +43,7 @@ final class HttpMessageConverters {
|
||||
|
||||
static {
|
||||
ClassLoader classLoader = HttpMessageConverters.class.getClassLoader();
|
||||
jacksonPresent = ClassUtils.isPresent("tools.jackson.databind.json.JsonMapper", classLoader);
|
||||
jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader)
|
||||
&& ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
|
||||
gsonPresent = ClassUtils.isPresent("com.google.gson.Gson", classLoader);
|
||||
@@ -48,7 +53,11 @@ final class HttpMessageConverters {
|
||||
private HttpMessageConverters() {
|
||||
}
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
static GenericHttpMessageConverter<Object> getJsonMessageConverter() {
|
||||
if (jacksonPresent) {
|
||||
return new GenericHttpMessageConverterAdapter<>(new JacksonJsonHttpMessageConverter());
|
||||
}
|
||||
if (jackson2Present) {
|
||||
return new MappingJackson2HttpMessageConverter();
|
||||
}
|
||||
|
||||
+2
-2
@@ -90,7 +90,7 @@ public class OidcUserInfoHttpMessageConverterTests {
|
||||
" \"postal_code\": \"75007\",\n" +
|
||||
" \"country\": \"France\"\n" +
|
||||
" },\n" +
|
||||
" \"updated_at\": 1607633867\n" +
|
||||
" \"updated_at\": \"2020-12-10T20:57:47Z\"\n" +
|
||||
"}\n";
|
||||
// @formatter:on
|
||||
|
||||
@@ -178,7 +178,7 @@ public class OidcUserInfoHttpMessageConverterTests {
|
||||
assertThat(userInfoResponse).contains("\"address\":");
|
||||
assertThat(userInfoResponse)
|
||||
.contains("\"formatted\":\"Champ de Mars\\n5 Av. Anatole France\\n75007 Paris\\nFrance\"");
|
||||
assertThat(userInfoResponse).contains("\"updated_at\":1607633867");
|
||||
assertThat(userInfoResponse).contains("\"updated_at\":\"2020-12-10T20:57:47Z\"");
|
||||
assertThat(userInfoResponse).contains("\"custom_claim\":\"value\"");
|
||||
assertThat(userInfoResponse).contains("\"custom_collection_claim\":[\"value1\",\"value2\"]");
|
||||
}
|
||||
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2004-present 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.oauth2.core.http.converter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.http.HttpInputMessage;
|
||||
import org.springframework.http.HttpOutputMessage;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.GenericHttpMessageConverter;
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
import org.springframework.http.converter.HttpMessageNotWritableException;
|
||||
import org.springframework.http.converter.SmartHttpMessageConverter;
|
||||
|
||||
/**
|
||||
* {@link GenericHttpMessageConverter} implementation that delegates to a
|
||||
* {@link SmartHttpMessageConverter}.
|
||||
*
|
||||
* @param <T> the converted object type
|
||||
* @author Sebastien Deleuze
|
||||
* @since 7.0
|
||||
*/
|
||||
public class GenericHttpMessageConverterAdapter<T> implements GenericHttpMessageConverter<T> {
|
||||
|
||||
private final SmartHttpMessageConverter<T> smartConverter;
|
||||
|
||||
public GenericHttpMessageConverterAdapter(SmartHttpMessageConverter<T> smartConverter) {
|
||||
this.smartConverter = smartConverter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRead(Type type, @Nullable Class<?> contextClass, @Nullable MediaType mediaType) {
|
||||
return this.smartConverter.canRead(ResolvableType.forType(type), mediaType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T read(Type type, @Nullable Class<?> contextClass, HttpInputMessage inputMessage)
|
||||
throws IOException, HttpMessageNotReadableException {
|
||||
return this.smartConverter.read(ResolvableType.forType(type), inputMessage, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canWrite(@Nullable Type type, Class<?> clazz, @Nullable MediaType mediaType) {
|
||||
return this.smartConverter.canWrite(ResolvableType.forType(type), clazz, mediaType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(T t, @Nullable Type type, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
|
||||
throws IOException, HttpMessageNotWritableException {
|
||||
this.smartConverter.write(t, ResolvableType.forType(type), contentType, outputMessage, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRead(Class<?> clazz, @Nullable MediaType mediaType) {
|
||||
return this.smartConverter.canRead(ResolvableType.forClass(clazz), mediaType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType) {
|
||||
return this.smartConverter.canWrite(clazz, mediaType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MediaType> getSupportedMediaTypes() {
|
||||
return this.smartConverter.getSupportedMediaTypes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
|
||||
throws IOException, HttpMessageNotReadableException {
|
||||
return this.smartConverter.read(clazz, inputMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
|
||||
throws IOException, HttpMessageNotWritableException {
|
||||
this.smartConverter.write(t, contentType, outputMessage);
|
||||
}
|
||||
|
||||
}
|
||||
+8
@@ -19,6 +19,7 @@ package org.springframework.security.oauth2.core.http.converter;
|
||||
import org.springframework.http.converter.GenericHttpMessageConverter;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.json.GsonHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.JsonbHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.util.ClassUtils;
|
||||
@@ -32,6 +33,8 @@ import org.springframework.util.ClassUtils;
|
||||
*/
|
||||
final class HttpMessageConverters {
|
||||
|
||||
private static final boolean jacksonPresent;
|
||||
|
||||
private static final boolean jackson2Present;
|
||||
|
||||
private static final boolean gsonPresent;
|
||||
@@ -40,6 +43,7 @@ final class HttpMessageConverters {
|
||||
|
||||
static {
|
||||
ClassLoader classLoader = HttpMessageConverters.class.getClassLoader();
|
||||
jacksonPresent = ClassUtils.isPresent("tools.jackson.databind.json.JsonMapper", classLoader);
|
||||
jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader)
|
||||
&& ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
|
||||
gsonPresent = ClassUtils.isPresent("com.google.gson.Gson", classLoader);
|
||||
@@ -49,7 +53,11 @@ final class HttpMessageConverters {
|
||||
private HttpMessageConverters() {
|
||||
}
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
static GenericHttpMessageConverter<Object> getJsonMessageConverter() {
|
||||
if (jacksonPresent) {
|
||||
return new GenericHttpMessageConverterAdapter<>(new JacksonJsonHttpMessageConverter());
|
||||
}
|
||||
if (jackson2Present) {
|
||||
return new MappingJackson2HttpMessageConverter();
|
||||
}
|
||||
|
||||
+2
-1
@@ -52,7 +52,8 @@ public class OAuth2AccessTokenResponseHttpMessageConverter
|
||||
private static final ParameterizedTypeReference<Map<String, Object>> STRING_OBJECT_MAP = new ParameterizedTypeReference<>() {
|
||||
};
|
||||
|
||||
private GenericHttpMessageConverter<Object> jsonMessageConverter = HttpMessageConverters.getJsonMessageConverter();
|
||||
private final GenericHttpMessageConverter<Object> jsonMessageConverter = HttpMessageConverters
|
||||
.getJsonMessageConverter();
|
||||
|
||||
private Converter<Map<String, Object>, OAuth2AccessTokenResponse> accessTokenResponseConverter = new DefaultMapOAuth2AccessTokenResponseConverter();
|
||||
|
||||
|
||||
+2
-1
@@ -52,7 +52,8 @@ public class OAuth2ErrorHttpMessageConverter extends AbstractHttpMessageConverte
|
||||
private static final ParameterizedTypeReference<Map<String, Object>> STRING_OBJECT_MAP = new ParameterizedTypeReference<>() {
|
||||
};
|
||||
|
||||
private GenericHttpMessageConverter<Object> jsonMessageConverter = HttpMessageConverters.getJsonMessageConverter();
|
||||
private final GenericHttpMessageConverter<Object> jsonMessageConverter = HttpMessageConverters
|
||||
.getJsonMessageConverter();
|
||||
|
||||
protected Converter<Map<String, String>, OAuth2Error> errorConverter = new OAuth2ErrorConverter();
|
||||
|
||||
|
||||
+8
@@ -31,9 +31,11 @@ import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.GenericHttpMessageConverter;
|
||||
import org.springframework.http.converter.HttpMessageNotWritableException;
|
||||
import org.springframework.http.converter.json.GsonHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.JsonbHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.http.server.ServletServerHttpResponse;
|
||||
import org.springframework.security.oauth2.core.http.converter.GenericHttpMessageConverterAdapter;
|
||||
import org.springframework.security.oauth2.server.resource.OAuth2ProtectedResourceMetadata;
|
||||
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
|
||||
import org.springframework.security.web.util.UrlUtils;
|
||||
@@ -139,6 +141,8 @@ public final class OAuth2ProtectedResourceMetadataFilter extends OncePerRequestF
|
||||
|
||||
private static final class HttpMessageConverters {
|
||||
|
||||
private static final boolean jacksonPresent;
|
||||
|
||||
private static final boolean jackson2Present;
|
||||
|
||||
private static final boolean gsonPresent;
|
||||
@@ -147,6 +151,7 @@ public final class OAuth2ProtectedResourceMetadataFilter extends OncePerRequestF
|
||||
|
||||
static {
|
||||
ClassLoader classLoader = HttpMessageConverters.class.getClassLoader();
|
||||
jacksonPresent = ClassUtils.isPresent("tools.jackson.databind.json.JsonMapper", classLoader);
|
||||
jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader)
|
||||
&& ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
|
||||
gsonPresent = ClassUtils.isPresent("com.google.gson.Gson", classLoader);
|
||||
@@ -158,6 +163,9 @@ public final class OAuth2ProtectedResourceMetadataFilter extends OncePerRequestF
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
private static GenericHttpMessageConverter<Object> getJsonMessageConverter() {
|
||||
if (jacksonPresent) {
|
||||
return new GenericHttpMessageConverterAdapter<>(new JacksonJsonHttpMessageConverter());
|
||||
}
|
||||
if (jackson2Present) {
|
||||
return new MappingJackson2HttpMessageConverter();
|
||||
}
|
||||
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2004-present 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.security.web.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.http.HttpInputMessage;
|
||||
import org.springframework.http.HttpOutputMessage;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.GenericHttpMessageConverter;
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
import org.springframework.http.converter.HttpMessageNotWritableException;
|
||||
import org.springframework.http.converter.SmartHttpMessageConverter;
|
||||
|
||||
/**
|
||||
* {@link GenericHttpMessageConverter} implementation that delegates to a
|
||||
* {@link SmartHttpMessageConverter}.
|
||||
*
|
||||
* @param <T> the converted object type
|
||||
* @author Sebastien Deleuze
|
||||
* @since 7.0
|
||||
*/
|
||||
public class GenericHttpMessageConverterAdapter<T> implements GenericHttpMessageConverter<T> {
|
||||
|
||||
private final SmartHttpMessageConverter<T> smartConverter;
|
||||
|
||||
public GenericHttpMessageConverterAdapter(SmartHttpMessageConverter<T> smartConverter) {
|
||||
this.smartConverter = smartConverter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRead(Type type, @Nullable Class<?> contextClass, @Nullable MediaType mediaType) {
|
||||
return this.smartConverter.canRead(ResolvableType.forType(type), mediaType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T read(Type type, @Nullable Class<?> contextClass, HttpInputMessage inputMessage)
|
||||
throws IOException, HttpMessageNotReadableException {
|
||||
return this.smartConverter.read(ResolvableType.forType(type), inputMessage, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canWrite(@Nullable Type type, Class<?> clazz, @Nullable MediaType mediaType) {
|
||||
return this.smartConverter.canWrite(ResolvableType.forType(type), clazz, mediaType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(T t, @Nullable Type type, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
|
||||
throws IOException, HttpMessageNotWritableException {
|
||||
this.smartConverter.write(t, ResolvableType.forType(type), contentType, outputMessage, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canRead(Class<?> clazz, @Nullable MediaType mediaType) {
|
||||
return this.smartConverter.canRead(ResolvableType.forClass(clazz), mediaType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType) {
|
||||
return this.smartConverter.canWrite(clazz, mediaType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MediaType> getSupportedMediaTypes() {
|
||||
return this.smartConverter.getSupportedMediaTypes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
|
||||
throws IOException, HttpMessageNotReadableException {
|
||||
return this.smartConverter.read(clazz, inputMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
|
||||
throws IOException, HttpMessageNotWritableException {
|
||||
this.smartConverter.write(t, contentType, outputMessage);
|
||||
}
|
||||
|
||||
}
|
||||
+20
-7
@@ -38,6 +38,7 @@ import org.springframework.security.web.authentication.AuthenticationEntryPointF
|
||||
import org.springframework.security.web.authentication.HttpMessageConverterAuthenticationSuccessHandler;
|
||||
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
|
||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
||||
import org.springframework.security.web.http.GenericHttpMessageConverterAdapter;
|
||||
import org.springframework.security.web.webauthn.api.AuthenticatorAssertionResponse;
|
||||
import org.springframework.security.web.webauthn.api.PublicKeyCredential;
|
||||
import org.springframework.security.web.webauthn.api.PublicKeyCredentialRequestOptions;
|
||||
@@ -50,7 +51,8 @@ import static org.springframework.security.web.servlet.util.matcher.PathPatternR
|
||||
/**
|
||||
* Authenticates {@code PublicKeyCredential<AuthenticatorAssertionResponse>} that is
|
||||
* parsed from the body of the {@link HttpServletRequest} using the
|
||||
* {@link #setConverter(SmartHttpMessageConverter)}. An example request is provided below:
|
||||
* {@link #setConverter(GenericHttpMessageConverter)}. An example request is provided
|
||||
* below:
|
||||
*
|
||||
* <pre>
|
||||
* {
|
||||
@@ -72,8 +74,8 @@ import static org.springframework.security.web.servlet.util.matcher.PathPatternR
|
||||
*/
|
||||
public class WebAuthnAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
|
||||
|
||||
private SmartHttpMessageConverter<Object> converter = new JacksonJsonHttpMessageConverter(
|
||||
JsonMapper.builder().addModule(new WebauthnJacksonModule()).build());
|
||||
private GenericHttpMessageConverter<Object> converter = new GenericHttpMessageConverterAdapter<>(
|
||||
new JacksonJsonHttpMessageConverter(JsonMapper.builder().addModule(new WebauthnJacksonModule()).build()));
|
||||
|
||||
private PublicKeyCredentialRequestOptionsRepository requestOptionsRepository = new HttpSessionPublicKeyCredentialRequestOptionsRepository();
|
||||
|
||||
@@ -94,7 +96,7 @@ public class WebAuthnAuthenticationFilter extends AbstractAuthenticationProcessi
|
||||
PublicKeyCredential<AuthenticatorAssertionResponse> publicKeyCredential = null;
|
||||
try {
|
||||
publicKeyCredential = (PublicKeyCredential<AuthenticatorAssertionResponse>) this.converter
|
||||
.read(resolvableType, httpRequest, null);
|
||||
.read(resolvableType.getType(), getClass(), httpRequest);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new BadCredentialsException("Unable to authenticate the PublicKeyCredential", ex);
|
||||
@@ -114,15 +116,26 @@ public class WebAuthnAuthenticationFilter extends AbstractAuthenticationProcessi
|
||||
/**
|
||||
* Sets the {@link GenericHttpMessageConverter} to use for writing
|
||||
* {@code PublicKeyCredential<AuthenticatorAssertionResponse>} to the response. The
|
||||
* default is @{code Jackson2HttpMessageConverter}
|
||||
* default is @{code MappingJackson2HttpMessageConverter}
|
||||
* @param converter the {@link GenericHttpMessageConverter} to use. Cannot be null.
|
||||
*/
|
||||
// TODO Accept HttpMessageConverter
|
||||
public void setConverter(SmartHttpMessageConverter<Object> converter) {
|
||||
public void setConverter(GenericHttpMessageConverter<Object> converter) {
|
||||
Assert.notNull(converter, "converter cannot be null");
|
||||
this.converter = converter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link SmartHttpMessageConverter} to use for writing
|
||||
* {@code PublicKeyCredential<AuthenticatorAssertionResponse>} to the response. The
|
||||
* default is @{code MappingJackson2HttpMessageConverter}
|
||||
* @param converter the {@link SmartHttpMessageConverter} to use. Cannot be null.
|
||||
* @since 7.0
|
||||
*/
|
||||
public void setConverter(SmartHttpMessageConverter<Object> converter) {
|
||||
Assert.notNull(converter, "converter cannot be null");
|
||||
this.converter = new GenericHttpMessageConverterAdapter<>(converter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link PublicKeyCredentialRequestOptionsRepository} to use. The default is
|
||||
* {@link HttpSessionPublicKeyCredentialRequestOptionsRepository}.
|
||||
|
||||
+5
-1
@@ -27,6 +27,7 @@ import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.skyscreamer.jsonassert.JSONAssert;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.converter.GenericHttpMessageConverter;
|
||||
import org.springframework.http.converter.SmartHttpMessageConverter;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
@@ -101,7 +102,10 @@ class WebAuthnAuthenticationFilterTests {
|
||||
|
||||
@Test
|
||||
void setConverterWhenNullThenIllegalArgumentException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> this.filter.setConverter(null));
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.filter.setConverter((GenericHttpMessageConverter<Object>) null));
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> this.filter.setConverter((SmartHttpMessageConverter<Object>) null));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user