Skip to content

Commit 3336a6e

Browse files
committed
Use AuthorizationAnnotationPropertyConversionService
1 parent ff41521 commit 3336a6e

File tree

3 files changed

+119
-2
lines changed

3 files changed

+119
-2
lines changed

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -998,6 +998,14 @@ public void adviseWhenPrePostEnabledThenEachInterceptorRunsExactlyOnce() {
998998
verify(expressionHandler, times(4)).createEvaluationContext(any(Supplier.class), any());
999999
}
10001000

1001+
@Test
1002+
@WithMockUser(roles = "uid")
1003+
public void methodWhenMetaAnnotationPropertiesHasClassProperties() {
1004+
this.spring.register(MetaAnnotationPlaceholderConfig.class).autowire();
1005+
MetaAnnotationService service = this.spring.getContext().getBean(MetaAnnotationService.class);
1006+
assertThat(service.getIdPath("uid")).isEqualTo("uid");
1007+
}
1008+
10011009
private static Consumer<ConfigurableWebApplicationContext> disallowBeanOverriding() {
10021010
return (context) -> ((AnnotationConfigWebApplicationContext) context).setAllowBeanDefinitionOverriding(false);
10031011
}
@@ -1376,6 +1384,23 @@ List<String> resultsContainDave(List<String> list) {
13761384
return list;
13771385
}
13781386

1387+
@RestrictedAccess(entityClass = EntityClass.class)
1388+
String getIdPath(String id) {
1389+
return id;
1390+
}
1391+
1392+
}
1393+
1394+
@Retention(RetentionPolicy.RUNTIME)
1395+
@PreAuthorize("hasRole({idPath})")
1396+
@interface RestrictedAccess {
1397+
1398+
String idPath() default "#id";
1399+
1400+
Class<?> entityClass();
1401+
1402+
String[] recipes() default {};
1403+
13791404
}
13801405

13811406
@Retention(RetentionPolicy.RUNTIME)
@@ -1386,6 +1411,10 @@ List<String> resultsContainDave(List<String> list) {
13861411

13871412
}
13881413

1414+
static class EntityClass {
1415+
1416+
}
1417+
13891418
@Retention(RetentionPolicy.RUNTIME)
13901419
@PreAuthorize("hasAuthority('SCOPE_{claim}') || hasAnyRole({roles})")
13911420
@interface HasClaim {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Copyright 2002-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.security.authorization.method;
18+
19+
import java.util.Collections;
20+
import java.util.Set;
21+
22+
import org.springframework.core.convert.ConversionService;
23+
import org.springframework.core.convert.TypeDescriptor;
24+
import org.springframework.core.convert.converter.ConverterRegistry;
25+
import org.springframework.core.convert.converter.GenericConverter;
26+
import org.springframework.core.convert.support.DefaultConversionService;
27+
import org.springframework.core.convert.support.GenericConversionService;
28+
29+
/**
30+
* A {@link ConversionService} configured with converters that provide class to string
31+
* conversion
32+
*
33+
* @author DingHao
34+
* @since 6.3
35+
*/
36+
public final class AuthorizationAnnotationPropertyConversionService extends GenericConversionService {
37+
38+
private static volatile AuthorizationAnnotationPropertyConversionService sharedInstance;
39+
40+
private AuthorizationAnnotationPropertyConversionService() {
41+
addConverters(this);
42+
}
43+
44+
/**
45+
* Returns a shared instance of
46+
* {@code AuthorizationAnnotationPropertyConversionService}.
47+
* @return a shared instance of
48+
* {@code AuthorizationAnnotationPropertyConversionService}
49+
*/
50+
public static AuthorizationAnnotationPropertyConversionService getSharedInstance() {
51+
AuthorizationAnnotationPropertyConversionService cs = sharedInstance;
52+
if (cs == null) {
53+
synchronized (AuthorizationAnnotationPropertyConversionService.class) {
54+
cs = sharedInstance;
55+
if (cs == null) {
56+
cs = new AuthorizationAnnotationPropertyConversionService();
57+
sharedInstance = cs;
58+
}
59+
}
60+
}
61+
return cs;
62+
}
63+
64+
/**
65+
* Adds the converters that provide type conversion for
66+
* AuthorizationAnnotationProperty values to the provided {@link ConverterRegistry}.
67+
* @param converterRegistry the registry of converters to add to
68+
*/
69+
public static void addConverters(ConverterRegistry converterRegistry) {
70+
DefaultConversionService.addDefaultConverters(converterRegistry);
71+
converterRegistry.addConverter(new ClassToStringConverter());
72+
}
73+
74+
static class ClassToStringConverter implements GenericConverter {
75+
76+
@Override
77+
public Set<ConvertiblePair> getConvertibleTypes() {
78+
return Collections.singleton(new ConvertiblePair(Class.class, String.class));
79+
}
80+
81+
@Override
82+
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
83+
return (source != null) ? source.toString() : null;
84+
}
85+
86+
}
87+
88+
}

core/src/main/java/org/springframework/security/authorization/method/AuthorizationAnnotationUtils.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
import org.springframework.core.annotation.MergedAnnotations;
3030
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
3131
import org.springframework.core.annotation.RepeatableContainers;
32-
import org.springframework.core.convert.support.DefaultConversionService;
3332
import org.springframework.util.PropertyPlaceholderHelper;
3433

3534
/**
@@ -70,7 +69,8 @@ static <A extends Annotation> Function<AnnotatedElement, A> withDefaults(Class<A
7069
String key = property.getKey();
7170
Object value = property.getValue();
7271
String asString = (value instanceof String) ? (String) value
73-
: DefaultConversionService.getSharedInstance().convert(value, String.class);
72+
: AuthorizationAnnotationPropertyConversionService.getSharedInstance()
73+
.convert(value, String.class);
7474
stringProperties.put(key, asString);
7575
}
7676
AnnotatedElement annotatedElement = (AnnotatedElement) mergedAnnotation.getSource();

0 commit comments

Comments
 (0)