spring-projects / spring-projects/spring-security
Bug: Jackson Mixin Allowlist Keys in Kotlin are Lowercase Primitive Names Instead of Fully Qualified Class Names
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 9.6k
- Forks
- 6.3k
- Avg merge
- 2d 11h
- Merged PRs (30d)
- 52
Description
Describe the bug
When using Spring Security's Jackson deserialization with Kotlin, there's a bug in how Mixin classes are applied to primitive wrapper classes. In Java, when applying a Mixin to Long.class, the key is correctly set to "java.lang.Long". However, in Kotlin, the equivalent code results in the key being set to lowercase "long", causing allowlist configurations to fail.
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:293) ~[spring-security-core-6.4.3.jar:6.4.3]
at com.fasterxml.jackson.databind.jsontype.impl.TypeDeserializerBase._findDeserializer(TypeDeserializerBase.java:159) ~[jackson-databind-2.18.2.jar:2.18.2]
at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer._deserialize(AsArrayTypeDeserializer.java:100) ~[jackson-databind-2.18.2.jar:2.18.2]
at com.fasterxml.jackson.databind.jsontype.impl.AsArrayTypeDeserializer.deserializeTypedFromArray(AsArrayTypeDeserializer.java:56) ~[jackson-databind-2.18.2.jar:2.18.2]
at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer.deserializeTypedFromAny(AsPropertyTypeDeserializer.java:238) ~[jackson-databind-2.18.2.jar:2.18.2]
at com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializerNR.deserializeWithType(UntypedObjectDeserializerNR.java:112) ~[jackson-databind-2.18.2.jar:2.18.2]
at com.fasterxml.jackson.databind.deser.std.MapDeserializer._readAndBindStringKeyMap(MapDeserializer.java:625) ~[jackson-databind-2.18.2.jar:2.18.2]
... 16 common frames omitted
To Reproduce
- Create a Spring Boot application using Kotlin
- Configure Jackson ObjectMapper with Security modules
- Try to add a Mixin for
Long.classusingaddMixIn(Long::class.java, LongMixin::class.java) - Observe that the Mixin is registered with key "long" instead of "java.lang.Long"
Expected behavior
When adding a Mixin in Kotlin using addMixIn(Long::class.java, LongMixin::class.java), the key should be set to "java.lang.Long" just like in Java, not lowercase "long".
Sample
Java code (working correctly):
@JsonMixin(Long.class)
abstract class LongMixin {}
public void customObjectMapper(ObjectMapper objectMapper) {
ObjectMapper copied = objectMapper.copy();
copied.registerModules(SecurityJackson2Modules.getModules(this.classLoader));
copied.addMixIn(Long.class, LongMixin.class);
// Mixin key is set to "java.lang.Long"
}
Kotlin code (exhibiting the bug):
@JsonMixin(Long::class)
abstract class LongMixin {}
fun customObjectMapper(objectMapper: ObjectMapper) {
val copied: ObjectMapper = objectMapper.copy()
copied.registerModules(SecurityJackson2Modules.getModules(this.classLoader))
copied.addMixIn(Long::class.java, LongMixin::class.java)
// Mixin key is incorrectly set to "long" instead of "java.lang.Long"
}
I'm not entirely sure if this is the right place to report this issue, so I apologize if I've posted it in the wrong location.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in SecurityJackson2Modules.java around AllowlistTypeIdResolver.typeFromId at line 293, then reproduce the reported Kotlin addMixIn(Long::class.java, LongMixin::class.java) behavior. Confirm that the allowlist uses the fully qualified name java.lang.Long rather than long, and verify the fix against both the Java and Kotlin examples.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, kotlin
- Domain
- backend, security
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100