Improve @CurrentSecurityContext meta-annotations

Closes gh-15551
This commit is contained in:
DingHao
2024-08-11 22:43:52 +08:00
committed by Josh Cummings
parent 079b5b91f2
commit ed16c86115
10 changed files with 332 additions and 63 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* 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.
@@ -27,10 +27,12 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AliasFor;
import org.springframework.expression.BeanResolver;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults;
import org.springframework.security.core.annotation.CurrentSecurityContext;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContext;
@@ -247,6 +249,23 @@ public class CurrentSecurityContextArgumentResolverTests {
.resolveArgument(showCurrentSecurityWithErrorOnInvalidTypeMisMatch(), null, null, null));
}
@Test
public void resolveArgumentCustomMetaAnnotation() {
String principal = "current_authentcation";
setAuthenticationPrincipal(principal);
String p = (String) this.resolver.resolveArgument(showUserCustomMetaAnnotation(), null, null, null);
assertThat(p).isEqualTo(principal);
}
@Test
public void resolveArgumentCustomMetaAnnotationTpl() {
String principal = "current_authentcation";
setAuthenticationPrincipal(principal);
this.resolver.setTemplateDefaults(new AnnotationTemplateExpressionDefaults());
String p = (String) this.resolver.resolveArgument(showUserCustomMetaAnnotationTpl(), null, null, null);
assertThat(p).isEqualTo(principal);
}
private MethodParameter showSecurityContextNoAnnotationTypeMismatch() {
return getMethodParameter("showSecurityContextNoAnnotation", String.class);
}
@@ -307,6 +326,14 @@ public class CurrentSecurityContextArgumentResolverTests {
return getMethodParameter("showCurrentAuthentication", Authentication.class);
}
public MethodParameter showUserCustomMetaAnnotation() {
return getMethodParameter("showUserCustomMetaAnnotation", String.class);
}
public MethodParameter showUserCustomMetaAnnotationTpl() {
return getMethodParameter("showUserCustomMetaAnnotationTpl", String.class);
}
public MethodParameter showCurrentSecurityWithErrorOnInvalidType() {
return getMethodParameter("showCurrentSecurityWithErrorOnInvalidType", SecurityContext.class);
}
@@ -394,6 +421,14 @@ public class CurrentSecurityContextArgumentResolverTests {
public void showCurrentAuthentication(@CurrentAuthentication Authentication authentication) {
}
public void showUserCustomMetaAnnotation(
@AliasedCurrentSecurityContext(expression = "authentication.principal") String name) {
}
public void showUserCustomMetaAnnotationTpl(
@CurrentAuthenticationProperty(property = "principal") String name) {
}
public void showCurrentSecurityWithErrorOnInvalidType(
@CurrentSecurityWithErrorOnInvalidType SecurityContext context) {
}
@@ -447,4 +482,23 @@ public class CurrentSecurityContextArgumentResolverTests {
}
@Target({ ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
@CurrentSecurityContext
@interface AliasedCurrentSecurityContext {
@AliasFor(annotation = CurrentSecurityContext.class)
String expression() default "";
}
@Target({ ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
@CurrentSecurityContext(expression = "authentication.{property}")
@interface CurrentAuthenticationProperty {
String property() default "";
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* 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.
@@ -31,10 +31,12 @@ import reactor.util.context.Context;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.annotation.AliasFor;
import org.springframework.expression.BeanResolver;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults;
import org.springframework.security.core.annotation.CurrentSecurityContext;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.security.core.context.SecurityContext;
@@ -402,6 +404,42 @@ public class CurrentSecurityContextArgumentResolverTests {
ReactiveSecurityContextHolder.clearContext();
}
@Test
public void resolveArgumentCustomMetaAnnotation() {
MethodParameter parameter = ResolvableMethod.on(getClass())
.named("showUserCustomMetaAnnotation")
.build()
.arg(Mono.class, String.class);
Authentication auth = buildAuthenticationWithPrincipal("current_authentication");
Context context = ReactiveSecurityContextHolder.withAuthentication(auth);
Mono<Object> argument = this.resolver.resolveArgument(parameter, this.bindingContext, this.exchange);
String principal = (String) argument.contextWrite(context).cast(Mono.class).block().block();
assertThat(principal).isSameAs(auth.getPrincipal());
ReactiveSecurityContextHolder.clearContext();
}
@Test
public void resolveArgumentCustomMetaAnnotationTpl() {
this.resolver.setTemplateDefaults(new AnnotationTemplateExpressionDefaults());
MethodParameter parameter = ResolvableMethod.on(getClass())
.named("showUserCustomMetaAnnotationTpl")
.build()
.arg(Mono.class, String.class);
Authentication auth = buildAuthenticationWithPrincipal("current_authentication");
Context context = ReactiveSecurityContextHolder.withAuthentication(auth);
Mono<Object> argument = this.resolver.resolveArgument(parameter, this.bindingContext, this.exchange);
String principal = (String) argument.contextWrite(context).cast(Mono.class).block().block();
assertThat(principal).isSameAs(auth.getPrincipal());
ReactiveSecurityContextHolder.clearContext();
}
void showUserCustomMetaAnnotation(
@AliasedCurrentSecurityContext(expression = "authentication.principal") Mono<String> user) {
}
void showUserCustomMetaAnnotationTpl(@CurrentAuthenticationProperty(property = "principal") Mono<String> user) {
}
void securityContext(@CurrentSecurityContext Mono<SecurityContext> monoSecurityContext) {
}
@@ -479,6 +517,25 @@ public class CurrentSecurityContextArgumentResolverTests {
}
@Target({ ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
@CurrentSecurityContext
@interface AliasedCurrentSecurityContext {
@AliasFor(annotation = CurrentSecurityContext.class)
String expression() default "";
}
@Target({ ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
@CurrentSecurityContext(expression = "authentication.{property}")
@interface CurrentAuthenticationProperty {
String property() default "";
}
static class CustomSecurityContext implements SecurityContext {
private Authentication authentication;