diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcLogoutAuthenticationProvider.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcLogoutAuthenticationProvider.java index 5323108e..8b59322a 100644 --- a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcLogoutAuthenticationProvider.java +++ b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcLogoutAuthenticationProvider.java @@ -97,7 +97,8 @@ public final class OidcLogoutAuthenticationProvider implements AuthenticationPro } OAuth2Authorization.Token authorizedIdToken = authorization.getToken(OidcIdToken.class); - if (!authorizedIdToken.isActive()) { + if (authorizedIdToken.isInvalidated() || + authorizedIdToken.isBeforeUse()) { // Expired ID Token should be accepted throwError(OAuth2ErrorCodes.INVALID_TOKEN, "id_token_hint"); } diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcLogoutAuthenticationProviderTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcLogoutAuthenticationProviderTests.java index 63b29a24..ceb4e011 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcLogoutAuthenticationProviderTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcLogoutAuthenticationProviderTests.java @@ -30,6 +30,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.security.authentication.TestingAuthenticationToken; +import org.springframework.security.core.Authentication; import org.springframework.security.core.session.SessionInformation; import org.springframework.security.core.session.SessionRegistry; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; @@ -134,7 +135,7 @@ public class OidcLogoutAuthenticationProviderTests { } @Test - public void authenticateWhenIdTokenNotActiveThenThrowOAuth2AuthenticationException() { + public void authenticateWhenIdTokenInvalidatedThenThrowOAuth2AuthenticationException() { TestingAuthenticationToken principal = new TestingAuthenticationToken("principal", "credentials"); RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build(); OidcIdToken idToken = OidcIdToken.withTokenValue("id-token") @@ -501,6 +502,28 @@ public class OidcLogoutAuthenticationProviderTests { .expiresAt(Instant.now().plusSeconds(60).truncatedTo(ChronoUnit.MILLIS)) .claim("sid", createHash(sessionId)) .build(); + authenticateValidIdToken(principal, registeredClient, sessionId, idToken); + } + + // gh-1440 + @Test + public void authenticateWhenValidExpiredIdTokenThenAuthenticated() throws Exception { + TestingAuthenticationToken principal = new TestingAuthenticationToken("principal", "credentials"); + RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build(); + String sessionId = "session-1"; + OidcIdToken idToken = OidcIdToken.withTokenValue("id-token") + .issuer("https://provider.com") + .subject(principal.getName()) + .audience(Collections.singleton(registeredClient.getClientId())) + .issuedAt(Instant.now().minusSeconds(60).truncatedTo(ChronoUnit.MILLIS)) + .expiresAt(Instant.now().minusSeconds(30).truncatedTo(ChronoUnit.MILLIS)) // Expired + .claim("sid", createHash(sessionId)) + .build(); + authenticateValidIdToken(principal, registeredClient, sessionId, idToken); + } + + private void authenticateValidIdToken(Authentication principal, RegisteredClient registeredClient, + String sessionId, OidcIdToken idToken) { OAuth2Authorization authorization = TestOAuth2Authorizations.authorization(registeredClient) .principalName(principal.getName()) .token(idToken,