Skip to content

Commit e6b4d46

Browse files
committed
Fix OAuth2AuthorizationServerJacksonModule type validator configuration
Closes gh-18102
1 parent 4daf089 commit e6b4d46

File tree

7 files changed

+60
-34
lines changed

7 files changed

+60
-34
lines changed

core/src/main/java/org/springframework/security/jackson/SecurityJacksonModules.java

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,9 @@
3636

3737
/**
3838
* This utility class will find all the Jackson modules contributed by Spring Security in
39-
* the classpath (except {@code OAuth2AuthorizationServerJacksonModule} and
40-
* {@code WebauthnJacksonModule}), enable automatic inclusion of type information and
41-
* configure a {@link PolymorphicTypeValidator} that handles the validation of class
42-
* names.
39+
* the classpath (except {@code WebauthnJacksonModule}), enable automatic inclusion of
40+
* type information and configure a {@link PolymorphicTypeValidator} that handles the
41+
* validation of class names.
4342
*
4443
* <p>
4544
* <pre>
@@ -77,6 +76,8 @@ public final class SecurityJacksonModules {
7776

7877
private static final String oauth2ClientJacksonModuleClass = "org.springframework.security.oauth2.client.jackson.OAuth2ClientJacksonModule";
7978

79+
private static final String oauth2AuthorizationServerJacksonModuleClass = "org.springframework.security.oauth2.server.authorization.jackson.OAuth2AuthorizationServerJacksonModule";
80+
8081
private static final String ldapJacksonModuleClass = "org.springframework.security.ldap.jackson.LdapJacksonModule";
8182

8283
private static final String saml2JacksonModuleClass = "org.springframework.security.saml2.jackson.Saml2JacksonModule";
@@ -87,18 +88,21 @@ public final class SecurityJacksonModules {
8788

8889
private static final boolean oauth2ClientPresent;
8990

91+
private static final boolean oauth2AuthorizationServerPresent;
92+
9093
private static final boolean ldapJacksonPresent;
9194

9295
private static final boolean saml2JacksonPresent;
9396

9497
private static final boolean casJacksonPresent;
9598

9699
static {
97-
98100
ClassLoader classLoader = SecurityJacksonModules.class.getClassLoader();
99101
webServletPresent = ClassUtils.isPresent("jakarta.servlet.http.Cookie", classLoader);
100102
oauth2ClientPresent = ClassUtils.isPresent("org.springframework.security.oauth2.client.OAuth2AuthorizedClient",
101103
classLoader);
104+
oauth2AuthorizationServerPresent = ClassUtils
105+
.isPresent("org.springframework.security.oauth2.server.authorization.OAuth2Authorization", classLoader);
102106
ldapJacksonPresent = ClassUtils.isPresent(ldapJacksonModuleClass, classLoader);
103107
saml2JacksonPresent = ClassUtils.isPresent(saml2JacksonModuleClass, classLoader);
104108
casJacksonPresent = ClassUtils.isPresent(casJacksonModuleClass, classLoader);
@@ -156,6 +160,9 @@ public static List<JacksonModule> getModules(ClassLoader loader,
156160
if (oauth2ClientPresent) {
157161
addToModulesList(loader, modules, oauth2ClientJacksonModuleClass);
158162
}
163+
if (oauth2AuthorizationServerPresent) {
164+
addToModulesList(loader, modules, oauth2AuthorizationServerJacksonModuleClass);
165+
}
159166
if (ldapJacksonPresent) {
160167
addToModulesList(loader, modules, ldapJacksonModuleClass);
161168
}

docs/modules/ROOT/pages/features/integrations/jackson.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ The following Spring Security modules provide Jackson support:
8686
- spring-security-core (javadoc:org.springframework.security.jackson.CoreJacksonModule[])
8787
- 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[])
8888
- spring-security-oauth2-client (javadoc:org.springframework.security.oauth2.client.jackson.OAuth2ClientJacksonModule[])
89+
- spring-security-oauth2-authorization-server (javadoc:org.springframework.security.oauth2.server.authorization.jackson.OAuth2AuthorizationServerJacksonModule[])
8990
- spring-security-cas (javadoc:org.springframework.security.cas.jackson.CasJacksonModule[])
9091
- spring-security-ldap (javadoc:org.springframework.security.ldap.jackson.LdapJacksonModule[])
9192
- spring-security-saml2 (javadoc:org.springframework.security.saml2.jackson.Saml2JacksonModule[])

oauth2/oauth2-authorization-server/spring-security-oauth2-authorization-server.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ dependencies {
1313
api "com.nimbusds:nimbus-jose-jwt"
1414
api 'tools.jackson.core:jackson-databind'
1515

16+
optional "com.fasterxml.jackson.core:jackson-databind"
1617
optional "com.fasterxml.jackson.datatype:jackson-datatype-jsr310"
1718
optional "org.springframework:spring-jdbc"
18-
optional "com.fasterxml.jackson.core:jackson-databind"
1919

2020
testImplementation project(":spring-security-test")
2121
testImplementation project(path : ':spring-security-oauth2-jose', configuration : 'tests')

oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/JdbcOAuth2AuthorizationService.java

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@
6868
import org.springframework.security.oauth2.core.oidc.endpoint.OidcParameterNames;
6969
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
7070
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
71-
import org.springframework.security.oauth2.server.authorization.jackson.OAuth2AuthorizationServerJacksonModule;
7271
import org.springframework.security.oauth2.server.authorization.jackson2.OAuth2AuthorizationServerJackson2Module;
7372
import org.springframework.util.Assert;
7473
import org.springframework.util.CollectionUtils;
@@ -361,7 +360,7 @@ private OAuth2Authorization findBy(String filter, List<SqlParameterValue> parame
361360
/**
362361
* Sets the {@link RowMapper} used for mapping the current row in
363362
* {@code java.sql.ResultSet} to {@link OAuth2Authorization}. The default is
364-
* {@link OAuth2AuthorizationRowMapper}.
363+
* {@link JsonMapperOAuth2AuthorizationRowMapper}.
365364
* @param authorizationRowMapper the {@link RowMapper} used for mapping the current
366365
* row in {@code ResultSet} to {@link OAuth2Authorization}
367366
*/
@@ -373,7 +372,7 @@ public final void setAuthorizationRowMapper(RowMapper<OAuth2Authorization> autho
373372
/**
374373
* Sets the {@code Function} used for mapping {@link OAuth2Authorization} to a
375374
* {@code List} of {@link SqlParameterValue}. The default is
376-
* {@link OAuth2AuthorizationParametersMapper}.
375+
* {@link JsonMapperOAuth2AuthorizationParametersMapper}.
377376
* @param authorizationParametersMapper the {@code Function} used for mapping
378377
* {@link OAuth2Authorization} to a {@code List} of {@link SqlParameterValue}
379378
*/
@@ -743,10 +742,7 @@ private static final class Jackson3 {
743742

744743
static JsonMapper createJsonMapper() {
745744
List<JacksonModule> modules = SecurityJacksonModules.getModules(Jackson3.class.getClassLoader());
746-
return JsonMapper.builder()
747-
.addModules(modules)
748-
.addModules(new OAuth2AuthorizationServerJacksonModule())
749-
.build();
745+
return JsonMapper.builder().addModules(modules).build();
750746
}
751747

752748
}

oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/jackson/OAuth2AuthorizationServerJacksonModule.java

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,11 @@
1818

1919
import java.net.URL;
2020

21-
import com.fasterxml.jackson.annotation.JsonTypeInfo;
2221
import tools.jackson.core.Version;
23-
import tools.jackson.databind.DefaultTyping;
24-
import tools.jackson.databind.cfg.MapperBuilder;
2522
import tools.jackson.databind.jsontype.BasicPolymorphicTypeValidator;
2623

27-
import org.springframework.security.jackson.CoreJacksonModule;
24+
import org.springframework.security.jackson.SecurityJacksonModule;
25+
import org.springframework.security.jackson.SecurityJacksonModules;
2826
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
2927
import org.springframework.security.oauth2.jose.jws.MacAlgorithm;
3028
import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
@@ -37,36 +35,37 @@
3735
* registers the following mix-in annotations:
3836
*
3937
* <ul>
40-
* <li>{@link OAuth2TokenExchangeActor}</li>
38+
* <li>{@link OAuth2TokenExchangeActorMixin}</li>
4139
* <li>{@link OAuth2AuthorizationRequestMixin}</li>
4240
* <li>{@link OAuth2TokenExchangeCompositeAuthenticationTokenMixin}</li>
4341
* <li>{@link JwsAlgorithmMixin}</li>
4442
* <li>{@link OAuth2TokenFormatMixin}</li>
4543
* </ul>
4644
*
47-
* If not already enabled, default typing will be automatically enabled as type info is
48-
* required to properly serialize/deserialize objects. In order to use this module just
49-
* add it to your {@code JsonMapper.Builder} configuration.
45+
* <p>
46+
* The recommended way to configure it is to use {@link SecurityJacksonModules} in order
47+
* to enable properly automatic inclusion of type information with related validation.
5048
*
5149
* <pre>
50+
* ClassLoader loader = getClass().getClassLoader();
5251
* JsonMapper mapper = JsonMapper.builder()
53-
* .addModules(new OAuth2AuthorizationServerJacksonModule()).build;
52+
* .addModules(SecurityJacksonModules.getModules(loader))
53+
* .build();
5454
* </pre>
5555
*
5656
* @author Sebastien Deleuze
5757
* @author Steve Riesenberg
5858
* @since 7.0
5959
*/
6060
@SuppressWarnings("serial")
61-
public class OAuth2AuthorizationServerJacksonModule extends CoreJacksonModule {
61+
public class OAuth2AuthorizationServerJacksonModule extends SecurityJacksonModule {
6262

6363
public OAuth2AuthorizationServerJacksonModule() {
6464
super(OAuth2AuthorizationServerJacksonModule.class.getName(), new Version(1, 0, 0, null, null, null));
6565
}
6666

6767
@Override
6868
public void configurePolymorphicTypeValidator(BasicPolymorphicTypeValidator.Builder builder) {
69-
super.configurePolymorphicTypeValidator(builder);
7069
builder.allowIfSubType(OAuth2TokenFormat.class)
7170
.allowIfSubType(OAuth2TokenExchangeActor.class)
7271
.allowIfSubType(OAuth2TokenExchangeCompositeAuthenticationToken.class)
@@ -78,11 +77,6 @@ public void configurePolymorphicTypeValidator(BasicPolymorphicTypeValidator.Buil
7877

7978
@Override
8079
public void setupModule(SetupContext context) {
81-
super.setupModule(context);
82-
BasicPolymorphicTypeValidator.Builder builder = BasicPolymorphicTypeValidator.builder();
83-
this.configurePolymorphicTypeValidator(builder);
84-
((MapperBuilder<?, ?>) context.getOwner()).activateDefaultTyping(builder.build(), DefaultTyping.NON_FINAL,
85-
JsonTypeInfo.As.PROPERTY);
8680
context.setMixIn(OAuth2TokenExchangeActor.class, OAuth2TokenExchangeActorMixin.class);
8781
context.setMixIn(OAuth2AuthorizationRequest.class, OAuth2AuthorizationRequestMixin.class);
8882
context.setMixIn(OAuth2TokenExchangeCompositeAuthenticationToken.class,

oauth2/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/JdbcOAuth2AuthorizationServiceTests.java

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.security.oauth2.server.authorization;
1818

19+
import java.security.Principal;
1920
import java.sql.ResultSet;
2021
import java.sql.SQLException;
2122
import java.sql.Timestamp;
@@ -45,6 +46,7 @@
4546
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
4647
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
4748
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
49+
import org.springframework.security.authentication.TestingAuthenticationToken;
4850
import org.springframework.security.jackson.SecurityJacksonModules;
4951
import org.springframework.security.oauth2.core.AuthorizationGrantType;
5052
import org.springframework.security.oauth2.core.OAuth2AccessToken;
@@ -58,6 +60,7 @@
5860
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
5961
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
6062
import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients;
63+
import org.springframework.security.web.authentication.WebAuthenticationDetails;
6164
import org.springframework.util.CollectionUtils;
6265
import org.springframework.util.StringUtils;
6366

@@ -227,10 +230,11 @@ public void saveLoadAuthorizationWhenCustomStrategiesSetThenCalled() throws Exce
227230
.build();
228231

229232
RowMapper<OAuth2Authorization> authorizationRowMapper = spy(
230-
new JdbcOAuth2AuthorizationService.OAuth2AuthorizationRowMapper(this.registeredClientRepository));
233+
new JdbcOAuth2AuthorizationService.JsonMapperOAuth2AuthorizationRowMapper(
234+
this.registeredClientRepository));
231235
this.authorizationService.setAuthorizationRowMapper(authorizationRowMapper);
232236
Function<OAuth2Authorization, List<SqlParameterValue>> authorizationParametersMapper = spy(
233-
new JdbcOAuth2AuthorizationService.OAuth2AuthorizationParametersMapper());
237+
new JdbcOAuth2AuthorizationService.JsonMapperOAuth2AuthorizationParametersMapper());
234238
this.authorizationService.setAuthorizationParametersMapper(authorizationParametersMapper);
235239

236240
this.authorizationService.save(originalAuthorization);
@@ -461,6 +465,28 @@ public void findByTokenWhenTokenDoesNotExistThenNull() {
461465
assertThat(result).isNull();
462466
}
463467

468+
// gh-18102
469+
@Test
470+
public void findByTokenWhenPrincipalHasWebAuthenticationDetailsThenDeserializes() {
471+
given(this.registeredClientRepository.findById(eq(REGISTERED_CLIENT.getId()))).willReturn(REGISTERED_CLIENT);
472+
473+
String state = "state";
474+
TestingAuthenticationToken principal = new TestingAuthenticationToken(PRINCIPAL_NAME, "credentials");
475+
principal.setDetails(new WebAuthenticationDetails("remoteAddress", "sessionId"));
476+
477+
OAuth2Authorization authorization = OAuth2Authorization.withRegisteredClient(REGISTERED_CLIENT)
478+
.id(ID)
479+
.principalName(PRINCIPAL_NAME)
480+
.authorizationGrantType(AUTHORIZATION_GRANT_TYPE)
481+
.attribute(OAuth2ParameterNames.STATE, state)
482+
.attribute(Principal.class.getName(), principal)
483+
.build();
484+
this.authorizationService.save(authorization);
485+
486+
OAuth2Authorization result = this.authorizationService.findByToken(state, STATE_TOKEN_TYPE);
487+
assertThat(authorization).isEqualTo(result);
488+
}
489+
464490
@Test
465491
public void tableDefinitionWhenCustomThenAbleToOverride() {
466492
given(this.registeredClientRepository.findById(eq(REGISTERED_CLIENT.getId()))).willReturn(REGISTERED_CLIENT);

oauth2/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/jackson/OAuth2AuthorizationServerJacksonModuleTests.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,20 @@
2727

2828
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
2929
import org.springframework.security.core.Authentication;
30+
import org.springframework.security.jackson.SecurityJacksonModules;
3031
import org.springframework.security.oauth2.jose.jws.MacAlgorithm;
3132
import org.springframework.security.oauth2.jwt.JwtClaimNames;
3233
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
3334
import org.springframework.security.oauth2.server.authorization.TestOAuth2Authorizations;
3435
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2TokenExchangeActor;
3536
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2TokenExchangeCompositeAuthenticationToken;
36-
import org.springframework.security.oauth2.server.authorization.jackson2.OAuth2AuthorizationServerJackson2Module;
3737
import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;
3838
import org.springframework.security.oauth2.server.authorization.settings.TokenSettings;
3939

4040
import static org.assertj.core.api.Assertions.assertThat;
4141

4242
/**
43-
* Tests for {@link OAuth2AuthorizationServerJackson2Module}.
43+
* Tests for {@link OAuth2AuthorizationServerJacksonModule}.
4444
*
4545
* @author Steve Riesenberg
4646
* @author Joe Grandja
@@ -55,7 +55,9 @@ public class OAuth2AuthorizationServerJacksonModuleTests {
5555

5656
@BeforeEach
5757
public void setup() {
58-
this.mapper = JsonMapper.builder().addModules(new OAuth2AuthorizationServerJacksonModule()).build();
58+
this.mapper = JsonMapper.builder()
59+
.addModules(SecurityJacksonModules.getModules(getClass().getClassLoader()))
60+
.build();
5961
}
6062

6163
@Test

0 commit comments

Comments
 (0)