Skip to content

Commit 4152488

Browse files
committed
Fix auth_time claim should represent authentication time
Closes gh-18282
1 parent 2361dc1 commit 4152488

4 files changed

Lines changed: 40 additions & 11 deletions

File tree

config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OidcTests.java

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
import org.springframework.security.config.test.SpringTestContextExtension;
6161
import org.springframework.security.core.Authentication;
6262
import org.springframework.security.core.GrantedAuthority;
63+
import org.springframework.security.core.authority.FactorGrantedAuthority;
6364
import org.springframework.security.core.session.SessionRegistry;
6465
import org.springframework.security.core.session.SessionRegistryImpl;
6566
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
@@ -210,7 +211,8 @@ public void requestWhenAuthenticationRequestThenTokenResponseIncludesIdToken() t
210211
registeredClient);
211212
MvcResult mvcResult = this.mvc
212213
.perform(get(DEFAULT_AUTHORIZATION_ENDPOINT_URI).queryParams(authorizationRequestParameters)
213-
.with(user("user").roles("A", "B")))
214+
.with(user("user").roles("A", "B")
215+
.authorities(FactorGrantedAuthority.fromAuthority(FactorGrantedAuthority.PASSWORD_AUTHORITY))))
214216
.andExpect(status().is3xxRedirection())
215217
.andReturn();
216218
String redirectedUrl = mvcResult.getResponse().getRedirectedUrl();
@@ -270,7 +272,8 @@ public void requestWhenRefreshTokenRequestThenIdTokenContainsSidClaim() throws E
270272
registeredClient);
271273
MvcResult mvcResult = this.mvc
272274
.perform(get(DEFAULT_AUTHORIZATION_ENDPOINT_URI).queryParams(authorizationRequestParameters)
273-
.with(user("user").roles("A", "B")))
275+
.with(user("user").roles("A", "B")
276+
.authorities(FactorGrantedAuthority.fromAuthority(FactorGrantedAuthority.PASSWORD_AUTHORITY))))
274277
.andExpect(status().is3xxRedirection())
275278
.andReturn();
276279
String redirectedUrl = mvcResult.getResponse().getRedirectedUrl();
@@ -335,7 +338,8 @@ public void requestWhenLogoutRequestThenLogout() throws Exception {
335338
registeredClient);
336339
MvcResult mvcResult = this.mvc
337340
.perform(get(issuer.concat(DEFAULT_AUTHORIZATION_ENDPOINT_URI)).queryParams(authorizationRequestParameters)
338-
.with(user("user")))
341+
.with(user("user")
342+
.authorities(FactorGrantedAuthority.fromAuthority(FactorGrantedAuthority.PASSWORD_AUTHORITY))))
339343
.andExpect(status().is3xxRedirection())
340344
.andReturn();
341345

@@ -388,7 +392,8 @@ public void requestWhenLogoutRequestWithOtherUsersIdTokenThenNotLogout() throws
388392
registeredClient1);
389393
MvcResult mvcResult = this.mvc
390394
.perform(get(DEFAULT_AUTHORIZATION_ENDPOINT_URI).queryParams(authorizationRequestParameters)
391-
.with(user("user1")))
395+
.with(user("user1")
396+
.authorities(FactorGrantedAuthority.fromAuthority(FactorGrantedAuthority.PASSWORD_AUTHORITY))))
392397
.andExpect(status().is3xxRedirection())
393398
.andReturn();
394399

@@ -424,7 +429,8 @@ public void requestWhenLogoutRequestWithOtherUsersIdTokenThenNotLogout() throws
424429
authorizationRequestParameters = getAuthorizationRequestParameters(registeredClient2);
425430
mvcResult = this.mvc
426431
.perform(get(DEFAULT_AUTHORIZATION_ENDPOINT_URI).queryParams(authorizationRequestParameters)
427-
.with(user("user2")))
432+
.with(user("user2")
433+
.authorities(FactorGrantedAuthority.fromAuthority(FactorGrantedAuthority.PASSWORD_AUTHORITY))))
428434
.andExpect(status().is3xxRedirection())
429435
.andReturn();
430436

@@ -497,7 +503,8 @@ public void requestWhenAuthenticationRequestWithOfflineAccessScopeThenTokenRespo
497503
registeredClient);
498504
MvcResult mvcResult = this.mvc
499505
.perform(get(DEFAULT_AUTHORIZATION_ENDPOINT_URI).queryParams(authorizationRequestParameters)
500-
.with(user("user")))
506+
.with(user("user")
507+
.authorities(FactorGrantedAuthority.fromAuthority(FactorGrantedAuthority.PASSWORD_AUTHORITY))))
501508
.andExpect(status().is3xxRedirection())
502509
.andReturn();
503510
String redirectedUrl = mvcResult.getResponse().getRedirectedUrl();
@@ -537,7 +544,8 @@ public void requestWhenAuthenticationRequestWithoutOfflineAccessScopeThenTokenRe
537544
registeredClient);
538545
MvcResult mvcResult = this.mvc
539546
.perform(get(DEFAULT_AUTHORIZATION_ENDPOINT_URI).queryParams(authorizationRequestParameters)
540-
.with(user("user")))
547+
.with(user("user")
548+
.authorities(FactorGrantedAuthority.fromAuthority(FactorGrantedAuthority.PASSWORD_AUTHORITY))))
541549
.andExpect(status().is3xxRedirection())
542550
.andReturn();
543551
String redirectedUrl = mvcResult.getResponse().getRedirectedUrl();

oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/token/JwtGenerator.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
import java.util.UUID;
2525

2626
import org.springframework.lang.Nullable;
27+
import org.springframework.security.core.Authentication;
28+
import org.springframework.security.core.GrantedAuthority;
29+
import org.springframework.security.core.authority.FactorGrantedAuthority;
2730
import org.springframework.security.core.session.SessionInformation;
2831
import org.springframework.security.oauth2.core.AuthorizationGrantType;
2932
import org.springframework.security.oauth2.core.OAuth2AccessToken;
@@ -141,7 +144,7 @@ else if (OidcParameterNames.ID_TOKEN.equals(context.getTokenType().getValue()))
141144
SessionInformation sessionInformation = context.get(SessionInformation.class);
142145
if (sessionInformation != null) {
143146
claimsBuilder.claim("sid", sessionInformation.getSessionId());
144-
claimsBuilder.claim(IdTokenClaimNames.AUTH_TIME, sessionInformation.getLastRequest());
147+
claimsBuilder.claim(IdTokenClaimNames.AUTH_TIME, getAuthenticationTime(context.getPrincipal()));
145148
}
146149
}
147150
else if (AuthorizationGrantType.REFRESH_TOKEN.equals(context.getAuthorizationGrantType())) {
@@ -222,4 +225,17 @@ public void setClock(Clock clock) {
222225
this.clock = clock;
223226
}
224227

228+
static Date getAuthenticationTime(Authentication authentication) {
229+
Instant authenticationTime = null;
230+
for (GrantedAuthority grantedAuthority : authentication.getAuthorities()) {
231+
if (grantedAuthority instanceof FactorGrantedAuthority factorGrantedAuthority) {
232+
if (authenticationTime == null || factorGrantedAuthority.getIssuedAt().isAfter(authenticationTime)) {
233+
authenticationTime = factorGrantedAuthority.getIssuedAt();
234+
}
235+
}
236+
}
237+
Assert.notNull(authenticationTime, "authenticationTime cannot be null");
238+
return Date.from(authenticationTime);
239+
}
240+
225241
}

oauth2/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/TestOAuth2Authorizations.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
import java.util.Map;
2525

2626
import org.springframework.security.authentication.TestingAuthenticationToken;
27+
import org.springframework.security.core.Authentication;
28+
import org.springframework.security.core.authority.FactorGrantedAuthority;
29+
import org.springframework.security.core.authority.SimpleGrantedAuthority;
2730
import org.springframework.security.oauth2.core.AuthorizationGrantType;
2831
import org.springframework.security.oauth2.core.OAuth2AccessToken;
2932
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
@@ -85,6 +88,9 @@ private static OAuth2Authorization.Builder authorization(RegisteredClient regist
8588
.additionalParameters(authorizationRequestAdditionalParameters)
8689
.state("state")
8790
.build();
91+
Authentication principal = new TestingAuthenticationToken("principal", null,
92+
new SimpleGrantedAuthority("ROLE_A"), new SimpleGrantedAuthority("ROLE_B"),
93+
FactorGrantedAuthority.fromAuthority(FactorGrantedAuthority.PASSWORD_AUTHORITY));
8894
OAuth2Authorization.Builder builder = OAuth2Authorization.withRegisteredClient(registeredClient)
8995
.id("id")
9096
.principalName("principal")
@@ -93,8 +99,7 @@ private static OAuth2Authorization.Builder authorization(RegisteredClient regist
9399
.token(authorizationCode)
94100
.attribute(OAuth2ParameterNames.STATE, "consent-state")
95101
.attribute(OAuth2AuthorizationRequest.class.getName(), authorizationRequest)
96-
.attribute(Principal.class.getName(),
97-
new TestingAuthenticationToken("principal", null, "ROLE_A", "ROLE_B"));
102+
.attribute(Principal.class.getName(), principal);
98103
if (accessToken != null) {
99104
OAuth2RefreshToken refreshToken = new OAuth2RefreshToken("refresh-token", Instant.now(),
100105
Instant.now().plus(1, ChronoUnit.HOURS));

oauth2/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/token/JwtGeneratorTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ private void assertGeneratedTokenType(OAuth2TokenContext tokenContext, Clock clo
363363
SessionInformation sessionInformation = tokenContext.get(SessionInformation.class);
364364
assertThat(jwtClaimsSet.<String>getClaim("sid")).isEqualTo(sessionInformation.getSessionId());
365365
assertThat(jwtClaimsSet.<Date>getClaim(IdTokenClaimNames.AUTH_TIME))
366-
.isEqualTo(sessionInformation.getLastRequest());
366+
.isEqualTo(JwtGenerator.getAuthenticationTime(tokenContext.getPrincipal()));
367367
}
368368
else if (tokenContext.getAuthorizationGrantType().equals(AuthorizationGrantType.REFRESH_TOKEN)) {
369369
OidcIdToken currentIdToken = tokenContext.getAuthorization().getToken(OidcIdToken.class).getToken();

0 commit comments

Comments
 (0)