diff --git a/core/src/main/java/org/springframework/security/jackson/SecurityJacksonModules.java b/core/src/main/java/org/springframework/security/jackson/SecurityJacksonModules.java index 4c5b484b65..5869e9f53a 100644 --- a/core/src/main/java/org/springframework/security/jackson/SecurityJacksonModules.java +++ b/core/src/main/java/org/springframework/security/jackson/SecurityJacksonModules.java @@ -36,10 +36,9 @@ import org.springframework.util.ClassUtils; /** * This utility class will find all the Jackson modules contributed by Spring Security in - * the classpath (except {@code OAuth2AuthorizationServerJacksonModule} and - * {@code WebauthnJacksonModule}), enable automatic inclusion of type information and - * configure a {@link PolymorphicTypeValidator} that handles the validation of class - * names. + * the classpath (except {@code WebauthnJacksonModule}), enable automatic inclusion of + * type information and configure a {@link PolymorphicTypeValidator} that handles the + * validation of class names. * *

*

@@ -77,6 +76,8 @@ public final class SecurityJacksonModules {
 
 	private static final String oauth2ClientJacksonModuleClass = "org.springframework.security.oauth2.client.jackson.OAuth2ClientJacksonModule";
 
+	private static final String oauth2AuthorizationServerJacksonModuleClass = "org.springframework.security.oauth2.server.authorization.jackson.OAuth2AuthorizationServerJacksonModule";
+
 	private static final String ldapJacksonModuleClass = "org.springframework.security.ldap.jackson.LdapJacksonModule";
 
 	private static final String saml2JacksonModuleClass = "org.springframework.security.saml2.jackson.Saml2JacksonModule";
@@ -87,6 +88,8 @@ public final class SecurityJacksonModules {
 
 	private static final boolean oauth2ClientPresent;
 
+	private static final boolean oauth2AuthorizationServerPresent;
+
 	private static final boolean ldapJacksonPresent;
 
 	private static final boolean saml2JacksonPresent;
@@ -94,11 +97,12 @@ public final class SecurityJacksonModules {
 	private static final boolean casJacksonPresent;
 
 	static {
-
 		ClassLoader classLoader = SecurityJacksonModules.class.getClassLoader();
 		webServletPresent = ClassUtils.isPresent("jakarta.servlet.http.Cookie", classLoader);
 		oauth2ClientPresent = ClassUtils.isPresent("org.springframework.security.oauth2.client.OAuth2AuthorizedClient",
 				classLoader);
+		oauth2AuthorizationServerPresent = ClassUtils
+			.isPresent("org.springframework.security.oauth2.server.authorization.OAuth2Authorization", classLoader);
 		ldapJacksonPresent = ClassUtils.isPresent(ldapJacksonModuleClass, classLoader);
 		saml2JacksonPresent = ClassUtils.isPresent(saml2JacksonModuleClass, classLoader);
 		casJacksonPresent = ClassUtils.isPresent(casJacksonModuleClass, classLoader);
@@ -156,6 +160,9 @@ public final class SecurityJacksonModules {
 		if (oauth2ClientPresent) {
 			addToModulesList(loader, modules, oauth2ClientJacksonModuleClass);
 		}
+		if (oauth2AuthorizationServerPresent) {
+			addToModulesList(loader, modules, oauth2AuthorizationServerJacksonModuleClass);
+		}
 		if (ldapJacksonPresent) {
 			addToModulesList(loader, modules, ldapJacksonModuleClass);
 		}
diff --git a/docs/modules/ROOT/pages/features/integrations/jackson.adoc b/docs/modules/ROOT/pages/features/integrations/jackson.adoc
index 1e2cd49fc2..b94fa44396 100644
--- a/docs/modules/ROOT/pages/features/integrations/jackson.adoc
+++ b/docs/modules/ROOT/pages/features/integrations/jackson.adoc
@@ -86,6 +86,7 @@ The following Spring Security modules provide Jackson support:
 - spring-security-core (javadoc:org.springframework.security.jackson.CoreJacksonModule[])
 - spring-security-web (javadoc:org.springframework.security.web.jackson.WebJacksonModule[], javadoc:org.springframework.security.web.jackson.WebServletJacksonModule[], javadoc:org.springframework.security.web.server.jackson.WebServerJacksonModule[])
 - spring-security-oauth2-client (javadoc:org.springframework.security.oauth2.client.jackson.OAuth2ClientJacksonModule[])
+- spring-security-oauth2-authorization-server (javadoc:org.springframework.security.oauth2.server.authorization.jackson.OAuth2AuthorizationServerJacksonModule[])
 - spring-security-cas (javadoc:org.springframework.security.cas.jackson.CasJacksonModule[])
 - spring-security-ldap (javadoc:org.springframework.security.ldap.jackson.LdapJacksonModule[])
 - spring-security-saml2 (javadoc:org.springframework.security.saml2.jackson.Saml2JacksonModule[])
diff --git a/oauth2/oauth2-authorization-server/spring-security-oauth2-authorization-server.gradle b/oauth2/oauth2-authorization-server/spring-security-oauth2-authorization-server.gradle
index beb19bd536..0d19d51df5 100644
--- a/oauth2/oauth2-authorization-server/spring-security-oauth2-authorization-server.gradle
+++ b/oauth2/oauth2-authorization-server/spring-security-oauth2-authorization-server.gradle
@@ -13,9 +13,9 @@ dependencies {
 	api "com.nimbusds:nimbus-jose-jwt"
 	api 'tools.jackson.core:jackson-databind'
 
+	optional "com.fasterxml.jackson.core:jackson-databind"
 	optional "com.fasterxml.jackson.datatype:jackson-datatype-jsr310"
 	optional "org.springframework:spring-jdbc"
-	optional "com.fasterxml.jackson.core:jackson-databind"
 
 	testImplementation project(":spring-security-test")
 	testImplementation project(path : ':spring-security-oauth2-jose', configuration : 'tests')
diff --git a/oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/JdbcOAuth2AuthorizationService.java b/oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/JdbcOAuth2AuthorizationService.java
index 45018582ec..1d4ee29083 100644
--- a/oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/JdbcOAuth2AuthorizationService.java
+++ b/oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/JdbcOAuth2AuthorizationService.java
@@ -68,7 +68,6 @@ import org.springframework.security.oauth2.core.oidc.OidcIdToken;
 import org.springframework.security.oauth2.core.oidc.endpoint.OidcParameterNames;
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
-import org.springframework.security.oauth2.server.authorization.jackson.OAuth2AuthorizationServerJacksonModule;
 import org.springframework.security.oauth2.server.authorization.jackson2.OAuth2AuthorizationServerJackson2Module;
 import org.springframework.util.Assert;
 import org.springframework.util.CollectionUtils;
@@ -361,7 +360,7 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 	/**
 	 * Sets the {@link RowMapper} used for mapping the current row in
 	 * {@code java.sql.ResultSet} to {@link OAuth2Authorization}. The default is
-	 * {@link OAuth2AuthorizationRowMapper}.
+	 * {@link JsonMapperOAuth2AuthorizationRowMapper}.
 	 * @param authorizationRowMapper the {@link RowMapper} used for mapping the current
 	 * row in {@code ResultSet} to {@link OAuth2Authorization}
 	 */
@@ -373,7 +372,7 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 	/**
 	 * Sets the {@code Function} used for mapping {@link OAuth2Authorization} to a
 	 * {@code List} of {@link SqlParameterValue}. The default is
-	 * {@link OAuth2AuthorizationParametersMapper}.
+	 * {@link JsonMapperOAuth2AuthorizationParametersMapper}.
 	 * @param authorizationParametersMapper the {@code Function} used for mapping
 	 * {@link OAuth2Authorization} to a {@code List} of {@link SqlParameterValue}
 	 */
@@ -743,10 +742,7 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
 
 		static JsonMapper createJsonMapper() {
 			List modules = SecurityJacksonModules.getModules(Jackson3.class.getClassLoader());
-			return JsonMapper.builder()
-				.addModules(modules)
-				.addModules(new OAuth2AuthorizationServerJacksonModule())
-				.build();
+			return JsonMapper.builder().addModules(modules).build();
 		}
 
 	}
diff --git a/oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/jackson/OAuth2AuthorizationServerJacksonModule.java b/oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/jackson/OAuth2AuthorizationServerJacksonModule.java
index fd8b1b8d6a..ea23b1336e 100644
--- a/oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/jackson/OAuth2AuthorizationServerJacksonModule.java
+++ b/oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/jackson/OAuth2AuthorizationServerJacksonModule.java
@@ -18,13 +18,11 @@ package org.springframework.security.oauth2.server.authorization.jackson;
 
 import java.net.URL;
 
-import com.fasterxml.jackson.annotation.JsonTypeInfo;
 import tools.jackson.core.Version;
-import tools.jackson.databind.DefaultTyping;
-import tools.jackson.databind.cfg.MapperBuilder;
 import tools.jackson.databind.jsontype.BasicPolymorphicTypeValidator;
 
-import org.springframework.security.jackson.CoreJacksonModule;
+import org.springframework.security.jackson.SecurityJacksonModule;
+import org.springframework.security.jackson.SecurityJacksonModules;
 import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
 import org.springframework.security.oauth2.jose.jws.MacAlgorithm;
 import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
@@ -37,20 +35,22 @@ import org.springframework.security.oauth2.server.authorization.settings.OAuth2T
  * registers the following mix-in annotations:
  *
  * 
  *
- * If not already enabled, default typing will be automatically enabled as type info is
- * required to properly serialize/deserialize objects. In order to use this module just
- * add it to your {@code JsonMapper.Builder} configuration.
+ * 

+ * The recommended way to configure it is to use {@link SecurityJacksonModules} in order + * to enable properly automatic inclusion of type information with related validation. * *

+ *     ClassLoader loader = getClass().getClassLoader();
  *     JsonMapper mapper = JsonMapper.builder()
- *             .addModules(new OAuth2AuthorizationServerJacksonModule()).build;
+ * 				.addModules(SecurityJacksonModules.getModules(loader))
+ * 				.build();
  * 
* * @author Sebastien Deleuze @@ -58,7 +58,7 @@ import org.springframework.security.oauth2.server.authorization.settings.OAuth2T * @since 7.0 */ @SuppressWarnings("serial") -public class OAuth2AuthorizationServerJacksonModule extends CoreJacksonModule { +public class OAuth2AuthorizationServerJacksonModule extends SecurityJacksonModule { public OAuth2AuthorizationServerJacksonModule() { super(OAuth2AuthorizationServerJacksonModule.class.getName(), new Version(1, 0, 0, null, null, null)); @@ -66,7 +66,6 @@ public class OAuth2AuthorizationServerJacksonModule extends CoreJacksonModule { @Override public void configurePolymorphicTypeValidator(BasicPolymorphicTypeValidator.Builder builder) { - super.configurePolymorphicTypeValidator(builder); builder.allowIfSubType(OAuth2TokenFormat.class) .allowIfSubType(OAuth2TokenExchangeActor.class) .allowIfSubType(OAuth2TokenExchangeCompositeAuthenticationToken.class) @@ -78,11 +77,6 @@ public class OAuth2AuthorizationServerJacksonModule extends CoreJacksonModule { @Override public void setupModule(SetupContext context) { - super.setupModule(context); - BasicPolymorphicTypeValidator.Builder builder = BasicPolymorphicTypeValidator.builder(); - this.configurePolymorphicTypeValidator(builder); - ((MapperBuilder) context.getOwner()).activateDefaultTyping(builder.build(), DefaultTyping.NON_FINAL, - JsonTypeInfo.As.PROPERTY); context.setMixIn(OAuth2TokenExchangeActor.class, OAuth2TokenExchangeActorMixin.class); context.setMixIn(OAuth2AuthorizationRequest.class, OAuth2AuthorizationRequestMixin.class); context.setMixIn(OAuth2TokenExchangeCompositeAuthenticationToken.class, diff --git a/oauth2/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/JdbcOAuth2AuthorizationServiceTests.java b/oauth2/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/JdbcOAuth2AuthorizationServiceTests.java index 8d428a2fb2..04f7a9a310 100644 --- a/oauth2/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/JdbcOAuth2AuthorizationServiceTests.java +++ b/oauth2/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/JdbcOAuth2AuthorizationServiceTests.java @@ -16,6 +16,7 @@ package org.springframework.security.oauth2.server.authorization; +import java.security.Principal; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Timestamp; @@ -45,6 +46,7 @@ import org.springframework.jdbc.core.SqlParameterValue; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; +import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.jackson.SecurityJacksonModules; import org.springframework.security.oauth2.core.AuthorizationGrantType; import org.springframework.security.oauth2.core.OAuth2AccessToken; @@ -58,6 +60,7 @@ import org.springframework.security.oauth2.core.oidc.endpoint.OidcParameterNames import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository; import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients; +import org.springframework.security.web.authentication.WebAuthenticationDetails; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; @@ -227,10 +230,11 @@ public class JdbcOAuth2AuthorizationServiceTests { .build(); RowMapper authorizationRowMapper = spy( - new JdbcOAuth2AuthorizationService.OAuth2AuthorizationRowMapper(this.registeredClientRepository)); + new JdbcOAuth2AuthorizationService.JsonMapperOAuth2AuthorizationRowMapper( + this.registeredClientRepository)); this.authorizationService.setAuthorizationRowMapper(authorizationRowMapper); Function> authorizationParametersMapper = spy( - new JdbcOAuth2AuthorizationService.OAuth2AuthorizationParametersMapper()); + new JdbcOAuth2AuthorizationService.JsonMapperOAuth2AuthorizationParametersMapper()); this.authorizationService.setAuthorizationParametersMapper(authorizationParametersMapper); this.authorizationService.save(originalAuthorization); @@ -461,6 +465,28 @@ public class JdbcOAuth2AuthorizationServiceTests { assertThat(result).isNull(); } + // gh-18102 + @Test + public void findByTokenWhenPrincipalHasWebAuthenticationDetailsThenDeserializes() { + given(this.registeredClientRepository.findById(eq(REGISTERED_CLIENT.getId()))).willReturn(REGISTERED_CLIENT); + + String state = "state"; + TestingAuthenticationToken principal = new TestingAuthenticationToken(PRINCIPAL_NAME, "credentials"); + principal.setDetails(new WebAuthenticationDetails("remoteAddress", "sessionId")); + + OAuth2Authorization authorization = OAuth2Authorization.withRegisteredClient(REGISTERED_CLIENT) + .id(ID) + .principalName(PRINCIPAL_NAME) + .authorizationGrantType(AUTHORIZATION_GRANT_TYPE) + .attribute(OAuth2ParameterNames.STATE, state) + .attribute(Principal.class.getName(), principal) + .build(); + this.authorizationService.save(authorization); + + OAuth2Authorization result = this.authorizationService.findByToken(state, STATE_TOKEN_TYPE); + assertThat(authorization).isEqualTo(result); + } + @Test public void tableDefinitionWhenCustomThenAbleToOverride() { given(this.registeredClientRepository.findById(eq(REGISTERED_CLIENT.getId()))).willReturn(REGISTERED_CLIENT); diff --git a/oauth2/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/jackson/OAuth2AuthorizationServerJacksonModuleTests.java b/oauth2/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/jackson/OAuth2AuthorizationServerJacksonModuleTests.java index 00b3cb8662..baa8b47cd4 100644 --- a/oauth2/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/jackson/OAuth2AuthorizationServerJacksonModuleTests.java +++ b/oauth2/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/jackson/OAuth2AuthorizationServerJacksonModuleTests.java @@ -27,20 +27,20 @@ import tools.jackson.databind.json.JsonMapper; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; +import org.springframework.security.jackson.SecurityJacksonModules; import org.springframework.security.oauth2.jose.jws.MacAlgorithm; import org.springframework.security.oauth2.jwt.JwtClaimNames; import org.springframework.security.oauth2.server.authorization.OAuth2Authorization; import org.springframework.security.oauth2.server.authorization.TestOAuth2Authorizations; 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.jackson2.OAuth2AuthorizationServerJackson2Module; import org.springframework.security.oauth2.server.authorization.settings.ClientSettings; import org.springframework.security.oauth2.server.authorization.settings.TokenSettings; import static org.assertj.core.api.Assertions.assertThat; /** - * Tests for {@link OAuth2AuthorizationServerJackson2Module}. + * Tests for {@link OAuth2AuthorizationServerJacksonModule}. * * @author Steve Riesenberg * @author Joe Grandja @@ -55,7 +55,9 @@ public class OAuth2AuthorizationServerJacksonModuleTests { @BeforeEach public void setup() { - this.mapper = JsonMapper.builder().addModules(new OAuth2AuthorizationServerJacksonModule()).build(); + this.mapper = JsonMapper.builder() + .addModules(SecurityJacksonModules.getModules(getClass().getClassLoader())) + .build(); } @Test