JwtGenerator serializes Date as timestamp in seconds but CommonProfile treat it as timestamp in milliseconds

68 views
Skip to first unread message

Nguyen

unread,
Oct 22, 2021, 9:42:58 AM10/22/21
to Pac4j users mailing list

Hello, I've encountered a problem (similar to https://groups.google.com/g/pac4j-users/c/aYuLjX3Z2AY/m/8fmi4uaiAQAJ) with the custom "expiration" claim added and used by OidcProfile to verify profile expiration in OidcProfile.isExpired. I'll modify slightly the test code above to demonstrate the bug (modifications are in red):

@Test
void contextLoads() {
GoogleOidcProfile googleOidcProfile = new GoogleOidcProfile();
googleOidcProfile.setTokenExpirationAdvance(-1);

final Date expiration = Date.from(Instant.now().plusSeconds(3600));
googleOidcProfile.addAttribute(OidcProfileDefinition.EXPIRATION, expiration); // normally this is set by OidcProfile.setAccessToken

final SecretSignatureConfiguration secretSignatureConfiguration = new SecretSignatureConfiguration("12345678901234567890123456789012");

final JwtGenerator generator = new JwtGenerator();
generator.setSignatureConfiguration(secretSignatureConfiguration);
String token = generator.generate(googleOidcProfile);

JwtAuthenticator jwtAuthenticator = new JwtAuthenticator();
jwtAuthenticator.setSignatureConfiguration(secretSignatureConfiguration);


UserProfile userProfile = jwtAuthenticator.validateToken(token);
assertFalse(userProfile.isExpired()); // this failed
}

The problem here is that Nimbus json serializer turned a Date value into unix epoch time (in seconds) whereas OidcProfile.isExpired (more specifically CommonProfile.getAttributeAsDate) treated the serialized value as unix time in milliseconds and tried to restore a Date object from it, thus falsified the result.

According to the comment in getAttributeAsDate, I believe that conversion has been added in order to mitigate the serialization of Jackson that converts Date into unix timestamp in milliseconds. Maybe we should just ignore that particular case and treat "expiration" as number of seconds, as in "exp" or "iat" of the oidc specs, every time we see it ?

Jérôme LELEU

unread,
Nov 3, 2021, 8:36:16 AM11/3/21
to Nguyen, Pac4j users mailing list
Hi,

Yes, this can be a problem.

You should set the expiration date as a long and not as a Date: googleOidcProfile.addAttribute(OidcProfileDefinition.EXPIRATION, expiration.getTime());

BTW, I added a setExpiration method to do that: googleOidcProfile.setExpiration(expiration);

Thanks.
Best regards,
Jérôme



--
You received this message because you are subscribed to the Google Groups "Pac4j users mailing list" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pac4j-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/pac4j-users/fbbb220e-cf32-401c-9e25-6c4ab501eb69n%40googlegroups.com.

Nguyen

unread,
Nov 3, 2021, 11:48:16 AM11/3/21
to Pac4j users mailing list
Hi Jérôme,

Thanks for the response. You might want to fix this too:

// pac4j-oidc/src/main/java/org/pac4j/oidc/profile/OidcProfile.java

    public void setAccessToken(final AccessToken accessToken) {
        addAttribute(OidcProfileDefinition.ACCESS_TOKEN, accessToken);
        if (accessToken != null) {
            if (accessToken.getLifetime() != 0) {
                addAttribute(OidcProfileDefinition.EXPIRATION,
                    Date.from(Instant.now().plusSeconds(accessToken.getLifetime())));

            } else {
                Date exp = null;
                try {
                    final var jwtClaimsSet = JWTParser.parse(accessToken.getValue()).getJWTClaimsSet();
                    if (jwtClaimsSet != null) {
                        exp = jwtClaimsSet.getExpirationTime();
                    }
                } catch (ParseException e) {
                    logger.trace(e.getMessage(), e);
                }
                if (exp != null) {
                    addAttribute(OidcProfileDefinition.EXPIRATION,
                        exp);
                }

            }
        }
    }

Jérôme LELEU

unread,
Nov 5, 2021, 9:11:48 AM11/5/21
to Nguyen, Pac4j users mailing list
Hi,

Excellent! You're right.
Thanks for the follow up.
Best regards,
Jérôme


Reply all
Reply to author
Forward
0 new messages