Skip to content

Commit 6f8cf72

Browse files
committed
Update Argument Resolver to Use AnnotationSynthesizer
Issue gh-15286
1 parent e5d360f commit 6f8cf72

File tree

3 files changed

+16
-117
lines changed

3 files changed

+16
-117
lines changed

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

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

messaging/src/main/java/org/springframework/security/messaging/context/AuthenticationPrincipalArgumentResolver.java

Lines changed: 13 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -17,33 +17,26 @@
1717
package org.springframework.security.messaging.context;
1818

1919
import java.lang.annotation.Annotation;
20-
import java.lang.reflect.AnnotatedElement;
21-
import java.util.HashMap;
2220
import java.util.Map;
2321
import java.util.concurrent.ConcurrentHashMap;
24-
import java.util.function.Function;
2522

2623
import org.springframework.core.MethodParameter;
27-
import org.springframework.core.annotation.MergedAnnotation;
28-
import org.springframework.core.annotation.MergedAnnotations;
29-
import org.springframework.core.annotation.RepeatableContainers;
30-
import org.springframework.core.convert.support.DefaultConversionService;
3124
import org.springframework.expression.Expression;
3225
import org.springframework.expression.ExpressionParser;
3326
import org.springframework.expression.spel.standard.SpelExpressionParser;
3427
import org.springframework.expression.spel.support.StandardEvaluationContext;
35-
import org.springframework.lang.NonNull;
3628
import org.springframework.messaging.Message;
3729
import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
38-
import org.springframework.security.authorization.method.AuthenticationPrincipalTemplateDefaults;
3930
import org.springframework.security.core.Authentication;
31+
import org.springframework.security.core.annotation.AnnotationSynthesizer;
32+
import org.springframework.security.core.annotation.AnnotationSynthesizers;
33+
import org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults;
4034
import org.springframework.security.core.annotation.AuthenticationPrincipal;
4135
import org.springframework.security.core.context.SecurityContextHolder;
4236
import org.springframework.security.core.context.SecurityContextHolderStrategy;
4337
import org.springframework.stereotype.Controller;
4438
import org.springframework.util.Assert;
4539
import org.springframework.util.ClassUtils;
46-
import org.springframework.util.PropertyPlaceholderHelper;
4740
import org.springframework.util.StringUtils;
4841

4942
/**
@@ -106,11 +99,12 @@ public final class AuthenticationPrincipalArgumentResolver implements HandlerMet
10699

107100
private ExpressionParser parser = new SpelExpressionParser();
108101

109-
private AuthenticationPrincipalTemplateDefaults principalTemplateDefaults = new AuthenticationPrincipalTemplateDefaults();
102+
private AnnotationSynthesizer<AuthenticationPrincipal> synthesizer = AnnotationSynthesizers
103+
.requireUnique(AuthenticationPrincipal.class);
110104

111105
@Override
112106
public boolean supportsParameter(MethodParameter parameter) {
113-
return findMethodAnnotation(AuthenticationPrincipal.class, parameter) != null;
107+
return findMethodAnnotation(parameter) != null;
114108
}
115109

116110
@Override
@@ -120,7 +114,7 @@ public Object resolveArgument(MethodParameter parameter, Message<?> message) {
120114
return null;
121115
}
122116
Object principal = authentication.getPrincipal();
123-
AuthenticationPrincipal authPrincipal = findMethodAnnotation(AuthenticationPrincipal.class, parameter);
117+
AuthenticationPrincipal authPrincipal = findMethodAnnotation(parameter);
124118
String expressionToParse = authPrincipal.expression();
125119
if (StringUtils.hasLength(expressionToParse)) {
126120
StandardEvaluationContext context = new StandardEvaluationContext();
@@ -154,69 +148,24 @@ public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy secur
154148
* <p>
155149
* By default, this value is <code>null</code>, which indicates that templates should
156150
* not be resolved.
157-
* @param principalTemplateDefaults - whether to resolve AuthenticationPrincipal
158-
* templates parameters
151+
* @param templateDefaults - whether to resolve AuthenticationPrincipal templates
152+
* parameters
159153
* @since 6.4
160154
*/
161-
public void setTemplateDefaults(@NonNull AuthenticationPrincipalTemplateDefaults principalTemplateDefaults) {
162-
Assert.notNull(principalTemplateDefaults, "principalTemplateDefaults cannot be null");
163-
this.principalTemplateDefaults = principalTemplateDefaults;
155+
public void setTemplateDefaults(AnnotationTemplateExpressionDefaults templateDefaults) {
156+
this.synthesizer = AnnotationSynthesizers.requireUnique(AuthenticationPrincipal.class, templateDefaults);
164157
}
165158

166159
/**
167160
* Obtains the specified {@link Annotation} on the specified {@link MethodParameter}.
168-
* @param annotationClass the class of the {@link Annotation} to find on the
169161
* {@link MethodParameter}
170162
* @param parameter the {@link MethodParameter} to search for an {@link Annotation}
171163
* @return the {@link Annotation} that was found or null.
172164
*/
173165
@SuppressWarnings("unchecked")
174-
private <T extends Annotation> T findMethodAnnotation(Class<T> annotationClass, MethodParameter parameter) {
166+
private <T extends Annotation> T findMethodAnnotation(MethodParameter parameter) {
175167
return (T) this.cachedAttributes.computeIfAbsent(parameter,
176-
(methodParameter) -> findMethodAnnotation(annotationClass, methodParameter,
177-
this.principalTemplateDefaults));
178-
}
179-
180-
private static <T extends Annotation> T findMethodAnnotation(Class<T> annotationClass, MethodParameter parameter,
181-
AuthenticationPrincipalTemplateDefaults principalTemplateDefaults) {
182-
T annotation = parameter.getParameterAnnotation(annotationClass);
183-
if (annotation != null) {
184-
return annotation;
185-
}
186-
return MergedAnnotations
187-
.from(parameter.getParameter(), MergedAnnotations.SearchStrategy.TYPE_HIERARCHY,
188-
RepeatableContainers.none())
189-
.stream(annotationClass)
190-
.map(mapper(annotationClass, principalTemplateDefaults.isIgnoreUnknown(), "expression"))
191-
.findFirst()
192-
.orElse(null);
193-
}
194-
195-
private static <T extends Annotation> Function<MergedAnnotation<T>, T> mapper(Class<T> annotationClass,
196-
boolean ignoreUnresolvablePlaceholders, String... attrs) {
197-
return (mergedAnnotation) -> {
198-
MergedAnnotation<?> metaSource = mergedAnnotation.getMetaSource();
199-
if (metaSource == null) {
200-
return mergedAnnotation.synthesize();
201-
}
202-
PropertyPlaceholderHelper helper = new PropertyPlaceholderHelper("{", "}", null, null,
203-
ignoreUnresolvablePlaceholders);
204-
Map<String, String> stringProperties = new HashMap<>();
205-
for (Map.Entry<String, Object> property : metaSource.asMap().entrySet()) {
206-
String key = property.getKey();
207-
Object value = property.getValue();
208-
String asString = (value instanceof String) ? (String) value
209-
: DefaultConversionService.getSharedInstance().convert(value, String.class);
210-
stringProperties.put(key, asString);
211-
}
212-
Map<String, Object> attrMap = mergedAnnotation.asMap();
213-
Map<String, Object> properties = new HashMap<>(attrMap);
214-
for (String attr : attrs) {
215-
properties.put(attr, helper.replacePlaceholders((String) attrMap.get(attr), stringProperties::get));
216-
}
217-
return MergedAnnotation.of((AnnotatedElement) mergedAnnotation.getSource(), annotationClass, properties)
218-
.synthesize();
219-
};
168+
(methodParameter) -> this.synthesizer.synthesize(methodParameter.getParameter()));
220169
}
221170

222171
}

messaging/src/test/java/org/springframework/security/messaging/context/AuthenticationPrincipalArgumentResolverTests.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.springframework.core.MethodParameter;
3030
import org.springframework.core.annotation.AliasFor;
3131
import org.springframework.security.authentication.TestingAuthenticationToken;
32+
import org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults;
3233
import org.springframework.security.core.annotation.AuthenticationPrincipal;
3334
import org.springframework.security.core.authority.AuthorityUtils;
3435
import org.springframework.security.core.context.SecurityContextHolder;
@@ -180,6 +181,7 @@ public void resolveArgumentCustomMetaAnnotation() throws Exception {
180181
public void resolveArgumentCustomMetaAnnotationTpl() throws Exception {
181182
CustomUserPrincipal principal = new CustomUserPrincipal();
182183
setAuthenticationPrincipal(principal);
184+
this.resolver.setTemplateDefaults(new AnnotationTemplateExpressionDefaults());
183185
this.expectedPrincipal = principal.id;
184186
assertThat(this.resolver.resolveArgument(showUserCustomMetaAnnotationTpl(), null)).isEqualTo(principal.id);
185187
}
@@ -302,7 +304,7 @@ public void showUserAnnotation(@AuthenticationPrincipal CustomUserPrincipal user
302304
public void showUserCustomAnnotation(@CurrentUser CustomUserPrincipal user) {
303305
}
304306

305-
public void showUserCustomMetaAnnotation(@CurrentUser2(expression = "id") int userId) {
307+
public void showUserCustomMetaAnnotation(@CurrentUser2(expression = "principal.id") int userId) {
306308
}
307309

308310
public void showUserCustomMetaAnnotationTpl(@CurrentUser3(property = "id") int userId) {

0 commit comments

Comments
 (0)