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 4cff3c9c1d998e02fb843ca147bcbf09014c91cc Author: Colm O hEigeartaigh <[email protected]> AuthorDate: Sun Nov 1 15:46:37 2026 +0000 Apply ClaimsAuthorizingInterceptor aliases set after the secured object (#3657) (cherry picked from commit c003c55add97ceb199aeaed1cee8061a57e5037e) --- .../interceptor/ClaimsAuthorizingInterceptor.java | 29 ++++++++++++++- .../ClaimsAuthorizingInterceptorTest.java | 43 ++++++++++++++++++++++ 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/rt/security/src/main/java/org/apache/cxf/rt/security/claims/interceptor/ClaimsAuthorizingInterceptor.java b/rt/security/src/main/java/org/apache/cxf/rt/security/claims/interceptor/ClaimsAuthorizingInterceptor.java index e61755804ba..84ab8e45459 100644 --- a/rt/security/src/main/java/org/apache/cxf/rt/security/claims/interceptor/ClaimsAuthorizingInterceptor.java +++ b/rt/security/src/main/java/org/apache/cxf/rt/security/claims/interceptor/ClaimsAuthorizingInterceptor.java @@ -65,6 +65,9 @@ public class ClaimsAuthorizingInterceptor extends AbstractPhaseInterceptor<Messa private final Map<String, Set<String>> overriddenSignatures = new HashMap<>(); private final Map<String, Set<String>> signaturesByName = new HashMap<>(); private final Set<Class<?>> securedClasses = new HashSet<>(); + // The classes passed to setSecuredObject, so their claims can be resolved again + // if the aliases change afterwards + private final List<Class<?>> securedObjectClasses = new ArrayList<>(); private boolean annotationClaimsFound; private Map<String, String> nameAliases = Collections.emptyMap(); private Map<String, String> formatAliases = Collections.emptyMap(); @@ -196,6 +199,7 @@ public class ClaimsAuthorizingInterceptor extends AbstractPhaseInterceptor<Messa public void setSecuredObject(Object object) { Class<?> cls = ClassHelper.getRealClass(object); + securedObjectClasses.add(cls); findClaims(cls); if (!annotationClaimsFound) { LOG.warning("The claims list is empty, the service object is not protected"); @@ -285,11 +289,32 @@ public class ClaimsAuthorizingInterceptor extends AbstractPhaseInterceptor<Messa } public void setNameAliases(Map<String, String> nameAliases) { - this.nameAliases = nameAliases; + this.nameAliases = nameAliases == null ? Collections.emptyMap() : nameAliases; + resolveSecuredObjectClaims(); } public void setFormatAliases(Map<String, String> formatAliases) { - this.formatAliases = formatAliases; + this.formatAliases = formatAliases == null ? Collections.emptyMap() : formatAliases; + resolveSecuredObjectClaims(); + } + + /** + * The aliases are applied when the annotation claims are read, so read them again for any + * secured object which was set before the aliases. Otherwise the claims would keep the + * unresolved names, which never match, and a ClaimMode.LAX claim would always pass. + */ + private void resolveSecuredObjectClaims() { + if (securedObjectClasses.isEmpty()) { + return; + } + declarationsBySignature.clear(); + overriddenSignatures.clear(); + signaturesByName.clear(); + securedClasses.clear(); + annotationClaimsFound = false; + for (Class<?> cls : securedObjectClasses) { + findClaims(cls); + } } private static final class ClaimsDeclaration { diff --git a/rt/security/src/test/java/org/apache/cxf/rt/security/claims/interceptor/ClaimsAuthorizingInterceptorTest.java b/rt/security/src/test/java/org/apache/cxf/rt/security/claims/interceptor/ClaimsAuthorizingInterceptorTest.java index c75e9d63e0d..ef1155a4677 100644 --- a/rt/security/src/test/java/org/apache/cxf/rt/security/claims/interceptor/ClaimsAuthorizingInterceptorTest.java +++ b/rt/security/src/test/java/org/apache/cxf/rt/security/claims/interceptor/ClaimsAuthorizingInterceptorTest.java @@ -473,6 +473,39 @@ public class ClaimsAuthorizingInterceptorTest { assertDenied(in, prepareMessage(method, createDefaultClaim("user"))); } + @Test + public void testAliasesSetAfterSecuredObject() throws Exception { + ClaimsAuthorizingInterceptor in = new ClaimsAuthorizingInterceptor(); + in.setSecuredObject(new AliasService()); + in.setNameAliases(Collections.singletonMap("authentication", "http://authentication")); + in.setFormatAliases(Collections.singletonMap("claims", "http://claims")); + Method lax = AliasService.class.getMethod("laxClaim"); + Method strict = AliasService.class.getMethod("strictClaim"); + + in.handleMessage(prepareMessage(lax, createClaim("http://authentication", "http://claims", "password"))); + assertDenied(in, prepareMessage(lax, + createClaim("http://authentication", "http://claims", "smartcard"))); + in.handleMessage(prepareMessage(strict, + createClaim("http://authentication", "http://claims", "password"))); + assertDenied(in, prepareMessage(strict, + createClaim("http://authentication", "http://claims", "smartcard"))); + } + + @Test + public void testAliasesReplacedAfterSecuredObject() throws Exception { + ClaimsAuthorizingInterceptor in = new ClaimsAuthorizingInterceptor(); + in.setNameAliases(Collections.singletonMap("authentication", "http://old-authentication")); + in.setFormatAliases(Collections.singletonMap("claims", "http://claims")); + in.setSecuredObject(new AliasService()); + in.setNameAliases(Collections.singletonMap("authentication", "http://authentication")); + Method lax = AliasService.class.getMethod("laxClaim"); + + assertDenied(in, prepareMessage(lax, + createClaim("http://authentication", "http://claims", "smartcard"))); + in.handleMessage(prepareMessage(lax, + createClaim("http://old-authentication", "http://claims", "smartcard"))); + } + private static ClaimsAuthorizingInterceptor createInterceptor(Object service) { ClaimsAuthorizingInterceptor in = new ClaimsAuthorizingInterceptor(); in.setSecuredObject(service); @@ -640,6 +673,16 @@ public class ClaimsAuthorizingInterceptorTest { } } + public static class AliasService { + @Claim(name = "authentication", format = "claims", value = "password", mode = ClaimMode.LAX) + public void laxClaim() { + } + + @Claim(name = "authentication", format = "claims", value = "password") + public void strictClaim() { + } + } + public static class TestService2 { @SecureRole("admin") public void test() {
