Skip to content

Commit 39cb9bf

Browse files
committed
Validate expiry for request_uri used in PAR
Issue gh-1925 Closes gh-1973
1 parent 5458e08 commit 39cb9bf

File tree

3 files changed

+46
-1
lines changed

3 files changed

+46
-1
lines changed

oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeRequestAuthenticationProvider.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package org.springframework.security.oauth2.server.authorization.authentication;
1717

1818
import java.security.Principal;
19+
import java.time.Instant;
1920
import java.util.Arrays;
2021
import java.util.Base64;
2122
import java.util.Collections;
@@ -27,6 +28,7 @@
2728
import org.apache.commons.logging.Log;
2829
import org.apache.commons.logging.LogFactory;
2930

31+
import org.springframework.core.log.LogMessage;
3032
import org.springframework.security.authentication.AnonymousAuthenticationToken;
3133
import org.springframework.security.authentication.AuthenticationProvider;
3234
import org.springframework.security.core.Authentication;
@@ -353,6 +355,10 @@ private OAuth2AuthorizationCodeRequestAuthenticationToken fromPushedAuthorizatio
353355
throwError(OAuth2ErrorCodes.INVALID_REQUEST, "request_uri", authorizationCodeRequestAuthentication, null);
354356
}
355357

358+
if (this.logger.isTraceEnabled()) {
359+
this.logger.trace("Retrieved authorization with pushed authorization request");
360+
}
361+
356362
OAuth2AuthorizationRequest authorizationRequest = authorization
357363
.getAttribute(OAuth2AuthorizationRequest.class.getName());
358364

@@ -361,6 +367,16 @@ private OAuth2AuthorizationCodeRequestAuthenticationToken fromPushedAuthorizatio
361367
authorizationCodeRequestAuthentication, null);
362368
}
363369

370+
if (Instant.now().isAfter(pushedAuthorizationRequestUri.getExpiresAt())) {
371+
// Remove (effectively invalidating) the pushed authorization request
372+
this.authorizationService.remove(authorization);
373+
if (this.logger.isWarnEnabled()) {
374+
this.logger.warn(LogMessage.format("Removed expired pushed authorization request for client id '%s'",
375+
authorizationRequest.getClientId()));
376+
}
377+
throwError(OAuth2ErrorCodes.INVALID_REQUEST, "request_uri", authorizationCodeRequestAuthentication, null);
378+
}
379+
364380
return new OAuth2AuthorizationCodeRequestAuthenticationToken(
365381
authorizationCodeRequestAuthentication.getAuthorizationUri(), authorizationRequest.getClientId(),
366382
(Authentication) authorizationCodeRequestAuthentication.getPrincipal(),

oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2PushedAuthorizationRequestUri.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,11 @@ final class OAuth2PushedAuthorizationRequestUri {
4141
private Instant expiresAt;
4242

4343
static OAuth2PushedAuthorizationRequestUri create() {
44+
return create(Instant.now().plusSeconds(30));
45+
}
46+
47+
static OAuth2PushedAuthorizationRequestUri create(Instant expiresAt) {
4448
String state = DEFAULT_STATE_GENERATOR.generateKey();
45-
Instant expiresAt = Instant.now().plusSeconds(30);
4649
OAuth2PushedAuthorizationRequestUri pushedAuthorizationRequestUri = new OAuth2PushedAuthorizationRequestUri();
4750
pushedAuthorizationRequestUri.requestUri = REQUEST_URI_PREFIX + state + REQUEST_URI_DELIMITER
4851
+ expiresAt.toEpochMilli();

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package org.springframework.security.oauth2.server.authorization.authentication;
1717

1818
import java.security.Principal;
19+
import java.time.Instant;
1920
import java.util.Collections;
2021
import java.util.HashMap;
2122
import java.util.Map;
@@ -690,6 +691,31 @@ public void authenticateWhenAuthorizationCodeRequestWithRequestUriIssuedToAnothe
690691
OAuth2ErrorCodes.INVALID_REQUEST, "client_id", null));
691692
}
692693

694+
@Test
695+
public void authenticateWhenAuthorizationCodeRequestWithExpiredRequestUriThenThrowOAuth2AuthorizationCodeRequestAuthenticationException() {
696+
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
697+
698+
OAuth2PushedAuthorizationRequestUri pushedAuthorizationRequestUri = OAuth2PushedAuthorizationRequestUri
699+
.create(Instant.now().minusSeconds(5));
700+
Map<String, Object> additionalParameters = new HashMap<>();
701+
additionalParameters.put("request_uri", pushedAuthorizationRequestUri.getRequestUri());
702+
OAuth2Authorization authorization = TestOAuth2Authorizations
703+
.authorization(registeredClient, additionalParameters)
704+
.build();
705+
given(this.authorizationService.findByToken(eq(pushedAuthorizationRequestUri.getState()), eq(STATE_TOKEN_TYPE)))
706+
.willReturn(authorization);
707+
708+
OAuth2AuthorizationCodeRequestAuthenticationToken authentication = new OAuth2AuthorizationCodeRequestAuthenticationToken(
709+
AUTHORIZATION_URI, registeredClient.getClientId(), this.principal, null, null, null,
710+
additionalParameters);
711+
712+
assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
713+
.isInstanceOf(OAuth2AuthorizationCodeRequestAuthenticationException.class)
714+
.satisfies((ex) -> assertAuthenticationException((OAuth2AuthorizationCodeRequestAuthenticationException) ex,
715+
OAuth2ErrorCodes.INVALID_REQUEST, "request_uri", null));
716+
verify(this.authorizationService).remove(eq(authorization));
717+
}
718+
693719
@Test
694720
public void authenticateWhenAuthorizationCodeNotGeneratedThenThrowOAuth2AuthorizationCodeRequestAuthenticationException() {
695721
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();

0 commit comments

Comments
 (0)