From 42db8c0eabf16a82c7b2e90b79cd3735eeb0e226 Mon Sep 17 00:00:00 2001 From: gpanthe Date: Thu, 29 Nov 2018 17:40:41 +0100 Subject: [PATCH 1/2] Issue 6187: support ISO Date formatted timestamps (for 'updated_at' by Auth0 and OneLogin) --- .../security/oauth2/core/ClaimAccessor.java | 13 ++++++++++++- .../security/oauth2/core/ClaimAccessorTests.java | 11 +++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/ClaimAccessor.java b/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/ClaimAccessor.java index e4505a4a907..60422187afd 100644 --- a/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/ClaimAccessor.java +++ b/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/ClaimAccessor.java @@ -20,6 +20,7 @@ import java.net.MalformedURLException; import java.net.URL; import java.time.Instant; +import java.time.format.DateTimeParseException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; @@ -98,8 +99,18 @@ default Instant getClaimAsInstant(String claim) { if (Instant.class.isAssignableFrom(claimValue.getClass())) { return (Instant) claimValue; } + if (String.class.isAssignableFrom(claimValue.getClass())) { + try { + return Instant.parse((String) claimValue); + } + catch(DateTimeParseException e){ + throw new IllegalArgumentException("Unable to convert claim '" + claim + + "' from string '" + claimValue + "' to Instant."); + } + } throw new IllegalArgumentException("Unable to convert claim '" + claim + - "' of type '" + claimValue.getClass() + "' to Instant."); + "' of type '" + claimValue.getClass() + "' to Instant."); + } /** diff --git a/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/ClaimAccessorTests.java b/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/ClaimAccessorTests.java index dc89d1dbe63..ce354485df7 100644 --- a/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/ClaimAccessorTests.java +++ b/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/ClaimAccessorTests.java @@ -93,6 +93,17 @@ public void getClaimAsInstantWhenDoubleTypeSecondsThenReturnInstant() { expectedClaimValue.minusSeconds(1), expectedClaimValue.plusSeconds(1)); } + // gh-6187 + @Test + public void getClaimAsInstantWhenISODateStringThenReturnInstant() { + Instant expectedClaimValue = Instant.now(); + String claimName = "isoDate"; + this.claims.put(claimName, expectedClaimValue.toString()); + + assertThat(this.claimAccessor.getClaimAsInstant(claimName)).isBetween( + expectedClaimValue.minusSeconds(1), expectedClaimValue.plusSeconds(1)); + } + // gh-5608 @Test public void getClaimAsStringWhenValueIsNullThenReturnNull() { From 16aede90ed375f593c6f88a9822102e3c5e5e1b8 Mon Sep 17 00:00:00 2001 From: gpanthe Date: Wed, 5 Dec 2018 15:31:15 +0100 Subject: [PATCH 2/2] Issue 6187: resolve remarks --- .../security/oauth2/core/ClaimAccessor.java | 16 ++++++++++++---- .../oauth2/core/ClaimAccessorTests.java | 18 ++++++++++++++++-- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/ClaimAccessor.java b/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/ClaimAccessor.java index 60422187afd..eece01b4819 100644 --- a/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/ClaimAccessor.java +++ b/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/ClaimAccessor.java @@ -20,6 +20,8 @@ import java.net.MalformedURLException; import java.net.URL; import java.time.Instant; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import java.util.ArrayList; import java.util.Date; @@ -101,15 +103,21 @@ default Instant getClaimAsInstant(String claim) { } if (String.class.isAssignableFrom(claimValue.getClass())) { try { - return Instant.parse((String) claimValue); + return Instant.from(DateTimeFormatter.ISO_INSTANT.parse((String)claimValue)); } catch(DateTimeParseException e){ - throw new IllegalArgumentException("Unable to convert claim '" + claim + - "' from string '" + claimValue + "' to Instant."); + try { + return ZonedDateTime.from(DateTimeFormatter.ISO_ZONED_DATE_TIME.parse((String)claimValue)) + .toInstant(); + } + catch(DateTimeParseException e2){ + throw new IllegalArgumentException("Unable to convert claim '" + claim + + "' from string '" + claimValue + "' to Instant."); + } } } throw new IllegalArgumentException("Unable to convert claim '" + claim + - "' of type '" + claimValue.getClass() + "' to Instant."); + "' of type '" + claimValue.getClass() + "' to Instant."); } diff --git a/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/ClaimAccessorTests.java b/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/ClaimAccessorTests.java index ce354485df7..465e77269cf 100644 --- a/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/ClaimAccessorTests.java +++ b/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/ClaimAccessorTests.java @@ -96,14 +96,28 @@ public void getClaimAsInstantWhenDoubleTypeSecondsThenReturnInstant() { // gh-6187 @Test public void getClaimAsInstantWhenISODateStringThenReturnInstant() { - Instant expectedClaimValue = Instant.now(); + Instant expectedClaimValue = Instant.parse("2011-12-03T09:15:30Z"); String claimName = "isoDate"; - this.claims.put(claimName, expectedClaimValue.toString()); + this.claims.put(claimName, "2011-12-03T09:15:30Z"); + assertThat(this.claimAccessor.getClaimAsInstant(claimName)).isBetween( + expectedClaimValue.minusSeconds(1), expectedClaimValue.plusSeconds(1)); + this.claims.put(claimName, "2011-12-03T10:15:30+01:00"); + assertThat(this.claimAccessor.getClaimAsInstant(claimName)).isBetween( + expectedClaimValue.minusSeconds(1), expectedClaimValue.plusSeconds(1)); + this.claims.put(claimName, "2011-12-03T10:15:30+01:00[Europe/Paris]"); assertThat(this.claimAccessor.getClaimAsInstant(claimName)).isBetween( expectedClaimValue.minusSeconds(1), expectedClaimValue.plusSeconds(1)); } + // gh-6187 + @Test(expected = IllegalArgumentException.class) + public void getClaimAsInstantWithoutTimezoneThrowsIAE() { + String claimName = "isoDate"; + this.claims.put(claimName, "2011-12-03T09:15:30"); + this.claimAccessor.getClaimAsInstant(claimName); + } + // gh-5608 @Test public void getClaimAsStringWhenValueIsNullThenReturnNull() {