Skip to content

Commit c736e07

Browse files
committed
Add AnnotationSythesizer API
Closes gh-13234 Closes gh-13490 Closes gh-15097
1 parent e3438aa commit c736e07

17 files changed

+1183
-464
lines changed

aspects/src/test/java/org/springframework/security/authorization/method/aspectj/PreAuthorizeAspectTests.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ public class PreAuthorizeAspectTests {
4747

4848
private PrePostSecured prePostSecured = new PrePostSecured();
4949

50+
private MultipleInterfaces multiple = new MultipleInterfaces();
51+
5052
@BeforeEach
5153
public final void setUp() {
5254
MockitoAnnotations.initMocks(this);
@@ -110,6 +112,12 @@ public void nestedDenyAllPreAuthorizeDeniesAccess() {
110112
.isThrownBy(() -> this.secured.myObject().denyAllMethod());
111113
}
112114

115+
@Test
116+
public void multipleInterfacesPreAuthorizeAllows() {
117+
// aspectj doesn't inherit annotations
118+
this.multiple.securedMethod();
119+
}
120+
113121
interface SecuredInterface {
114122

115123
@PreAuthorize("hasRole('X')")
@@ -177,4 +185,19 @@ void denyAllMethod() {
177185

178186
}
179187

188+
interface AnotherSecuredInterface {
189+
190+
@PreAuthorize("hasRole('Y')")
191+
void securedMethod();
192+
193+
}
194+
195+
static class MultipleInterfaces implements SecuredInterface, AnotherSecuredInterface {
196+
197+
@Override
198+
public void securedMethod() {
199+
}
200+
201+
}
202+
180203
}

core/src/main/java/org/springframework/security/authorization/method/AbstractExpressionAttributeRegistry.java

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,9 @@
1616

1717
package org.springframework.security.authorization.method;
1818

19-
import java.lang.annotation.Annotation;
20-
import java.lang.reflect.AnnotatedElement;
2119
import java.lang.reflect.Method;
2220
import java.util.Map;
2321
import java.util.concurrent.ConcurrentHashMap;
24-
import java.util.function.Function;
2522

2623
import org.aopalliance.intercept.MethodInvocation;
2724

@@ -43,8 +40,6 @@ abstract class AbstractExpressionAttributeRegistry<T extends ExpressionAttribute
4340

4441
private MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
4542

46-
private PrePostTemplateDefaults defaults;
47-
4843
/**
4944
* Returns an {@link ExpressionAttribute} for the {@link MethodInvocation}.
5045
* @param mi the {@link MethodInvocation} to use
@@ -68,11 +63,6 @@ final T getAttribute(Method method, Class<?> targetClass) {
6863
return this.cachedAttributes.computeIfAbsent(cacheKey, (k) -> resolveAttribute(method, targetClass));
6964
}
7065

71-
final <A extends Annotation> Function<AnnotatedElement, A> findUniqueAnnotation(Class<A> type) {
72-
return (this.defaults != null) ? AuthorizationAnnotationUtils.withDefaults(type, this.defaults)
73-
: AuthorizationAnnotationUtils.withDefaults(type);
74-
}
75-
7666
/**
7767
* Returns the {@link MethodSecurityExpressionHandler}.
7868
* @return the {@link MethodSecurityExpressionHandler} to use
@@ -86,10 +76,6 @@ void setExpressionHandler(MethodSecurityExpressionHandler expressionHandler) {
8676
this.expressionHandler = expressionHandler;
8777
}
8878

89-
void setTemplateDefaults(PrePostTemplateDefaults defaults) {
90-
this.defaults = defaults;
91-
}
92-
9379
/**
9480
* Subclasses should implement this method to provide the non-null
9581
* {@link ExpressionAttribute} for the method and the target class.

core/src/main/java/org/springframework/security/authorization/method/AuthorizationAnnotationUtils.java

Lines changed: 0 additions & 155 deletions
This file was deleted.

core/src/main/java/org/springframework/security/authorization/method/Jsr250AuthorizationManager.java

Lines changed: 8 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.lang.reflect.Method;
2121
import java.util.Collection;
2222
import java.util.HashSet;
23+
import java.util.List;
2324
import java.util.Set;
2425
import java.util.function.Supplier;
2526

@@ -29,12 +30,13 @@
2930
import org.aopalliance.intercept.MethodInvocation;
3031

3132
import org.springframework.aop.support.AopUtils;
32-
import org.springframework.core.annotation.AnnotationConfigurationException;
3333
import org.springframework.lang.NonNull;
3434
import org.springframework.security.authorization.AuthoritiesAuthorizationManager;
3535
import org.springframework.security.authorization.AuthorizationDecision;
3636
import org.springframework.security.authorization.AuthorizationManager;
3737
import org.springframework.security.core.Authentication;
38+
import org.springframework.security.core.annotation.AnnotationSynthesizer;
39+
import org.springframework.security.core.annotation.AnnotationSynthesizers;
3840
import org.springframework.util.Assert;
3941

4042
/**
@@ -49,14 +51,6 @@
4951
*/
5052
public final class Jsr250AuthorizationManager implements AuthorizationManager<MethodInvocation> {
5153

52-
private static final Set<Class<? extends Annotation>> JSR250_ANNOTATIONS = new HashSet<>();
53-
54-
static {
55-
JSR250_ANNOTATIONS.add(DenyAll.class);
56-
JSR250_ANNOTATIONS.add(PermitAll.class);
57-
JSR250_ANNOTATIONS.add(RolesAllowed.class);
58-
}
59-
6054
private final Jsr250AuthorizationManagerRegistry registry = new Jsr250AuthorizationManagerRegistry();
6155

6256
private AuthorizationManager<Collection<String>> authoritiesAuthorizationManager = new AuthoritiesAuthorizationManager();
@@ -102,6 +96,9 @@ public AuthorizationDecision check(Supplier<Authentication> authentication, Meth
10296

10397
private final class Jsr250AuthorizationManagerRegistry extends AbstractAuthorizationManagerRegistry {
10498

99+
private final AnnotationSynthesizer<?> synthesizer = AnnotationSynthesizers
100+
.requireUnique(List.of(DenyAll.class, PermitAll.class, RolesAllowed.class));
101+
105102
@NonNull
106103
@Override
107104
AuthorizationManager<MethodInvocation> resolveManager(Method method, Class<?> targetClass) {
@@ -121,45 +118,8 @@ AuthorizationManager<MethodInvocation> resolveManager(Method method, Class<?> ta
121118

122119
private Annotation findJsr250Annotation(Method method, Class<?> targetClass) {
123120
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
124-
Annotation annotation = findAnnotation(specificMethod);
125-
return (annotation != null) ? annotation
126-
: findAnnotation((targetClass != null) ? targetClass : specificMethod.getDeclaringClass());
127-
}
128-
129-
private Annotation findAnnotation(Method method) {
130-
Set<Annotation> annotations = new HashSet<>();
131-
for (Class<? extends Annotation> annotationClass : JSR250_ANNOTATIONS) {
132-
Annotation annotation = AuthorizationAnnotationUtils.findUniqueAnnotation(method, annotationClass);
133-
if (annotation != null) {
134-
annotations.add(annotation);
135-
}
136-
}
137-
if (annotations.isEmpty()) {
138-
return null;
139-
}
140-
if (annotations.size() > 1) {
141-
throw new AnnotationConfigurationException(
142-
"The JSR-250 specification disallows DenyAll, PermitAll, and RolesAllowed from appearing on the same method.");
143-
}
144-
return annotations.iterator().next();
145-
}
146-
147-
private Annotation findAnnotation(Class<?> clazz) {
148-
Set<Annotation> annotations = new HashSet<>();
149-
for (Class<? extends Annotation> annotationClass : JSR250_ANNOTATIONS) {
150-
Annotation annotation = AuthorizationAnnotationUtils.findUniqueAnnotation(clazz, annotationClass);
151-
if (annotation != null) {
152-
annotations.add(annotation);
153-
}
154-
}
155-
if (annotations.isEmpty()) {
156-
return null;
157-
}
158-
if (annotations.size() > 1) {
159-
throw new AnnotationConfigurationException(
160-
"The JSR-250 specification disallows DenyAll, PermitAll, and RolesAllowed from appearing on the same class definition.");
161-
}
162-
return annotations.iterator().next();
121+
Class<?> targetClassToUse = (targetClass != null) ? targetClass : specificMethod.getDeclaringClass();
122+
return this.synthesizer.synthesize(specificMethod, targetClassToUse);
163123
}
164124

165125
private Set<String> getAllowedRolesWithPrefix(RolesAllowed rolesAllowed) {

0 commit comments

Comments
 (0)