From 536824beb65bc36d7218870f6550d155fec11b18 Mon Sep 17 00:00:00 2001 From: stianst Date: Fri, 14 Feb 2020 11:37:16 +0100 Subject: [PATCH] KEYCLOAK-12960 Use Long for time based values in JsonWebToken --- .../org/keycloak/representations/IDToken.java | 26 ++++-- .../representations/JsonWebToken.java | 89 +++++++++++++++---- .../actiontoken/DefaultActionTokenKey.java | 2 +- .../testsuite/oauth/AccessTokenTest.java | 9 ++ .../oauth/TokenIntrospectionTest.java | 8 +- 5 files changed, 106 insertions(+), 28 deletions(-) diff --git a/core/src/main/java/org/keycloak/representations/IDToken.java b/core/src/main/java/org/keycloak/representations/IDToken.java index 5a7f18a255..e318a6d8b8 100755 --- a/core/src/main/java/org/keycloak/representations/IDToken.java +++ b/core/src/main/java/org/keycloak/representations/IDToken.java @@ -17,6 +17,7 @@ package org.keycloak.representations; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import org.keycloak.TokenCategory; @@ -61,8 +62,7 @@ public class IDToken extends JsonWebToken { @JsonProperty(NONCE) protected String nonce; - @JsonProperty(AUTH_TIME) - protected int authTime; + protected Long auth_time; @JsonProperty(SESSION_STATE) protected String sessionState; @@ -149,12 +149,28 @@ public class IDToken extends JsonWebToken { this.nonce = nonce; } - public int getAuthTime() { - return authTime; + public Long getAuth_time() { + return auth_time; } + /** + * @deprecated int will overflow with values after 2038. Use {@link #getAuth_time()} instead. + */ + @Deprecated + @JsonIgnore + public int getAuthTime() { + return auth_time != null ? auth_time.intValue() : 0; + } + + public void setAuth_time(Long auth_time) { + this.auth_time = auth_time; + } + + /** + * @deprecated int will overflow with values after 2038. Use {@link #setAuth_time(Long)} ()} instead. + */ public void setAuthTime(int authTime) { - this.authTime = authTime; + this.auth_time = Long.valueOf(authTime); } public String getSessionState() { diff --git a/core/src/main/java/org/keycloak/representations/JsonWebToken.java b/core/src/main/java/org/keycloak/representations/JsonWebToken.java index 42dd19659f..b61615b820 100755 --- a/core/src/main/java/org/keycloak/representations/JsonWebToken.java +++ b/core/src/main/java/org/keycloak/representations/JsonWebToken.java @@ -41,12 +41,11 @@ import java.util.Map; public class JsonWebToken implements Serializable, Token { @JsonProperty("jti") protected String id; - @JsonProperty("exp") - protected int expiration; - @JsonProperty("nbf") - protected int notBefore; - @JsonProperty("iat") - protected int issuedAt; + + protected Long exp; + protected Long nbf; + protected Long iat; + @JsonProperty("iss") protected String issuer; @JsonProperty("aud") @@ -70,33 +69,68 @@ public class JsonWebToken implements Serializable, Token { return this; } - - public int getExpiration() { - return expiration; + public Long getExp() { + return exp; } + /** + * @deprecated int will overflow with values after 2038. Use {@link #getExp()} instead. + */ + @Deprecated + @JsonIgnore + public int getExpiration() { + return exp != null ? exp.intValue() : 0; + } + + public JsonWebToken exp(Long exp) { + this.exp = exp; + return this; + } + + /** + * @deprecated int will overflow with values after 2038. Use {@link #exp(Long)} instead. + */ public JsonWebToken expiration(int expiration) { - this.expiration = expiration; + this.exp = Long.valueOf(expiration); return this; } @JsonIgnore public boolean isExpired() { - return Time.currentTime() > expiration; + return exp != null && exp != 0 ? Time.currentTime() > exp : false; } + public Long getNbf() { + return nbf; + } + + /** + * @deprecated int will overflow with values after 2038. Use {@link #getNbf()} instead. + */ + @Deprecated + @JsonIgnore public int getNotBefore() { - return notBefore; + return nbf != null ? nbf.intValue() : 0; } + public JsonWebToken nbf(Long nbf) { + this.nbf = nbf; + return this; + } + + /** + * @deprecated int will overflow with values after 2038. Use {@link #nbf(Long)} instead. + */ + @Deprecated + @JsonIgnore public JsonWebToken notBefore(int notBefore) { - this.notBefore = notBefore; + this.nbf = Long.valueOf(notBefore); return this; } @JsonIgnore public boolean isNotBefore(int allowedTimeSkew) { - return Time.currentTime() + allowedTimeSkew >= notBefore; + return nbf != null ? Time.currentTime() + allowedTimeSkew >= nbf : true; } /** @@ -111,11 +145,20 @@ public class JsonWebToken implements Serializable, Token { @JsonIgnore public boolean isActive(int allowedTimeSkew) { - return (!isExpired() || expiration == 0) && (isNotBefore(allowedTimeSkew) || notBefore == 0); + return !isExpired() && isNotBefore(allowedTimeSkew); } + public Long getIat() { + return iat; + } + + /** + * @deprecated int will overflow with values after 2038. Use {@link #getIat()} instead. + */ + @Deprecated + @JsonIgnore public int getIssuedAt() { - return issuedAt; + return iat != null ? iat.intValue() : 0; } /** @@ -123,12 +166,22 @@ public class JsonWebToken implements Serializable, Token { */ @JsonIgnore public JsonWebToken issuedNow() { - issuedAt = Time.currentTime(); + iat = Long.valueOf(Time.currentTime()); return this; } + public JsonWebToken iat(Long iat) { + this.iat = iat; + return this; + } + + /** + * @deprecated int will overflow with values after 2038. Use {@link #iat(Long)} ()} instead. + */ + @Deprecated + @JsonIgnore public JsonWebToken issuedAt(int issuedAt) { - this.issuedAt = issuedAt; + this.iat = Long.valueOf(issuedAt); return this; } diff --git a/services/src/main/java/org/keycloak/authentication/actiontoken/DefaultActionTokenKey.java b/services/src/main/java/org/keycloak/authentication/actiontoken/DefaultActionTokenKey.java index d468dea55d..15c1aa655c 100644 --- a/services/src/main/java/org/keycloak/authentication/actiontoken/DefaultActionTokenKey.java +++ b/services/src/main/java/org/keycloak/authentication/actiontoken/DefaultActionTokenKey.java @@ -46,7 +46,7 @@ public class DefaultActionTokenKey extends JsonWebToken implements ActionTokenKe public DefaultActionTokenKey(String userId, String actionId, int absoluteExpirationInSecs, UUID actionVerificationNonce) { this.subject = userId; this.type = actionId; - this.expiration = absoluteExpirationInSecs; + this.exp = Long.valueOf(absoluteExpirationInSecs); this.actionVerificationNonce = actionVerificationNonce == null ? UUID.randomUUID() : actionVerificationNonce; } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java index caac6f1e64..87f3ea8cc1 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java @@ -222,6 +222,15 @@ public class AccessTokenTest extends AbstractKeycloakTest { assertEquals(sessionId, token.getSessionState()); + assertNull(token.getNbf()); + assertEquals(0, token.getNotBefore()); + + assertNotNull(token.getIat()); + assertEquals(token.getIat().intValue(), token.getIssuedAt()); + + assertNotNull(token.getExp()); + assertEquals(token.getExp().intValue(), token.getExpiration()); + assertEquals(1, token.getRealmAccess().getRoles().size()); assertTrue(token.getRealmAccess().isUserInRole("user")); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/TokenIntrospectionTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/TokenIntrospectionTest.java index 6851e9e0dd..a188cf41ab 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/TokenIntrospectionTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/TokenIntrospectionTest.java @@ -108,7 +108,7 @@ public class TokenIntrospectionTest extends AbstractTestRealmKeycloakTest { assertEquals("test-app", jsonNode.get("client_id").asText()); assertTrue(jsonNode.has("exp")); assertTrue(jsonNode.has("iat")); - assertTrue(jsonNode.has("nbf")); + assertFalse(jsonNode.has("nbf")); assertTrue(jsonNode.has("sub")); assertTrue(jsonNode.has("aud")); assertTrue(jsonNode.has("iss")); @@ -121,7 +121,7 @@ public class TokenIntrospectionTest extends AbstractTestRealmKeycloakTest { assertEquals("test-app", rep.getClientId()); assertEquals(jsonNode.get("exp").asInt(), rep.getExpiration()); assertEquals(jsonNode.get("iat").asInt(), rep.getIssuedAt()); - assertEquals(jsonNode.get("nbf").asInt(), rep.getNotBefore()); + assertEquals(jsonNode.get("nbf"), rep.getNbf()); assertEquals(jsonNode.get("sub").asText(), rep.getSubject()); List audiences = new ArrayList<>(); @@ -163,7 +163,7 @@ public class TokenIntrospectionTest extends AbstractTestRealmKeycloakTest { assertEquals("test-app", jsonNode.get("client_id").asText()); assertTrue(jsonNode.has("exp")); assertTrue(jsonNode.has("iat")); - assertTrue(jsonNode.has("nbf")); + assertFalse(jsonNode.has("nbf")); assertTrue(jsonNode.has("sub")); assertTrue(jsonNode.has("aud")); assertTrue(jsonNode.has("iss")); @@ -177,7 +177,7 @@ public class TokenIntrospectionTest extends AbstractTestRealmKeycloakTest { assertEquals(jsonNode.get("session_state").asText(), rep.getSessionState()); assertEquals(jsonNode.get("exp").asInt(), rep.getExpiration()); assertEquals(jsonNode.get("iat").asInt(), rep.getIssuedAt()); - assertEquals(jsonNode.get("nbf").asInt(), rep.getNotBefore()); + assertEquals(jsonNode.get("nbf"), rep.getNbf()); assertEquals(jsonNode.get("iss").asText(), rep.getIssuer()); assertEquals(jsonNode.get("jti").asText(), rep.getId()); assertEquals(jsonNode.get("typ").asText(), "Refresh");