This is an automated email from the ASF dual-hosted git repository.

coheigea pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cxf.git


The following commit(s) were added to refs/heads/main by this push:
     new 7816e8e7022 Resolve ClaimsAuthorizingInterceptor annotation claims by 
method sign… (#3646)
7816e8e7022 is described below

commit 7816e8e7022fb1a56f382e06fdcce9069797ef7c
Author: Colm O hEigeartaigh <[email protected]>
AuthorDate: Fri Oct 30 14:21:53 2026 +0000

    Resolve ClaimsAuthorizingInterceptor annotation claims by method sign… 
(#3646)
    
    * Resolve ClaimsAuthorizingInterceptor annotation claims by method signature
    
    * Resolve ClaimsAuthorizingInterceptor claims by method signature
---
 .../interceptor/ClaimsAuthorizingInterceptor.java  | 115 ++++-
 .../ClaimsAuthorizingInterceptorTest.java          | 508 ++++++++++++++++++++-
 2 files changed, 603 insertions(+), 20 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 94a9c9d7b11..e61755804ba 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
@@ -31,6 +31,7 @@ import java.util.logging.Logger;
 
 import org.apache.cxf.common.logging.LogUtils;
 import org.apache.cxf.common.util.ClassHelper;
+import org.apache.cxf.common.util.ReflectionUtil;
 import org.apache.cxf.interceptor.Fault;
 import org.apache.cxf.interceptor.security.AccessDeniedException;
 import org.apache.cxf.message.Message;
@@ -53,7 +54,18 @@ public class ClaimsAuthorizingInterceptor extends 
AbstractPhaseInterceptor<Messa
     private static final Set<String> SKIP_METHODS = new HashSet<>(
             Arrays.asList("wait", "notify", "notifyAll", "equals", "toString", 
"hashCode"));
 
+    // Claims configured explicitly via setClaims, keyed by method name
     private Map<String, List<ClaimBean>> claims = new HashMap<>();
+    // The method-level and class-level @Claim/@Claims declarations which 
apply to each method
+    // signature in the secured object's hierarchy. Keying by signature means 
that overloaded
+    // methods do not share a rule
+    private final Map<String, List<ClaimsDeclaration>> declarationsBySignature 
= new HashMap<>();
+    // The erased signatures a method overrides with a different signature, 
e.g. update(Object)
+    // for update(String) implementing update(T) of Repository<String>
+    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<>();
+    private boolean annotationClaimsFound;
     private Map<String, String> nameAliases = Collections.emptyMap();
     private Map<String, String> formatAliases = Collections.emptyMap();
 
@@ -82,7 +94,63 @@ public class ClaimsAuthorizingInterceptor extends 
AbstractPhaseInterceptor<Messa
     }
 
     protected boolean authorize(ClaimsSecurityContext sc, Method method) {
-        List<ClaimBean> list = claims.get(method.getName());
+        String signature = ReflectionUtil.getMethodSignature(method);
+        boolean securedMethod = declarationsBySignature.containsKey(signature);
+        Set<String> signatures = new HashSet<>();
+        if (securedMethod) {
+            signatures.add(signature);
+            signatures.addAll(overriddenSignatures.getOrDefault(signature, 
Collections.emptySet()));
+        } else {
+            // The method is not one of the secured object's methods, so every 
rule
+            // recorded for its name applies
+            signatures.addAll(signaturesByName.getOrDefault(method.getName(), 
Collections.emptySet()));
+        }
+        List<ClaimBean> requiredClaims = new ArrayList<>();
+        for (String s : signatures) {
+            requiredClaims.addAll(getAnnotationClaims(s));
+        }
+        List<ClaimBean> configuredClaims = claims.get(method.getName());
+        if (configuredClaims != null) {
+            requiredClaims.addAll(configuredClaims);
+        } else if (!securedMethod && requiredClaims.isEmpty()) {
+            // A method without claims requirements is only permitted if it is 
one of
+            // the secured object's methods
+            return false;
+        }
+        // Every claim which applies to the method has to be matched
+        return isAuthorized(sc, requiredClaims);
+    }
+
+    private List<ClaimBean> getAnnotationClaims(String signature) {
+        // Every @Claim which applies to the method has to be met, from any 
class or interface
+        // in the hierarchy. A class-level @Claim is replaced by a 
method-level @Claim of the same
+        // name and format declared on the same class or interface, or on a 
subclass of it
+        List<ClaimsDeclaration> declarations =
+            declarationsBySignature.getOrDefault(signature, 
Collections.emptyList());
+        List<ClaimBean> requiredClaims = new ArrayList<>();
+        for (ClaimsDeclaration declaration : declarations) {
+            for (ClaimBean bean : declaration.claims) {
+                if (declaration.methodLevel
+                    || !isClaimOverridden(bean, declaration.declaringClass, 
declarations)) {
+                    requiredClaims.add(bean);
+                }
+            }
+        }
+        return requiredClaims;
+    }
+
+    private static boolean isClaimOverridden(ClaimBean bean, Class<?> cls,
+                                             List<ClaimsDeclaration> 
declarations) {
+        for (ClaimsDeclaration declaration : declarations) {
+            if (declaration.methodLevel && 
cls.isAssignableFrom(declaration.declaringClass)
+                && isClaimOverridden(bean, declaration.claims)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static boolean isAuthorized(ClaimsSecurityContext sc, 
List<ClaimBean> list) {
         org.apache.cxf.rt.security.claims.ClaimCollection actualClaims = 
sc.getClaims();
 
         for (ClaimBean claimBean : list) {
@@ -129,13 +197,13 @@ public class ClaimsAuthorizingInterceptor extends 
AbstractPhaseInterceptor<Messa
     public void setSecuredObject(Object object) {
         Class<?> cls = ClassHelper.getRealClass(object);
         findClaims(cls);
-        if (claims.isEmpty()) {
+        if (!annotationClaimsFound) {
             LOG.warning("The claims list is empty, the service object is not 
protected");
         }
     }
 
     protected void findClaims(Class<?> cls) {
-        if (cls == null || cls == Object.class) {
+        if (cls == null || cls == Object.class || !securedClasses.add(cls)) {
             return;
         }
         List<ClaimBean> clsClaims =
@@ -147,26 +215,26 @@ public class ClaimsAuthorizingInterceptor extends 
AbstractPhaseInterceptor<Messa
             List<ClaimBean> methodClaims =
                 getClaims(m.getAnnotation(Claims.class), 
m.getAnnotation(Claim.class));
 
-            List<ClaimBean> allClaims = new ArrayList<>(methodClaims);
-            for (ClaimBean bean : clsClaims) {
-                if (isClaimOverridden(bean, methodClaims)) {
-                    continue;
+            String signature = ReflectionUtil.getMethodSignature(m);
+            List<ClaimsDeclaration> declarations =
+                declarationsBySignature.computeIfAbsent(signature, k -> new 
ArrayList<>());
+            if (!methodClaims.isEmpty()) {
+                declarations.add(new ClaimsDeclaration(m.getDeclaringClass(), 
methodClaims, true));
+            }
+            if (!clsClaims.isEmpty()) {
+                declarations.add(new ClaimsDeclaration(cls, clsClaims, false));
+            }
+            signaturesByName.computeIfAbsent(m.getName(), k -> new 
HashSet<>()).add(signature);
+            annotationClaimsFound |= !methodClaims.isEmpty() || 
!clsClaims.isEmpty();
+            if (!m.isBridge()) {
+                for (Method overridden : 
ReflectionUtil.getGenericallyOverriddenMethods(cls, m)) {
+                    overriddenSignatures.computeIfAbsent(signature, k -> new 
HashSet<>())
+                        .add(ReflectionUtil.getMethodSignature(overridden));
                 }
-                allClaims.add(bean);
             }
-
-            claims.put(m.getName(), allClaims);
-        }
-        if (!claims.isEmpty()) {
-            return;
         }
 
         findClaims(cls.getSuperclass());
-
-        if (!claims.isEmpty()) {
-            return;
-        }
-
         for (Class<?> interfaceCls : cls.getInterfaces()) {
             findClaims(interfaceCls);
         }
@@ -224,4 +292,15 @@ public class ClaimsAuthorizingInterceptor extends 
AbstractPhaseInterceptor<Messa
         this.formatAliases = formatAliases;
     }
 
+    private static final class ClaimsDeclaration {
+        private final Class<?> declaringClass;
+        private final List<ClaimBean> claims;
+        private final boolean methodLevel;
+
+        ClaimsDeclaration(Class<?> declaringClass, List<ClaimBean> claims, 
boolean methodLevel) {
+            this.declaringClass = declaringClass;
+            this.claims = claims;
+            this.methodLevel = methodLevel;
+        }
+    }
 }
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 2a2e19db945..c75e9d63e0d 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
@@ -22,6 +22,7 @@ import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
+import java.lang.reflect.Method;
 import java.security.Principal;
 import java.util.Arrays;
 import java.util.Collections;
@@ -226,6 +227,275 @@ public class ClaimsAuthorizingInterceptorTest {
         }
     }
 
+    @Test
+    public void testOverloadedMethodWithoutClaimsDoesNotRemoveClaims() throws 
Exception {
+        ClaimsAuthorizingInterceptor in = createInterceptor(new 
OverloadingService());
+        Method adminMethod = OverloadingService.class.getMethod("delete", 
String.class);
+        Method unsecuredMethod = OverloadingService.class.getMethod("delete");
+
+        in.handleMessage(prepareMessage(adminMethod, 
createDefaultClaim("admin")));
+        assertDenied(in, prepareMessage(adminMethod, 
createDefaultClaim("user")));
+
+        // A method without claims of its own is not secured by the claims of 
its overloads
+        in.handleMessage(prepareMessage(unsecuredMethod, 
createDefaultClaim("user")));
+    }
+
+    @Test
+    public void testOverloadedMethodsKeepTheirOwnClaims() throws Exception {
+        ClaimsAuthorizingInterceptor in = createInterceptor(new 
OverloadingService());
+        Method adminMethod = OverloadingService.class.getMethod("update", 
String.class);
+        Method userMethod = OverloadingService.class.getMethod("update");
+
+        in.handleMessage(prepareMessage(adminMethod, 
createDefaultClaim("admin")));
+        assertDenied(in, prepareMessage(adminMethod, 
createDefaultClaim("user")));
+        in.handleMessage(prepareMessage(userMethod, 
createDefaultClaim("user")));
+        assertDenied(in, prepareMessage(userMethod, 
createDefaultClaim("admin")));
+    }
+
+    @Test
+    public void testOverridingMethodClaimsApplyTogetherWithSuperclassClaims() 
throws Exception {
+        ClaimsAuthorizingInterceptor in = createInterceptor(new 
OverridingService());
+        Method method = OverridingService.class.getMethod("update");
+
+        in.handleMessage(prepareMessage(method, createDefaultClaim("admin", 
"user")));
+        assertDenied(in, prepareMessage(method, createDefaultClaim("admin")));
+        assertDenied(in, prepareMessage(method, createDefaultClaim("user")));
+    }
+
+    @Test
+    public void testOverridingMethodCannotWeakenSuperclassClaims() throws 
Exception {
+        ClaimsAuthorizingInterceptor in = createInterceptor(new 
UserOverridingService());
+        Method method = UserOverridingService.class.getMethod("update");
+
+        in.handleMessage(prepareMessage(method, createDefaultClaim("admin", 
"user")));
+        assertDenied(in, prepareMessage(method, createDefaultClaim("user")));
+    }
+
+    @Test
+    public void testSubclassClaimsApplyTogetherWithSuperclassMethodClaims() 
throws Exception {
+        ClaimsAuthorizingInterceptor in = createInterceptor(new 
AdminSubService());
+        Method method = AdminSubService.class.getMethod("update");
+
+        in.handleMessage(prepareMessage(method, createDefaultClaim("admin", 
"user")));
+        assertDenied(in, prepareMessage(method, createDefaultClaim("admin")));
+        assertDenied(in, prepareMessage(method, createDefaultClaim("user")));
+    }
+
+    @Test
+    public void testMethodClaimsFromUnrelatedSupertypesApplyTogether() throws 
Exception {
+        ClaimsAuthorizingInterceptor in = createInterceptor(new 
AdminApiUserService());
+        Method method = AdminApiUserService.class.getMethod("update");
+
+        in.handleMessage(prepareMessage(method, createDefaultClaim("admin", 
"user")));
+        assertDenied(in, prepareMessage(method, createDefaultClaim("admin")));
+        assertDenied(in, prepareMessage(method, createDefaultClaim("user")));
+    }
+
+    @Test
+    public void testInterfaceClaimsAreEnforced() throws Exception {
+        ClaimsAuthorizingInterceptor in = createInterceptor(new 
InterfaceService());
+        Method implMethod = InterfaceService.class.getMethod("delete");
+        Method interfaceMethod = SecuredApi.class.getMethod("delete");
+
+        in.handleMessage(prepareMessage(implMethod, 
createDefaultClaim("admin")));
+        assertDenied(in, prepareMessage(implMethod, 
createDefaultClaim("user")));
+        assertDenied(in, prepareMessage(interfaceMethod, 
createDefaultClaim("user")));
+    }
+
+    @Test
+    public void testGenericInterfaceMethodClaimsAreEnforced() throws Exception 
{
+        ClaimsAuthorizingInterceptor in = createInterceptor(new 
StringRepository());
+        Method updateMethod = StringRepository.class.getMethod("update", 
String.class);
+
+        // update(String) overrides the erased update(Object), but not the 
update() overload
+        in.handleMessage(prepareMessage(updateMethod, 
createDefaultClaim("admin")));
+        assertDenied(in, prepareMessage(updateMethod, 
createDefaultClaim("user")));
+
+        Method userMethod = StringRepository.class.getMethod("update");
+        in.handleMessage(prepareMessage(userMethod, 
createDefaultClaim("user")));
+        assertDenied(in, prepareMessage(userMethod, 
createDefaultClaim("admin")));
+    }
+
+    @Test
+    public void testGenericInterfaceMethodClaimsApplyTogetherWithClassClaims() 
throws Exception {
+        ClaimsAuthorizingInterceptor in = createInterceptor(new 
ClassClaimsStringRepository());
+        Method method = ClassClaimsStringRepository.class.getMethod("update", 
String.class);
+
+        in.handleMessage(prepareMessage(method, createDefaultClaim("admin", 
"user")));
+        assertDenied(in, prepareMessage(method, createDefaultClaim("admin")));
+        assertDenied(in, prepareMessage(method, createDefaultClaim("user")));
+    }
+
+    @Test
+    public void 
testGenericInterfaceMethodClaimsApplyToInheritedImplementation() throws 
Exception {
+        ClaimsAuthorizingInterceptor in = createInterceptor(new 
InheritingStringRepository());
+        Method method = InheritingStringRepository.class.getMethod("update", 
String.class);
+
+        in.handleMessage(prepareMessage(method, createDefaultClaim("admin")));
+        assertDenied(in, prepareMessage(method, createDefaultClaim("user")));
+    }
+
+    @Test
+    public void testMethodWithoutConfiguredClaimsIsDenied() throws Exception {
+        ClaimsAuthorizingInterceptor in = new ClaimsAuthorizingInterceptor();
+        in.setClaims(Collections.singletonMap("update",
+            Collections.singletonList(createDefaultClaimBean("admin"))));
+
+        
in.handleMessage(prepareMessage(OverloadingService.class.getMethod("update"),
+            createDefaultClaim("admin")));
+        assertDenied(in, 
prepareMessage(OverloadingService.class.getMethod("delete"),
+            createDefaultClaim("admin")));
+    }
+
+    @Test
+    public void testConfiguredClaimsAreEnforcedTogetherWithAnnotations() 
throws Exception {
+        ClaimsAuthorizingInterceptor in = createInterceptor(new 
OverloadingService());
+        in.setClaims(Collections.singletonMap("update",
+            Collections.singletonList(createDefaultClaimBean("manager"))));
+        Method method = OverloadingService.class.getMethod("update");
+
+        in.handleMessage(prepareMessage(method, createDefaultClaim("user", 
"manager")));
+        assertDenied(in, prepareMessage(method, createDefaultClaim("user")));
+        assertDenied(in, prepareMessage(method, 
createDefaultClaim("manager")));
+    }
+
+    @Test
+    public void testOverloadedSubclassMethodKeepsItsOwnClaims() throws 
Exception {
+        ClaimsAuthorizingInterceptor in = createInterceptor(new 
OverloadingSubService());
+        Method adminMethod = OverloadingSubService.class.getMethod("update", 
String.class);
+        Method userMethod = OverloadingSubService.class.getMethod("update");
+
+        in.handleMessage(prepareMessage(adminMethod, 
createDefaultClaim("admin")));
+        assertDenied(in, prepareMessage(adminMethod, 
createDefaultClaim("user")));
+        in.handleMessage(prepareMessage(userMethod, 
createDefaultClaim("user")));
+        assertDenied(in, prepareMessage(userMethod, 
createDefaultClaim("admin")));
+    }
+
+    @Test
+    public void testOverridingMethodClaimsReplaceSuperclassClassClaims() 
throws Exception {
+        ClaimsAuthorizingInterceptor in = createInterceptor(new 
OverridingSubResource());
+        Method method = OverridingSubResource.class.getMethod("update");
+
+        in.handleMessage(prepareMessage(method, createDefaultClaim("admin")));
+        assertDenied(in, prepareMessage(method, createDefaultClaim("user")));
+    }
+
+    @Test
+    public void testOverridingMethodClaimsReplaceInterfaceClassClaims() throws 
Exception {
+        ClaimsAuthorizingInterceptor in = createInterceptor(new 
UserApiAdminService());
+        Method method = UserApiAdminService.class.getMethod("update");
+
+        in.handleMessage(prepareMessage(method, createDefaultClaim("admin")));
+        assertDenied(in, prepareMessage(method, createDefaultClaim("user")));
+    }
+
+    @Test
+    public void testClassClaimsOfOtherTypesStillApply() throws Exception {
+        ClaimsAuthorizingInterceptor in = createInterceptor(new 
LocationSubService());
+        Method method = LocationSubService.class.getMethod("update");
+        org.apache.cxf.rt.security.claims.Claim location = 
createClaim("http://location";,
+            "urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified", "UK");
+
+        in.handleMessage(prepareMessage(method, createDefaultClaim("admin"), 
location));
+        assertDenied(in, prepareMessage(method, createDefaultClaim("admin")));
+        assertDenied(in, prepareMessage(method, createDefaultClaim("user"), 
location));
+    }
+
+    @Test
+    public void 
testMethodClaimsReplaceSuperclassClassClaimsForUnannotatedOverride() throws 
Exception {
+        ClaimsAuthorizingInterceptor in = createInterceptor(new 
UnannotatedSubResource());
+        Method method = UnannotatedSubResource.class.getMethod("update");
+
+        in.handleMessage(prepareMessage(method, createDefaultClaim("admin")));
+        assertDenied(in, prepareMessage(method, createDefaultClaim("user")));
+    }
+
+    @Test
+    public void testSuperclassClassClaimsDoNotApplyToSubclassMethods() throws 
Exception {
+        // @Claim is not @Inherited, so a class-level @Claim only applies to 
the methods of
+        // the class which declares it
+        ClaimsAuthorizingInterceptor in = createInterceptor(new 
SubclassOnlyService());
+        Method adminMethod = 
SubclassOnlyService.class.getMethod("adminOperation");
+
+        in.handleMessage(prepareMessage(adminMethod, 
createDefaultClaim("admin")));
+        assertDenied(in, prepareMessage(adminMethod, 
createDefaultClaim("user")));
+        
in.handleMessage(prepareMessage(SubclassOnlyService.class.getMethod("update"),
+            createDefaultClaim("user")));
+    }
+
+    @Test
+    public void testClaimMatchAllIsResolvedPerSignature() throws Exception {
+        ClaimsAuthorizingInterceptor in = createInterceptor(new 
MatchAllService());
+        Method matchAllMethod = MatchAllService.class.getMethod("update", 
String.class);
+        Method matchAnyMethod = MatchAllService.class.getMethod("update");
+
+        in.handleMessage(prepareMessage(matchAllMethod, 
createDefaultClaim("admin", "manager")));
+        assertDenied(in, prepareMessage(matchAllMethod, 
createDefaultClaim("admin")));
+        in.handleMessage(prepareMessage(matchAnyMethod, 
createDefaultClaim("user")));
+    }
+
+    @Test
+    public void testInheritedMethodClaimsStillApply() throws Exception {
+        ClaimsAuthorizingInterceptor in = createInterceptor(new 
InheritingService());
+        Method method = InheritingService.class.getMethod("update");
+
+        in.handleMessage(prepareMessage(method, createDefaultClaim("user")));
+        assertDenied(in, prepareMessage(method, createDefaultClaim("admin")));
+    }
+
+    @Test
+    public void testUnannotatedOverrideInheritsSuperclassClaims() throws 
Exception {
+        ClaimsAuthorizingInterceptor in = createInterceptor(new 
UnannotatedOverridingService());
+        Method method = UnannotatedOverridingService.class.getMethod("update");
+
+        in.handleMessage(prepareMessage(method, createDefaultClaim("user")));
+        assertDenied(in, prepareMessage(method, createDefaultClaim("admin")));
+    }
+
+    @Test
+    public void testUnrelatedOverloadIsNotLinkedToGenericInterfaceMethod() 
throws Exception {
+        ClaimsAuthorizingInterceptor in = createInterceptor(new 
OverloadingStringRepository());
+        Method integerMethod = 
OverloadingStringRepository.class.getMethod("update", Integer.class);
+        Method stringMethod = 
OverloadingStringRepository.class.getMethod("update", String.class);
+
+        in.handleMessage(prepareMessage(integerMethod, 
createDefaultClaim("user")));
+        assertDenied(in, prepareMessage(integerMethod, 
createDefaultClaim("admin")));
+        in.handleMessage(prepareMessage(stringMethod, 
createDefaultClaim("admin")));
+        assertDenied(in, prepareMessage(stringMethod, 
createDefaultClaim("user")));
+    }
+
+    @Test
+    public void testGenericInterfaceMethodClaimsApplyThroughTypeVariables() 
throws Exception {
+        ClaimsAuthorizingInterceptor in = createInterceptor(new 
TypedStringRepository());
+        Method method = TypedStringRepository.class.getMethod("update", 
String.class);
+
+        in.handleMessage(prepareMessage(method, createDefaultClaim("admin")));
+        assertDenied(in, prepareMessage(method, createDefaultClaim("user")));
+    }
+
+    private static ClaimsAuthorizingInterceptor createInterceptor(Object 
service) {
+        ClaimsAuthorizingInterceptor in = new ClaimsAuthorizingInterceptor();
+        in.setSecuredObject(service);
+        return in;
+    }
+
+    private static void assertDenied(ClaimsAuthorizingInterceptor in, Message 
m) {
+        try {
+            in.handleMessage(m);
+            fail("AccessDeniedException expected");
+        } catch (AccessDeniedException ex) {
+            // expected
+        }
+    }
+
+    private static ClaimBean createDefaultClaimBean(String value) {
+        org.apache.cxf.rt.security.claims.Claim claim = new 
org.apache.cxf.rt.security.claims.Claim();
+        claim.setClaimType(SAMLClaim.SAML_ROLE_ATTRIBUTENAME_DEFAULT);
+        claim.addValue(value);
+        return new ClaimBean(claim, 
"urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified",
+                             ClaimMode.STRICT, false);
+    }
+
     private void doTestClaims(String methodName,
             org.apache.cxf.rt.security.claims.Claim... claim)
         throws Exception {
@@ -245,6 +515,17 @@ public class ClaimsAuthorizingInterceptorTest {
                                    String roleName,
                                    org.apache.cxf.rt.security.claims.Claim... 
claim)
                                throws Exception {
+        return prepareMessage(cls.getMethod(methodName, new Class[]{}), 
roleName, claim);
+    }
+
+    private Message prepareMessage(Method method,
+                                   org.apache.cxf.rt.security.claims.Claim... 
claim) {
+        return prepareMessage(method, 
SAMLClaim.SAML_ROLE_ATTRIBUTENAME_DEFAULT, claim);
+    }
+
+    private Message prepareMessage(Method method,
+                                   String roleName,
+                                   org.apache.cxf.rt.security.claims.Claim... 
claim) {
         ClaimCollection claims = new ClaimCollection();
         Collections.addAll(claims, claim);
 
@@ -293,8 +574,7 @@ public class ClaimsAuthorizingInterceptorTest {
         Message m = new MessageImpl();
         m.setExchange(new ExchangeImpl());
         m.put(SecurityContext.class, sc);
-        m.put("org.apache.cxf.resource.method",
-               cls.getMethod(methodName, new Class[]{}));
+        m.put("org.apache.cxf.resource.method", method);
         return m;
     }
 
@@ -366,6 +646,230 @@ public class ClaimsAuthorizingInterceptorTest {
 
         }
     }
+    public static class OverloadingService {
+        @Claim("admin")
+        public void delete(String id) {
+
+        }
+
+        public void delete() {
+
+        }
+
+        @Claim("admin")
+        public void update(String value) {
+
+        }
+
+        @Claim("user")
+        public void update() {
+
+        }
+    }
+    public static class BaseService {
+        @Claim("user")
+        public void update() {
+
+        }
+    }
+    public static class OverridingService extends BaseService {
+        @Override
+        @Claim("admin")
+        public void update() {
+
+        }
+    }
+    public static class AdminBaseService {
+        @Claim("admin")
+        public void update() {
+
+        }
+    }
+    public static class UserOverridingService extends AdminBaseService {
+        @Override
+        @Claim("user")
+        public void update() {
+
+        }
+    }
+    @Claim("admin")
+    public static class AdminSubService extends BaseService {
+        @Override
+        public void update() {
+
+        }
+    }
+    public interface AdminApi {
+        @Claim("admin")
+        void update();
+    }
+    public static class AdminApiUserService extends BaseService implements 
AdminApi {
+        @Override
+        public void update() {
+
+        }
+    }
+    public interface SecuredApi {
+        @Claim("admin")
+        void delete();
+    }
+    public static class InterfaceService implements SecuredApi {
+        @Override
+        public void delete() {
+
+        }
+    }
+    public interface Repository<T> {
+        @Claim("admin")
+        void update(T value);
+
+        @Claim("user")
+        void update();
+    }
+    public static class StringRepository implements Repository<String> {
+        @Override
+        public void update(String value) {
+
+        }
+
+        @Override
+        public void update() {
+
+        }
+    }
+    @Claim("user")
+    public static class ClassClaimsStringRepository implements 
Repository<String> {
+        @Override
+        public void update(String value) {
+
+        }
+
+        @Override
+        public void update() {
+
+        }
+    }
+    public static class StringUpdater {
+        public void update(String value) {
+
+        }
+
+        public void update() {
+
+        }
+    }
+    public static class InheritingStringRepository extends StringUpdater 
implements Repository<String> {
+    }
+    public static class OverloadingSubService extends BaseService {
+        @Claim("admin")
+        public void update(String value) {
+
+        }
+    }
+    @Claim("user")
+    public static class ClaimsBaseResource {
+        public void update() {
+
+        }
+    }
+    public static class OverridingSubResource extends ClaimsBaseResource {
+        @Override
+        @Claim("admin")
+        public void update() {
+
+        }
+    }
+    public static class SubclassOnlyService extends ClaimsBaseResource {
+        @Override
+        public void update() {
+
+        }
+
+        @Claim("admin")
+        public void adminOperation() {
+
+        }
+    }
+    @Claim("user")
+    public interface UserApi {
+        void update();
+    }
+    public static class UserApiAdminService implements UserApi {
+        @Override
+        @Claim("admin")
+        public void update() {
+
+        }
+    }
+    @Claim(name = "http://location";, value = "UK")
+    public static class LocationBaseService {
+        public void update() {
+
+        }
+    }
+    public static class LocationSubService extends LocationBaseService {
+        @Override
+        @Claim("admin")
+        public void update() {
+
+        }
+    }
+    @Claim("user")
+    public static class ClaimsAndMethodBaseResource {
+        @Claim("admin")
+        public void update() {
+
+        }
+    }
+    public static class UnannotatedSubResource extends 
ClaimsAndMethodBaseResource {
+        @Override
+        public void update() {
+
+        }
+    }
+    public static class MatchAllService extends BaseService {
+        @Claim(value = {"admin", "manager" }, matchAll = true)
+        public void update(String value) {
+
+        }
+    }
+    public static class InheritingService extends BaseService {
+    }
+    public static class UnannotatedOverridingService extends BaseService {
+        @Override
+        public void update() {
+
+        }
+    }
+    public static class OverloadingStringRepository implements 
Repository<String> {
+        @Override
+        public void update(String value) {
+
+        }
+
+        @Override
+        public void update() {
+
+        }
+
+        @Claim("user")
+        public void update(Integer value) {
+
+        }
+    }
+    public abstract static class AbstractRepository<T> implements 
Repository<T> { // NOPMD
+    }
+    public static class TypedStringRepository extends 
AbstractRepository<String> {
+        @Override
+        public void update(String value) {
+
+        }
+
+        @Override
+        public void update() {
+
+        }
+    }
     @Target(ElementType.METHOD)
     @Retention(RetentionPolicy.RUNTIME)
     public @interface SecureRole {

Reply via email to