Skip to content

Commit

Permalink
Use available RoleHierachy Bean for MethodSecurity Config
Browse files Browse the repository at this point in the history
Closes gh-12783
  • Loading branch information
kandaguru17 authored and jzheaux committed Dec 7, 2023
1 parent bb6b55a commit b76f7c0
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,13 @@

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Role;
import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.authorization.AuthoritiesAuthorizationManager;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor;
import org.springframework.security.authorization.method.Jsr250AuthorizationManager;
Expand All @@ -49,8 +53,13 @@ final class Jsr250MethodSecurityConfiguration {
static MethodInterceptor jsr250AuthorizationMethodInterceptor(
ObjectProvider<GrantedAuthorityDefaults> defaultsProvider,
ObjectProvider<SecurityContextHolderStrategy> strategyProvider,
ObjectProvider<ObservationRegistry> registryProvider) {
ObjectProvider<ObservationRegistry> registryProvider, ApplicationContext context) {
Jsr250AuthorizationManager jsr250 = new Jsr250AuthorizationManager();
AuthoritiesAuthorizationManager authoritiesAuthorizationManager = new AuthoritiesAuthorizationManager();
RoleHierarchy roleHierarchy = (context.getBeanNamesForType(RoleHierarchy.class).length > 0)
? context.getBean(RoleHierarchy.class) : new NullRoleHierarchy();
authoritiesAuthorizationManager.setRoleHierarchy(roleHierarchy);
jsr250.setAuthoritiesAuthorizationManager(authoritiesAuthorizationManager);
defaultsProvider.ifAvailable((d) -> jsr250.setRolePrefix(d.getRolePrefix()));
SecurityContextHolderStrategy strategy = strategyProvider
.getIfAvailable(SecurityContextHolder::getContextHolderStrategy);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
import org.springframework.expression.ExpressionParser;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.authorization.AuthorizationEventPublisher;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.authorization.method.AuthorizationManagerAfterMethodInterceptor;
Expand Down Expand Up @@ -123,6 +125,9 @@ static MethodInterceptor postFilterAuthorizationMethodInterceptor(
private static MethodSecurityExpressionHandler defaultExpressionHandler(
ObjectProvider<GrantedAuthorityDefaults> defaultsProvider, ApplicationContext context) {
DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler();
RoleHierarchy roleHierarchy = (context.getBeanNamesForType(RoleHierarchy.class).length > 0)
? context.getBean(RoleHierarchy.class) : new NullRoleHierarchy();
handler.setRoleHierarchy(roleHierarchy);
defaultsProvider.ifAvailable((d) -> handler.setDefaultRolePrefix(d.getRolePrefix()));
handler.setApplicationContext(context);
return handler;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,14 @@

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Role;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.authorization.AuthoritiesAuthorizationManager;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor;
import org.springframework.security.authorization.method.SecuredAuthorizationManager;
Expand All @@ -48,8 +52,13 @@ final class SecuredMethodSecurityConfiguration {
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
static MethodInterceptor securedAuthorizationMethodInterceptor(
ObjectProvider<SecurityContextHolderStrategy> strategyProvider,
ObjectProvider<ObservationRegistry> registryProvider) {
ObjectProvider<ObservationRegistry> registryProvider, ApplicationContext context) {
SecuredAuthorizationManager secured = new SecuredAuthorizationManager();
AuthoritiesAuthorizationManager authoritiesAuthorizationManager = new AuthoritiesAuthorizationManager();
RoleHierarchy roleHierarchy = (context.getBeanNamesForType(RoleHierarchy.class).length > 0)
? context.getBean(RoleHierarchy.class) : new NullRoleHierarchy();
authoritiesAuthorizationManager.setRoleHierarchy(roleHierarchy);
secured.setAuthoritiesAuthorizationManager(authoritiesAuthorizationManager);
SecurityContextHolderStrategy strategy = strategyProvider
.getIfAvailable(SecurityContextHolder::getContextHolderStrategy);
AuthorizationManager<MethodInvocation> manager = new DeferringObservationAuthorizationManager<>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public interface MethodSecurityService {
@PermitAll
String jsr250PermitAll();

@RolesAllowed("ADMIN")
@RolesAllowed({ "ADMIN", "USER" })
String jsr250RolesAllowed();

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

@PreAuthorize("hasRole('USER')")
void preAuthorizeUser();

@PreAuthorize("hasPermission(#object,'read')")
String hasPermission(String object);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ public void preAuthorizeBean(boolean b) {
public void preAuthorizeAdmin() {
}

@Override
public void preAuthorizeUser() {
}

@Override
public String preAuthorizePermitAll() {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
import org.springframework.security.access.annotation.Jsr250BusinessServiceImpl;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationEventPublisher;
import org.springframework.security.authorization.AuthorizationManager;
Expand Down Expand Up @@ -447,6 +449,24 @@ public void configureWhenBeanOverridingDisallowedThenWorks() {
.autowire();
}

@WithMockUser(roles = "ADMIN")
@Test
public void methodSecurityAdminWhenRoleHierarchyBeanAvailableThenUses() {
this.spring.register(RoleHierarchyConfig.class, MethodSecurityServiceConfig.class).autowire();
this.methodSecurityService.preAuthorizeAdmin();
this.methodSecurityService.secured();
this.methodSecurityService.jsr250RolesAllowed();
}

@WithMockUser
@Test
public void methodSecurityUserWhenRoleHierarchyBeanAvailableThenUses() {
this.spring.register(RoleHierarchyConfig.class, MethodSecurityServiceConfig.class).autowire();
this.methodSecurityService.preAuthorizeUser();
this.methodSecurityService.securedUser();
this.methodSecurityService.jsr250RolesAllowed();
}

private static Consumer<ConfigurableWebApplicationContext> disallowBeanOverriding() {
return (context) -> ((AnnotationConfigWebApplicationContext) context).setAllowBeanDefinitionOverriding(false);
}
Expand Down Expand Up @@ -627,4 +647,17 @@ Authz authz() {

}

@Configuration
@EnableMethodSecurity(jsr250Enabled = true, securedEnabled = true)
static class RoleHierarchyConfig {

@Bean
RoleHierarchy roleHierarchy() {
RoleHierarchyImpl roleHierarchyImpl = new RoleHierarchyImpl();
roleHierarchyImpl.setHierarchy("ADMIN > USER");
return roleHierarchyImpl;
}

}

}

0 comments on commit b76f7c0

Please sign in to comment.