From 626610a9755177c46be88ea6ff40f4352075a09a Mon Sep 17 00:00:00 2001 From: Josh Cummings Date: Thu, 29 Aug 2024 17:24:57 -0600 Subject: [PATCH] Polish Annotation API Rename to a class that isn't focused on the synthesis implementation detail. Also add Security to the front of the name to clarify that it is only intended for security annotations, reminiscent of SecurityMetadataSource. Refine method signatures to better articulate supported use cases. Issue gh-15286 --- .../method/Jsr250AuthorizationManager.java | 8 +- ...tAuthorizeExpressionAttributeRegistry.java | 15 +-- ...PostFilterExpressionAttributeRegistry.java | 10 +- ...eAuthorizeExpressionAttributeRegistry.java | 15 +-- .../PreFilterExpressionAttributeRegistry.java | 10 +- .../method/SecuredAuthorizationManager.java | 8 +- .../AbstractSecurityAnnotationScanner.java | 66 +++++++++ .../annotation/AnnotationSynthesizers.java | 81 ----------- ...ionTemplateSecurityAnnotationScanner.java} | 17 +-- ...er.java => SecurityAnnotationScanner.java} | 16 +-- .../SecurityAnnotationScanners.java | 81 +++++++++++ ...a => UniqueSecurityAnnotationScanner.java} | 8 +- ...UniqueSecurityAnnotationScannerTests.java} | 126 +++++++++--------- ...thenticationPrincipalArgumentResolver.java | 10 +- ...thenticationPrincipalArgumentResolver.java | 10 +- ...urrentSecurityContextArgumentResolver.java | 10 +- ...thenticationPrincipalArgumentResolver.java | 10 +- ...urrentSecurityContextArgumentResolver.java | 10 +- ...thenticationPrincipalArgumentResolver.java | 10 +- ...urrentSecurityContextArgumentResolver.java | 10 +- 20 files changed, 298 insertions(+), 233 deletions(-) create mode 100644 core/src/main/java/org/springframework/security/core/annotation/AbstractSecurityAnnotationScanner.java delete mode 100644 core/src/main/java/org/springframework/security/core/annotation/AnnotationSynthesizers.java rename core/src/main/java/org/springframework/security/core/annotation/{ExpressionTemplateAnnotationSynthesizer.java => ExpressionTemplateSecurityAnnotationScanner.java} (88%) rename core/src/main/java/org/springframework/security/core/annotation/{AnnotationSynthesizer.java => SecurityAnnotationScanner.java} (83%) create mode 100644 core/src/main/java/org/springframework/security/core/annotation/SecurityAnnotationScanners.java rename core/src/main/java/org/springframework/security/core/annotation/{UniqueMergedAnnotationSynthesizer.java => UniqueSecurityAnnotationScanner.java} (96%) rename core/src/test/java/org/springframework/security/core/annotation/{UniqueMergedAnnotationSynthesizerTests.java => UniqueSecurityAnnotationScannerTests.java} (69%) diff --git a/core/src/main/java/org/springframework/security/authorization/method/Jsr250AuthorizationManager.java b/core/src/main/java/org/springframework/security/authorization/method/Jsr250AuthorizationManager.java index 1af1edc0aa..74d03e7862 100644 --- a/core/src/main/java/org/springframework/security/authorization/method/Jsr250AuthorizationManager.java +++ b/core/src/main/java/org/springframework/security/authorization/method/Jsr250AuthorizationManager.java @@ -34,8 +34,8 @@ import org.springframework.security.authorization.AuthoritiesAuthorizationManage 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.security.core.annotation.SecurityAnnotationScanner; +import org.springframework.security.core.annotation.SecurityAnnotationScanners; import org.springframework.util.Assert; /** @@ -95,7 +95,7 @@ public final class Jsr250AuthorizationManager implements AuthorizationManager synthesizer = AnnotationSynthesizers + private final SecurityAnnotationScanner scanner = SecurityAnnotationScanners .requireUnique(List.of(DenyAll.class, PermitAll.class, RolesAllowed.class)); @NonNull @@ -117,7 +117,7 @@ public final class Jsr250AuthorizationManager implements AuthorizationManager targetClass) { Class targetClassToUse = (targetClass != null) ? targetClass : method.getDeclaringClass(); - return this.synthesizer.synthesize(method, targetClassToUse); + return this.scanner.scan(method, targetClassToUse); } private Set getAllowedRolesWithPrefix(RolesAllowed rolesAllowed) { diff --git a/core/src/main/java/org/springframework/security/authorization/method/PostAuthorizeExpressionAttributeRegistry.java b/core/src/main/java/org/springframework/security/authorization/method/PostAuthorizeExpressionAttributeRegistry.java index 2838d8ed0f..7dc96c106f 100644 --- a/core/src/main/java/org/springframework/security/authorization/method/PostAuthorizeExpressionAttributeRegistry.java +++ b/core/src/main/java/org/springframework/security/authorization/method/PostAuthorizeExpressionAttributeRegistry.java @@ -25,9 +25,9 @@ import reactor.util.annotation.NonNull; import org.springframework.context.ApplicationContext; import org.springframework.expression.Expression; import org.springframework.security.access.prepost.PostAuthorize; -import org.springframework.security.core.annotation.AnnotationSynthesizer; -import org.springframework.security.core.annotation.AnnotationSynthesizers; import org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults; +import org.springframework.security.core.annotation.SecurityAnnotationScanner; +import org.springframework.security.core.annotation.SecurityAnnotationScanners; import org.springframework.util.Assert; /** @@ -41,12 +41,12 @@ final class PostAuthorizeExpressionAttributeRegistry extends AbstractExpressionA private final MethodAuthorizationDeniedHandler defaultHandler = new ThrowingMethodAuthorizationDeniedHandler(); - private final AnnotationSynthesizer handleAuthorizationDeniedSynthesizer = AnnotationSynthesizers + private final SecurityAnnotationScanner handleAuthorizationDeniedScanner = SecurityAnnotationScanners .requireUnique(HandleAuthorizationDenied.class); private Function, MethodAuthorizationDeniedHandler> handlerResolver; - private AnnotationSynthesizer postAuthorizeSynthesizer = AnnotationSynthesizers + private SecurityAnnotationScanner postAuthorizeScanner = SecurityAnnotationScanners .requireUnique(PostAuthorize.class); PostAuthorizeExpressionAttributeRegistry() { @@ -68,8 +68,7 @@ final class PostAuthorizeExpressionAttributeRegistry extends AbstractExpressionA private MethodAuthorizationDeniedHandler resolveHandler(Method method, Class targetClass) { Class targetClassToUse = targetClass(method, targetClass); - HandleAuthorizationDenied deniedHandler = this.handleAuthorizationDeniedSynthesizer.synthesize(method, - targetClassToUse); + HandleAuthorizationDenied deniedHandler = this.handleAuthorizationDeniedScanner.scan(method, targetClassToUse); if (deniedHandler != null) { return this.handlerResolver.apply(deniedHandler.handlerClass()); } @@ -78,7 +77,7 @@ final class PostAuthorizeExpressionAttributeRegistry extends AbstractExpressionA private PostAuthorize findPostAuthorizeAnnotation(Method method, Class targetClass) { Class targetClassToUse = targetClass(method, targetClass); - return this.postAuthorizeSynthesizer.synthesize(method, targetClassToUse); + return this.postAuthorizeScanner.scan(method, targetClassToUse); } /** @@ -92,7 +91,7 @@ final class PostAuthorizeExpressionAttributeRegistry extends AbstractExpressionA } void setTemplateDefaults(AnnotationTemplateExpressionDefaults templateDefaults) { - this.postAuthorizeSynthesizer = AnnotationSynthesizers.requireUnique(PostAuthorize.class, templateDefaults); + this.postAuthorizeScanner = SecurityAnnotationScanners.requireUnique(PostAuthorize.class, templateDefaults); } private MethodAuthorizationDeniedHandler resolveHandler(ApplicationContext context, diff --git a/core/src/main/java/org/springframework/security/authorization/method/PostFilterExpressionAttributeRegistry.java b/core/src/main/java/org/springframework/security/authorization/method/PostFilterExpressionAttributeRegistry.java index b9d678c749..3d6881a8d3 100644 --- a/core/src/main/java/org/springframework/security/authorization/method/PostFilterExpressionAttributeRegistry.java +++ b/core/src/main/java/org/springframework/security/authorization/method/PostFilterExpressionAttributeRegistry.java @@ -21,9 +21,9 @@ import java.lang.reflect.Method; import org.springframework.expression.Expression; import org.springframework.lang.NonNull; import org.springframework.security.access.prepost.PostFilter; -import org.springframework.security.core.annotation.AnnotationSynthesizer; -import org.springframework.security.core.annotation.AnnotationSynthesizers; import org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults; +import org.springframework.security.core.annotation.SecurityAnnotationScanner; +import org.springframework.security.core.annotation.SecurityAnnotationScanners; /** * For internal use only, as this contract is likely to change. @@ -34,7 +34,7 @@ import org.springframework.security.core.annotation.AnnotationTemplateExpression */ final class PostFilterExpressionAttributeRegistry extends AbstractExpressionAttributeRegistry { - private AnnotationSynthesizer synthesizer = AnnotationSynthesizers.requireUnique(PostFilter.class); + private SecurityAnnotationScanner scanner = SecurityAnnotationScanners.requireUnique(PostFilter.class); @NonNull @Override @@ -49,12 +49,12 @@ final class PostFilterExpressionAttributeRegistry extends AbstractExpressionAttr } void setTemplateDefaults(AnnotationTemplateExpressionDefaults defaults) { - this.synthesizer = AnnotationSynthesizers.requireUnique(PostFilter.class, defaults); + this.scanner = SecurityAnnotationScanners.requireUnique(PostFilter.class, defaults); } private PostFilter findPostFilterAnnotation(Method method, Class targetClass) { Class targetClassToUse = targetClass(method, targetClass); - return this.synthesizer.synthesize(method, targetClassToUse); + return this.scanner.scan(method, targetClassToUse); } } diff --git a/core/src/main/java/org/springframework/security/authorization/method/PreAuthorizeExpressionAttributeRegistry.java b/core/src/main/java/org/springframework/security/authorization/method/PreAuthorizeExpressionAttributeRegistry.java index d514674941..35d672cbe6 100644 --- a/core/src/main/java/org/springframework/security/authorization/method/PreAuthorizeExpressionAttributeRegistry.java +++ b/core/src/main/java/org/springframework/security/authorization/method/PreAuthorizeExpressionAttributeRegistry.java @@ -25,9 +25,9 @@ import reactor.util.annotation.NonNull; import org.springframework.context.ApplicationContext; import org.springframework.expression.Expression; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.security.core.annotation.AnnotationSynthesizer; -import org.springframework.security.core.annotation.AnnotationSynthesizers; import org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults; +import org.springframework.security.core.annotation.SecurityAnnotationScanner; +import org.springframework.security.core.annotation.SecurityAnnotationScanners; import org.springframework.util.Assert; /** @@ -41,12 +41,12 @@ final class PreAuthorizeExpressionAttributeRegistry extends AbstractExpressionAt private final MethodAuthorizationDeniedHandler defaultHandler = new ThrowingMethodAuthorizationDeniedHandler(); - private final AnnotationSynthesizer handleAuthorizationDeniedSynthesizer = AnnotationSynthesizers + private final SecurityAnnotationScanner handleAuthorizationDeniedScanner = SecurityAnnotationScanners .requireUnique(HandleAuthorizationDenied.class); private Function, MethodAuthorizationDeniedHandler> handlerResolver; - private AnnotationSynthesizer preAuthorizeSynthesizer = AnnotationSynthesizers + private SecurityAnnotationScanner preAuthorizeScanner = SecurityAnnotationScanners .requireUnique(PreAuthorize.class); PreAuthorizeExpressionAttributeRegistry() { @@ -68,8 +68,7 @@ final class PreAuthorizeExpressionAttributeRegistry extends AbstractExpressionAt private MethodAuthorizationDeniedHandler resolveHandler(Method method, Class targetClass) { Class targetClassToUse = targetClass(method, targetClass); - HandleAuthorizationDenied deniedHandler = this.handleAuthorizationDeniedSynthesizer.synthesize(method, - targetClassToUse); + HandleAuthorizationDenied deniedHandler = this.handleAuthorizationDeniedScanner.scan(method, targetClassToUse); if (deniedHandler != null) { return this.handlerResolver.apply(deniedHandler.handlerClass()); } @@ -78,7 +77,7 @@ final class PreAuthorizeExpressionAttributeRegistry extends AbstractExpressionAt private PreAuthorize findPreAuthorizeAnnotation(Method method, Class targetClass) { Class targetClassToUse = targetClass(method, targetClass); - return this.preAuthorizeSynthesizer.synthesize(method, targetClassToUse); + return this.preAuthorizeScanner.scan(method, targetClassToUse); } /** @@ -92,7 +91,7 @@ final class PreAuthorizeExpressionAttributeRegistry extends AbstractExpressionAt } void setTemplateDefaults(AnnotationTemplateExpressionDefaults defaults) { - this.preAuthorizeSynthesizer = AnnotationSynthesizers.requireUnique(PreAuthorize.class, defaults); + this.preAuthorizeScanner = SecurityAnnotationScanners.requireUnique(PreAuthorize.class, defaults); } private MethodAuthorizationDeniedHandler resolveHandler(ApplicationContext context, diff --git a/core/src/main/java/org/springframework/security/authorization/method/PreFilterExpressionAttributeRegistry.java b/core/src/main/java/org/springframework/security/authorization/method/PreFilterExpressionAttributeRegistry.java index 6d52698850..654c6c2514 100644 --- a/core/src/main/java/org/springframework/security/authorization/method/PreFilterExpressionAttributeRegistry.java +++ b/core/src/main/java/org/springframework/security/authorization/method/PreFilterExpressionAttributeRegistry.java @@ -21,9 +21,9 @@ import java.lang.reflect.Method; import org.springframework.expression.Expression; import org.springframework.lang.NonNull; import org.springframework.security.access.prepost.PreFilter; -import org.springframework.security.core.annotation.AnnotationSynthesizer; -import org.springframework.security.core.annotation.AnnotationSynthesizers; import org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults; +import org.springframework.security.core.annotation.SecurityAnnotationScanner; +import org.springframework.security.core.annotation.SecurityAnnotationScanners; /** * For internal use only, as this contract is likely to change. @@ -35,7 +35,7 @@ import org.springframework.security.core.annotation.AnnotationTemplateExpression final class PreFilterExpressionAttributeRegistry extends AbstractExpressionAttributeRegistry { - private AnnotationSynthesizer synthesizer = AnnotationSynthesizers.requireUnique(PreFilter.class); + private SecurityAnnotationScanner scanner = SecurityAnnotationScanners.requireUnique(PreFilter.class); @NonNull @Override @@ -50,12 +50,12 @@ final class PreFilterExpressionAttributeRegistry } void setTemplateDefaults(AnnotationTemplateExpressionDefaults defaults) { - this.synthesizer = AnnotationSynthesizers.requireUnique(PreFilter.class, defaults); + this.scanner = SecurityAnnotationScanners.requireUnique(PreFilter.class, defaults); } private PreFilter findPreFilterAnnotation(Method method, Class targetClass) { Class targetClassToUse = targetClass(method, targetClass); - return this.synthesizer.synthesize(method, targetClassToUse); + return this.scanner.scan(method, targetClassToUse); } static final class PreFilterExpressionAttribute extends ExpressionAttribute { diff --git a/core/src/main/java/org/springframework/security/authorization/method/SecuredAuthorizationManager.java b/core/src/main/java/org/springframework/security/authorization/method/SecuredAuthorizationManager.java index 9d1d800577..ba71b56626 100644 --- a/core/src/main/java/org/springframework/security/authorization/method/SecuredAuthorizationManager.java +++ b/core/src/main/java/org/springframework/security/authorization/method/SecuredAuthorizationManager.java @@ -32,8 +32,8 @@ import org.springframework.security.authorization.AuthoritiesAuthorizationManage 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.security.core.annotation.SecurityAnnotationScanner; +import org.springframework.security.core.annotation.SecurityAnnotationScanners; import org.springframework.util.Assert; /** @@ -51,7 +51,7 @@ public final class SecuredAuthorizationManager implements AuthorizationManager> cachedAuthorities = new ConcurrentHashMap<>(); - private final AnnotationSynthesizer synthesizer = AnnotationSynthesizers.requireUnique(Secured.class); + private final SecurityAnnotationScanner scanner = SecurityAnnotationScanners.requireUnique(Secured.class); /** * Sets an {@link AuthorizationManager} that accepts a collection of authority @@ -95,7 +95,7 @@ public final class SecuredAuthorizationManager implements AuthorizationManager targetClass) { Class targetClassToUse = (targetClass != null) ? targetClass : method.getDeclaringClass(); - return this.synthesizer.synthesize(method, targetClassToUse); + return this.scanner.scan(method, targetClassToUse); } } diff --git a/core/src/main/java/org/springframework/security/core/annotation/AbstractSecurityAnnotationScanner.java b/core/src/main/java/org/springframework/security/core/annotation/AbstractSecurityAnnotationScanner.java new file mode 100644 index 0000000000..e192405eb1 --- /dev/null +++ b/core/src/main/java/org/springframework/security/core/annotation/AbstractSecurityAnnotationScanner.java @@ -0,0 +1,66 @@ +/* + * Copyright 2002-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.core.annotation; + +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; + +import org.springframework.core.annotation.MergedAnnotation; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; + +/** + * An abstract class to hide the {@link MergedAnnotation} implementation details. + * + *

+ * Also handy for allowing each scanner to delegate to another without needing to + * synthesize twice. + */ +abstract class AbstractSecurityAnnotationScanner implements SecurityAnnotationScanner { + + /** + * {@inheritDoc} + **/ + @Nullable + @Override + public A scan(Method method, Class targetClass) { + Assert.notNull(targetClass, "targetClass cannot be null"); + MergedAnnotation annotation = merge(method, targetClass); + if (annotation == null) { + return null; + } + return annotation.synthesize(); + } + + /** + * {@inheritDoc} + **/ + @Nullable + @Override + public A scan(Parameter parameter) { + MergedAnnotation annotation = merge(parameter, null); + if (annotation == null) { + return null; + } + return annotation.synthesize(); + } + + abstract MergedAnnotation merge(AnnotatedElement element, Class targetClass); + +} diff --git a/core/src/main/java/org/springframework/security/core/annotation/AnnotationSynthesizers.java b/core/src/main/java/org/springframework/security/core/annotation/AnnotationSynthesizers.java deleted file mode 100644 index 33085588b9..0000000000 --- a/core/src/main/java/org/springframework/security/core/annotation/AnnotationSynthesizers.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2002-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.core.annotation; - -import java.lang.annotation.Annotation; -import java.lang.reflect.AnnotatedElement; -import java.util.ArrayList; -import java.util.List; - -/** - * Factory for creating {@link AnnotationSynthesizer} instances. - * - * @author Josh Cummings - * @since 6.4 - */ -public final class AnnotationSynthesizers { - - private AnnotationSynthesizers() { - } - - /** - * Create a {@link AnnotationSynthesizer} that requires synthesized annotations to be - * unique on the given {@link AnnotatedElement}. - * @param type the annotation type - * @param the annotation type - * @return the default {@link AnnotationSynthesizer} - */ - public static AnnotationSynthesizer requireUnique(Class type) { - return new UniqueMergedAnnotationSynthesizer<>(type); - } - - /** - * Create a {@link AnnotationSynthesizer} that requires synthesized annotations to be - * unique on the given {@link AnnotatedElement}. - * - *

- * When a {@link AnnotationTemplateExpressionDefaults} is provided, it will return a - * synthesizer that supports placeholders in the annotation's attributes in addition - * to the meta-annotation synthesizing provided by {@link #requireUnique(Class)}. - * @param type the annotation type - * @param templateDefaults the defaults for resolving placeholders in the annotation's - * attributes - * @param the annotation type - * @return the default {@link AnnotationSynthesizer} - */ - public static AnnotationSynthesizer requireUnique(Class type, - AnnotationTemplateExpressionDefaults templateDefaults) { - if (templateDefaults == null) { - return new UniqueMergedAnnotationSynthesizer<>(type); - } - return new ExpressionTemplateAnnotationSynthesizer<>(type, templateDefaults); - } - - /** - * Create a {@link AnnotationSynthesizer} that requires synthesized annotations to be - * unique on the given {@link AnnotatedElement}. Supplying multiple types implies that - * the synthesized annotation must be unique across all specified types. - * @param types the annotation types - * @return the default {@link AnnotationSynthesizer} - */ - public static AnnotationSynthesizer requireUnique(List> types) { - List> casted = new ArrayList<>(); - types.forEach((type) -> casted.add((Class) type)); - return new UniqueMergedAnnotationSynthesizer<>(casted); - } - -} diff --git a/core/src/main/java/org/springframework/security/core/annotation/ExpressionTemplateAnnotationSynthesizer.java b/core/src/main/java/org/springframework/security/core/annotation/ExpressionTemplateSecurityAnnotationScanner.java similarity index 88% rename from core/src/main/java/org/springframework/security/core/annotation/ExpressionTemplateAnnotationSynthesizer.java rename to core/src/main/java/org/springframework/security/core/annotation/ExpressionTemplateSecurityAnnotationScanner.java index 3a6f2342f0..c4ff94b2a5 100644 --- a/core/src/main/java/org/springframework/security/core/annotation/ExpressionTemplateAnnotationSynthesizer.java +++ b/core/src/main/java/org/springframework/security/core/annotation/ExpressionTemplateSecurityAnnotationScanner.java @@ -35,8 +35,8 @@ import org.springframework.util.PropertyPlaceholderHelper; * *

* Note that in all cases, Spring Security does not allow for repeatable annotations. So - * this class delegates to {@link UniqueMergedAnnotationSynthesizer} in order to error if - * a repeat is discovered. + * this class delegates to {@link UniqueSecurityAnnotationScanner} in order to error if a + * repeat is discovered. * *

* It supports meta-annotations with placeholders, like the following: @@ -49,8 +49,8 @@ import org.springframework.util.PropertyPlaceholderHelper; * * *

- * In that case, you could use an {@link ExpressionTemplateAnnotationSynthesizer} of type - * {@link org.springframework.security.access.prepost.PreAuthorize} to synthesize any + * In that case, you could use an {@link ExpressionTemplateSecurityAnnotationScanner} of + * type {@link org.springframework.security.access.prepost.PreAuthorize} to synthesize any * {@code @HasRole} annotation found on a given {@link AnnotatedElement}. * *

@@ -61,11 +61,12 @@ import org.springframework.util.PropertyPlaceholderHelper; * @author Josh Cummings * @since 6.4 */ -final class ExpressionTemplateAnnotationSynthesizer extends AbstractAnnotationSynthesizer { +final class ExpressionTemplateSecurityAnnotationScanner + extends AbstractSecurityAnnotationScanner { private final Class type; - private final UniqueMergedAnnotationSynthesizer unique; + private final UniqueSecurityAnnotationScanner unique; private final AnnotationTemplateExpressionDefaults templateDefaults; @@ -73,11 +74,11 @@ final class ExpressionTemplateAnnotationSynthesizer extend private final Map> uniqueMethodAnnotationCache = new HashMap<>(); - ExpressionTemplateAnnotationSynthesizer(Class type, AnnotationTemplateExpressionDefaults templateDefaults) { + ExpressionTemplateSecurityAnnotationScanner(Class type, AnnotationTemplateExpressionDefaults templateDefaults) { Assert.notNull(type, "type cannot be null"); Assert.notNull(templateDefaults, "templateDefaults cannot be null"); this.type = type; - this.unique = new UniqueMergedAnnotationSynthesizer<>(type); + this.unique = new UniqueSecurityAnnotationScanner<>(type); this.templateDefaults = templateDefaults; } diff --git a/core/src/main/java/org/springframework/security/core/annotation/AnnotationSynthesizer.java b/core/src/main/java/org/springframework/security/core/annotation/SecurityAnnotationScanner.java similarity index 83% rename from core/src/main/java/org/springframework/security/core/annotation/AnnotationSynthesizer.java rename to core/src/main/java/org/springframework/security/core/annotation/SecurityAnnotationScanner.java index 712c840905..c6b2535aae 100644 --- a/core/src/main/java/org/springframework/security/core/annotation/AnnotationSynthesizer.java +++ b/core/src/main/java/org/springframework/security/core/annotation/SecurityAnnotationScanner.java @@ -23,7 +23,7 @@ import java.lang.reflect.Parameter; import org.springframework.lang.Nullable; /** - * An interface to search for and synthesize an annotation on a type, method, or method + * An interface to scan for and synthesize an annotation on a type, method, or method * parameter into an annotation of type {@code }. * *

@@ -43,13 +43,13 @@ import org.springframework.lang.Nullable; * @param the annotation to search for and synthesize * @author Josh Cummings * @since 6.4 - * @see UniqueMergedAnnotationSynthesizer - * @see ExpressionTemplateAnnotationSynthesizer + * @see UniqueSecurityAnnotationScanner + * @see ExpressionTemplateSecurityAnnotationScanner */ -public interface AnnotationSynthesizer { +public interface SecurityAnnotationScanner { /** - * Synthesize an annotation of type {@code A} from the given method. + * Scan for an annotation of type {@code A}, starting from the given method. * *

* Implementations should fail if they encounter more than one annotation of that type @@ -63,10 +63,10 @@ public interface AnnotationSynthesizer { * @return the synthesized annotation or {@code null} if not found */ @Nullable - A synthesize(Method method, Class targetClass); + A scan(Method method, Class targetClass); /** - * Synthesize an annotation of type {@code A} from the given method parameter. + * Scan for an annotation of type {@code A}, starting from the given method parameter. * *

* Implementations should fail if they encounter more than one annotation of that type @@ -79,6 +79,6 @@ public interface AnnotationSynthesizer { * @return the synthesized annotation or {@code null} if not found */ @Nullable - A synthesize(Parameter parameter); + A scan(Parameter parameter); } diff --git a/core/src/main/java/org/springframework/security/core/annotation/SecurityAnnotationScanners.java b/core/src/main/java/org/springframework/security/core/annotation/SecurityAnnotationScanners.java new file mode 100644 index 0000000000..aa031d1347 --- /dev/null +++ b/core/src/main/java/org/springframework/security/core/annotation/SecurityAnnotationScanners.java @@ -0,0 +1,81 @@ +/* + * Copyright 2002-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.security.core.annotation; + +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; +import java.util.ArrayList; +import java.util.List; + +/** + * Factory for creating {@link SecurityAnnotationScanner} instances. + * + * @author Josh Cummings + * @since 6.4 + */ +public final class SecurityAnnotationScanners { + + private SecurityAnnotationScanners() { + } + + /** + * Create a {@link SecurityAnnotationScanner} that requires synthesized annotations to + * be unique on the given {@link AnnotatedElement}. + * @param type the annotation type + * @param the annotation type + * @return the default {@link SecurityAnnotationScanner} + */ + public static SecurityAnnotationScanner requireUnique(Class type) { + return new UniqueSecurityAnnotationScanner<>(type); + } + + /** + * Create a {@link SecurityAnnotationScanner} that requires synthesized annotations to + * be unique on the given {@link AnnotatedElement}. + * + *

+ * When a {@link AnnotationTemplateExpressionDefaults} is provided, it will return a + * scanner that supports placeholders in the annotation's attributes in addition to + * the meta-annotation synthesizing provided by {@link #requireUnique(Class)}. + * @param type the annotation type + * @param templateDefaults the defaults for resolving placeholders in the annotation's + * attributes + * @param the annotation type + * @return the default {@link SecurityAnnotationScanner} + */ + public static SecurityAnnotationScanner requireUnique(Class type, + AnnotationTemplateExpressionDefaults templateDefaults) { + if (templateDefaults == null) { + return new UniqueSecurityAnnotationScanner<>(type); + } + return new ExpressionTemplateSecurityAnnotationScanner<>(type, templateDefaults); + } + + /** + * Create a {@link SecurityAnnotationScanner} that requires synthesized annotations to + * be unique on the given {@link AnnotatedElement}. Supplying multiple types implies + * that the synthesized annotation must be unique across all specified types. + * @param types the annotation types + * @return the default {@link SecurityAnnotationScanner} + */ + public static SecurityAnnotationScanner requireUnique(List> types) { + List> casted = new ArrayList<>(); + types.forEach((type) -> casted.add((Class) type)); + return new UniqueSecurityAnnotationScanner<>(casted); + } + +} diff --git a/core/src/main/java/org/springframework/security/core/annotation/UniqueMergedAnnotationSynthesizer.java b/core/src/main/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScanner.java similarity index 96% rename from core/src/main/java/org/springframework/security/core/annotation/UniqueMergedAnnotationSynthesizer.java rename to core/src/main/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScanner.java index e2715cc2f5..e8579c28e1 100644 --- a/core/src/main/java/org/springframework/security/core/annotation/UniqueMergedAnnotationSynthesizer.java +++ b/core/src/main/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScanner.java @@ -69,7 +69,7 @@ import org.springframework.util.ClassUtils; * * *

- * In that case, you can use an {@link UniqueMergedAnnotationSynthesizer} of type + * In that case, you can use an {@link UniqueSecurityAnnotationScanner} of type * {@link org.springframework.security.access.prepost.PreAuthorize} to synthesize any * {@code @HasRole} annotation found on a given method or class into its * {@link org.springframework.security.access.prepost.PreAuthorize} meta-annotation. @@ -82,16 +82,16 @@ import org.springframework.util.ClassUtils; * @author Josh Cummings * @since 6.4 */ -final class UniqueMergedAnnotationSynthesizer extends AbstractAnnotationSynthesizer { +final class UniqueSecurityAnnotationScanner extends AbstractSecurityAnnotationScanner { private final List> types; - UniqueMergedAnnotationSynthesizer(Class type) { + UniqueSecurityAnnotationScanner(Class type) { Assert.notNull(type, "type cannot be null"); this.types = List.of(type); } - UniqueMergedAnnotationSynthesizer(List> types) { + UniqueSecurityAnnotationScanner(List> types) { Assert.notNull(types, "types cannot be null"); this.types = types; } diff --git a/core/src/test/java/org/springframework/security/core/annotation/UniqueMergedAnnotationSynthesizerTests.java b/core/src/test/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScannerTests.java similarity index 69% rename from core/src/test/java/org/springframework/security/core/annotation/UniqueMergedAnnotationSynthesizerTests.java rename to core/src/test/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScannerTests.java index fd9c1ac8c0..b1a7a779aa 100644 --- a/core/src/test/java/org/springframework/security/core/annotation/UniqueMergedAnnotationSynthesizerTests.java +++ b/core/src/test/java/org/springframework/security/core/annotation/UniqueSecurityAnnotationScannerTests.java @@ -27,227 +27,227 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; /** - * Tests for {@link UniqueMergedAnnotationSynthesizer} + * Tests for {@link UniqueSecurityAnnotationScanner} */ -public class UniqueMergedAnnotationSynthesizerTests { +public class UniqueSecurityAnnotationScannerTests { - private UniqueMergedAnnotationSynthesizer synthesizer = new UniqueMergedAnnotationSynthesizer<>( + private UniqueSecurityAnnotationScanner scanner = new UniqueSecurityAnnotationScanner<>( PreAuthorize.class); @Test - void synthesizeWhenAnnotationOnInterfaceThenResolves() throws Exception { + void scanWhenAnnotationOnInterfaceThenResolves() throws Exception { Method method = AnnotationOnInterface.class.getDeclaredMethod("method"); - PreAuthorize preAuthorize = this.synthesizer.synthesize(method, method.getDeclaringClass()); + PreAuthorize preAuthorize = this.scanner.scan(method, method.getDeclaringClass()); assertThat(preAuthorize.value()).isEqualTo("one"); } @Test - void synthesizeWhenAnnotationOnMethodThenResolves() throws Exception { + void scanWhenAnnotationOnMethodThenResolves() throws Exception { Method method = AnnotationOnInterfaceMethod.class.getDeclaredMethod("method"); - PreAuthorize preAuthorize = this.synthesizer.synthesize(method, method.getDeclaringClass()); + PreAuthorize preAuthorize = this.scanner.scan(method, method.getDeclaringClass()); assertThat(preAuthorize.value()).isEqualTo("three"); } @Test - void synthesizeWhenAnnotationOnClassThenResolves() throws Exception { + void scanWhenAnnotationOnClassThenResolves() throws Exception { Method method = AnnotationOnClass.class.getDeclaredMethod("method"); - PreAuthorize preAuthorize = this.synthesizer.synthesize(method, method.getDeclaringClass()); + PreAuthorize preAuthorize = this.scanner.scan(method, method.getDeclaringClass()); assertThat(preAuthorize.value()).isEqualTo("five"); } @Test - void synthesizeWhenAnnotationOnClassMethodThenResolves() throws Exception { + void scanWhenAnnotationOnClassMethodThenResolves() throws Exception { Method method = AnnotationOnClassMethod.class.getDeclaredMethod("method"); - PreAuthorize preAuthorize = this.synthesizer.synthesize(method, method.getDeclaringClass()); + PreAuthorize preAuthorize = this.scanner.scan(method, method.getDeclaringClass()); assertThat(preAuthorize.value()).isEqualTo("six"); } @Test - void synthesizeWhenInterfaceOverridingAnnotationOnInterfaceThenResolves() throws Exception { + void scanWhenInterfaceOverridingAnnotationOnInterfaceThenResolves() throws Exception { Method method = InterfaceMethodOverridingAnnotationOnInterface.class.getDeclaredMethod("method"); - PreAuthorize preAuthorize = this.synthesizer.synthesize(method, method.getDeclaringClass()); + PreAuthorize preAuthorize = this.scanner.scan(method, method.getDeclaringClass()); assertThat(preAuthorize.value()).isEqualTo("eight"); } @Test - void synthesizeWhenInterfaceOverridingMultipleInterfaceInheritanceThenResolves() throws Exception { + void scanWhenInterfaceOverridingMultipleInterfaceInheritanceThenResolves() throws Exception { Method method = ClassInheritingInterfaceOverridingMultipleInterfaceInheritance.class .getDeclaredMethod("method"); - PreAuthorize preAuthorize = this.synthesizer.synthesize(method, method.getDeclaringClass()); + PreAuthorize preAuthorize = this.scanner.scan(method, method.getDeclaringClass()); assertThat(preAuthorize.value()).isEqualTo("ten"); } @Test - void synthesizeWhenInterfaceMethodOverridingAnnotationOnInterfaceThenResolves() throws Exception { + void scanWhenInterfaceMethodOverridingAnnotationOnInterfaceThenResolves() throws Exception { Method method = InterfaceMethodOverridingMultipleInterfaceInheritance.class.getDeclaredMethod("method"); - PreAuthorize preAuthorize = this.synthesizer.synthesize(method, method.getDeclaringClass()); + PreAuthorize preAuthorize = this.scanner.scan(method, method.getDeclaringClass()); assertThat(preAuthorize.value()).isEqualTo("eleven"); } @Test - void synthesizeWhenClassMultipleInheritanceThenException() throws Exception { + void scanWhenClassMultipleInheritanceThenException() throws Exception { Method method = ClassAttemptingMultipleInterfaceInheritance.class.getDeclaredMethod("method"); assertThatExceptionOfType(AnnotationConfigurationException.class) - .isThrownBy(() -> this.synthesizer.synthesize(method, method.getDeclaringClass())); + .isThrownBy(() -> this.scanner.scan(method, method.getDeclaringClass())); } // gh-15097 @Test - void synthesizeWhenClassOverridingMultipleInterfaceInheritanceThenResolves() throws Exception { + void scanWhenClassOverridingMultipleInterfaceInheritanceThenResolves() throws Exception { Method method = ClassOverridingMultipleInterfaceInheritance.class.getDeclaredMethod("method"); - PreAuthorize preAuthorize = this.synthesizer.synthesize(method, method.getDeclaringClass()); + PreAuthorize preAuthorize = this.scanner.scan(method, method.getDeclaringClass()); assertThat(preAuthorize.value()).isEqualTo("thirteen"); } @Test - void synthesizeWhenClassMethodOverridingMultipleInterfaceInheritanceThenResolves() throws Exception { + void scanWhenClassMethodOverridingMultipleInterfaceInheritanceThenResolves() throws Exception { Method method = ClassMethodOverridingMultipleInterfaceInheritance.class.getDeclaredMethod("method"); - PreAuthorize preAuthorize = this.synthesizer.synthesize(method, method.getDeclaringClass()); + PreAuthorize preAuthorize = this.scanner.scan(method, method.getDeclaringClass()); assertThat(preAuthorize.value()).isEqualTo("fourteen"); } @Test - void synthesizeWhenClassInheritingInterfaceOverridingInterfaceAnnotationThenResolves() throws Exception { + void scanWhenClassInheritingInterfaceOverridingInterfaceAnnotationThenResolves() throws Exception { Method method = ClassInheritingInterfaceOverridingInterfaceAnnotation.class.getDeclaredMethod("method"); - PreAuthorize preAuthorize = this.synthesizer.synthesize(method, method.getDeclaringClass()); + PreAuthorize preAuthorize = this.scanner.scan(method, method.getDeclaringClass()); assertThat(preAuthorize.value()).isEqualTo("seven"); } @Test - void synthesizeWhenClassOverridingGrandparentInterfaceAnnotationThenResolves() throws Exception { + void scanWhenClassOverridingGrandparentInterfaceAnnotationThenResolves() throws Exception { Method method = ClassOverridingGrandparentInterfaceAnnotation.class.getDeclaredMethod("method"); - PreAuthorize preAuthorize = this.synthesizer.synthesize(method, method.getDeclaringClass()); + PreAuthorize preAuthorize = this.scanner.scan(method, method.getDeclaringClass()); assertThat(preAuthorize.value()).isEqualTo("sixteen"); } @Test - void synthesizeWhenMethodOverridingGrandparentInterfaceAnnotationThenResolves() throws Exception { + void scanWhenMethodOverridingGrandparentInterfaceAnnotationThenResolves() throws Exception { Method method = MethodOverridingGrandparentInterfaceAnnotation.class.getDeclaredMethod("method"); - PreAuthorize preAuthorize = this.synthesizer.synthesize(method, method.getDeclaringClass()); + PreAuthorize preAuthorize = this.scanner.scan(method, method.getDeclaringClass()); assertThat(preAuthorize.value()).isEqualTo("seventeen"); } @Test - void synthesizeWhenClassInheritingMethodOverriddenAnnotationThenResolves() throws Exception { + void scanWhenClassInheritingMethodOverriddenAnnotationThenResolves() throws Exception { Method method = ClassInheritingMethodOverriddenAnnotation.class.getDeclaredMethod("method"); - PreAuthorize preAuthorize = this.synthesizer.synthesize(method, method.getDeclaringClass()); + PreAuthorize preAuthorize = this.scanner.scan(method, method.getDeclaringClass()); assertThat(preAuthorize.value()).isEqualTo("eight"); } @Test - void synthesizeWhenClassOverridingMethodOverriddenAnnotationThenResolves() throws Exception { + void scanWhenClassOverridingMethodOverriddenAnnotationThenResolves() throws Exception { Method method = ClassOverridingMethodOverriddenAnnotation.class.getDeclaredMethod("method"); - PreAuthorize preAuthorize = this.synthesizer.synthesize(method, method.getDeclaringClass()); + PreAuthorize preAuthorize = this.scanner.scan(method, method.getDeclaringClass()); assertThat(preAuthorize.value()).isEqualTo("eight"); } @Test - void synthesizeWhenMethodOverridingMethodOverriddenAnnotationThenResolves() throws Exception { + void scanWhenMethodOverridingMethodOverriddenAnnotationThenResolves() throws Exception { Method method = MethodOverridingMethodOverriddenAnnotation.class.getDeclaredMethod("method"); - PreAuthorize preAuthorize = this.synthesizer.synthesize(method, method.getDeclaringClass()); + PreAuthorize preAuthorize = this.scanner.scan(method, method.getDeclaringClass()); assertThat(preAuthorize.value()).isEqualTo("twenty"); } @Test - void synthesizeWhenClassInheritingMultipleInheritanceThenException() throws Exception { + void scanWhenClassInheritingMultipleInheritanceThenException() throws Exception { Method method = ClassInheritingMultipleInheritance.class.getDeclaredMethod("method"); assertThatExceptionOfType(AnnotationConfigurationException.class) - .isThrownBy(() -> this.synthesizer.synthesize(method, method.getDeclaringClass())); + .isThrownBy(() -> this.scanner.scan(method, method.getDeclaringClass())); } @Test - void synthesizeWhenClassOverridingMultipleInheritanceThenResolves() throws Exception { + void scanWhenClassOverridingMultipleInheritanceThenResolves() throws Exception { Method method = ClassOverridingMultipleInheritance.class.getDeclaredMethod("method"); - PreAuthorize preAuthorize = this.synthesizer.synthesize(method, method.getDeclaringClass()); + PreAuthorize preAuthorize = this.scanner.scan(method, method.getDeclaringClass()); assertThat(preAuthorize.value()).isEqualTo("twentytwo"); } @Test - void synthesizeWhenMethodOverridingMultipleInheritanceThenResolves() throws Exception { + void scanWhenMethodOverridingMultipleInheritanceThenResolves() throws Exception { Method method = MethodOverridingMultipleInheritance.class.getDeclaredMethod("method"); - PreAuthorize preAuthorize = this.synthesizer.synthesize(method, method.getDeclaringClass()); + PreAuthorize preAuthorize = this.scanner.scan(method, method.getDeclaringClass()); assertThat(preAuthorize.value()).isEqualTo("twentythree"); } @Test - void synthesizeWhenInheritingInterfaceAndMethodAnnotationsThenResolves() throws Exception { + void scanWhenInheritingInterfaceAndMethodAnnotationsThenResolves() throws Exception { Method method = InheritingInterfaceAndMethodAnnotations.class.getDeclaredMethod("method"); - PreAuthorize preAuthorize = this.synthesizer.synthesize(method, method.getDeclaringClass()); + PreAuthorize preAuthorize = this.scanner.scan(method, method.getDeclaringClass()); assertThat(preAuthorize.value()).isEqualTo("three"); } @Test - void synthesizeWhenClassOverridingInterfaceAndMethodInheritanceThenResolves() throws Exception { + void scanWhenClassOverridingInterfaceAndMethodInheritanceThenResolves() throws Exception { Method method = ClassOverridingInterfaceAndMethodInheritance.class.getDeclaredMethod("method"); - PreAuthorize preAuthorize = this.synthesizer.synthesize(method, method.getDeclaringClass()); + PreAuthorize preAuthorize = this.scanner.scan(method, method.getDeclaringClass()); assertThat(preAuthorize.value()).isEqualTo("three"); } @Test - void synthesizeWhenMethodOverridingInterfaceAndMethodInheritanceThenResolves() throws Exception { + void scanWhenMethodOverridingInterfaceAndMethodInheritanceThenResolves() throws Exception { Method method = MethodOverridingInterfaceAndMethodInheritance.class.getDeclaredMethod("method"); - PreAuthorize preAuthorize = this.synthesizer.synthesize(method, method.getDeclaringClass()); + PreAuthorize preAuthorize = this.scanner.scan(method, method.getDeclaringClass()); assertThat(preAuthorize.value()).isEqualTo("twentysix"); } @Test - void synthesizeWhenMultipleMethodInheritanceThenException() throws Exception { + void scanWhenMultipleMethodInheritanceThenException() throws Exception { Method method = MultipleMethodInheritance.class.getDeclaredMethod("method"); assertThatExceptionOfType(AnnotationConfigurationException.class) - .isThrownBy(() -> this.synthesizer.synthesize(method, method.getDeclaringClass())); + .isThrownBy(() -> this.scanner.scan(method, method.getDeclaringClass())); } // gh-13234 @Test - void synthesizeWhenClassInheritingInterfaceAnnotationThenResolves() throws Exception { + void scanWhenClassInheritingInterfaceAnnotationThenResolves() throws Exception { Method method = ClassInheritingInterfaceMethodAnnotation.class.getDeclaredMethod("method"); - PreAuthorize preAuthorize = this.synthesizer.synthesize(method, method.getDeclaringClass()); + PreAuthorize preAuthorize = this.scanner.scan(method, method.getDeclaringClass()); assertThat(preAuthorize.value()).isEqualTo("three"); } @Test - void synthesizeWhenMethodInheritingMethodOverridingInterfaceAndMethodInheritanceThenResolves() throws Exception { + void scanWhenMethodInheritingMethodOverridingInterfaceAndMethodInheritanceThenResolves() throws Exception { Method method = MethodInheritingMethodOverridingInterfaceAndMethodInheritance.class.getMethod("method"); - PreAuthorize preAuthorize = this.synthesizer.synthesize(method, method.getDeclaringClass()); + PreAuthorize preAuthorize = this.scanner.scan(method, method.getDeclaringClass()); assertThat(preAuthorize.value()).isEqualTo("twentysix"); } @Test - void synthesizeWhenClassOverridingMethodOverridingInterfaceAndMethodInheritanceThenResolves() throws Exception { + void scanWhenClassOverridingMethodOverridingInterfaceAndMethodInheritanceThenResolves() throws Exception { Method method = ClassOverridingMethodOverridingInterfaceAndMethodInheritance.class.getMethod("method"); - PreAuthorize preAuthorize = this.synthesizer.synthesize(method, + PreAuthorize preAuthorize = this.scanner.scan(method, ClassOverridingMethodOverridingInterfaceAndMethodInheritance.class); assertThat(preAuthorize.value()).isEqualTo("twentysix"); } @Test - void synthesizeWhenInterfaceInheritingAnnotationsAtDifferentLevelsThenException() throws Exception { + void scanWhenInterfaceInheritingAnnotationsAtDifferentLevelsThenException() throws Exception { Method method = InterfaceInheritingAnnotationsAtDifferentLevels.class.getMethod("method"); assertThatExceptionOfType(AnnotationConfigurationException.class) - .isThrownBy(() -> this.synthesizer.synthesize(method, method.getDeclaringClass())); + .isThrownBy(() -> this.scanner.scan(method, method.getDeclaringClass())); } @Test - void synthesizeWhenClassMethodOverridingAnnotationOnMethodThenResolves() throws Exception { + void scanWhenClassMethodOverridingAnnotationOnMethodThenResolves() throws Exception { Method method = ClassMethodOverridingAnnotationOnMethod.class.getDeclaredMethod("method"); - PreAuthorize preAuthorize = this.synthesizer.synthesize(method, method.getDeclaringClass()); + PreAuthorize preAuthorize = this.scanner.scan(method, method.getDeclaringClass()); assertThat(preAuthorize.value()).isEqualTo("twentyeight"); } // gh-13490 @Test - void synthesizeWhenClassInheritingInterfaceInheritingInterfaceMethodAnnotationThenResolves() throws Exception { + void scanWhenClassInheritingInterfaceInheritingInterfaceMethodAnnotationThenResolves() throws Exception { Method method = ClassInheritingInterfaceInheritingInterfaceMethodAnnotation.class.getDeclaredMethod("method"); - PreAuthorize preAuthorize = this.synthesizer.synthesize(method, method.getDeclaringClass()); + PreAuthorize preAuthorize = this.scanner.scan(method, method.getDeclaringClass()); assertThat(preAuthorize.value()).isEqualTo("three"); } // gh-15352 @Test - void synthesizeWhenClassInheritingAbstractClassNoAnnotationsThenNoAnnotation() throws Exception { + void scanWhenClassInheritingAbstractClassNoAnnotationsThenNoAnnotation() throws Exception { Method method = ClassInheritingAbstractClassNoAnnotations.class.getMethod("otherMethod"); Class targetClass = ClassInheritingAbstractClassNoAnnotations.class; - PreAuthorize preAuthorize = this.synthesizer.synthesize(method, targetClass); + PreAuthorize preAuthorize = this.scanner.scan(method, targetClass); assertThat(preAuthorize).isNull(); } diff --git a/messaging/src/main/java/org/springframework/security/messaging/context/AuthenticationPrincipalArgumentResolver.java b/messaging/src/main/java/org/springframework/security/messaging/context/AuthenticationPrincipalArgumentResolver.java index 482434db54..c4e686e9ea 100644 --- a/messaging/src/main/java/org/springframework/security/messaging/context/AuthenticationPrincipalArgumentResolver.java +++ b/messaging/src/main/java/org/springframework/security/messaging/context/AuthenticationPrincipalArgumentResolver.java @@ -28,10 +28,10 @@ import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.messaging.Message; import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver; import org.springframework.security.core.Authentication; -import org.springframework.security.core.annotation.AnnotationSynthesizer; -import org.springframework.security.core.annotation.AnnotationSynthesizers; import org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults; import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.core.annotation.SecurityAnnotationScanner; +import org.springframework.security.core.annotation.SecurityAnnotationScanners; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolderStrategy; import org.springframework.stereotype.Controller; @@ -99,7 +99,7 @@ public final class AuthenticationPrincipalArgumentResolver implements HandlerMet private ExpressionParser parser = new SpelExpressionParser(); - private AnnotationSynthesizer synthesizer = AnnotationSynthesizers + private SecurityAnnotationScanner scanner = SecurityAnnotationScanners .requireUnique(AuthenticationPrincipal.class); @Override @@ -153,7 +153,7 @@ public final class AuthenticationPrincipalArgumentResolver implements HandlerMet * @since 6.4 */ public void setTemplateDefaults(AnnotationTemplateExpressionDefaults templateDefaults) { - this.synthesizer = AnnotationSynthesizers.requireUnique(AuthenticationPrincipal.class, templateDefaults); + this.scanner = SecurityAnnotationScanners.requireUnique(AuthenticationPrincipal.class, templateDefaults); } /** @@ -165,7 +165,7 @@ public final class AuthenticationPrincipalArgumentResolver implements HandlerMet @SuppressWarnings("unchecked") private T findMethodAnnotation(MethodParameter parameter) { return (T) this.cachedAttributes.computeIfAbsent(parameter, - (methodParameter) -> this.synthesizer.synthesize(methodParameter.getParameter())); + (methodParameter) -> this.scanner.scan(methodParameter.getParameter())); } } diff --git a/messaging/src/main/java/org/springframework/security/messaging/handler/invocation/reactive/AuthenticationPrincipalArgumentResolver.java b/messaging/src/main/java/org/springframework/security/messaging/handler/invocation/reactive/AuthenticationPrincipalArgumentResolver.java index 7d0f20296e..198f40c532 100644 --- a/messaging/src/main/java/org/springframework/security/messaging/handler/invocation/reactive/AuthenticationPrincipalArgumentResolver.java +++ b/messaging/src/main/java/org/springframework/security/messaging/handler/invocation/reactive/AuthenticationPrincipalArgumentResolver.java @@ -35,10 +35,10 @@ import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.messaging.Message; import org.springframework.messaging.handler.invocation.reactive.HandlerMethodArgumentResolver; import org.springframework.security.core.Authentication; -import org.springframework.security.core.annotation.AnnotationSynthesizer; -import org.springframework.security.core.annotation.AnnotationSynthesizers; import org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults; import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.core.annotation.SecurityAnnotationScanner; +import org.springframework.security.core.annotation.SecurityAnnotationScanners; import org.springframework.security.core.context.ReactiveSecurityContextHolder; import org.springframework.security.core.context.SecurityContext; import org.springframework.stereotype.Controller; @@ -103,7 +103,7 @@ public class AuthenticationPrincipalArgumentResolver implements HandlerMethodArg private ExpressionParser parser = new SpelExpressionParser(); - private AnnotationSynthesizer synthesizer = AnnotationSynthesizers + private SecurityAnnotationScanner scanner = SecurityAnnotationScanners .requireUnique(AuthenticationPrincipal.class); private BeanResolver beanResolver; @@ -194,7 +194,7 @@ public class AuthenticationPrincipalArgumentResolver implements HandlerMethodArg * @since 6.4 */ public void setTemplateDefaults(AnnotationTemplateExpressionDefaults templateDefaults) { - this.synthesizer = AnnotationSynthesizers.requireUnique(AuthenticationPrincipal.class, templateDefaults); + this.scanner = SecurityAnnotationScanners.requireUnique(AuthenticationPrincipal.class, templateDefaults); } /** @@ -206,7 +206,7 @@ public class AuthenticationPrincipalArgumentResolver implements HandlerMethodArg @SuppressWarnings("unchecked") private T findMethodAnnotation(MethodParameter parameter) { return (T) this.cachedAttributes.computeIfAbsent(parameter, - (methodParameter) -> this.synthesizer.synthesize(methodParameter.getParameter())); + (methodParameter) -> this.scanner.scan(methodParameter.getParameter())); } } diff --git a/messaging/src/main/java/org/springframework/security/messaging/handler/invocation/reactive/CurrentSecurityContextArgumentResolver.java b/messaging/src/main/java/org/springframework/security/messaging/handler/invocation/reactive/CurrentSecurityContextArgumentResolver.java index 303b351e55..a66ba6784c 100644 --- a/messaging/src/main/java/org/springframework/security/messaging/handler/invocation/reactive/CurrentSecurityContextArgumentResolver.java +++ b/messaging/src/main/java/org/springframework/security/messaging/handler/invocation/reactive/CurrentSecurityContextArgumentResolver.java @@ -35,10 +35,10 @@ import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.messaging.Message; import org.springframework.messaging.handler.invocation.reactive.HandlerMethodArgumentResolver; import org.springframework.security.core.Authentication; -import org.springframework.security.core.annotation.AnnotationSynthesizer; -import org.springframework.security.core.annotation.AnnotationSynthesizers; import org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults; import org.springframework.security.core.annotation.CurrentSecurityContext; +import org.springframework.security.core.annotation.SecurityAnnotationScanner; +import org.springframework.security.core.annotation.SecurityAnnotationScanners; import org.springframework.security.core.context.ReactiveSecurityContextHolder; import org.springframework.security.core.context.SecurityContext; import org.springframework.stereotype.Controller; @@ -101,7 +101,7 @@ public class CurrentSecurityContextArgumentResolver implements HandlerMethodArgu private ExpressionParser parser = new SpelExpressionParser(); - private AnnotationSynthesizer synthesizer = AnnotationSynthesizers + private SecurityAnnotationScanner scanner = SecurityAnnotationScanners .requireUnique(CurrentSecurityContext.class); private BeanResolver beanResolver; @@ -212,7 +212,7 @@ public class CurrentSecurityContextArgumentResolver implements HandlerMethodArgu * @since 6.4 */ public void setTemplateDefaults(AnnotationTemplateExpressionDefaults templateDefaults) { - this.synthesizer = AnnotationSynthesizers.requireUnique(CurrentSecurityContext.class, templateDefaults); + this.scanner = SecurityAnnotationScanners.requireUnique(CurrentSecurityContext.class, templateDefaults); } /** @@ -223,7 +223,7 @@ public class CurrentSecurityContextArgumentResolver implements HandlerMethodArgu @SuppressWarnings("unchecked") private T findMethodAnnotation(MethodParameter parameter) { return (T) this.cachedAttributes.computeIfAbsent(parameter, - (methodParameter) -> this.synthesizer.synthesize(methodParameter.getParameter())); + (methodParameter) -> this.scanner.scan(methodParameter.getParameter())); } } diff --git a/web/src/main/java/org/springframework/security/web/method/annotation/AuthenticationPrincipalArgumentResolver.java b/web/src/main/java/org/springframework/security/web/method/annotation/AuthenticationPrincipalArgumentResolver.java index d3d34fe74f..c119cbdc0b 100644 --- a/web/src/main/java/org/springframework/security/web/method/annotation/AuthenticationPrincipalArgumentResolver.java +++ b/web/src/main/java/org/springframework/security/web/method/annotation/AuthenticationPrincipalArgumentResolver.java @@ -27,10 +27,10 @@ import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.security.core.Authentication; -import org.springframework.security.core.annotation.AnnotationSynthesizer; -import org.springframework.security.core.annotation.AnnotationSynthesizers; import org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults; import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.core.annotation.SecurityAnnotationScanner; +import org.springframework.security.core.annotation.SecurityAnnotationScanners; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolderStrategy; import org.springframework.stereotype.Controller; @@ -102,7 +102,7 @@ public final class AuthenticationPrincipalArgumentResolver implements HandlerMet private ExpressionParser parser = new SpelExpressionParser(); - private AnnotationSynthesizer synthesizer = AnnotationSynthesizers + private SecurityAnnotationScanner scanner = SecurityAnnotationScanners .requireUnique(AuthenticationPrincipal.class); private BeanResolver beanResolver; @@ -168,7 +168,7 @@ public final class AuthenticationPrincipalArgumentResolver implements HandlerMet * @since 6.4 */ public void setTemplateDefaults(AnnotationTemplateExpressionDefaults templateDefaults) { - this.synthesizer = AnnotationSynthesizers.requireUnique(AuthenticationPrincipal.class, templateDefaults); + this.scanner = SecurityAnnotationScanners.requireUnique(AuthenticationPrincipal.class, templateDefaults); } /** @@ -180,7 +180,7 @@ public final class AuthenticationPrincipalArgumentResolver implements HandlerMet @SuppressWarnings("unchecked") private T findMethodAnnotation(MethodParameter parameter) { return (T) this.cachedAttributes.computeIfAbsent(parameter, - (methodParameter) -> this.synthesizer.synthesize(methodParameter.getParameter())); + (methodParameter) -> this.scanner.scan(methodParameter.getParameter())); } } diff --git a/web/src/main/java/org/springframework/security/web/method/annotation/CurrentSecurityContextArgumentResolver.java b/web/src/main/java/org/springframework/security/web/method/annotation/CurrentSecurityContextArgumentResolver.java index 475d650c9a..f73c5fc719 100644 --- a/web/src/main/java/org/springframework/security/web/method/annotation/CurrentSecurityContextArgumentResolver.java +++ b/web/src/main/java/org/springframework/security/web/method/annotation/CurrentSecurityContextArgumentResolver.java @@ -26,10 +26,10 @@ import org.springframework.expression.Expression; import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; -import org.springframework.security.core.annotation.AnnotationSynthesizer; -import org.springframework.security.core.annotation.AnnotationSynthesizers; import org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults; import org.springframework.security.core.annotation.CurrentSecurityContext; +import org.springframework.security.core.annotation.SecurityAnnotationScanner; +import org.springframework.security.core.annotation.SecurityAnnotationScanners; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolderStrategy; @@ -88,7 +88,7 @@ public final class CurrentSecurityContextArgumentResolver implements HandlerMeth private ExpressionParser parser = new SpelExpressionParser(); - private AnnotationSynthesizer synthesizer = AnnotationSynthesizers + private SecurityAnnotationScanner scanner = SecurityAnnotationScanners .requireUnique(CurrentSecurityContext.class); private BeanResolver beanResolver; @@ -144,7 +144,7 @@ public final class CurrentSecurityContextArgumentResolver implements HandlerMeth * @since 6.4 */ public void setTemplateDefaults(AnnotationTemplateExpressionDefaults templateDefaults) { - this.synthesizer = AnnotationSynthesizers.requireUnique(CurrentSecurityContext.class, templateDefaults); + this.scanner = SecurityAnnotationScanners.requireUnique(CurrentSecurityContext.class, templateDefaults); } private Object resolveSecurityContextFromAnnotation(MethodParameter parameter, CurrentSecurityContext annotation, @@ -178,7 +178,7 @@ public final class CurrentSecurityContextArgumentResolver implements HandlerMeth @SuppressWarnings("unchecked") private T findMethodAnnotation(MethodParameter parameter) { return (T) this.cachedAttributes.computeIfAbsent(parameter, - (methodParameter) -> this.synthesizer.synthesize(methodParameter.getParameter())); + (methodParameter) -> this.scanner.scan(methodParameter.getParameter())); } } diff --git a/web/src/main/java/org/springframework/security/web/reactive/result/method/annotation/AuthenticationPrincipalArgumentResolver.java b/web/src/main/java/org/springframework/security/web/reactive/result/method/annotation/AuthenticationPrincipalArgumentResolver.java index f4e99c4f02..1e4cfca6ae 100644 --- a/web/src/main/java/org/springframework/security/web/reactive/result/method/annotation/AuthenticationPrincipalArgumentResolver.java +++ b/web/src/main/java/org/springframework/security/web/reactive/result/method/annotation/AuthenticationPrincipalArgumentResolver.java @@ -32,10 +32,10 @@ import org.springframework.expression.Expression; import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; -import org.springframework.security.core.annotation.AnnotationSynthesizer; -import org.springframework.security.core.annotation.AnnotationSynthesizers; import org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults; import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.core.annotation.SecurityAnnotationScanner; +import org.springframework.security.core.annotation.SecurityAnnotationScanners; import org.springframework.security.core.context.ReactiveSecurityContextHolder; import org.springframework.security.core.context.SecurityContext; import org.springframework.util.ClassUtils; @@ -57,7 +57,7 @@ public class AuthenticationPrincipalArgumentResolver extends HandlerMethodArgume private ExpressionParser parser = new SpelExpressionParser(); - private AnnotationSynthesizer synthesizer = AnnotationSynthesizers + private SecurityAnnotationScanner scanner = SecurityAnnotationScanners .requireUnique(AuthenticationPrincipal.class); private BeanResolver beanResolver; @@ -138,7 +138,7 @@ public class AuthenticationPrincipalArgumentResolver extends HandlerMethodArgume * @since 6.4 */ public void setTemplateDefaults(AnnotationTemplateExpressionDefaults templateDefaults) { - this.synthesizer = AnnotationSynthesizers.requireUnique(AuthenticationPrincipal.class, templateDefaults); + this.scanner = SecurityAnnotationScanners.requireUnique(AuthenticationPrincipal.class, templateDefaults); } /** @@ -150,7 +150,7 @@ public class AuthenticationPrincipalArgumentResolver extends HandlerMethodArgume @SuppressWarnings("unchecked") private T findMethodAnnotation(MethodParameter parameter) { return (T) this.cachedAttributes.computeIfAbsent(parameter, - (methodParameter) -> this.synthesizer.synthesize(methodParameter.getParameter())); + (methodParameter) -> this.scanner.scan(methodParameter.getParameter())); } } diff --git a/web/src/main/java/org/springframework/security/web/reactive/result/method/annotation/CurrentSecurityContextArgumentResolver.java b/web/src/main/java/org/springframework/security/web/reactive/result/method/annotation/CurrentSecurityContextArgumentResolver.java index 432743d2d9..038dcac649 100644 --- a/web/src/main/java/org/springframework/security/web/reactive/result/method/annotation/CurrentSecurityContextArgumentResolver.java +++ b/web/src/main/java/org/springframework/security/web/reactive/result/method/annotation/CurrentSecurityContextArgumentResolver.java @@ -32,10 +32,10 @@ import org.springframework.expression.Expression; import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; -import org.springframework.security.core.annotation.AnnotationSynthesizer; -import org.springframework.security.core.annotation.AnnotationSynthesizers; import org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults; import org.springframework.security.core.annotation.CurrentSecurityContext; +import org.springframework.security.core.annotation.SecurityAnnotationScanner; +import org.springframework.security.core.annotation.SecurityAnnotationScanners; import org.springframework.security.core.context.ReactiveSecurityContextHolder; import org.springframework.security.core.context.SecurityContext; import org.springframework.util.Assert; @@ -57,7 +57,7 @@ public class CurrentSecurityContextArgumentResolver extends HandlerMethodArgumen private ExpressionParser parser = new SpelExpressionParser(); - private AnnotationSynthesizer synthesizer = AnnotationSynthesizers + private SecurityAnnotationScanner scanner = SecurityAnnotationScanners .requireUnique(CurrentSecurityContext.class); private BeanResolver beanResolver; @@ -85,7 +85,7 @@ public class CurrentSecurityContextArgumentResolver extends HandlerMethodArgumen * @since 6.4 */ public void setTemplateDefaults(AnnotationTemplateExpressionDefaults templateDefaults) { - this.synthesizer = AnnotationSynthesizers.requireUnique(CurrentSecurityContext.class, templateDefaults); + this.scanner = SecurityAnnotationScanners.requireUnique(CurrentSecurityContext.class, templateDefaults); } @Override @@ -190,7 +190,7 @@ public class CurrentSecurityContextArgumentResolver extends HandlerMethodArgumen @SuppressWarnings("unchecked") private T findMethodAnnotation(MethodParameter parameter) { return (T) this.cachedAttributes.computeIfAbsent(parameter, - (methodParameter) -> this.synthesizer.synthesize(methodParameter.getParameter())); + (methodParameter) -> this.scanner.scan(methodParameter.getParameter())); } }