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;
     }

Reply via email to