Skip to content

Commit

Permalink
Add AnnotationSythesizer API
Browse files Browse the repository at this point in the history
Closes gh-13234
Closes gh-13490
Closes gh-15097
  • Loading branch information
jzheaux committed Jul 18, 2024
1 parent e3438aa commit c736e07
Show file tree
Hide file tree
Showing 17 changed files with 1,183 additions and 464 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ public class PreAuthorizeAspectTests {

private PrePostSecured prePostSecured = new PrePostSecured();

private MultipleInterfaces multiple = new MultipleInterfaces();

@BeforeEach
public final void setUp() {
MockitoAnnotations.initMocks(this);
Expand Down Expand Up @@ -110,6 +112,12 @@ public void nestedDenyAllPreAuthorizeDeniesAccess() {
.isThrownBy(() -> this.secured.myObject().denyAllMethod());
}

@Test
public void multipleInterfacesPreAuthorizeAllows() {
// aspectj doesn't inherit annotations
this.multiple.securedMethod();
}

interface SecuredInterface {

@PreAuthorize("hasRole('X')")
Expand Down Expand Up @@ -177,4 +185,19 @@ void denyAllMethod() {

}

interface AnotherSecuredInterface {

@PreAuthorize("hasRole('Y')")
void securedMethod();

}

static class MultipleInterfaces implements SecuredInterface, AnotherSecuredInterface {

@Override
public void securedMethod() {
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,9 @@

package org.springframework.security.authorization.method;

import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;

import org.aopalliance.intercept.MethodInvocation;

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

private MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();

private PrePostTemplateDefaults defaults;

/**
* Returns an {@link ExpressionAttribute} for the {@link MethodInvocation}.
* @param mi the {@link MethodInvocation} to use
Expand All @@ -68,11 +63,6 @@ final T getAttribute(Method method, Class<?> targetClass) {
return this.cachedAttributes.computeIfAbsent(cacheKey, (k) -> resolveAttribute(method, targetClass));
}

final <A extends Annotation> Function<AnnotatedElement, A> findUniqueAnnotation(Class<A> type) {
return (this.defaults != null) ? AuthorizationAnnotationUtils.withDefaults(type, this.defaults)
: AuthorizationAnnotationUtils.withDefaults(type);
}

/**
* Returns the {@link MethodSecurityExpressionHandler}.
* @return the {@link MethodSecurityExpressionHandler} to use
Expand All @@ -86,10 +76,6 @@ void setExpressionHandler(MethodSecurityExpressionHandler expressionHandler) {
this.expressionHandler = expressionHandler;
}

void setTemplateDefaults(PrePostTemplateDefaults defaults) {
this.defaults = defaults;
}

/**
* Subclasses should implement this method to provide the non-null
* {@link ExpressionAttribute} for the method and the target class.
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Supplier;

Expand All @@ -29,12 +30,13 @@
import org.aopalliance.intercept.MethodInvocation;

import org.springframework.aop.support.AopUtils;
import org.springframework.core.annotation.AnnotationConfigurationException;
import org.springframework.lang.NonNull;
import org.springframework.security.authorization.AuthoritiesAuthorizationManager;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.annotation.AnnotationSynthesizer;
import org.springframework.security.core.annotation.AnnotationSynthesizers;
import org.springframework.util.Assert;

/**
Expand All @@ -49,14 +51,6 @@
*/
public final class Jsr250AuthorizationManager implements AuthorizationManager<MethodInvocation> {

private static final Set<Class<? extends Annotation>> JSR250_ANNOTATIONS = new HashSet<>();

static {
JSR250_ANNOTATIONS.add(DenyAll.class);
JSR250_ANNOTATIONS.add(PermitAll.class);
JSR250_ANNOTATIONS.add(RolesAllowed.class);
}

private final Jsr250AuthorizationManagerRegistry registry = new Jsr250AuthorizationManagerRegistry();

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

private final class Jsr250AuthorizationManagerRegistry extends AbstractAuthorizationManagerRegistry {

private final AnnotationSynthesizer<?> synthesizer = AnnotationSynthesizers
.requireUnique(List.of(DenyAll.class, PermitAll.class, RolesAllowed.class));

@NonNull
@Override
AuthorizationManager<MethodInvocation> resolveManager(Method method, Class<?> targetClass) {
Expand All @@ -121,45 +118,8 @@ AuthorizationManager<MethodInvocation> resolveManager(Method method, Class<?> ta

private Annotation findJsr250Annotation(Method method, Class<?> targetClass) {
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
Annotation annotation = findAnnotation(specificMethod);
return (annotation != null) ? annotation
: findAnnotation((targetClass != null) ? targetClass : specificMethod.getDeclaringClass());
}

private Annotation findAnnotation(Method method) {
Set<Annotation> annotations = new HashSet<>();
for (Class<? extends Annotation> annotationClass : JSR250_ANNOTATIONS) {
Annotation annotation = AuthorizationAnnotationUtils.findUniqueAnnotation(method, annotationClass);
if (annotation != null) {
annotations.add(annotation);
}
}
if (annotations.isEmpty()) {
return null;
}
if (annotations.size() > 1) {
throw new AnnotationConfigurationException(
"The JSR-250 specification disallows DenyAll, PermitAll, and RolesAllowed from appearing on the same method.");
}
return annotations.iterator().next();
}

private Annotation findAnnotation(Class<?> clazz) {
Set<Annotation> annotations = new HashSet<>();
for (Class<? extends Annotation> annotationClass : JSR250_ANNOTATIONS) {
Annotation annotation = AuthorizationAnnotationUtils.findUniqueAnnotation(clazz, annotationClass);
if (annotation != null) {
annotations.add(annotation);
}
}
if (annotations.isEmpty()) {
return null;
}
if (annotations.size() > 1) {
throw new AnnotationConfigurationException(
"The JSR-250 specification disallows DenyAll, PermitAll, and RolesAllowed from appearing on the same class definition.");
}
return annotations.iterator().next();
Class<?> targetClassToUse = (targetClass != null) ? targetClass : specificMethod.getDeclaringClass();
return this.synthesizer.synthesize(specificMethod, targetClassToUse);
}

private Set<String> getAllowedRolesWithPrefix(RolesAllowed rolesAllowed) {
Expand Down
Loading

0 comments on commit c736e07

Please sign in to comment.