Skip to content

Commit b76f7c0

Browse files
kandaguru17jzheaux
authored andcommitted
Use available RoleHierachy Bean for MethodSecurity Config
Closes gh-12783
1 parent bb6b55a commit b76f7c0

File tree

6 files changed

+66
-3
lines changed

6 files changed

+66
-3
lines changed

config/src/main/java/org/springframework/security/config/annotation/method/configuration/Jsr250MethodSecurityConfiguration.java

+10-1
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,13 @@
2222

2323
import org.springframework.beans.factory.ObjectProvider;
2424
import org.springframework.beans.factory.config.BeanDefinition;
25+
import org.springframework.context.ApplicationContext;
2526
import org.springframework.context.annotation.Bean;
2627
import org.springframework.context.annotation.Configuration;
2728
import org.springframework.context.annotation.Role;
29+
import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
30+
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
31+
import org.springframework.security.authorization.AuthoritiesAuthorizationManager;
2832
import org.springframework.security.authorization.AuthorizationManager;
2933
import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor;
3034
import org.springframework.security.authorization.method.Jsr250AuthorizationManager;
@@ -49,8 +53,13 @@ final class Jsr250MethodSecurityConfiguration {
4953
static MethodInterceptor jsr250AuthorizationMethodInterceptor(
5054
ObjectProvider<GrantedAuthorityDefaults> defaultsProvider,
5155
ObjectProvider<SecurityContextHolderStrategy> strategyProvider,
52-
ObjectProvider<ObservationRegistry> registryProvider) {
56+
ObjectProvider<ObservationRegistry> registryProvider, ApplicationContext context) {
5357
Jsr250AuthorizationManager jsr250 = new Jsr250AuthorizationManager();
58+
AuthoritiesAuthorizationManager authoritiesAuthorizationManager = new AuthoritiesAuthorizationManager();
59+
RoleHierarchy roleHierarchy = (context.getBeanNamesForType(RoleHierarchy.class).length > 0)
60+
? context.getBean(RoleHierarchy.class) : new NullRoleHierarchy();
61+
authoritiesAuthorizationManager.setRoleHierarchy(roleHierarchy);
62+
jsr250.setAuthoritiesAuthorizationManager(authoritiesAuthorizationManager);
5463
defaultsProvider.ifAvailable((d) -> jsr250.setRolePrefix(d.getRolePrefix()));
5564
SecurityContextHolderStrategy strategy = strategyProvider
5665
.getIfAvailable(SecurityContextHolder::getContextHolderStrategy);

config/src/main/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfiguration.java

+5
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
import org.springframework.expression.ExpressionParser;
3434
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
3535
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
36+
import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
37+
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
3638
import org.springframework.security.authorization.AuthorizationEventPublisher;
3739
import org.springframework.security.authorization.AuthorizationManager;
3840
import org.springframework.security.authorization.method.AuthorizationManagerAfterMethodInterceptor;
@@ -123,6 +125,9 @@ static MethodInterceptor postFilterAuthorizationMethodInterceptor(
123125
private static MethodSecurityExpressionHandler defaultExpressionHandler(
124126
ObjectProvider<GrantedAuthorityDefaults> defaultsProvider, ApplicationContext context) {
125127
DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler();
128+
RoleHierarchy roleHierarchy = (context.getBeanNamesForType(RoleHierarchy.class).length > 0)
129+
? context.getBean(RoleHierarchy.class) : new NullRoleHierarchy();
130+
handler.setRoleHierarchy(roleHierarchy);
126131
defaultsProvider.ifAvailable((d) -> handler.setDefaultRolePrefix(d.getRolePrefix()));
127132
handler.setApplicationContext(context);
128133
return handler;

config/src/main/java/org/springframework/security/config/annotation/method/configuration/SecuredMethodSecurityConfiguration.java

+10-1
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,14 @@
2222

2323
import org.springframework.beans.factory.ObjectProvider;
2424
import org.springframework.beans.factory.config.BeanDefinition;
25+
import org.springframework.context.ApplicationContext;
2526
import org.springframework.context.annotation.Bean;
2627
import org.springframework.context.annotation.Configuration;
2728
import org.springframework.context.annotation.Role;
2829
import org.springframework.security.access.annotation.Secured;
30+
import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
31+
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
32+
import org.springframework.security.authorization.AuthoritiesAuthorizationManager;
2933
import org.springframework.security.authorization.AuthorizationManager;
3034
import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor;
3135
import org.springframework.security.authorization.method.SecuredAuthorizationManager;
@@ -48,8 +52,13 @@ final class SecuredMethodSecurityConfiguration {
4852
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
4953
static MethodInterceptor securedAuthorizationMethodInterceptor(
5054
ObjectProvider<SecurityContextHolderStrategy> strategyProvider,
51-
ObjectProvider<ObservationRegistry> registryProvider) {
55+
ObjectProvider<ObservationRegistry> registryProvider, ApplicationContext context) {
5256
SecuredAuthorizationManager secured = new SecuredAuthorizationManager();
57+
AuthoritiesAuthorizationManager authoritiesAuthorizationManager = new AuthoritiesAuthorizationManager();
58+
RoleHierarchy roleHierarchy = (context.getBeanNamesForType(RoleHierarchy.class).length > 0)
59+
? context.getBean(RoleHierarchy.class) : new NullRoleHierarchy();
60+
authoritiesAuthorizationManager.setRoleHierarchy(roleHierarchy);
61+
secured.setAuthoritiesAuthorizationManager(authoritiesAuthorizationManager);
5362
SecurityContextHolderStrategy strategy = strategyProvider
5463
.getIfAvailable(SecurityContextHolder::getContextHolderStrategy);
5564
AuthorizationManager<MethodInvocation> manager = new DeferringObservationAuthorizationManager<>(

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

+4-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public interface MethodSecurityService {
5050
@PermitAll
5151
String jsr250PermitAll();
5252

53-
@RolesAllowed("ADMIN")
53+
@RolesAllowed({ "ADMIN", "USER" })
5454
String jsr250RolesAllowed();
5555

5656
@Secured({ "ROLE_USER", "RUN_AS_SUPER" })
@@ -68,6 +68,9 @@ public interface MethodSecurityService {
6868
@PreAuthorize("hasRole('ADMIN')")
6969
void preAuthorizeAdmin();
7070

71+
@PreAuthorize("hasRole('USER')")
72+
void preAuthorizeUser();
73+
7174
@PreAuthorize("hasPermission(#object,'read')")
7275
String hasPermission(String object);
7376

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

+4
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ public void preAuthorizeBean(boolean b) {
7373
public void preAuthorizeAdmin() {
7474
}
7575

76+
@Override
77+
public void preAuthorizeUser() {
78+
}
79+
7680
@Override
7781
public String preAuthorizePermitAll() {
7882
return null;

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

+33
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@
4646
import org.springframework.security.access.annotation.Jsr250BusinessServiceImpl;
4747
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
4848
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
49+
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
50+
import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
4951
import org.springframework.security.authorization.AuthorizationDecision;
5052
import org.springframework.security.authorization.AuthorizationEventPublisher;
5153
import org.springframework.security.authorization.AuthorizationManager;
@@ -447,6 +449,24 @@ public void configureWhenBeanOverridingDisallowedThenWorks() {
447449
.autowire();
448450
}
449451

452+
@WithMockUser(roles = "ADMIN")
453+
@Test
454+
public void methodSecurityAdminWhenRoleHierarchyBeanAvailableThenUses() {
455+
this.spring.register(RoleHierarchyConfig.class, MethodSecurityServiceConfig.class).autowire();
456+
this.methodSecurityService.preAuthorizeAdmin();
457+
this.methodSecurityService.secured();
458+
this.methodSecurityService.jsr250RolesAllowed();
459+
}
460+
461+
@WithMockUser
462+
@Test
463+
public void methodSecurityUserWhenRoleHierarchyBeanAvailableThenUses() {
464+
this.spring.register(RoleHierarchyConfig.class, MethodSecurityServiceConfig.class).autowire();
465+
this.methodSecurityService.preAuthorizeUser();
466+
this.methodSecurityService.securedUser();
467+
this.methodSecurityService.jsr250RolesAllowed();
468+
}
469+
450470
private static Consumer<ConfigurableWebApplicationContext> disallowBeanOverriding() {
451471
return (context) -> ((AnnotationConfigWebApplicationContext) context).setAllowBeanDefinitionOverriding(false);
452472
}
@@ -627,4 +647,17 @@ Authz authz() {
627647

628648
}
629649

650+
@Configuration
651+
@EnableMethodSecurity(jsr250Enabled = true, securedEnabled = true)
652+
static class RoleHierarchyConfig {
653+
654+
@Bean
655+
RoleHierarchy roleHierarchy() {
656+
RoleHierarchyImpl roleHierarchyImpl = new RoleHierarchyImpl();
657+
roleHierarchyImpl.setHierarchy("ADMIN > USER");
658+
return roleHierarchyImpl;
659+
}
660+
661+
}
662+
630663
}

0 commit comments

Comments
 (0)