spring-projects / spring-projects/spring-security

Bug: Jackson Mixin Allowlist Keys in Kotlin are Lowercase Primitive Names Instead of Fully Qualified Class Names

Open
#16,684 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

status: waiting-for-triage type: bug
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

  1. Create a Spring Boot application using Kotlin
  2. Configure Jackson ObjectMapper with Security modules
  3. Try to add a Mixin for Long.class using addMixIn(Long::class.java, LongMixin::class.java)
  4. 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.