From 3e5600f83f3a4b6712720da3363ed1b221ccbec8 Mon Sep 17 00:00:00 2001 From: Joe Grandja Date: Mon, 24 Feb 2020 11:09:43 -0500 Subject: [PATCH] Add configurable Clock in OidcIdTokenValidator Fixes gh-8019 --- .../authentication/OidcIdTokenValidator.java | 19 +++++++++++-- .../OidcIdTokenValidatorTests.java | 28 +++++++++++-------- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/authentication/OidcIdTokenValidator.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/authentication/OidcIdTokenValidator.java index 9a23f25c14..7ceaee3a70 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/authentication/OidcIdTokenValidator.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/authentication/OidcIdTokenValidator.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,6 +27,7 @@ import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import java.net.URL; +import java.time.Clock; import java.time.Duration; import java.time.Instant; import java.util.HashMap; @@ -48,6 +49,7 @@ public final class OidcIdTokenValidator implements OAuth2TokenValidator { private static final Duration DEFAULT_CLOCK_SKEW = Duration.ofSeconds(60); private final ClientRegistration clientRegistration; private Duration clockSkew = DEFAULT_CLOCK_SKEW; + private Clock clock = Clock.systemUTC(); public OidcIdTokenValidator(ClientRegistration clientRegistration) { Assert.notNull(clientRegistration, "clientRegistration cannot be null"); @@ -95,7 +97,7 @@ public final class OidcIdTokenValidator implements OAuth2TokenValidator { // TODO Depends on gh-4413 // 9. The current time MUST be before the time represented by the exp Claim. - Instant now = Instant.now(); + Instant now = Instant.now(this.clock); if (now.minus(this.clockSkew).isAfter(idToken.getExpiresAt())) { invalidClaims.put(IdTokenClaimNames.EXP, idToken.getExpiresAt()); } @@ -128,6 +130,19 @@ public final class OidcIdTokenValidator implements OAuth2TokenValidator { this.clockSkew = clockSkew; } + /** + * Sets the {@link Clock} used in {@link Instant#now(Clock)} + * when validating the {@link JwtClaimNames#EXP exp} + * and {@link JwtClaimNames#IAT iat} claims. + * + * @since 5.3 + * @param clock the clock + */ + public void setClock(Clock clock) { + Assert.notNull(clock, "clock cannot be null"); + this.clock = clock; + } + private static OAuth2Error invalidIdToken(Map invalidClaims) { return new OAuth2Error("invalid_id_token", "The ID Token contains invalid claims: " + invalidClaims, diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/oidc/authentication/OidcIdTokenValidatorTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/oidc/authentication/OidcIdTokenValidatorTests.java index 6152ab7afa..f357cc38c8 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/oidc/authentication/OidcIdTokenValidatorTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/oidc/authentication/OidcIdTokenValidatorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,6 +15,15 @@ */ package org.springframework.security.oauth2.client.oidc.authentication; +import org.junit.Before; +import org.junit.Test; +import org.springframework.security.oauth2.client.registration.ClientRegistration; +import org.springframework.security.oauth2.client.registration.TestClientRegistrations; +import org.springframework.security.oauth2.core.OAuth2Error; +import org.springframework.security.oauth2.core.oidc.IdTokenClaimNames; +import org.springframework.security.oauth2.jose.jws.JwsAlgorithms; +import org.springframework.security.oauth2.jwt.Jwt; + import java.time.Duration; import java.time.Instant; import java.util.Arrays; @@ -23,16 +32,6 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; -import org.junit.Before; -import org.junit.Test; - -import org.springframework.security.oauth2.client.registration.ClientRegistration; -import org.springframework.security.oauth2.client.registration.TestClientRegistrations; -import org.springframework.security.oauth2.core.OAuth2Error; -import org.springframework.security.oauth2.core.oidc.IdTokenClaimNames; -import org.springframework.security.oauth2.jose.jws.JwsAlgorithms; -import org.springframework.security.oauth2.jwt.Jwt; - import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -77,6 +76,13 @@ public class OidcIdTokenValidatorTests { .isInstanceOf(IllegalArgumentException.class); } + @Test + public void setClockWhenNullThenThrowIllegalArgumentException() { + OidcIdTokenValidator idTokenValidator = new OidcIdTokenValidator(this.registration.build()); + assertThatThrownBy(() -> idTokenValidator.setClock(null)) + .isInstanceOf(IllegalArgumentException.class); + } + @Test public void validateWhenIssuerNullThenHasErrors() { this.claims.remove(IdTokenClaimNames.ISS);