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 {