diff --git a/oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeRequestAuthenticationProvider.java b/oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeRequestAuthenticationProvider.java index 7cdc21f013..1b9c65145b 100644 --- a/oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeRequestAuthenticationProvider.java +++ b/oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeRequestAuthenticationProvider.java @@ -500,7 +500,8 @@ public final class OAuth2AuthorizationCodeRequestAuthenticationProvider implemen registeredClient); if (error.getErrorCode().equals(OAuth2ErrorCodes.INVALID_REQUEST) && (parameterName.equals(OAuth2ParameterNames.CLIENT_ID) - || parameterName.equals(OAuth2ParameterNames.STATE))) { + || parameterName.equals(OAuth2ParameterNames.STATE) + || parameterName.equals(OAuth2ParameterNames.REQUEST_URI))) { redirectUri = null; // Prevent redirects } diff --git a/oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeRequestAuthenticationValidator.java b/oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeRequestAuthenticationValidator.java index 839ae289c0..0ce170cbc2 100644 --- a/oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeRequestAuthenticationValidator.java +++ b/oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeRequestAuthenticationValidator.java @@ -298,8 +298,10 @@ public final class OAuth2AuthorizationCodeRequestAuthenticationValidator String redirectUri = StringUtils.hasText(authorizationCodeRequestAuthentication.getRedirectUri()) ? authorizationCodeRequestAuthentication.getRedirectUri() : registeredClient.getRedirectUris().iterator().next(); - if (error.getErrorCode().equals(OAuth2ErrorCodes.INVALID_REQUEST) - && parameterName.equals(OAuth2ParameterNames.REDIRECT_URI)) { + if ((error.getErrorCode().equals(OAuth2ErrorCodes.INVALID_REQUEST) + || error.getErrorCode().equals(OAuth2ErrorCodes.UNAUTHORIZED_CLIENT)) + && (parameterName.equals(OAuth2ParameterNames.CLIENT_ID) + || parameterName.equals(OAuth2ParameterNames.REDIRECT_URI))) { redirectUri = null; // Prevent redirects } diff --git a/oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/authentication/OAuth2AuthorizationCodeRequestAuthenticationConverter.java b/oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/authentication/OAuth2AuthorizationCodeRequestAuthenticationConverter.java index ba7ecf5b69..f395cedd98 100644 --- a/oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/authentication/OAuth2AuthorizationCodeRequestAuthenticationConverter.java +++ b/oauth2/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/web/authentication/OAuth2AuthorizationCodeRequestAuthenticationConverter.java @@ -132,52 +132,66 @@ public final class OAuth2AuthorizationCodeRequestAuthenticationConverter impleme principal = ANONYMOUS_AUTHENTICATION; } - // redirect_uri (OPTIONAL) - String redirectUri = parameters.getFirst(OAuth2ParameterNames.REDIRECT_URI); - List redirectUriParams = parameters.get(OAuth2ParameterNames.REDIRECT_URI); - if (StringUtils.hasText(redirectUri) && redirectUriParams != null && redirectUriParams.size() != 1) { - throwError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.REDIRECT_URI); + String redirectUri = null; + if (!StringUtils.hasText(requestUri)) { + // redirect_uri (OPTIONAL) + redirectUri = parameters.getFirst(OAuth2ParameterNames.REDIRECT_URI); + List redirectUriParams = parameters.get(OAuth2ParameterNames.REDIRECT_URI); + if (StringUtils.hasText(redirectUri) && redirectUriParams != null && redirectUriParams.size() != 1) { + throwError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.REDIRECT_URI); + } } - // scope (OPTIONAL) Set scopes = null; - String scope = parameters.getFirst(OAuth2ParameterNames.SCOPE); - List scopeParams = parameters.get(OAuth2ParameterNames.SCOPE); - if (StringUtils.hasText(scope) && scopeParams != null && scopeParams.size() != 1) { - throwError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.SCOPE); - } - if (StringUtils.hasText(scope)) { - scopes = new HashSet<>(Arrays.asList(StringUtils.delimitedListToStringArray(scope, " "))); + if (!StringUtils.hasText(requestUri)) { + // scope (OPTIONAL) + String scope = parameters.getFirst(OAuth2ParameterNames.SCOPE); + List scopeParams = parameters.get(OAuth2ParameterNames.SCOPE); + if (StringUtils.hasText(scope) && scopeParams != null && scopeParams.size() != 1) { + throwError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.SCOPE); + } + if (StringUtils.hasText(scope)) { + scopes = new HashSet<>(Arrays.asList(StringUtils.delimitedListToStringArray(scope, " "))); + } } - // state (RECOMMENDED) - String state = parameters.getFirst(OAuth2ParameterNames.STATE); - List stateParams = parameters.get(OAuth2ParameterNames.STATE); - if (StringUtils.hasText(state) && stateParams != null && stateParams.size() != 1) { - throwError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.STATE); + String state = null; + if (!StringUtils.hasText(requestUri)) { + // state (RECOMMENDED) + state = parameters.getFirst(OAuth2ParameterNames.STATE); + List stateParams = parameters.get(OAuth2ParameterNames.STATE); + if (StringUtils.hasText(state) && stateParams != null && stateParams.size() != 1) { + throwError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.STATE); + } } - // code_challenge (REQUIRED for public clients) - RFC 7636 (PKCE) - String codeChallenge = parameters.getFirst(PkceParameterNames.CODE_CHALLENGE); - List codeChallengeParams = parameters.get(PkceParameterNames.CODE_CHALLENGE); - if (StringUtils.hasText(codeChallenge) && codeChallengeParams != null && codeChallengeParams.size() != 1) { - throwError(OAuth2ErrorCodes.INVALID_REQUEST, PkceParameterNames.CODE_CHALLENGE, PKCE_ERROR_URI); + if (!StringUtils.hasText(requestUri)) { + // code_challenge (REQUIRED for public clients) - RFC 7636 (PKCE) + String codeChallenge = parameters.getFirst(PkceParameterNames.CODE_CHALLENGE); + List codeChallengeParams = parameters.get(PkceParameterNames.CODE_CHALLENGE); + if (StringUtils.hasText(codeChallenge) && codeChallengeParams != null && codeChallengeParams.size() != 1) { + throwError(OAuth2ErrorCodes.INVALID_REQUEST, PkceParameterNames.CODE_CHALLENGE, PKCE_ERROR_URI); + } } - // code_challenge_method (OPTIONAL for public clients) - RFC 7636 (PKCE) - String codeChallengeMethod = parameters.getFirst(PkceParameterNames.CODE_CHALLENGE_METHOD); - List codeChallengeMethodParams = parameters.get(PkceParameterNames.CODE_CHALLENGE_METHOD); - if (StringUtils.hasText(codeChallengeMethod) && codeChallengeMethodParams != null - && codeChallengeMethodParams.size() != 1) { - throwError(OAuth2ErrorCodes.INVALID_REQUEST, PkceParameterNames.CODE_CHALLENGE_METHOD, PKCE_ERROR_URI); + if (!StringUtils.hasText(requestUri)) { + // code_challenge_method (OPTIONAL for public clients) - RFC 7636 (PKCE) + String codeChallengeMethod = parameters.getFirst(PkceParameterNames.CODE_CHALLENGE_METHOD); + List codeChallengeMethodParams = parameters.get(PkceParameterNames.CODE_CHALLENGE_METHOD); + if (StringUtils.hasText(codeChallengeMethod) && codeChallengeMethodParams != null + && codeChallengeMethodParams.size() != 1) { + throwError(OAuth2ErrorCodes.INVALID_REQUEST, PkceParameterNames.CODE_CHALLENGE_METHOD, PKCE_ERROR_URI); + } } - // prompt (OPTIONAL for OpenID Connect 1.0 Authentication Request) - if (!CollectionUtils.isEmpty(scopes) && scopes.contains(OidcScopes.OPENID)) { - String prompt = parameters.getFirst("prompt"); - List promptParams = parameters.get("prompt"); - if (StringUtils.hasText(prompt) && promptParams != null && promptParams.size() != 1) { - throwError(OAuth2ErrorCodes.INVALID_REQUEST, "prompt"); + if (!StringUtils.hasText(requestUri)) { + // prompt (OPTIONAL for OpenID Connect 1.0 Authentication Request) + if (!CollectionUtils.isEmpty(scopes) && scopes.contains(OidcScopes.OPENID)) { + String prompt = parameters.getFirst("prompt"); + List promptParams = parameters.get("prompt"); + if (StringUtils.hasText(prompt) && promptParams != null && promptParams.size() != 1) { + throwError(OAuth2ErrorCodes.INVALID_REQUEST, "prompt"); + } } } diff --git a/oauth2/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeRequestAuthenticationProviderTests.java b/oauth2/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeRequestAuthenticationProviderTests.java index 3af0793d52..3bd338494d 100644 --- a/oauth2/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeRequestAuthenticationProviderTests.java +++ b/oauth2/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeRequestAuthenticationProviderTests.java @@ -311,7 +311,7 @@ public class OAuth2AuthorizationCodeRequestAuthenticationProviderTests { assertThatExceptionOfType(OAuth2AuthorizationCodeRequestAuthenticationException.class) .isThrownBy(() -> this.authenticationProvider.authenticate(authentication)) .satisfies((ex) -> assertAuthenticationException(ex, OAuth2ErrorCodes.UNAUTHORIZED_CLIENT, - OAuth2ParameterNames.CLIENT_ID, authentication.getRedirectUri())); + OAuth2ParameterNames.CLIENT_ID, null)); } @Test diff --git a/oauth2/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2PushedAuthorizationRequestAuthenticationProviderTests.java b/oauth2/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2PushedAuthorizationRequestAuthenticationProviderTests.java index b704062db3..64f3bf3728 100644 --- a/oauth2/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2PushedAuthorizationRequestAuthenticationProviderTests.java +++ b/oauth2/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2PushedAuthorizationRequestAuthenticationProviderTests.java @@ -128,7 +128,7 @@ public class OAuth2PushedAuthorizationRequestAuthenticationProviderTests { assertThatExceptionOfType(OAuth2AuthorizationCodeRequestAuthenticationException.class) .isThrownBy(() -> this.authenticationProvider.authenticate(authentication)) .satisfies((ex) -> assertAuthenticationException(ex, OAuth2ErrorCodes.UNAUTHORIZED_CLIENT, - OAuth2ParameterNames.CLIENT_ID, authentication.getRedirectUri())); + OAuth2ParameterNames.CLIENT_ID, null)); } @Test