Expected Behavior
When using spring-security-oauth2-client in combination with spring-session-data-redis and enabling JSON serializing via
@Bean
public RedisSerializer<Object> springSessionDefaultRedisSerializer() {
var om = new ObjectMapper();
om.registerModules(SecurityJackson2Modules.getModules(loader));
return new GenericJackson2JsonRedisSerializer(om);
}
the session should be successfully deserialized when containing a type of java.lang.Long.
Current Behavior
The deserialization fails with the exception:
org.springframework.data.redis.serializer.SerializationException: Could not read JSON: The class with java.lang.Long and name of java.lang.Long is not in the allowlist. If you believe this class is safe to deserialize, please provide an explicit mapping using Jackson annotations or by providing a Mixin. If the serialization is only done by a trusted source, you can also enable default typing. See https://github.com/spring-projects/spring-security/issues/4370 for details (through reference chain: org.springframework.security.core.context.SecurityContextImpl["authentication"]->org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken["principal"]->org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser["authorities"]->org.springframework.security.oauth2.core.oidc.user.OidcUserAuthority["idToken"]->org.springframework.security.oauth2.core.oidc.OidcIdToken["claims"])
Context
At least our Okta returns a claim ver with a java.lang.Long of 1. When persisting the spring-security session with spring-session as JSON within redis this is serialized as
...
"ver": [
"java.lang.Long",
1
],
...
and can not be deserialized because java.lang.Long is not within the allow list.
As a workaround, I can fall back to storing the session not as JSON.
Comment From: TolstovM
Hello!
As a workaround you can create LongMixin
public abstract class LongMixin {
}
and add it to your objectMapper
mapper.addMixIn(Long.class, LongMixin.class);
It works fine for me.
Comment From: TolstovM
I've added PR, which would fix this issue https://github.com/spring-projects/spring-security/pull/12584
Comment From: marcusdacoregio
I think that this is related to https://github.com/spring-projects/spring-session/issues/2227
Comment From: TolstovM
@marcusdacoregio Yep, it is
Comment From: marcusdacoregio
Hi @mvitz, which version of Spring Security and Spring Session are you using?
Comment From: mvitz
I think I was playing around with Spring Boot 3.0.0 which would resolve to: * Spring Security: 6.0.0 * Spring Session: 3.0.0
Comment From: mvitz
After upgrading to Boot 3.0.2 (including 6.0.1) the same exception keeps occuring.
Comment From: gustavovitor
The same issue it happens using spring-session-jdbc:
Caused by: java.lang.IllegalArgumentException: The class with java.lang.Long and name of java.lang.Long is not in the allowlist. If you believe this class is safe to deserialize, please provide an explicit mapping using Jackson annotations or by providing a Mixin. If the serialization is only done by a trusted source, you can also enable default typing. See https://github.com/spring-projects/spring-security/issues/4370 for details
at org.springframework.security.jackson2.SecurityJackson2Modules$AllowlistTypeIdResolver.typeFromId(SecurityJackson2Modules.java:265) ~[spring-security-core-6.0.1.jar:6.0.1]
at com.fasterxml.jackson.databind.jsontype.impl.TypeDeserializerBase._findDeserializer(TypeDeserializerBase.java:159) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer._deserialize(AsArrayTypeDeserializer.java:97) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer.deserializeTypedFromArray(AsArrayTypeDeserializer.java:53) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer.deserializeTypedFromAny(AsPropertyTypeDeserializer.java:211) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializerNR.deserializeWithType(UntypedObjectDeserializerNR.java:115) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer.deserialize(TypeWrappedDeserializer.java:74) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:323) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.ObjectMapper._readValue(ObjectMapper.java:4706) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2879) ~[jackson-databind-2.14.1.jar:2.14.1]
at org.springframework.security.oauth2.server.authorization.jackson2.UnmodifiableMapDeserializer.deserialize(UnmodifiableMapDeserializer.java:47) ~[spring-security-oauth2-authorization-server-1.0.0.jar:1.0.0]
at org.springframework.security.oauth2.server.authorization.jackson2.UnmodifiableMapDeserializer.deserialize(UnmodifiableMapDeserializer.java:37) ~[spring-security-oauth2-authorization-server-1.0.0.jar:1.0.0]
at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer._deserializeTypedForId(AsPropertyTypeDeserializer.java:144) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer.deserializeTypedFromObject(AsPropertyTypeDeserializer.java:110) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer.deserializeTypedFromAny(AsPropertyTypeDeserializer.java:213) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializerNR.deserializeWithType(UntypedObjectDeserializerNR.java:115) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer.deserialize(TypeWrappedDeserializer.java:74) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:323) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.ObjectMapper._readValue(ObjectMapper.java:4706) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2879) ~[jackson-databind-2.14.1.jar:2.14.1]
at org.springframework.security.oauth2.server.authorization.jackson2.UnmodifiableMapDeserializer.deserialize(UnmodifiableMapDeserializer.java:47) ~[spring-security-oauth2-authorization-server-1.0.0.jar:1.0.0]
at org.springframework.security.oauth2.server.authorization.jackson2.UnmodifiableMapDeserializer.deserialize(UnmodifiableMapDeserializer.java:37) ~[spring-security-oauth2-authorization-server-1.0.0.jar:1.0.0]
at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer._deserializeTypedForId(AsPropertyTypeDeserializer.java:144) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer.deserializeTypedFromObject(AsPropertyTypeDeserializer.java:110) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserializeWithType(MapDeserializer.java:492) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer.deserialize(TypeWrappedDeserializer.java:74) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:323) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4730) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3677) ~[jackson-databind-2.14.1.jar:2.14.1]
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3660) ~[jackson-databind-2.14.1.jar:2.14.1]
at org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService$OAuth2AuthorizationRowMapper.parseMap(JdbcOAuth2AuthorizationService.java:465) ~[spring-security-oauth2-authorization-server-1.0.0.jar:1.0.0]
... 108 common frames omitted
Comment From: gustavovitor
I don't know if collaborators team will be accept any pull request to solve it, but, we can implement our own RowMapper to solve it directly: https://stackoverflow.com/questions/72413823/spring-authorization-server-use-exit-model-for-user
This approach is elegant because we can map other classes such as a custom UserDetails.
Comment From: marcusdacoregio
Hi everyone, since this is an issue that is related to Spring Session, I'll close this as superseded by https://github.com/spring-projects/spring-session/issues/2305. I'll prioritize that issue for the next minor release in Spring Session, so please subscribe to it and try the solution when it is out.