瀏覽代碼

Validate expiry for request_uri used in PAR

Issue gh-1925

Closes gh-1973
Joe Grandja 4 月之前
父節點
當前提交
39cb9bfcea

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

@@ -16,6 +16,7 @@
 package org.springframework.security.oauth2.server.authorization.authentication;
 package org.springframework.security.oauth2.server.authorization.authentication;
 
 
 import java.security.Principal;
 import java.security.Principal;
+import java.time.Instant;
 import java.util.Arrays;
 import java.util.Arrays;
 import java.util.Base64;
 import java.util.Base64;
 import java.util.Collections;
 import java.util.Collections;
@@ -27,6 +28,7 @@ import java.util.function.Predicate;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.commons.logging.LogFactory;
 
 
+import org.springframework.core.log.LogMessage;
 import org.springframework.security.authentication.AnonymousAuthenticationToken;
 import org.springframework.security.authentication.AnonymousAuthenticationToken;
 import org.springframework.security.authentication.AuthenticationProvider;
 import org.springframework.security.authentication.AuthenticationProvider;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.Authentication;
@@ -353,6 +355,10 @@ public final class OAuth2AuthorizationCodeRequestAuthenticationProvider implemen
 			throwError(OAuth2ErrorCodes.INVALID_REQUEST, "request_uri", authorizationCodeRequestAuthentication, null);
 			throwError(OAuth2ErrorCodes.INVALID_REQUEST, "request_uri", authorizationCodeRequestAuthentication, null);
 		}
 		}
 
 
+		if (this.logger.isTraceEnabled()) {
+			this.logger.trace("Retrieved authorization with pushed authorization request");
+		}
+
 		OAuth2AuthorizationRequest authorizationRequest = authorization
 		OAuth2AuthorizationRequest authorizationRequest = authorization
 			.getAttribute(OAuth2AuthorizationRequest.class.getName());
 			.getAttribute(OAuth2AuthorizationRequest.class.getName());
 
 
@@ -361,6 +367,16 @@ public final class OAuth2AuthorizationCodeRequestAuthenticationProvider implemen
 					authorizationCodeRequestAuthentication, null);
 					authorizationCodeRequestAuthentication, null);
 		}
 		}
 
 
+		if (Instant.now().isAfter(pushedAuthorizationRequestUri.getExpiresAt())) {
+			// Remove (effectively invalidating) the pushed authorization request
+			this.authorizationService.remove(authorization);
+			if (this.logger.isWarnEnabled()) {
+				this.logger.warn(LogMessage.format("Removed expired pushed authorization request for client id '%s'",
+						authorizationRequest.getClientId()));
+			}
+			throwError(OAuth2ErrorCodes.INVALID_REQUEST, "request_uri", authorizationCodeRequestAuthentication, null);
+		}
+
 		return new OAuth2AuthorizationCodeRequestAuthenticationToken(
 		return new OAuth2AuthorizationCodeRequestAuthenticationToken(
 				authorizationCodeRequestAuthentication.getAuthorizationUri(), authorizationRequest.getClientId(),
 				authorizationCodeRequestAuthentication.getAuthorizationUri(), authorizationRequest.getClientId(),
 				(Authentication) authorizationCodeRequestAuthentication.getPrincipal(),
 				(Authentication) authorizationCodeRequestAuthentication.getPrincipal(),

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

@@ -41,8 +41,11 @@ final class OAuth2PushedAuthorizationRequestUri {
 	private Instant expiresAt;
 	private Instant expiresAt;
 
 
 	static OAuth2PushedAuthorizationRequestUri create() {
 	static OAuth2PushedAuthorizationRequestUri create() {
+		return create(Instant.now().plusSeconds(30));
+	}
+
+	static OAuth2PushedAuthorizationRequestUri create(Instant expiresAt) {
 		String state = DEFAULT_STATE_GENERATOR.generateKey();
 		String state = DEFAULT_STATE_GENERATOR.generateKey();
-		Instant expiresAt = Instant.now().plusSeconds(30);
 		OAuth2PushedAuthorizationRequestUri pushedAuthorizationRequestUri = new OAuth2PushedAuthorizationRequestUri();
 		OAuth2PushedAuthorizationRequestUri pushedAuthorizationRequestUri = new OAuth2PushedAuthorizationRequestUri();
 		pushedAuthorizationRequestUri.requestUri = REQUEST_URI_PREFIX + state + REQUEST_URI_DELIMITER
 		pushedAuthorizationRequestUri.requestUri = REQUEST_URI_PREFIX + state + REQUEST_URI_DELIMITER
 				+ expiresAt.toEpochMilli();
 				+ expiresAt.toEpochMilli();

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

@@ -16,6 +16,7 @@
 package org.springframework.security.oauth2.server.authorization.authentication;
 package org.springframework.security.oauth2.server.authorization.authentication;
 
 
 import java.security.Principal;
 import java.security.Principal;
+import java.time.Instant;
 import java.util.Collections;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Map;
@@ -690,6 +691,31 @@ public class OAuth2AuthorizationCodeRequestAuthenticationProviderTests {
 					OAuth2ErrorCodes.INVALID_REQUEST, "client_id", null));
 					OAuth2ErrorCodes.INVALID_REQUEST, "client_id", null));
 	}
 	}
 
 
+	@Test
+	public void authenticateWhenAuthorizationCodeRequestWithExpiredRequestUriThenThrowOAuth2AuthorizationCodeRequestAuthenticationException() {
+		RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
+
+		OAuth2PushedAuthorizationRequestUri pushedAuthorizationRequestUri = OAuth2PushedAuthorizationRequestUri
+			.create(Instant.now().minusSeconds(5));
+		Map<String, Object> additionalParameters = new HashMap<>();
+		additionalParameters.put("request_uri", pushedAuthorizationRequestUri.getRequestUri());
+		OAuth2Authorization authorization = TestOAuth2Authorizations
+			.authorization(registeredClient, additionalParameters)
+			.build();
+		given(this.authorizationService.findByToken(eq(pushedAuthorizationRequestUri.getState()), eq(STATE_TOKEN_TYPE)))
+			.willReturn(authorization);
+
+		OAuth2AuthorizationCodeRequestAuthenticationToken authentication = new OAuth2AuthorizationCodeRequestAuthenticationToken(
+				AUTHORIZATION_URI, registeredClient.getClientId(), this.principal, null, null, null,
+				additionalParameters);
+
+		assertThatThrownBy(() -> this.authenticationProvider.authenticate(authentication))
+			.isInstanceOf(OAuth2AuthorizationCodeRequestAuthenticationException.class)
+			.satisfies((ex) -> assertAuthenticationException((OAuth2AuthorizationCodeRequestAuthenticationException) ex,
+					OAuth2ErrorCodes.INVALID_REQUEST, "request_uri", null));
+		verify(this.authorizationService).remove(eq(authorization));
+	}
+
 	@Test
 	@Test
 	public void authenticateWhenAuthorizationCodeNotGeneratedThenThrowOAuth2AuthorizationCodeRequestAuthenticationException() {
 	public void authenticateWhenAuthorizationCodeNotGeneratedThenThrowOAuth2AuthorizationCodeRequestAuthenticationException() {
 		RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();
 		RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build();