From 5e851e0b2628088290e8d1646f69931219df9ae3 Mon Sep 17 00:00:00 2001 From: Rob Winch <362503+rwinch@users.noreply.github.com> Date: Fri, 17 Oct 2025 13:47:27 -0500 Subject: [PATCH] Remove JdbcOAuth2AuthorizationService.Mapper - We should not introduce an unnecessary public API - It would need to be removed when Jackson 2 support was removed, but was required to configure Jackson 3 support - There are already existing interfaces that could be used - OAuth2AuthorizationRowMapper & OAuth2AuthorizationParametersMapper had unnecessary breaking changes by removing getter/setter for ObjectMapper - To prevent NoClassDefFoundErrors all optional (Jackson) dependencies need to be on different classes & we wish to preserve the existing accessors for ObjectMapper which is this uses subclasses - With added TestAuthenticationTokenMixin support, no need to explicitly add it in tests --- .../server/authorization/JwkSetTests.java | 29 +- .../OAuth2AuthorizationCodeGrantTests.java | 28 +- .../OAuth2ClientCredentialsGrantTests.java | 29 +- .../OAuth2RefreshTokenGrantTests.java | 29 +- .../OAuth2TokenIntrospectionTests.java | 29 +- .../OAuth2TokenRevocationTests.java | 29 +- .../server/authorization/OidcTests.java | 29 +- etc/checkstyle/checkstyle-suppressions.xml | 1 + .../JdbcOAuth2AuthorizationService.java | 283 +++++++++++------- .../JdbcOAuth2AuthorizationServiceTests.java | 19 +- 10 files changed, 198 insertions(+), 307 deletions(-) diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/JwkSetTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/JwkSetTests.java index 663b279c00..291ec87adf 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/JwkSetTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/JwkSetTests.java @@ -24,7 +24,6 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import tools.jackson.databind.json.JsonMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; @@ -35,7 +34,6 @@ import org.springframework.jdbc.core.JdbcTemplate; 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.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration; import org.springframework.security.config.test.SpringTestContext; @@ -45,7 +43,6 @@ import org.springframework.security.oauth2.server.authorization.JdbcOAuth2Author import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService; import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository; import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository; -import org.springframework.security.oauth2.server.authorization.jackson2.TestingAuthenticationTokenMixin; import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings; import org.springframework.test.web.servlet.MockMvc; @@ -142,11 +139,7 @@ public class JwkSetTests { @Bean OAuth2AuthorizationService authorizationService(JdbcOperations jdbcOperations, RegisteredClientRepository registeredClientRepository) { - JdbcOAuth2AuthorizationService authorizationService = new JdbcOAuth2AuthorizationService(jdbcOperations, - registeredClientRepository); - authorizationService.setAuthorizationRowMapper(new RowMapper(registeredClientRepository)); - authorizationService.setAuthorizationParametersMapper(new ParametersMapper()); - return authorizationService; + return new JdbcOAuth2AuthorizationService(jdbcOperations, registeredClientRepository); } @Bean @@ -164,26 +157,6 @@ public class JwkSetTests { return jwkSource; } - static class RowMapper extends JdbcOAuth2AuthorizationService.OAuth2AuthorizationRowMapper { - - RowMapper(RegisteredClientRepository registeredClientRepository) { - super(registeredClientRepository); - setMapper(new JdbcOAuth2AuthorizationService.JacksonDelegate(JsonMapper.builder() - .addMixIn(TestingAuthenticationToken.class, TestingAuthenticationTokenMixin.class))); - } - - } - - static class ParametersMapper extends JdbcOAuth2AuthorizationService.OAuth2AuthorizationParametersMapper { - - ParametersMapper() { - super(); - setMapper(new JdbcOAuth2AuthorizationService.JacksonDelegate(JsonMapper.builder() - .addMixIn(TestingAuthenticationToken.class, TestingAuthenticationTokenMixin.class))); - } - - } - } @EnableWebSecurity diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2AuthorizationCodeGrantTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2AuthorizationCodeGrantTests.java index 83d2b98250..7b485487d8 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2AuthorizationCodeGrantTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2AuthorizationCodeGrantTests.java @@ -46,7 +46,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; -import tools.jackson.databind.json.JsonMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; @@ -117,7 +116,6 @@ import org.springframework.security.oauth2.server.authorization.client.JdbcRegis 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.oauth2.server.authorization.jackson2.TestingAuthenticationTokenMixin; import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings; import org.springframework.security.oauth2.server.authorization.settings.ClientSettings; import org.springframework.security.oauth2.server.authorization.token.DelegatingOAuth2TokenGenerator; @@ -1240,11 +1238,7 @@ public class OAuth2AuthorizationCodeGrantTests { @Bean OAuth2AuthorizationService authorizationService(JdbcOperations jdbcOperations, RegisteredClientRepository registeredClientRepository) { - JdbcOAuth2AuthorizationService authorizationService = new JdbcOAuth2AuthorizationService(jdbcOperations, - registeredClientRepository); - authorizationService.setAuthorizationRowMapper(new RowMapper(registeredClientRepository)); - authorizationService.setAuthorizationParametersMapper(new ParametersMapper()); - return authorizationService; + return new JdbcOAuth2AuthorizationService(jdbcOperations, registeredClientRepository); } @Bean @@ -1297,26 +1291,6 @@ public class OAuth2AuthorizationCodeGrantTests { return NoOpPasswordEncoder.getInstance(); } - static class RowMapper extends JdbcOAuth2AuthorizationService.OAuth2AuthorizationRowMapper { - - RowMapper(RegisteredClientRepository registeredClientRepository) { - super(registeredClientRepository); - setMapper(new JdbcOAuth2AuthorizationService.JacksonDelegate(JsonMapper.builder() - .addMixIn(TestingAuthenticationToken.class, TestingAuthenticationTokenMixin.class))); - } - - } - - static class ParametersMapper extends JdbcOAuth2AuthorizationService.OAuth2AuthorizationParametersMapper { - - ParametersMapper() { - super(); - setMapper(new JdbcOAuth2AuthorizationService.JacksonDelegate(JsonMapper.builder() - .addMixIn(TestingAuthenticationToken.class, TestingAuthenticationTokenMixin.class))); - } - - } - } @EnableWebSecurity diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2ClientCredentialsGrantTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2ClientCredentialsGrantTests.java index f60511156b..6e0dc3ae83 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2ClientCredentialsGrantTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2ClientCredentialsGrantTests.java @@ -40,7 +40,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; -import tools.jackson.databind.json.JsonMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; @@ -53,7 +52,6 @@ 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.AuthenticationProvider; -import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration; @@ -94,7 +92,6 @@ import org.springframework.security.oauth2.server.authorization.client.JdbcRegis 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.oauth2.server.authorization.jackson2.TestingAuthenticationTokenMixin; import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings; import org.springframework.security.oauth2.server.authorization.settings.ClientSettings; import org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext; @@ -534,11 +531,7 @@ public class OAuth2ClientCredentialsGrantTests { @Bean OAuth2AuthorizationService authorizationService(JdbcOperations jdbcOperations, RegisteredClientRepository registeredClientRepository) { - JdbcOAuth2AuthorizationService authorizationService = new JdbcOAuth2AuthorizationService(jdbcOperations, - registeredClientRepository); - authorizationService.setAuthorizationRowMapper(new RowMapper(registeredClientRepository)); - authorizationService.setAuthorizationParametersMapper(new ParametersMapper()); - return authorizationService; + return new JdbcOAuth2AuthorizationService(jdbcOperations, registeredClientRepository); } @Bean @@ -570,26 +563,6 @@ public class OAuth2ClientCredentialsGrantTests { return NoOpPasswordEncoder.getInstance(); } - static class RowMapper extends JdbcOAuth2AuthorizationService.OAuth2AuthorizationRowMapper { - - RowMapper(RegisteredClientRepository registeredClientRepository) { - super(registeredClientRepository); - setMapper(new JdbcOAuth2AuthorizationService.JacksonDelegate(JsonMapper.builder() - .addMixIn(TestingAuthenticationToken.class, TestingAuthenticationTokenMixin.class))); - } - - } - - static class ParametersMapper extends JdbcOAuth2AuthorizationService.OAuth2AuthorizationParametersMapper { - - ParametersMapper() { - super(); - setMapper(new JdbcOAuth2AuthorizationService.JacksonDelegate(JsonMapper.builder() - .addMixIn(TestingAuthenticationToken.class, TestingAuthenticationTokenMixin.class))); - } - - } - } @EnableWebSecurity diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2RefreshTokenGrantTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2RefreshTokenGrantTests.java index 5f01cea6c2..16df4207b9 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2RefreshTokenGrantTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2RefreshTokenGrantTests.java @@ -39,7 +39,6 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import tools.jackson.databind.json.JsonMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; @@ -57,7 +56,6 @@ import org.springframework.lang.Nullable; import org.springframework.mock.http.client.MockClientHttpResponse; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.security.authentication.AuthenticationProvider; -import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration; @@ -99,7 +97,6 @@ import org.springframework.security.oauth2.server.authorization.client.JdbcRegis 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.oauth2.server.authorization.jackson2.TestingAuthenticationTokenMixin; import org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext; import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer; import org.springframework.security.web.SecurityFilterChain; @@ -468,11 +465,7 @@ public class OAuth2RefreshTokenGrantTests { @Bean OAuth2AuthorizationService authorizationService(JdbcOperations jdbcOperations, RegisteredClientRepository registeredClientRepository) { - JdbcOAuth2AuthorizationService authorizationService = new JdbcOAuth2AuthorizationService(jdbcOperations, - registeredClientRepository); - authorizationService.setAuthorizationRowMapper(new RowMapper(registeredClientRepository)); - authorizationService.setAuthorizationParametersMapper(new ParametersMapper()); - return authorizationService; + return new JdbcOAuth2AuthorizationService(jdbcOperations, registeredClientRepository); } @Bean @@ -513,26 +506,6 @@ public class OAuth2RefreshTokenGrantTests { return NoOpPasswordEncoder.getInstance(); } - static class RowMapper extends JdbcOAuth2AuthorizationService.OAuth2AuthorizationRowMapper { - - RowMapper(RegisteredClientRepository registeredClientRepository) { - super(registeredClientRepository); - setMapper(new JdbcOAuth2AuthorizationService.JacksonDelegate(JsonMapper.builder() - .addMixIn(TestingAuthenticationToken.class, TestingAuthenticationTokenMixin.class))); - } - - } - - static class ParametersMapper extends JdbcOAuth2AuthorizationService.OAuth2AuthorizationParametersMapper { - - ParametersMapper() { - super(); - setMapper(new JdbcOAuth2AuthorizationService.JacksonDelegate(JsonMapper.builder() - .addMixIn(TestingAuthenticationToken.class, TestingAuthenticationTokenMixin.class))); - } - - } - } @EnableWebSecurity diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2TokenIntrospectionTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2TokenIntrospectionTests.java index 018ca4ad36..e4bd35d062 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2TokenIntrospectionTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2TokenIntrospectionTests.java @@ -35,7 +35,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; -import tools.jackson.databind.json.JsonMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; @@ -52,7 +51,6 @@ import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; import org.springframework.mock.http.client.MockClientHttpResponse; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.security.authentication.AuthenticationProvider; -import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration; @@ -88,7 +86,6 @@ import org.springframework.security.oauth2.server.authorization.client.Registere import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository; import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients; import org.springframework.security.oauth2.server.authorization.http.converter.OAuth2TokenIntrospectionHttpMessageConverter; -import org.springframework.security.oauth2.server.authorization.jackson2.TestingAuthenticationTokenMixin; import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings; import org.springframework.security.oauth2.server.authorization.settings.ClientSettings; import org.springframework.security.oauth2.server.authorization.settings.OAuth2TokenFormat; @@ -508,11 +505,7 @@ public class OAuth2TokenIntrospectionTests { @Bean OAuth2AuthorizationService authorizationService(JdbcOperations jdbcOperations, RegisteredClientRepository registeredClientRepository) { - JdbcOAuth2AuthorizationService authorizationService = new JdbcOAuth2AuthorizationService(jdbcOperations, - registeredClientRepository); - authorizationService.setAuthorizationRowMapper(new RowMapper(registeredClientRepository)); - authorizationService.setAuthorizationParametersMapper(new ParametersMapper()); - return authorizationService; + return new JdbcOAuth2AuthorizationService(jdbcOperations, registeredClientRepository); } @Bean @@ -550,26 +543,6 @@ public class OAuth2TokenIntrospectionTests { return NoOpPasswordEncoder.getInstance(); } - static class RowMapper extends JdbcOAuth2AuthorizationService.OAuth2AuthorizationRowMapper { - - RowMapper(RegisteredClientRepository registeredClientRepository) { - super(registeredClientRepository); - setMapper(new JdbcOAuth2AuthorizationService.JacksonDelegate(JsonMapper.builder() - .addMixIn(TestingAuthenticationToken.class, TestingAuthenticationTokenMixin.class))); - } - - } - - static class ParametersMapper extends JdbcOAuth2AuthorizationService.OAuth2AuthorizationParametersMapper { - - ParametersMapper() { - super(); - setMapper(new JdbcOAuth2AuthorizationService.JacksonDelegate(JsonMapper.builder() - .addMixIn(TestingAuthenticationToken.class, TestingAuthenticationTokenMixin.class))); - } - - } - } @EnableWebSecurity diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2TokenRevocationTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2TokenRevocationTests.java index 5506c81607..8ff0e389f1 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2TokenRevocationTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2TokenRevocationTests.java @@ -31,7 +31,6 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; -import tools.jackson.databind.json.JsonMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; @@ -44,7 +43,6 @@ 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.AuthenticationProvider; -import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration; @@ -72,7 +70,6 @@ import org.springframework.security.oauth2.server.authorization.client.JdbcRegis 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.oauth2.server.authorization.jackson2.TestingAuthenticationTokenMixin; import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings; import org.springframework.security.oauth2.server.authorization.web.authentication.OAuth2TokenRevocationAuthenticationConverter; import org.springframework.security.web.SecurityFilterChain; @@ -317,11 +314,7 @@ public class OAuth2TokenRevocationTests { @Bean OAuth2AuthorizationService authorizationService(JdbcOperations jdbcOperations, RegisteredClientRepository registeredClientRepository) { - JdbcOAuth2AuthorizationService authorizationService = new JdbcOAuth2AuthorizationService(jdbcOperations, - registeredClientRepository); - authorizationService.setAuthorizationRowMapper(new RowMapper(registeredClientRepository)); - authorizationService.setAuthorizationParametersMapper(new ParametersMapper()); - return authorizationService; + return new JdbcOAuth2AuthorizationService(jdbcOperations, registeredClientRepository); } @Bean @@ -348,26 +341,6 @@ public class OAuth2TokenRevocationTests { return NoOpPasswordEncoder.getInstance(); } - static class RowMapper extends JdbcOAuth2AuthorizationService.OAuth2AuthorizationRowMapper { - - RowMapper(RegisteredClientRepository registeredClientRepository) { - super(registeredClientRepository); - setMapper(new JdbcOAuth2AuthorizationService.JacksonDelegate(JsonMapper.builder() - .addMixIn(TestingAuthenticationToken.class, TestingAuthenticationTokenMixin.class))); - } - - } - - static class ParametersMapper extends JdbcOAuth2AuthorizationService.OAuth2AuthorizationParametersMapper { - - ParametersMapper() { - super(); - setMapper(new JdbcOAuth2AuthorizationService.JacksonDelegate(JsonMapper.builder() - .addMixIn(TestingAuthenticationToken.class, TestingAuthenticationTokenMixin.class))); - } - - } - } @EnableWebSecurity diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OidcTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OidcTests.java index 354c3a3926..34984b8fa8 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OidcTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OidcTests.java @@ -36,7 +36,6 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import tools.jackson.databind.json.JsonMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; @@ -53,7 +52,6 @@ import org.springframework.lang.Nullable; import org.springframework.mock.http.client.MockClientHttpResponse; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockHttpSession; -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; @@ -91,7 +89,6 @@ import org.springframework.security.oauth2.server.authorization.client.JdbcRegis 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.oauth2.server.authorization.jackson2.TestingAuthenticationTokenMixin; import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings; import org.springframework.security.oauth2.server.authorization.token.DelegatingOAuth2TokenGenerator; import org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext; @@ -632,11 +629,7 @@ public class OidcTests { @Bean OAuth2AuthorizationService authorizationService(JdbcOperations jdbcOperations, RegisteredClientRepository registeredClientRepository) { - JdbcOAuth2AuthorizationService authorizationService = new JdbcOAuth2AuthorizationService(jdbcOperations, - registeredClientRepository); - authorizationService.setAuthorizationRowMapper(new RowMapper(registeredClientRepository)); - authorizationService.setAuthorizationParametersMapper(new ParametersMapper()); - return authorizationService; + return new JdbcOAuth2AuthorizationService(jdbcOperations, registeredClientRepository); } @Bean @@ -692,26 +685,6 @@ public class OidcTests { return sessionRegistry; } - static class RowMapper extends JdbcOAuth2AuthorizationService.OAuth2AuthorizationRowMapper { - - RowMapper(RegisteredClientRepository registeredClientRepository) { - super(registeredClientRepository); - setMapper(new JdbcOAuth2AuthorizationService.JacksonDelegate(JsonMapper.builder() - .addMixIn(TestingAuthenticationToken.class, TestingAuthenticationTokenMixin.class))); - } - - } - - static class ParametersMapper extends JdbcOAuth2AuthorizationService.OAuth2AuthorizationParametersMapper { - - ParametersMapper() { - super(); - setMapper(new JdbcOAuth2AuthorizationService.JacksonDelegate(JsonMapper.builder() - .addMixIn(TestingAuthenticationToken.class, TestingAuthenticationTokenMixin.class))); - } - - } - } @EnableWebSecurity diff --git a/etc/checkstyle/checkstyle-suppressions.xml b/etc/checkstyle/checkstyle-suppressions.xml index 0f48fa1a0e..4dd1798f5a 100644 --- a/etc/checkstyle/checkstyle-suppressions.xml +++ b/etc/checkstyle/checkstyle-suppressions.xml @@ -24,6 +24,7 @@ + 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 1af8933a49..45018582ec 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 @@ -71,7 +71,6 @@ import org.springframework.security.oauth2.server.authorization.client.Registere 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.ClassUtils; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; @@ -245,11 +244,11 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic Assert.notNull(lobHandler, "lobHandler cannot be null"); this.jdbcOperations = jdbcOperations; this.lobHandler = lobHandler; - OAuth2AuthorizationRowMapper authorizationRowMapper = new OAuth2AuthorizationRowMapper( + JsonMapperOAuth2AuthorizationRowMapper authorizationRowMapper = new JsonMapperOAuth2AuthorizationRowMapper( registeredClientRepository); authorizationRowMapper.setLobHandler(lobHandler); this.authorizationRowMapper = authorizationRowMapper; - this.authorizationParametersMapper = new OAuth2AuthorizationParametersMapper(); + this.authorizationParametersMapper = new JsonMapperOAuth2AuthorizationParametersMapper(); initColumnMetadata(jdbcOperations); } @@ -467,18 +466,86 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic /** * The default {@link RowMapper} that maps the current row in - * {@code java.sql.ResultSet} to {@link OAuth2Authorization}. + * {@code java.sql.ResultSet} to {@link OAuth2Authorization} using Jackson 3's + * {@link JsonMapper} to read all {@code Map} within the result. + * + * @author Rob Winch + * @since 7.0 */ - public static class OAuth2AuthorizationRowMapper implements RowMapper { + public static class JsonMapperOAuth2AuthorizationRowMapper extends AbstractOAuth2AuthorizationRowMapper { + + private final JsonMapper jsonMapper; + + public JsonMapperOAuth2AuthorizationRowMapper(RegisteredClientRepository registeredClientRepository) { + this(registeredClientRepository, Jackson3.createJsonMapper()); + } + + public JsonMapperOAuth2AuthorizationRowMapper(RegisteredClientRepository registeredClientRepository, + JsonMapper jsonMapper) { + super(registeredClientRepository); + this.jsonMapper = jsonMapper; + } + + @Override + Map readValue(String data) { + final ParameterizedTypeReference> typeReference = new ParameterizedTypeReference<>() { + }; + tools.jackson.databind.JavaType javaType = this.jsonMapper.getTypeFactory() + .constructType(typeReference.getType()); + return this.jsonMapper.readValue(data, javaType); + } + + } + + /** + * A {@link RowMapper} that maps the current row in {@code java.sql.ResultSet} to + * {@link OAuth2Authorization} using Jackson 2's {@link ObjectMapper}. + * + * @deprecated Use {@link JsonMapperOAuth2AuthorizationRowMapper} to switch to Jackson + * 3. + */ + @Deprecated(forRemoval = true, since = "7.0") + public static class OAuth2AuthorizationRowMapper extends AbstractOAuth2AuthorizationRowMapper { + + private ObjectMapper objectMapper = Jackson2.createObjectMapper(); + + public OAuth2AuthorizationRowMapper(RegisteredClientRepository registeredClientRepository) { + super(registeredClientRepository); + } + + public final void setObjectMapper(ObjectMapper objectMapper) { + Assert.notNull(objectMapper, "objectMapper cannot be null"); + this.objectMapper = objectMapper; + } + + protected ObjectMapper getObjectMapper() { + return this.objectMapper; + } + + @Override + Map readValue(String data) throws JsonProcessingException { + final ParameterizedTypeReference> typeReference = new ParameterizedTypeReference<>() { + }; + com.fasterxml.jackson.databind.JavaType javaType = this.objectMapper.getTypeFactory() + .constructType(typeReference.getType()); + return this.objectMapper.readValue(data, javaType); + } + + } + + /** + * The base {@link RowMapper} that maps the current row in {@code java.sql.ResultSet} + * to {@link OAuth2Authorization}. This is extracted to a distinct class so that + * {@link OAuth2AuthorizationRowMapper} can be deprecated in favor of + * {@link JsonMapperOAuth2AuthorizationRowMapper}. + */ + private abstract static class AbstractOAuth2AuthorizationRowMapper implements RowMapper { private final RegisteredClientRepository registeredClientRepository; private LobHandler lobHandler = new DefaultLobHandler(); - private Mapper mapper = (ClassUtils.isPresent("tools.jackson.databind.json.JsonMapper", - OAuth2AuthorizationRowMapper.class.getClassLoader())) ? new JacksonDelegate() : new Jackson2Delegate(); - - public OAuth2AuthorizationRowMapper(RegisteredClientRepository registeredClientRepository) { + AbstractOAuth2AuthorizationRowMapper(RegisteredClientRepository registeredClientRepository) { Assert.notNull(registeredClientRepository, "registeredClientRepository cannot be null"); this.registeredClientRepository = registeredClientRepository; } @@ -625,11 +692,6 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic this.lobHandler = lobHandler; } - public final void setMapper(Mapper mapper) { - Assert.notNull(mapper, "objectMapper cannot be null"); - this.mapper = mapper; - } - protected final RegisteredClientRepository getRegisteredClientRepository() { return this.registeredClientRepository; } @@ -638,33 +700,116 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic return this.lobHandler; } - protected final Mapper getMapper() { - return this.mapper; - } - private Map parseMap(String data) { try { - return this.mapper.readValue(data, new ParameterizedTypeReference<>() { - }); + return readValue(data); } catch (Exception ex) { throw new IllegalArgumentException(ex.getMessage(), ex); } } + abstract Map readValue(String data) throws Exception; + + } + + /** + * Nested class to protect from getting {@link NoClassDefFoundError} when Jackson 2 is + * not on the classpath. + * + * @deprecated This is used to allow transition to Jackson 3. Use {@link Jackson3} + * instead. + */ + @Deprecated(forRemoval = true, since = "7.0") + private static final class Jackson2 { + + static ObjectMapper createObjectMapper() { + ObjectMapper objectMapper = new ObjectMapper(); + ClassLoader classLoader = Jackson2.class.getClassLoader(); + List securityModules = SecurityJackson2Modules.getModules(classLoader); + objectMapper.registerModules(securityModules); + objectMapper.registerModule(new OAuth2AuthorizationServerJackson2Module()); + return objectMapper; + } + + } + + /** + * Nested class used to get a common default instance of {@link JsonMapper}. It is in + * a nested class to protect from getting {@link NoClassDefFoundError} when Jackson 3 + * is not on the classpath. + */ + private static final class Jackson3 { + + static JsonMapper createJsonMapper() { + List modules = SecurityJacksonModules.getModules(Jackson3.class.getClassLoader()); + return JsonMapper.builder() + .addModules(modules) + .addModules(new OAuth2AuthorizationServerJacksonModule()) + .build(); + } + + } + + /** + * @deprecated Use {@link JsonMapperOAuth2AuthorizationParametersMapper} to migrate to + * Jackson 3. + */ + @Deprecated(forRemoval = true, since = "7.0") + public static class OAuth2AuthorizationParametersMapper extends AbstractOAuth2AuthorizationParametersMapper { + + private ObjectMapper objectMapper = Jackson2.createObjectMapper(); + + @Override + String writeValueAsString(Map data) throws JsonProcessingException { + return this.objectMapper.writeValueAsString(data); + } + + protected final ObjectMapper getObjectMapper() { + return this.objectMapper; + } + + public final void setObjectMapper(ObjectMapper objectMapper) { + Assert.notNull(objectMapper, "objectMapper cannot be null"); + this.objectMapper = objectMapper; + } + } /** * The default {@code Function} that maps {@link OAuth2Authorization} to a - * {@code List} of {@link SqlParameterValue}. + * {@code List} of {@link SqlParameterValue} using an instance of Jackson 3's + * {@link JsonMapper}. */ - public static class OAuth2AuthorizationParametersMapper + public static final class JsonMapperOAuth2AuthorizationParametersMapper + extends AbstractOAuth2AuthorizationParametersMapper { + + private final JsonMapper mapper; + + public JsonMapperOAuth2AuthorizationParametersMapper() { + this(Jackson3.createJsonMapper()); + } + + public JsonMapperOAuth2AuthorizationParametersMapper(JsonMapper mapper) { + Assert.notNull(mapper, "mapper cannot be null"); + this.mapper = mapper; + } + + @Override + String writeValueAsString(Map data) throws Exception { + return this.mapper.writeValueAsString(data); + } + + } + + /** + * The base {@code Function} that maps {@link OAuth2Authorization} to a {@code List} + * of {@link SqlParameterValue}. + */ + private abstract static class AbstractOAuth2AuthorizationParametersMapper implements Function> { - private Mapper mapper = (ClassUtils.isPresent("tools.jackson.databind.json.JsonMapper", - OAuth2AuthorizationRowMapper.class.getClassLoader())) ? new JacksonDelegate() : new Jackson2Delegate(); - - public OAuth2AuthorizationParametersMapper() { + protected AbstractOAuth2AuthorizationParametersMapper() { } @Override @@ -736,15 +881,6 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic return parameters; } - public final void setMapper(Mapper mapper) { - Assert.notNull(mapper, "mapper cannot be null"); - this.mapper = mapper; - } - - protected final Mapper getMapper() { - return this.mapper; - } - private List toSqlParameterList(String tokenColumnName, String tokenMetadataColumnName, OAuth2Authorization.Token token) { @@ -773,13 +909,15 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic private String writeMap(Map data) { try { - return this.mapper.writeValueAsString(data); + return writeValueAsString(data); } catch (Exception ex) { throw new IllegalArgumentException(ex.getMessage(), ex); } } + abstract String writeValueAsString(Map data) throws Exception; + } private static final class LobCreatorArgumentPreparedStatementSetter extends ArgumentPreparedStatementSetter { @@ -850,77 +988,4 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic } - public interface Mapper { - - String writeValueAsString(Object data); - - T readValue(String value, ParameterizedTypeReference typeReference); - - } - - @SuppressWarnings("removal") - public static class Jackson2Delegate implements Mapper { - - private final ObjectMapper objectMapper = new ObjectMapper(); - - public Jackson2Delegate() { - ClassLoader classLoader = Jackson2Delegate.class.getClassLoader(); - List securityModules = SecurityJackson2Modules.getModules(classLoader); - this.objectMapper.registerModules(securityModules); - this.objectMapper.registerModule(new OAuth2AuthorizationServerJackson2Module()); - } - - @Override - public String writeValueAsString(Object data) { - try { - return this.objectMapper.writeValueAsString(data); - } - catch (JsonProcessingException ex) { - throw new IllegalArgumentException(ex.getMessage(), ex); - } - } - - @Override - public T readValue(String value, ParameterizedTypeReference typeReference) { - try { - com.fasterxml.jackson.databind.JavaType javaType = this.objectMapper.getTypeFactory() - .constructType(typeReference.getType()); - return this.objectMapper.readValue(value, javaType); - } - catch (JsonProcessingException ex) { - throw new IllegalArgumentException(ex.getMessage(), ex); - } - } - - } - - public static class JacksonDelegate implements Mapper { - - private final JsonMapper jsonMapper; - - public JacksonDelegate() { - this(JsonMapper.builder()); - } - - public JacksonDelegate(JsonMapper.Builder builder) { - List modules = SecurityJacksonModules.getModules(getClass().getClassLoader()); - this.jsonMapper = builder.addModules(modules) - .addModules(new OAuth2AuthorizationServerJacksonModule()) - .build(); - } - - @Override - public String writeValueAsString(Object data) { - return this.jsonMapper.writeValueAsString(data); - } - - @Override - public T readValue(String value, ParameterizedTypeReference typeReference) { - tools.jackson.databind.JavaType javaType = this.jsonMapper.getTypeFactory() - .constructType(typeReference.getType()); - return this.jsonMapper.readValue(value, javaType); - } - - } - } 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 1f83dfc0f0..8d428a2fb2 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 @@ -32,8 +32,9 @@ import java.util.function.Function; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import tools.jackson.core.type.TypeReference; +import tools.jackson.databind.json.JsonMapper; -import org.springframework.core.ParameterizedTypeReference; import org.springframework.dao.DataRetrievalFailureException; import org.springframework.jdbc.core.ArgumentPreparedStatementSetter; import org.springframework.jdbc.core.JdbcOperations; @@ -44,6 +45,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.jackson.SecurityJacksonModules; import org.springframework.security.oauth2.core.AuthorizationGrantType; import org.springframework.security.oauth2.core.OAuth2AccessToken; import org.springframework.security.oauth2.core.OAuth2DeviceCode; @@ -526,6 +528,12 @@ public class JdbcOAuth2AuthorizationServiceTests { // @formatter:on } + private static JsonMapper createSecurityMapper() { + return JsonMapper.builder() + .addModules(SecurityJacksonModules.getModules(JdbcOAuth2AuthorizationServiceTests.class.getClassLoader())) + .build(); + } + private static final class CustomJdbcOAuth2AuthorizationService extends JdbcOAuth2AuthorizationService { // @formatter:off @@ -626,8 +634,11 @@ public class JdbcOAuth2AuthorizationServiceTests { private static final class CustomOAuth2AuthorizationRowMapper extends JdbcOAuth2AuthorizationService.OAuth2AuthorizationRowMapper { + private JsonMapper mapper; + private CustomOAuth2AuthorizationRowMapper(RegisteredClientRepository registeredClientRepository) { super(registeredClientRepository); + this.mapper = createSecurityMapper(); } @Override @@ -747,7 +758,7 @@ public class JdbcOAuth2AuthorizationServiceTests { private Map parseMap(String data) { try { - return getMapper().readValue(data, new ParameterizedTypeReference<>() { + return this.mapper.readValue(data, new TypeReference<>() { }); } catch (Exception ex) { @@ -760,6 +771,8 @@ public class JdbcOAuth2AuthorizationServiceTests { private static final class CustomOAuth2AuthorizationParametersMapper extends JdbcOAuth2AuthorizationService.OAuth2AuthorizationParametersMapper { + private final JsonMapper mapper = createSecurityMapper(); + @Override public List apply(OAuth2Authorization authorization) { List parameters = new ArrayList<>(); @@ -852,7 +865,7 @@ public class JdbcOAuth2AuthorizationServiceTests { private String writeMap(Map data) { try { - return getMapper().writeValueAsString(data); + return this.mapper.writeValueAsString(data); } catch (Exception ex) { throw new IllegalArgumentException(ex.getMessage(), ex);