This is an automated email from the ASF dual-hosted git repository. coheigea pushed a commit to branch coheigea/CXF-9223 in repository https://gitbox.apache.org/repos/asf/cxf.git
commit 06a3ddaab290e5f73657c3a7983ee3363d245fb3 Author: Colm O hEigeartaigh <[email protected]> AuthorDate: Thu Jul 23 10:47:10 2026 +0100 CXF-9223 - Improve prefix matching for OAuth audience URIs --- .../oauth2/filters/OAuthRequestFilter.java | 26 +++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/filters/OAuthRequestFilter.java b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/filters/OAuthRequestFilter.java index 0f5d8a04e62..72505c72130 100644 --- a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/filters/OAuthRequestFilter.java +++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/filters/OAuthRequestFilter.java @@ -286,7 +286,9 @@ public class OAuthRequestFilter extends AbstractAccessTokenValidator } String requestPath = (String)PhaseInterceptorChain.getCurrentMessage().get(Message.REQUEST_URL); for (String s : audiences) { - boolean matched = completeAudienceMatch ? requestPath.equals(s) : requestPath.startsWith(s); + // In non-exact mode, only allow prefix matches at path/query/fragment boundaries. + boolean matched = completeAudienceMatch ? requestPath.equals(s) + : matchesAudiencePrefix(requestPath, s); if (matched) { return s; } @@ -295,6 +297,28 @@ public class OAuthRequestFilter extends AbstractAccessTokenValidator return null; } + /** + * Checks whether a configured audience matches a request URL using safe prefix semantics. + * <p> + * This keeps subtree-style matching (for example, "/api/read" matching "/api/read/item") + * but prevents same-prefix sibling matches (for example, "/api/readadmin"). + * A match is accepted only when the configured audience is an exact match, ends with '/', + * or is followed by a URL boundary character ('/', '?', '#'). + */ + protected boolean matchesAudiencePrefix(String requestPath, String configuredAudience) { + if (requestPath == null || configuredAudience == null) { + return false; + } + if (!requestPath.startsWith(configuredAudience)) { + return false; + } + if (requestPath.length() == configuredAudience.length() || configuredAudience.endsWith("/")) { + return true; + } + char boundary = requestPath.charAt(configuredAudience.length()); + return boundary == '/' || boundary == '?' || boundary == '#'; + } + public void setCheckFormData(boolean checkFormData) { this.checkFormData = checkFormData; }
