AOT hints for authorization server Jackson 3 types should be registered

Closes gh-18146
This commit is contained in:
Joe Grandja 2025-11-06 10:14:00 -05:00
parent 27ae318992
commit 5fb2875f47

View File

@ -33,6 +33,7 @@ import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.User;
import org.springframework.security.jackson.CoreJacksonModule;
import org.springframework.security.jackson2.CoreJackson2Module; import org.springframework.security.jackson2.CoreJackson2Module;
import org.springframework.security.oauth2.core.AbstractOAuth2Token; import org.springframework.security.oauth2.core.AbstractOAuth2Token;
import org.springframework.security.oauth2.core.AuthorizationGrantType; import org.springframework.security.oauth2.core.AuthorizationGrantType;
@ -48,9 +49,11 @@ import org.springframework.security.oauth2.server.authorization.JdbcOAuth2Author
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2TokenExchangeActor; import org.springframework.security.oauth2.server.authorization.authentication.OAuth2TokenExchangeActor;
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2TokenExchangeCompositeAuthenticationToken; import org.springframework.security.oauth2.server.authorization.authentication.OAuth2TokenExchangeCompositeAuthenticationToken;
import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository; import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.jackson.OAuth2AuthorizationServerJacksonModule;
import org.springframework.security.oauth2.server.authorization.jackson2.OAuth2AuthorizationServerJackson2Module; import org.springframework.security.oauth2.server.authorization.jackson2.OAuth2AuthorizationServerJackson2Module;
import org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat; import org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat;
import org.springframework.security.web.authentication.WebAuthenticationDetails; import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.jackson.WebServletJacksonModule;
import org.springframework.security.web.jackson2.WebServletJackson2Module; import org.springframework.security.web.jackson2.WebServletJackson2Module;
import org.springframework.security.web.savedrequest.DefaultSavedRequest; import org.springframework.security.web.savedrequest.DefaultSavedRequest;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
@ -67,7 +70,18 @@ import org.springframework.util.ClassUtils;
*/ */
class OAuth2AuthorizationServerBeanRegistrationAotProcessor implements BeanRegistrationAotProcessor { class OAuth2AuthorizationServerBeanRegistrationAotProcessor implements BeanRegistrationAotProcessor {
private boolean jackson2Contributed; private static final boolean jackson2Present;
private static final boolean jackson3Present;
static {
ClassLoader classLoader = ClassUtils.getDefaultClassLoader();
jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader)
&& ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
jackson3Present = ClassUtils.isPresent("tools.jackson.databind.json.JsonMapper", classLoader);
}
private boolean jacksonContributed;
@Override @Override
public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) { public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) {
@ -79,17 +93,17 @@ class OAuth2AuthorizationServerBeanRegistrationAotProcessor implements BeanRegis
// @formatter:off // @formatter:off
if ((isJdbcBasedOAuth2AuthorizationService || isJdbcBasedRegisteredClientRepository) if ((isJdbcBasedOAuth2AuthorizationService || isJdbcBasedRegisteredClientRepository)
&& !this.jackson2Contributed) { && !this.jacksonContributed) {
Jackson2ConfigurationBeanRegistrationAotContribution jackson2Contribution = JacksonConfigurationBeanRegistrationAotContribution jacksonContribution =
new Jackson2ConfigurationBeanRegistrationAotContribution(); new JacksonConfigurationBeanRegistrationAotContribution();
this.jackson2Contributed = true; this.jacksonContributed = true;
return jackson2Contribution; return jacksonContribution;
} }
// @formatter:on // @formatter:on
return null; return null;
} }
private static class Jackson2ConfigurationBeanRegistrationAotContribution private static class JacksonConfigurationBeanRegistrationAotContribution
implements BeanRegistrationAotContribution { implements BeanRegistrationAotContribution {
private final BindingReflectionHintsRegistrar reflectionHintsRegistrar = new BindingReflectionHintsRegistrar(); private final BindingReflectionHintsRegistrar reflectionHintsRegistrar = new BindingReflectionHintsRegistrar();
@ -109,7 +123,6 @@ class OAuth2AuthorizationServerBeanRegistrationAotProcessor implements BeanRegis
.registerType(HashSet.class, MemberCategory.DECLARED_FIELDS, .registerType(HashSet.class, MemberCategory.DECLARED_FIELDS,
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_DECLARED_METHODS); MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_DECLARED_METHODS);
// Spring Security and Spring Authorization Server
hints.reflection() hints.reflection()
.registerTypes(Arrays.asList(TypeReference.of(AbstractAuthenticationToken.class), .registerTypes(Arrays.asList(TypeReference.of(AbstractAuthenticationToken.class),
TypeReference.of(DefaultSavedRequest.Builder.class), TypeReference.of(DefaultSavedRequest.Builder.class),
@ -128,16 +141,30 @@ class OAuth2AuthorizationServerBeanRegistrationAotProcessor implements BeanRegis
(builder) -> builder.withMembers(MemberCategory.DECLARED_FIELDS, (builder) -> builder.withMembers(MemberCategory.DECLARED_FIELDS,
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_DECLARED_METHODS)); MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_DECLARED_METHODS));
// Jackson Modules - Spring Security and Spring Authorization Server // Jackson Modules
if (jackson2Present) {
hints.reflection() hints.reflection()
.registerTypes( .registerTypes(
Arrays.asList(TypeReference.of(CoreJackson2Module.class), Arrays.asList(TypeReference.of(CoreJackson2Module.class),
TypeReference.of(WebServletJackson2Module.class), TypeReference.of(WebServletJackson2Module.class),
TypeReference.of(OAuth2AuthorizationServerJackson2Module.class)), TypeReference.of(OAuth2AuthorizationServerJackson2Module.class)),
(builder) -> builder.withMembers(MemberCategory.DECLARED_FIELDS, (builder) -> builder.withMembers(MemberCategory.DECLARED_FIELDS,
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_DECLARED_METHODS)); MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
MemberCategory.INVOKE_DECLARED_METHODS));
}
if (jackson3Present) {
hints.reflection()
.registerTypes(
Arrays.asList(TypeReference.of(CoreJacksonModule.class),
TypeReference.of(WebServletJacksonModule.class),
TypeReference.of(OAuth2AuthorizationServerJacksonModule.class)),
(builder) -> builder.withMembers(MemberCategory.DECLARED_FIELDS,
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
MemberCategory.INVOKE_DECLARED_METHODS));
}
// Jackson Mixins - Spring Security and Spring Authorization Server // Jackson Mixins
if (jackson2Present) {
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(), this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
loadClass("org.springframework.security.jackson2.UnmodifiableSetMixin")); loadClass("org.springframework.security.jackson2.UnmodifiableSetMixin"));
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(), this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
@ -166,23 +193,60 @@ class OAuth2AuthorizationServerBeanRegistrationAotProcessor implements BeanRegis
"org.springframework.security.oauth2.server.authorization.jackson2.OAuth2TokenExchangeCompositeAuthenticationTokenMixin")); "org.springframework.security.oauth2.server.authorization.jackson2.OAuth2TokenExchangeCompositeAuthenticationTokenMixin"));
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(), loadClass( this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(), loadClass(
"org.springframework.security.oauth2.server.authorization.jackson2.OAuth2TokenFormatMixin")); "org.springframework.security.oauth2.server.authorization.jackson2.OAuth2TokenFormatMixin"));
}
if (jackson3Present) {
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
loadClass("org.springframework.security.web.jackson.DefaultSavedRequestMixin"));
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
loadClass("org.springframework.security.web.jackson.WebAuthenticationDetailsMixin"));
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
loadClass("org.springframework.security.jackson.UsernamePasswordAuthenticationTokenMixin"));
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
loadClass("org.springframework.security.jackson.UserMixin"));
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
loadClass("org.springframework.security.jackson.SimpleGrantedAuthorityMixin"));
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(), loadClass(
"org.springframework.security.oauth2.server.authorization.jackson.OAuth2TokenExchangeActorMixin"));
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(), loadClass(
"org.springframework.security.oauth2.server.authorization.jackson.OAuth2AuthorizationRequestMixin"));
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(), loadClass(
"org.springframework.security.oauth2.server.authorization.jackson.OAuth2TokenExchangeCompositeAuthenticationTokenMixin"));
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(), loadClass(
"org.springframework.security.oauth2.server.authorization.jackson.OAuth2TokenFormatMixin"));
}
// Check if Spring Security OAuth2 Client is on classpath // Check if OAuth2 Client is on classpath
if (ClassUtils.isPresent("org.springframework.security.oauth2.client.registration.ClientRegistration", if (ClassUtils.isPresent("org.springframework.security.oauth2.client.registration.ClientRegistration",
ClassUtils.getDefaultClassLoader())) { ClassUtils.getDefaultClassLoader())) {
// Jackson Module (and required types) - Spring Security OAuth2 Client
hints.reflection() hints.reflection()
.registerTypes(Arrays.asList( .registerType(TypeReference
TypeReference .of("org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken"),
.of("org.springframework.security.oauth2.client.jackson2.OAuth2ClientJackson2Module"),
TypeReference
.of("org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken")),
(builder) -> builder.withMembers(MemberCategory.DECLARED_FIELDS, (builder) -> builder.withMembers(MemberCategory.DECLARED_FIELDS,
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
MemberCategory.INVOKE_DECLARED_METHODS)); MemberCategory.INVOKE_DECLARED_METHODS));
// Jackson Mixins - Spring Security OAuth2 Client // Jackson Module
if (jackson2Present) {
hints.reflection()
.registerType(TypeReference
.of("org.springframework.security.oauth2.client.jackson2.OAuth2ClientJackson2Module"),
(builder) -> builder.withMembers(MemberCategory.DECLARED_FIELDS,
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
MemberCategory.INVOKE_DECLARED_METHODS));
}
if (jackson3Present) {
hints.reflection()
.registerType(
TypeReference
.of("org.springframework.security.oauth2.client.jackson.OAuth2ClientJacksonModule"),
(builder) -> builder.withMembers(MemberCategory.DECLARED_FIELDS,
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
MemberCategory.INVOKE_DECLARED_METHODS));
}
// Jackson Mixins
if (jackson2Present) {
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(), loadClass( this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(), loadClass(
"org.springframework.security.oauth2.client.jackson2.OAuth2AuthenticationTokenMixin")); "org.springframework.security.oauth2.client.jackson2.OAuth2AuthenticationTokenMixin"));
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(), this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
@ -198,6 +262,23 @@ class OAuth2AuthorizationServerBeanRegistrationAotProcessor implements BeanRegis
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(), this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
loadClass("org.springframework.security.oauth2.client.jackson2.OidcUserInfoMixin")); loadClass("org.springframework.security.oauth2.client.jackson2.OidcUserInfoMixin"));
} }
if (jackson3Present) {
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(), loadClass(
"org.springframework.security.oauth2.client.jackson.OAuth2AuthenticationTokenMixin"));
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
loadClass("org.springframework.security.oauth2.client.jackson.DefaultOidcUserMixin"));
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
loadClass("org.springframework.security.oauth2.client.jackson.DefaultOAuth2UserMixin"));
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
loadClass("org.springframework.security.oauth2.client.jackson.OidcUserAuthorityMixin"));
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
loadClass("org.springframework.security.oauth2.client.jackson.OAuth2UserAuthorityMixin"));
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
loadClass("org.springframework.security.oauth2.client.jackson.OidcIdTokenMixin"));
this.reflectionHintsRegistrar.registerReflectionHints(hints.reflection(),
loadClass("org.springframework.security.oauth2.client.jackson.OidcUserInfoMixin"));
}
}
} }
private static Class<?> loadClass(String className) { private static Class<?> loadClass(String className) {