This is an automated email from the ASF dual-hosted git repository. coheigea pushed a commit to branch 4.1.x-fixes in repository https://gitbox.apache.org/repos/asf/cxf.git
commit 544a714507c375b3d15de40b67ce957c4ddff158 Author: Colm O hEigeartaigh <[email protected]> AuthorDate: Fri Sep 25 14:41:45 2026 +0100 Tighten scope and application_type validation in DynamicRegistrationService (#3506) (cherry picked from commit 2d8c3c8abeafb14294d765beb0643fc91e55fcc7) --- .../services/DynamicRegistrationService.java | 13 ++++++++- .../services/DynamicRegistrationServiceTest.java | 33 ++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/DynamicRegistrationService.java b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/DynamicRegistrationService.java index ecb4847e8ad..5bf67cae103 100644 --- a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/DynamicRegistrationService.java +++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/services/DynamicRegistrationService.java @@ -20,6 +20,7 @@ package org.apache.cxf.rs.security.oauth2.services; import java.net.URI; import java.security.cert.X509Certificate; +import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -270,6 +271,9 @@ public class DynamicRegistrationService { String appType = request.getApplicationType(); if (appType == null) { appType = DEFAULT_APPLICATION_TYPE; + } else if (!WEB_APPLICATION_TYPE.equalsIgnoreCase(appType) + && !NATIVE_APPLICATION_TYPE.equalsIgnoreCase(appType)) { + reportInvalidRequestError(new OAuthError(INVALID_CLIENT_METADATA, "Unsupported application type")); } boolean isConfidential = DEFAULT_APPLICATION_TYPE.equals(appType) && (passwordRequired @@ -394,6 +398,10 @@ public class DynamicRegistrationService { List<String> requestedScopes = OAuthUtils.parseScope(scope); validateClientScopes(requestedScopes); client.setRegisteredScopes(requestedScopes); + } else if (allowedClientScopes != null && client.getRegisteredScopes().isEmpty()) { + // An empty list of registered scopes allows any scope to be requested later on, + // so restrict the client to the configured scopes instead + client.setRegisteredScopes(new ArrayList<>(allowedClientScopes)); } // Client Application URI String clientUri = request.getClientUri(); @@ -466,6 +474,9 @@ public class DynamicRegistrationService { reportInvalidRequestError(new OAuthError(INVALID_CLIENT_METADATA, "Unsupported redirect URI hostname for scheme")); } + } else { + reportInvalidRequestError(new OAuthError(INVALID_CLIENT_METADATA, + "Unsupported application type")); } } @@ -533,7 +544,7 @@ public class DynamicRegistrationService { List<String> allowedScopes = allowedClientScopes; if (allowedScopes == null && clientProvider instanceof AbstractOAuthDataProvider) { - allowedScopes = new java.util.ArrayList<>( + allowedScopes = new ArrayList<>( ((AbstractOAuthDataProvider)clientProvider).getPermissionMap().keySet()); } diff --git a/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/services/DynamicRegistrationServiceTest.java b/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/services/DynamicRegistrationServiceTest.java index 3bfaceafffa..1b5593ad74f 100644 --- a/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/services/DynamicRegistrationServiceTest.java +++ b/rt/rs/security/oauth-parent/oauth2/src/test/java/org/apache/cxf/rs/security/oauth2/services/DynamicRegistrationServiceTest.java @@ -90,6 +90,39 @@ public class DynamicRegistrationServiceTest { assertEquals(Collections.singletonList("openid"), client.getRegisteredScopes()); } + @Test + public void testDefaultsToAllowedScopesWhenNoScopeRegistered() { + TestDynamicRegistrationService service = new TestDynamicRegistrationService(); + service.setAllowedClientScopes(Collections.singletonList("read")); + + Client client = createClient(); + service.applyClientRegistration(new ClientRegistration(), client); + + assertEquals(Collections.singletonList("read"), client.getRegisteredScopes()); + } + + @Test + public void testRejectsUnknownApplicationTypeRedirectUrl() { + TestDynamicRegistrationService service = new TestDynamicRegistrationService(); + + ClientRegistration request = new ClientRegistration(); + request.setApplicationType("x"); + request.setRedirectUris(List.of("http://evil.example/cb")); + + Client client = createClient(); + client.setAllowedGrantTypes(Collections.singletonList(OAuthConstants.IMPLICIT_GRANT)); + assertThrows(BadRequestException.class, () -> service.applyClientRegistration(request, client)); + } + + @Test + public void testRejectsUnknownApplicationType() { + TestDynamicRegistrationService service = new TestDynamicRegistrationService(); + + ClientRegistration request = new ClientRegistration(); + request.setApplicationType("x"); + assertThrows(BadRequestException.class, () -> service.createClient(request)); + } + @Test public void testAcceptsAllowedRedirectUrlsWebApp() { TestDynamicRegistrationService service = new TestDynamicRegistrationService();
