Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider reworking Jackson modules to support nanosecond precision #9460

Open
jzheaux opened this issue Feb 16, 2021 · 0 comments
Open

Consider reworking Jackson modules to support nanosecond precision #9460

jzheaux opened this issue Feb 16, 2021 · 0 comments
Labels
in: oauth2 An issue in OAuth2 modules (oauth2-core, oauth2-client, oauth2-resource-server, oauth2-jose) type: enhancement A general enhancement

Comments

@jzheaux
Copy link
Contributor

jzheaux commented Feb 16, 2021

As indicated in FasterXML/jackson-modules-java8#307, ObjectMapper#readTree cannot delay the evaluation of Instant values in the same fashion as ObjectMapper#readValue, which causes a loss of precision at deserialization when Instant values have nanosecond precision.

For example, this test will fail when OAuth2ClientJacksonModule is included in the configuration of ObjectMapper:

@Test 
public void testPrecisionLoss() {
    this.mapper = new ObjectMapper();
    this.mapper.registerModules(SecurityJackson2Modules.getModules(loader));
    Instant issuedAt = Instant.ofEpochSecond(1234567890, 123456789);
    OidcIdToken  token = TestOidcIdTokens.idToken().issuedAt(issuedAt).build();
    String serialized = this.mapper.writeValueAsString(map);
    OidcIdToken deserialized = this.mapper.readValue(serialized, OidcIdToken.class);
    assertThat(deserialized.getIssuedAt()).isEqualTo(token.getIssuedAt());
}

This is because Spring Security's Jackson modules include deserializers for unmodifiable collections, each of which relies on ObjectMapper#readTree, which can only support microsecond precision.

It is not necessary for OAuth2ClientJacksonModule to use these deserializers, though since any unmodifiable collections can be converted to their modifiable counterparts at serialization time using the @JsonSerialize annotation in the corresponding mixin constructor arguments.

For example, if OidcIdTokenMixin is changed to:

// ...
@JsonProperty("claims") @JsonSerialize(converter = MapCopier.class) Map<String, Object> claims
// ...

where MapCopier is a class that takes a collection and returns a LinkedHashMap copy, then the above test passes since the UnmodifiableMapSerialzier is no longer necessary and thus ObjectMapper#parseTree is no longer employed.

This would be applied for any unmodifiable collections referred to in the OAuth2ClientJacksonModule since there are constructs like OAuth2AuthenticationToken that contains an unmodifiable list of authorities where one of those authorities is an OidcUserAuthority that contains a claim set.

Alternative

There are performance implications that still need to be investigated to determine if this is a viable option. If not, the alternative is to document that the Spring Security Jackson modules only support microsecond-level precision for Instant values, updating OAuth2AuthenticationTokenMixinTests accordingly. Applications can achieve nanosecond precision on their own in this fashion by adding:

this.mapper.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true);

to their ObjectMapper configuration.

Additionally, the documentation could be updated in the future should Jackson find a way to be able to support nanosecond precision in ObjectMapper#readTree by default.

Additional Details

This can be verified on Windows using JDK 11 and modifying OAuth2AuthenticationTokenMixinTests to exclude the line:

this.mapper.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true);

Occassionally, the Instant obtained from the OS contains enough precision to cause rounding, making the assertions fail.

@jzheaux jzheaux added status: waiting-for-triage An issue we've not yet triaged type: enhancement A general enhancement in: oauth2 An issue in OAuth2 modules (oauth2-core, oauth2-client, oauth2-resource-server, oauth2-jose) and removed status: waiting-for-triage An issue we've not yet triaged labels Feb 16, 2021
@jzheaux jzheaux changed the title Consider changing OAuth2Client's Jackson mixins to not serialize collections as unmodifiable Consider reworking Jackson module to support nanosecond precision Feb 16, 2021
@jzheaux jzheaux changed the title Consider reworking Jackson module to support nanosecond precision Consider reworking Jackson modules to support nanosecond precision Feb 16, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: oauth2 An issue in OAuth2 modules (oauth2-core, oauth2-client, oauth2-resource-server, oauth2-jose) type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

1 participant