Skip to content

Commit 6e683f2

Browse files
committed
Fix ID Token auth_time validation
Closes gh-18839
1 parent b6e24db commit 6e683f2

2 files changed

Lines changed: 26 additions & 4 deletions

File tree

oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizedClientRefreshedEventListener.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,11 @@ private void validateAuthenticatedAt(OidcUser existingOidcUser, OidcIdToken idTo
300300
return;
301301
}
302302

303-
if (!idToken.getAuthenticatedAt().equals(existingOidcUser.getIdToken().getAuthenticatedAt())) {
303+
// The auth_time claim MUST represent the time of the original authentication OR
304+
// the most recent time when the end-user reauthenticated when "prompt=login" is
305+
// passed in the authentication request
306+
if (!idToken.getAuthenticatedAt().equals(existingOidcUser.getIdToken().getAuthenticatedAt())
307+
&& !idToken.getAuthenticatedAt().isAfter(existingOidcUser.getIdToken().getAuthenticatedAt())) {
304308
OAuth2Error oauth2Error = new OAuth2Error(INVALID_ID_TOKEN_ERROR_CODE, "Invalid authenticated at time",
305309
REFRESH_TOKEN_RESPONSE_ERROR_URI);
306310
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());

oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizedClientRefreshedEventListenerTests.java

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -419,8 +419,8 @@ public void onApplicationEventWhenIdTokenAudienceDoesNotMatchThenThrowsOAuth2Aut
419419
}
420420

421421
@Test
422-
public void onApplicationEventWhenIdTokenAuthenticatedAtDoesNotMatchThenThrowsOAuth2AuthenticationException() {
423-
Instant authTime = this.oidcUser.getAuthenticatedAt().plus(5, ChronoUnit.SECONDS);
422+
public void onApplicationEventWhenIdTokenAuthenticatedAtBeforeCurrentAuthenticatedAtThenThrowsOAuth2AuthenticationException() {
423+
Instant authTime = this.oidcUser.getAuthenticatedAt().minus(5, ChronoUnit.MINUTES);
424424
Jwt jwt = createJwt().claim(IdTokenClaimNames.AUTH_TIME, authTime).build();
425425
SecurityContextImpl securityContext = new SecurityContextImpl(this.authentication);
426426
given(this.securityContextHolderStrategy.getContext()).willReturn(securityContext);
@@ -440,8 +440,26 @@ public void onApplicationEventWhenIdTokenAuthenticatedAtDoesNotMatchThenThrowsOA
440440
verifyNoInteractions(this.userService, this.applicationEventPublisher);
441441
}
442442

443+
// gh-18839
443444
@Test
444-
public void onApplicationEventWhenIdTokenAuthenticatedAtMatchesThenOidcUserRefreshedEventPublished() {
445+
public void onApplicationEventWhenIdTokenAuthenticatedAtAfterCurrentAuthenticatedAtThenOidcUserRefreshedEventPublished() {
446+
Instant authTime = this.oidcUser.getAuthenticatedAt().plus(5, ChronoUnit.MINUTES);
447+
Jwt jwt = createJwt().claim(IdTokenClaimNames.AUTH_TIME, authTime).build();
448+
SecurityContextImpl securityContext = new SecurityContextImpl(this.authentication);
449+
given(this.securityContextHolderStrategy.getContext()).willReturn(securityContext);
450+
given(this.jwtDecoder.decode(anyString())).willReturn(jwt);
451+
given(this.userService.loadUser(any(OidcUserRequest.class))).willReturn(this.oidcUser);
452+
453+
OAuth2AuthorizedClientRefreshedEvent authorizedClientRefreshedEvent = new OAuth2AuthorizedClientRefreshedEvent(
454+
this.accessTokenResponse, this.authorizedClient);
455+
this.eventListener.onApplicationEvent(authorizedClientRefreshedEvent);
456+
457+
verify(this.applicationEventPublisher).publishEvent(any(OidcUserRefreshedEvent.class));
458+
verifyNoMoreInteractions(this.applicationEventPublisher);
459+
}
460+
461+
@Test
462+
public void onApplicationEventWhenIdTokenAuthenticatedAtMatchesCurrentAuthenticatedAtThenOidcUserRefreshedEventPublished() {
445463
Instant authTime = this.authentication.getPrincipal().getAttribute(IdTokenClaimNames.AUTH_TIME);
446464
Jwt jwt = createJwt().claim(IdTokenClaimNames.AUTH_TIME, authTime).build();
447465
SecurityContextImpl securityContext = new SecurityContextImpl(this.authentication);

0 commit comments

Comments
 (0)