Skip to content

Commit e901a92

Browse files
committed
Add ignoreUnconverted property for AnnotationTemplateExpressionDefaults
1 parent f0f47b5 commit e901a92

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/ExpressionTemplateSecurityAnnotationScanner.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;
@@ -117,23 +118,33 @@ private MergedAnnotation<A> resolvePlaceholders(MergedAnnotation<A> mergedAnnota
117118
Map<String, Object> metaAnnotationProperties = mergedAnnotation.getMetaSource().asMap();
118119
Map<String, String> stringProperties = new HashMap<>();
119120
for (Map.Entry<String, Object> property : metaAnnotationProperties.entrySet()) {
120-
String key = property.getKey();
121-
Object value = property.getValue();
122-
String asString = (value instanceof String) ? (String) value
123-
: DefaultConversionService.getSharedInstance().convert(value, String.class);
124-
stringProperties.put(key, asString);
121+
stringProperties.put(property.getKey(), convertValue(property.getValue()));
125122
}
126123
Map<String, Object> annotationProperties = mergedAnnotation.asMap();
127124
for (Map.Entry<String, Object> annotationProperty : annotationProperties.entrySet()) {
128-
if (!(annotationProperty.getValue() instanceof String)) {
125+
if (!(annotationProperty.getValue() instanceof String expression)) {
129126
continue;
130127
}
131-
String expression = (String) annotationProperty.getValue();
132128
String value = helper.replacePlaceholders(expression, stringProperties::get);
133129
properties.put(annotationProperty.getKey(), value);
134130
}
135131
AnnotatedElement annotatedElement = (AnnotatedElement) mergedAnnotation.getSource();
136132
return MergedAnnotation.of(annotatedElement, this.type, properties);
137133
}
138134

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

0 commit comments

Comments
 (0)