Skip to content

Commit 4cbaabb

Browse files
committed
Added Testing
Issue gh-16177
1 parent f565b23 commit 4cbaabb

File tree

6 files changed

+202
-8
lines changed

6 files changed

+202
-8
lines changed

config/src/test/java/org/springframework/security/config/annotation/web/reactive/EnableWebFluxSecurityTests.java

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616

1717
package org.springframework.security.config.annotation.web.reactive;
1818

19+
import java.lang.annotation.ElementType;
20+
import java.lang.annotation.Retention;
21+
import java.lang.annotation.RetentionPolicy;
22+
import java.lang.annotation.Target;
1923
import java.nio.charset.StandardCharsets;
2024

2125
import org.junit.jupiter.api.Test;
@@ -28,6 +32,7 @@
2832
import org.springframework.context.annotation.Configuration;
2933
import org.springframework.context.annotation.Import;
3034
import org.springframework.core.Ordered;
35+
import org.springframework.core.annotation.AliasFor;
3136
import org.springframework.core.annotation.Order;
3237
import org.springframework.core.io.buffer.DataBuffer;
3338
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
@@ -404,11 +409,28 @@ public String username(UserDetails user) {
404409

405410
}
406411

412+
@Target({ ElementType.PARAMETER })
413+
@Retention(RetentionPolicy.RUNTIME)
414+
@AuthenticationPrincipal
415+
@interface Property {
416+
417+
@AliasFor(attribute = "expression", annotation = AuthenticationPrincipal.class)
418+
String value() default "id";
419+
420+
}
421+
422+
interface UsernameResolver {
423+
424+
String username(@Property("@principalBean.username(#this)") String username);
425+
426+
}
427+
407428
@RestController
408-
static class AuthenticationPrincipalResolver {
429+
static class AuthenticationPrincipalResolver implements UsernameResolver {
409430

431+
@Override
410432
@GetMapping("/spel")
411-
String username(@AuthenticationPrincipal(expression = "@principalBean.username(#this)") String username) {
433+
public String username(String username) {
412434
return username;
413435
}
414436

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

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
import org.springframework.core.MethodParameter;
3030
import org.springframework.core.annotation.AliasFor;
31+
import org.springframework.core.annotation.AnnotatedMethod;
3132
import org.springframework.security.authentication.TestingAuthenticationToken;
3233
import org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults;
3334
import org.springframework.security.core.annotation.AuthenticationPrincipal;
@@ -186,10 +187,21 @@ public void resolveArgumentCustomMetaAnnotationTpl() throws Exception {
186187
assertThat(this.resolver.resolveArgument(showUserCustomMetaAnnotationTpl(), null)).isEqualTo(principal.id);
187188
}
188189

190+
@Test
191+
public void resolveArgumentWhenAliasForOnInterfaceThenInherits() {
192+
CustomUserPrincipal principal = new CustomUserPrincipal();
193+
setAuthenticationPrincipal(principal);
194+
assertThat(this.resolver.resolveArgument(showUserNoConcreteAnnotation(), null)).isEqualTo(principal.property);
195+
}
196+
189197
private MethodParameter showUserNoAnnotation() {
190198
return getMethodParameter("showUserNoAnnotation", String.class);
191199
}
192200

201+
private MethodParameter showUserNoConcreteAnnotation() {
202+
return getMethodParameter("showUserNoConcreteAnnotation", String.class);
203+
}
204+
193205
private MethodParameter showUserAnnotationString() {
194206
return getMethodParameter("showUserAnnotation", String.class);
195207
}
@@ -240,7 +252,7 @@ private MethodParameter showUserAnnotationObject() {
240252

241253
private MethodParameter getMethodParameter(String methodName, Class<?>... paramTypes) {
242254
Method method = ReflectionUtils.findMethod(TestController.class, methodName, paramTypes);
243-
return new MethodParameter(method, 0);
255+
return new AnnotatedMethod(method).getMethodParameters()[0];
244256
}
245257

246258
private void setAuthenticationPrincipal(Object principal) {
@@ -280,11 +292,32 @@ private void setAuthenticationPrincipal(Object principal) {
280292

281293
}
282294

283-
public static class TestController {
295+
@Target({ ElementType.PARAMETER })
296+
@Retention(RetentionPolicy.RUNTIME)
297+
@AuthenticationPrincipal
298+
@interface Property {
299+
300+
@AliasFor(attribute = "expression", annotation = AuthenticationPrincipal.class)
301+
String value() default "id";
302+
303+
}
304+
305+
private interface TestInterface {
306+
307+
void showUserNoConcreteAnnotation(@Property("property") String property);
308+
309+
}
310+
311+
public static class TestController implements TestInterface {
284312

285313
public void showUserNoAnnotation(String user) {
286314
}
287315

316+
@Override
317+
public void showUserNoConcreteAnnotation(String user) {
318+
319+
}
320+
288321
public void showUserAnnotation(@AuthenticationPrincipal String user) {
289322
}
290323

messaging/src/test/java/org/springframework/security/messaging/handler/invocation/reactive/AuthenticationPrincipalArgumentResolverTests.java

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

1717
package org.springframework.security.messaging.handler.invocation.reactive;
1818

19+
import java.lang.annotation.ElementType;
1920
import java.lang.annotation.Retention;
2021
import java.lang.annotation.RetentionPolicy;
22+
import java.lang.annotation.Target;
2123

2224
import org.junit.jupiter.api.Test;
2325
import reactor.core.publisher.Mono;
2426

2527
import org.springframework.core.MethodParameter;
2628
import org.springframework.core.annotation.AliasFor;
29+
import org.springframework.core.annotation.AnnotatedMethod;
2730
import org.springframework.core.annotation.SynthesizingMethodParameter;
2831
import org.springframework.security.authentication.TestAuthentication;
2932
import org.springframework.security.authentication.TestingAuthenticationToken;
@@ -128,6 +131,19 @@ public void supportsParameterWhenNotAnnotatedThenFalse() {
128131
assertThat(this.resolver.supportsParameter(arg0("monoUserDetails"))).isFalse();
129132
}
130133

134+
@Test
135+
public void resolveArgumentWhenAliasForOnInterfaceThenInherits() {
136+
CustomUserPrincipal principal = new CustomUserPrincipal();
137+
Authentication authentication = new TestingAuthenticationToken(principal, "password", "ROLE_USER");
138+
ResolvableMethod method = ResolvableMethod.on(TestController.class)
139+
.named("showUserNoConcreteAnnotation")
140+
.method();
141+
MethodParameter parameter = new AnnotatedMethod(method.method()).getMethodParameters()[0];
142+
Mono<Object> result = this.resolver.resolveArgument(parameter, null)
143+
.contextWrite(ReactiveSecurityContextHolder.withAuthentication(authentication));
144+
assertThat(result.block()).isEqualTo(principal.property);
145+
}
146+
131147
@SuppressWarnings("unused")
132148
private void monoUserDetails(Mono<UserDetails> user) {
133149
}
@@ -172,6 +188,8 @@ static class CustomUserPrincipal {
172188

173189
public final int id = 1;
174190

191+
public final String property = "property";
192+
175193
public Object getPrincipal() {
176194
return this;
177195
}
@@ -195,4 +213,29 @@ public Object getPrincipal() {
195213

196214
}
197215

216+
@Target({ ElementType.PARAMETER })
217+
@Retention(RetentionPolicy.RUNTIME)
218+
@AuthenticationPrincipal
219+
@interface Property {
220+
221+
@AliasFor(attribute = "expression", annotation = AuthenticationPrincipal.class)
222+
String value() default "id";
223+
224+
}
225+
226+
private interface TestInterface {
227+
228+
void showUserNoConcreteAnnotation(@Property("property") String property);
229+
230+
}
231+
232+
private static class TestController implements TestInterface {
233+
234+
@Override
235+
public void showUserNoConcreteAnnotation(String user) {
236+
237+
}
238+
239+
}
240+
198241
}

web/src/main/java/org/springframework/security/web/method/annotation/AuthenticationPrincipalArgumentResolver.java

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import java.lang.annotation.Annotation;
2020

2121
import org.springframework.core.MethodParameter;
22+
import org.springframework.core.annotation.AnnotationUtils;
23+
import org.springframework.core.annotation.MergedAnnotations;
2224
import org.springframework.expression.BeanResolver;
2325
import org.springframework.expression.Expression;
2426
import org.springframework.expression.ExpressionParser;
@@ -93,6 +95,8 @@
9395
*/
9496
public final class AuthenticationPrincipalArgumentResolver implements HandlerMethodArgumentResolver {
9597

98+
private final Class<AuthenticationPrincipal> annotationType = AuthenticationPrincipal.class;
99+
96100
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
97101
.getContextHolderStrategy();
98102

@@ -101,6 +105,8 @@ public final class AuthenticationPrincipalArgumentResolver implements HandlerMet
101105
private SecurityAnnotationScanner<AuthenticationPrincipal> scanner = SecurityAnnotationScanners
102106
.requireUnique(AuthenticationPrincipal.class);
103107

108+
private boolean useAnnotationTemplate = false;
109+
104110
private BeanResolver beanResolver;
105111

106112
@Override
@@ -165,6 +171,7 @@ public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy secur
165171
*/
166172
public void setTemplateDefaults(AnnotationTemplateExpressionDefaults templateDefaults) {
167173
this.scanner = SecurityAnnotationScanners.requireUnique(AuthenticationPrincipal.class, templateDefaults);
174+
this.useAnnotationTemplate = templateDefaults != null;
168175
}
169176

170177
/**
@@ -174,8 +181,22 @@ public void setTemplateDefaults(AnnotationTemplateExpressionDefaults templateDef
174181
* @return the {@link Annotation} that was found or null.
175182
*/
176183
@SuppressWarnings("unchecked")
177-
private <T extends Annotation> T findMethodAnnotation(MethodParameter parameter) {
178-
return (T) this.scanner.scan(parameter.getParameter());
184+
private AuthenticationPrincipal findMethodAnnotation(MethodParameter parameter) {
185+
if (this.useAnnotationTemplate) {
186+
return this.scanner.scan(parameter.getParameter());
187+
}
188+
AuthenticationPrincipal annotation = parameter.getParameterAnnotation(this.annotationType);
189+
if (annotation != null) {
190+
return annotation;
191+
}
192+
Annotation[] annotationsToSearch = parameter.getParameterAnnotations();
193+
for (Annotation toSearch : annotationsToSearch) {
194+
annotation = AnnotationUtils.findAnnotation(toSearch.annotationType(), this.annotationType);
195+
if (annotation != null) {
196+
return MergedAnnotations.from(toSearch).get(this.annotationType).synthesize();
197+
}
198+
}
199+
return null;
179200
}
180201

181202
}

web/src/test/java/org/springframework/security/web/method/annotation/AuthenticationPrincipalArgumentResolverTests.java

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
import org.springframework.core.MethodParameter;
3030
import org.springframework.core.annotation.AliasFor;
31+
import org.springframework.core.annotation.AnnotatedMethod;
3132
import org.springframework.expression.BeanResolver;
3233
import org.springframework.security.authentication.TestingAuthenticationToken;
3334
import org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults;
@@ -214,10 +215,22 @@ public void resolveArgumentCustomMetaAnnotationTpl() throws Exception {
214215
.isEqualTo(this.expectedPrincipal);
215216
}
216217

218+
@Test
219+
public void resolveArgumentWhenAliasForOnInterfaceThenInherits() throws Exception {
220+
CustomUserPrincipal principal = new CustomUserPrincipal();
221+
setAuthenticationPrincipal(principal);
222+
assertThat(this.resolver.resolveArgument(showUserNoConcreteAnnotation(), null, null, null))
223+
.isEqualTo(principal.property);
224+
}
225+
217226
private MethodParameter showUserNoAnnotation() {
218227
return getMethodParameter("showUserNoAnnotation", String.class);
219228
}
220229

230+
private MethodParameter showUserNoConcreteAnnotation() {
231+
return getMethodParameter("showUserNoConcreteAnnotation", String.class);
232+
}
233+
221234
private MethodParameter showUserAnnotationString() {
222235
return getMethodParameter("showUserAnnotation", String.class);
223236
}
@@ -272,7 +285,7 @@ private MethodParameter showUserCustomMetaAnnotationTpl() {
272285

273286
private MethodParameter getMethodParameter(String methodName, Class<?>... paramTypes) {
274287
Method method = ReflectionUtils.findMethod(TestController.class, methodName, paramTypes);
275-
return new MethodParameter(method, 0);
288+
return new AnnotatedMethod(method).getMethodParameters()[0];
276289
}
277290

278291
private void setAuthenticationPrincipal(Object principal) {
@@ -295,6 +308,16 @@ private void setAuthenticationPrincipal(Object principal) {
295308

296309
}
297310

311+
@Target({ ElementType.PARAMETER })
312+
@Retention(RetentionPolicy.RUNTIME)
313+
@AuthenticationPrincipal
314+
@interface Property {
315+
316+
@AliasFor(attribute = "expression", annotation = AuthenticationPrincipal.class)
317+
String value() default "id";
318+
319+
}
320+
298321
@Retention(RetentionPolicy.RUNTIME)
299322
@AuthenticationPrincipal
300323
public @interface CurrentUser2 {
@@ -312,11 +335,22 @@ private void setAuthenticationPrincipal(Object principal) {
312335

313336
}
314337

315-
public static class TestController {
338+
public interface TestInterface {
339+
340+
void showUserNoConcreteAnnotation(@Property("property") String property);
341+
342+
}
343+
344+
public static class TestController implements TestInterface {
316345

317346
public void showUserNoAnnotation(String user) {
318347
}
319348

349+
@Override
350+
public void showUserNoConcreteAnnotation(String user) {
351+
352+
}
353+
320354
public void showUserAnnotation(@AuthenticationPrincipal String user) {
321355
}
322356

0 commit comments

Comments
 (0)