1
0
mirror of synced 2026-05-22 13:23:17 +00:00

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
This commit is contained in:
Rob Winch
2025-10-17 13:47:27 -05:00
parent 803936cfbe
commit 5e851e0b26
10 changed files with 198 additions and 307 deletions
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -24,6 +24,7 @@
<suppress files="EnableWebFluxSecurityTests\.java" checks="SpringMethodVisibility"/>
<suppress files="ExpressionBasedPreInvocationAdviceTests\.java" checks="SpringMethodVisibility"/>
<suppress files="Jsr250MethodSecurityMetadataSourceTests\.java" checks="SpringMethodVisibility"/>
<suppress files="JdbcOAuth2AuthorizationService\.java" checks="SpringMethodVisibility"/>
<suppress files="MapBasedMethodSecurityMetadataSourceTests\.java" checks="SpringMethodVisibility"/>
<suppress files="OAuth2ResourceServerBeanDefinitionParserTests\.java" checks="SpringMethodVisibility"/>
<suppress files="ObjectIdentityImplTests\.java" checks="SpringMethodVisibility"/>
@@ -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<String,Object>} within the result.
*
* @author Rob Winch
* @since 7.0
*/
public static class OAuth2AuthorizationRowMapper implements RowMapper<OAuth2Authorization> {
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<String, Object> readValue(String data) {
final ParameterizedTypeReference<Map<String, Object>> 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<String, Object> readValue(String data) throws JsonProcessingException {
final ParameterizedTypeReference<Map<String, Object>> 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<OAuth2Authorization> {
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<String, Object> 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<String, Object> 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<Module> 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<JacksonModule> 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<String, Object> 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<String, Object> 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<OAuth2Authorization, List<SqlParameterValue>> {
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 <T extends OAuth2Token> List<SqlParameterValue> toSqlParameterList(String tokenColumnName,
String tokenMetadataColumnName, OAuth2Authorization.Token<T> token) {
@@ -773,13 +909,15 @@ public class JdbcOAuth2AuthorizationService implements OAuth2AuthorizationServic
private String writeMap(Map<String, Object> data) {
try {
return this.mapper.writeValueAsString(data);
return writeValueAsString(data);
}
catch (Exception ex) {
throw new IllegalArgumentException(ex.getMessage(), ex);
}
}
abstract String writeValueAsString(Map<String, Object> 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> T readValue(String value, ParameterizedTypeReference<T> typeReference);
}
@SuppressWarnings("removal")
public static class Jackson2Delegate implements Mapper {
private final ObjectMapper objectMapper = new ObjectMapper();
public Jackson2Delegate() {
ClassLoader classLoader = Jackson2Delegate.class.getClassLoader();
List<Module> 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> T readValue(String value, ParameterizedTypeReference<T> 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<JacksonModule> 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> T readValue(String value, ParameterizedTypeReference<T> typeReference) {
tools.jackson.databind.JavaType javaType = this.jsonMapper.getTypeFactory()
.constructType(typeReference.getType());
return this.jsonMapper.readValue(value, javaType);
}
}
}
@@ -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<String, Object> 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<SqlParameterValue> apply(OAuth2Authorization authorization) {
List<SqlParameterValue> parameters = new ArrayList<>();
@@ -852,7 +865,7 @@ public class JdbcOAuth2AuthorizationServiceTests {
private String writeMap(Map<String, Object> data) {
try {
return getMapper().writeValueAsString(data);
return this.mapper.writeValueAsString(data);
}
catch (Exception ex) {
throw new IllegalArgumentException(ex.getMessage(), ex);