From a325cb43a4badf721d16794f3342c4d12cab8ac5 Mon Sep 17 00:00:00 2001 From: Colm O hEigeartaigh Date: Fri, 26 Jun 2026 10:02:11 +0100 Subject: [PATCH] CXF-9222 - Remove partialMatchScopeValidation for OAuth --- .../oauth2/grants/AbstractGrantHandler.java | 3 +- .../refresh/RefreshTokenGrantHandler.java | 7 +-- .../RedirectionBasedGrantService.java | 11 +---- .../rs/security/oauth2/utils/OAuthUtils.java | 30 +++---------- .../security/oauth2/utils/OAuthUtilsTest.java | 43 ++++++++----------- 5 files changed, 28 insertions(+), 66 deletions(-) diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/grants/AbstractGrantHandler.java b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/grants/AbstractGrantHandler.java index 25071b31f0a..6ff15913bf8 100644 --- a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/grants/AbstractGrantHandler.java +++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/grants/AbstractGrantHandler.java @@ -144,8 +144,7 @@ protected ServerAccessToken getPreAuthorizedToken(Client client, String requestedGrant, List requestedScopes, List audiences) { - if (!OAuthUtils.validateScopes(requestedScopes, client.getRegisteredScopes(), - partialMatchScopeValidation)) { + if (!OAuthUtils.validateScopes(requestedScopes, client.getRegisteredScopes())) { throw new OAuthServiceException(new OAuthError(OAuthConstants.INVALID_SCOPE)); } if (!OAuthUtils.validateAudiences(audiences, client.getRegisteredAudiences())) { diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/grants/refresh/RefreshTokenGrantHandler.java b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/grants/refresh/RefreshTokenGrantHandler.java index 67e77e3d6ca..153f9882d59 100644 --- a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/grants/refresh/RefreshTokenGrantHandler.java +++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/grants/refresh/RefreshTokenGrantHandler.java @@ -33,7 +33,6 @@ public class RefreshTokenGrantHandler implements AccessTokenGrantHandler { private OAuthDataProvider dataProvider; - private boolean partialMatchScopeValidation; private boolean useAllClientScopes; public void setDataProvider(OAuthDataProvider dataProvider) { @@ -50,16 +49,12 @@ public ServerAccessToken createAccessToken(Client client, MultivaluedMap requestedScopes = OAuthUtils.getRequestedScopes(client, params.getFirst(OAuthConstants.SCOPE), useAllClientScopes, - partialMatchScopeValidation, false); + false); final ServerAccessToken st = dataProvider.refreshAccessToken(client, refreshToken, requestedScopes); st.setGrantType(OAuthConstants.REFRESH_TOKEN_GRANT); return st; } - public void setPartialMatchScopeValidation(boolean partialMatchScopeValidation) { - this.partialMatchScopeValidation = partialMatchScopeValidation; - } - public void setUseAllClientScopes(boolean useAllClientScopes) { this.useAllClientScopes = useAllClientScopes; } diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/RedirectionBasedGrantService.java b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/RedirectionBasedGrantService.java index 0267ed33080..ec64a26f1ed 100644 --- a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/RedirectionBasedGrantService.java +++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/RedirectionBasedGrantService.java @@ -61,7 +61,6 @@ public abstract class RedirectionBasedGrantService extends AbstractOAuthService private Set supportedResponseTypes; private String supportedGrantType; private boolean useAllClientScopes; - private boolean partialMatchScopeValidation; private boolean useRegisteredRedirectUriIfPossible = true; private SessionAuthenticityTokenProvider sessionAuthenticityTokenProvider; private SubjectCreator subjectCreator; @@ -180,8 +179,7 @@ protected Response startAuthorization(MultivaluedMap params, try { requestedScope = OAuthUtils.getRequestedScopes(client, providedScope, - useAllClientScopes, - partialMatchScopeValidation); + useAllClientScopes); requestedPermissions = getDataProvider().convertScopeToPermissions(client, requestedScope); } catch (OAuthServiceException ex) { LOG.log(Level.FINE, "Error processing scopes", ex); @@ -401,8 +399,7 @@ protected Response completeAuthorization(MultivaluedMap params) approvedScope.add(rScope); } } - if (!OAuthUtils.validateScopes(requestedScope, client.getRegisteredScopes(), - partialMatchScopeValidation)) { + if (!OAuthUtils.validateScopes(requestedScope, client.getRegisteredScopes())) { return createErrorResponse(params, redirectUri, OAuthConstants.INVALID_SCOPE); } getMessageContext().put(AUTHORIZATION_REQUEST_PARAMETERS, params); @@ -571,10 +568,6 @@ public void setResourceOwnerNameProvider(ResourceOwnerNameProvider resourceOwner this.resourceOwnerNameProvider = resourceOwnerNameProvider; } - public void setPartialMatchScopeValidation(boolean partialMatchScopeValidation) { - this.partialMatchScopeValidation = partialMatchScopeValidation; - } - public void setUseAllClientScopes(boolean useAllClientScopes) { this.useAllClientScopes = useAllClientScopes; } diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/OAuthUtils.java b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/OAuthUtils.java index cee0893b95d..2c0b54ce2d9 100644 --- a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/OAuthUtils.java +++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/utils/OAuthUtils.java @@ -321,15 +321,13 @@ public static boolean checkRequestURI(String servletPath, String uri) { public static List getRequestedScopes(Client client, String scopeParameter, - boolean useAllClientScopes, - boolean partialMatchScopeValidation) { - return getRequestedScopes(client, scopeParameter, useAllClientScopes, partialMatchScopeValidation, true); + boolean useAllClientScopes) { + return getRequestedScopes(client, scopeParameter, useAllClientScopes, true); } public static List getRequestedScopes(Client client, String scopeParameter, boolean useAllClientScopes, - boolean partialMatchScopeValidation, boolean defaultToRegisteredScopes) { List requestScopes = parseScope(scopeParameter); List registeredScopes = client.getRegisteredScopes(); @@ -339,7 +337,7 @@ public static List getRequestedScopes(Client client, } return requestScopes; } - if (!validateScopes(requestScopes, registeredScopes, partialMatchScopeValidation)) { + if (!validateScopes(requestScopes, registeredScopes)) { throw new OAuthServiceException("Unexpected scope"); } if (useAllClientScopes) { @@ -353,26 +351,10 @@ public static List getRequestedScopes(Client client, return requestScopes; } - public static boolean validateScopes(List requestScopes, List registeredScopes, - boolean partialMatchScopeValidation) { + public static boolean validateScopes(List requestScopes, List registeredScopes) { if (!registeredScopes.isEmpty()) { - // if it is a strict validation then pre-registered scopes have to contains all - // the current request scopes - if (!partialMatchScopeValidation) { - return registeredScopes.containsAll(requestScopes); - } - for (String requestScope : requestScopes) { - boolean match = false; - for (String registeredScope : registeredScopes) { - if (requestScope.startsWith(registeredScope)) { - match = true; - break; - } - } - if (!match) { - return false; - } - } + // pre-registered scopes have to contains all the current request scopes + return registeredScopes.containsAll(requestScopes); } return true; } diff --git a/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/utils/OAuthUtilsTest.java b/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/utils/OAuthUtilsTest.java index 72520960ce8..d0072a34e31 100644 --- a/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/utils/OAuthUtilsTest.java +++ b/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/utils/OAuthUtilsTest.java @@ -18,11 +18,8 @@ */ package org.apache.cxf.rs.security.oauth2.utils; -import java.util.Collections; import java.util.List; -import org.apache.cxf.rs.security.oauth2.common.Client; - import org.junit.Test; import static org.junit.Assert.assertEquals; @@ -35,42 +32,38 @@ public class OAuthUtilsTest { public void testValidateScopesStrict() { List requestScopes = OAuthUtils.parseScope("a c b"); List registeredScopes = OAuthUtils.parseScope("a b c d"); - assertTrue(OAuthUtils.validateScopes(requestScopes, registeredScopes, false)); + assertTrue(OAuthUtils.validateScopes(requestScopes, registeredScopes)); } @Test public void testValidateScopesStrictFail() { List requestScopes = OAuthUtils.parseScope("a b c d"); List registeredScopes = OAuthUtils.parseScope("a b d"); - assertFalse(OAuthUtils.validateScopes(requestScopes, registeredScopes, false)); - } - - @Test - public void testValidateScopesPartial() { - List requestScopes = OAuthUtils.parseScope("a b c-1"); - List registeredScopes = OAuthUtils.parseScope("a b c"); - assertTrue(OAuthUtils.validateScopes(requestScopes, registeredScopes, true)); + assertFalse(OAuthUtils.validateScopes(requestScopes, registeredScopes)); } @Test - public void testValidateScopesPartialFail() { - List requestScopes = OAuthUtils.parseScope("a b c"); - List registeredScopes = OAuthUtils.parseScope("a b"); - assertFalse(OAuthUtils.validateScopes(requestScopes, registeredScopes, true)); + public void testParseScopeEmpty() { + assertTrue(OAuthUtils.parseScope(null).isEmpty()); + assertTrue(OAuthUtils.parseScope("").isEmpty()); + assertTrue(OAuthUtils.parseScope(" ").isEmpty()); } @Test - public void testGetRequestedScopesRegistered() { - Client c = new Client(); - List scopes = Collections.singletonList("a"); - c.setRegisteredScopes(scopes); - assertEquals(scopes, OAuthUtils.getRequestedScopes(c, "", false, false)); + public void testParseScopeWithExtraSpaces() { + List scopes = OAuthUtils.parseScope(" read write admin "); + assertEquals(3, scopes.size()); + assertEquals("read", scopes.get(0)); + assertEquals("write", scopes.get(1)); + assertEquals("admin", scopes.get(2)); } @Test - public void testParseScopeEmpty() { - assertTrue(OAuthUtils.parseScope(null).isEmpty()); - assertTrue(OAuthUtils.parseScope("").isEmpty()); - assertTrue(OAuthUtils.parseScope(" ").isEmpty()); + public void testParseScopeWithDuplicates() { + List scopes = OAuthUtils.parseScope("a a b"); + assertEquals(3, scopes.size()); + assertEquals("a", scopes.get(0)); + assertEquals("a", scopes.get(1)); + assertEquals("b", scopes.get(2)); } }