Skip to content

Commit 23144f9

Browse files
committed
Add ignoreUnconverted property for AnnotationTemplateExpressionDefaults
1 parent 095929f commit 23144f9

File tree

3 files changed

+76
-7
lines changed

3 files changed

+76
-7
lines changed

config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfigurationTests.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
import org.springframework.context.annotation.Import;
5151
import org.springframework.context.annotation.Role;
5252
import org.springframework.core.annotation.AnnotationConfigurationException;
53+
import org.springframework.core.convert.ConversionException;
5354
import org.springframework.security.access.AccessDeniedException;
5455
import org.springframework.security.access.PermissionEvaluator;
5556
import org.springframework.security.access.annotation.BusinessService;
@@ -693,6 +694,17 @@ public void methodWhenPostFilterMetaAnnotationThenFilters(Class<?> config) {
693694
.containsExactly("dave");
694695
}
695696

697+
@Test
698+
@WithMockUser(roles = "uid")
699+
public void methodWhenMetaAnnotationPropertiesConversionFailed() {
700+
this.spring.register(MetaAnnotationPlaceholderConfig.class).autowire();
701+
AnnotationTemplateExpressionDefaults bean = this.spring.getContext()
702+
.getBean(AnnotationTemplateExpressionDefaults.class);
703+
bean.setIgnoreUnconverted(false);
704+
MetaAnnotationService service = this.spring.getContext().getBean(MetaAnnotationService.class);
705+
assertThatExceptionOfType(ConversionException.class).isThrownBy(() -> service.getIdPath("uid"));
706+
}
707+
696708
@Test
697709
@WithMockUser(authorities = "airplane:read")
698710
public void findByIdWhenAuthorizedResultThenAuthorizes() {
@@ -1403,6 +1415,27 @@ List<String> resultsContainDave(List<String> list) {
14031415
return list;
14041416
}
14051417

1418+
@RestrictedAccess(entityClass = EntityClass.class)
1419+
String getIdPath(String id) {
1420+
return id;
1421+
}
1422+
1423+
}
1424+
1425+
@Retention(RetentionPolicy.RUNTIME)
1426+
@PreAuthorize("hasRole({idPath})")
1427+
@interface RestrictedAccess {
1428+
1429+
String idPath() default "#id";
1430+
1431+
Class<?> entityClass();
1432+
1433+
String[] recipes() default {};
1434+
1435+
}
1436+
1437+
static class EntityClass {
1438+
14061439
}
14071440

14081441
@Retention(RetentionPolicy.RUNTIME)

core/src/main/java/org/springframework/security/core/annotation/AnnotationTemplateExpressionDefaults.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ public class AnnotationTemplateExpressionDefaults {
2929

3030
private boolean ignoreUnknown = true;
3131

32+
private boolean ignoreUnconverted = true;
33+
3234
/**
3335
* Whether template resolution should ignore placeholders it doesn't recognize.
3436
* <p>
@@ -50,4 +52,27 @@ public void setIgnoreUnknown(boolean ignoreUnknown) {
5052
this.ignoreUnknown = ignoreUnknown;
5153
}
5254

55+
/**
56+
* Whether metaAnnotationProperties conversion should ignore property it can't
57+
* convert.
58+
* <p>
59+
* By default, this value is <code>true</code>.
60+
*/
61+
public boolean isIgnoreUnconverted() {
62+
return this.ignoreUnconverted;
63+
}
64+
65+
/**
66+
* Configure metaAnnotationProperties conversion to ignore property it can't convert.
67+
* When set to <code>false</code>, metaAnnotationProperties conversion will throw an
68+
* exception for property it can't convert.
69+
* <p>
70+
* By default, this value is <code>true</code>.
71+
* @param ignoreUnconverted - whether to ignore metaAnnotationProperties it can't
72+
* convert
73+
*/
74+
public void setIgnoreUnconverted(boolean ignoreUnconverted) {
75+
this.ignoreUnconverted = ignoreUnconverted;
76+
}
77+
5378
}

core/src/main/java/org/springframework/security/core/annotation/ExpressionTemplateAnnotationSynthesizer.java

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
import org.springframework.core.MethodClassKey;
2727
import org.springframework.core.annotation.MergedAnnotation;
28+
import org.springframework.core.convert.ConversionException;
2829
import org.springframework.core.convert.support.DefaultConversionService;
2930
import org.springframework.util.Assert;
3031
import org.springframework.util.PropertyPlaceholderHelper;
@@ -113,23 +114,33 @@ private MergedAnnotation<A> resolvePlaceholders(MergedAnnotation<A> mergedAnnota
113114
Map<String, Object> metaAnnotationProperties = mergedAnnotation.getMetaSource().asMap();
114115
Map<String, String> stringProperties = new HashMap<>();
115116
for (Map.Entry<String, Object> property : metaAnnotationProperties.entrySet()) {
116-
String key = property.getKey();
117-
Object value = property.getValue();
118-
String asString = (value instanceof String) ? (String) value
119-
: DefaultConversionService.getSharedInstance().convert(value, String.class);
120-
stringProperties.put(key, asString);
117+
stringProperties.put(property.getKey(), convertValue(property.getValue()));
121118
}
122119
Map<String, Object> annotationProperties = mergedAnnotation.asMap();
123120
for (Map.Entry<String, Object> annotationProperty : annotationProperties.entrySet()) {
124-
if (!(annotationProperty.getValue() instanceof String)) {
121+
if (!(annotationProperty.getValue() instanceof String expression)) {
125122
continue;
126123
}
127-
String expression = (String) annotationProperty.getValue();
128124
String value = helper.replacePlaceholders(expression, stringProperties::get);
129125
properties.put(annotationProperty.getKey(), value);
130126
}
131127
AnnotatedElement annotatedElement = (AnnotatedElement) mergedAnnotation.getSource();
132128
return MergedAnnotation.of(annotatedElement, this.type, properties);
133129
}
134130

131+
private String convertValue(Object value) {
132+
if (value instanceof String stringValue) {
133+
return stringValue;
134+
}
135+
try {
136+
return DefaultConversionService.getSharedInstance().convert(value, String.class);
137+
}
138+
catch (ConversionException ex) {
139+
if (this.templateDefaults.isIgnoreUnconverted()) {
140+
return value.toString();
141+
}
142+
throw ex;
143+
}
144+
}
145+
135146
}

0 commit comments

Comments
 (0)