Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 93cb016

Browse files
mheathjzheaux
authored andcommitted
Add ExpressionTemplateValueProvider
Closes gh-17447 Signed-off-by: Mike Heath <michael.heath@familysearch.org>
1 parent dfc8be0 commit 93cb016

File tree

3 files changed

+96
-1
lines changed

3 files changed

+96
-1
lines changed

‎core/src/main/java/org/springframework/security/core/annotation/ExpressionTemplateSecurityAnnotationScanner.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,18 @@
5959
* {@code @HasRole} annotation found on a given {@link AnnotatedElement}.
6060
*
6161
* <p>
62+
* Meta-annotations that use enum values can use {@link ExpressionTemplateValueProvider} to
63+
* provide custom placeholder values.
64+
*
65+
* <p>
6266
* Since the process of synthesis is expensive, it is recommended to cache the synthesized
6367
* result to prevent multiple computations.
6468
*
6569
* @param <A> the annotation to search for and synthesize
6670
* @author Josh Cummings
6771
* @author DingHao
68-
* @since 6.4
72+
* @author Mike Heath
73+
* @since 7.0
6974
*/
7075
final class ExpressionTemplateSecurityAnnotationScanner<A extends Annotation>
7176
extends AbstractSecurityAnnotationScanner<A> {
@@ -74,6 +79,7 @@ final class ExpressionTemplateSecurityAnnotationScanner<A extends Annotation>
7479

7580
static {
7681
conversionService.addConverter(new ClassToStringConverter());
82+
conversionService.addConverter(new ExpressionTemplateValueProviderConverter());
7783
}
7884

7985
private final Class<A> type;
@@ -162,4 +168,18 @@ public Set<ConvertiblePair> getConvertibleTypes() {
162168

163169
}
164170

171+
static class ExpressionTemplateValueProviderConverter implements GenericConverter {
172+
173+
@Override
174+
public Set<ConvertiblePair> getConvertibleTypes() {
175+
return Collections.singleton(new ConvertiblePair(ExpressionTemplateValueProvider.class, String.class));
176+
}
177+
178+
@Override
179+
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
180+
return (source != null) ? ((ExpressionTemplateValueProvider)source).getExpressionTemplateValue() : null;
181+
}
182+
183+
}
184+
165185
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package org.springframework.security.core.annotation;
2+
3+
/**
4+
* Provides a mechanism for providing custom values from enum types used in security
5+
* meta-annotation expressions. For example:
6+
*
7+
* <pre>
8+
* enum Permission implements ExpressionTemplateValueProvider {
9+
* READ,
10+
* WRITE;
11+
*
12+
* &#64;Override
13+
* public String getExpressionTemplateValue() {
14+
* return switch (this) {
15+
* case READ -> "user.permission-read";
16+
* case WRITE -> "user.permission-write";
17+
* }
18+
* }
19+
*
20+
* }
21+
* </pre>
22+
*
23+
* @since 6.5
24+
* @author Mike Heath
25+
*/
26+
public interface ExpressionTemplateValueProvider {
27+
28+
/**
29+
* Returns the value to be used in an expression template.
30+
*
31+
* @return the value to be used in an expression template
32+
*/
33+
String getExpressionTemplateValue();
34+
35+
}

‎core/src/test/java/org/springframework/security/core/annotation/ExpressionTemplateSecurityAnnotationScannerTests.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,43 @@ void parseMultipleMetaSourceAnnotationParameterWithAliasFor() throws Exception {
5454
assertThat(preAuthorize.value()).isEqualTo("check(#name)");
5555
}
5656

57+
@Test
58+
void parseMetaSourceAnnotationWithEnumImplementingExpressionTemplateValueProvider() throws Exception {
59+
Method method = MessageService.class.getDeclaredMethod("process");
60+
PreAuthorize preAuthorize = this.scanner.scan(method, method.getDeclaringClass());
61+
assertThat(preAuthorize.value()).isEqualTo("hasAnyAuthority('user.READ','user.WRITE')");
62+
}
63+
64+
enum Permission implements ExpressionTemplateValueProvider {
65+
READ,
66+
WRITE;
67+
68+
@Override
69+
public String getExpressionTemplateValue() {
70+
return switch (this) {
71+
case READ -> "'user.READ'";
72+
case WRITE -> "'user.WRITE'";
73+
};
74+
}
75+
}
76+
77+
@Documented
78+
@Retention(RetentionPolicy.RUNTIME)
79+
@Target({ ElementType.TYPE, ElementType.METHOD })
80+
@PreAuthorize("hasAnyAuthority({permissions})")
81+
@interface HasAnyCustomPermissions {
82+
83+
Permission[] permissions();
84+
85+
}
86+
87+
@Documented
88+
@Retention(RetentionPolicy.RUNTIME)
89+
@Target({ ElementType.TYPE, ElementType.METHOD })
90+
@HasAnyCustomPermissions(permissions = { Permission.READ, Permission.WRITE })
91+
@interface HasAllCustomPermissions {
92+
}
93+
5794
@Documented
5895
@Retention(RetentionPolicy.RUNTIME)
5996
@Target({ ElementType.TYPE, ElementType.METHOD })
@@ -86,6 +123,9 @@ void parseMultipleMetaSourceAnnotationParameterWithAliasFor() throws Exception {
86123

87124
private interface MessageService {
88125

126+
@HasAllCustomPermissions
127+
void process();
128+
89129
@HasReadPermission("#name")
90130
String sayHello(String name);
91131

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /