Skip to content

Commit

Permalink
Better Fix
Browse files Browse the repository at this point in the history
This is better since it will accept the Spring 6.2 improvmements
without a lot of change
  • Loading branch information
jzheaux committed Aug 14, 2024
1 parent 7a7fe1a commit 982d9da
Show file tree
Hide file tree
Showing 4 changed files with 259 additions and 197 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package org.springframework.security.config.annotation.method.configuration;

import java.util.function.Supplier;

import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInvocation;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import org.springframework.aop.Pointcut;
import org.springframework.security.authorization.method.AuthorizationAdvisor;
import org.springframework.util.function.SingletonSupplier;

final class DeferringMethodInterceptor<M extends AuthorizationAdvisor> implements AuthorizationAdvisor {

private final Pointcut pointcut;

private final Supplier<M> delegate;

DeferringMethodInterceptor(Pointcut pointcut, Supplier<M> delegate) {
this.pointcut = pointcut;
this.delegate = SingletonSupplier.of(delegate);
}

@Nullable
@Override
public Object invoke(@NotNull MethodInvocation invocation) throws Throwable {
return this.delegate.get().invoke(invocation);
}

@Override
public Pointcut getPointcut() {
return this.pointcut;
}

@Override
public Advice getAdvice() {
return this;
}

@Override
public int getOrder() {
return this.delegate.get().getOrder();
}

@Override
public boolean isPerInstance() {
return true;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,30 @@

package org.springframework.security.config.annotation.method.configuration;

import java.util.function.Supplier;

import io.micrometer.observation.ObservationRegistry;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import org.springframework.aop.Pointcut;
import org.springframework.aop.framework.AopInfrastructureBean;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportAware;
import org.springframework.context.annotation.Role;
import org.springframework.core.type.AnnotationMetadata;
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.AuthorizationEventPublisher;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.authorization.ObservationAuthorizationManager;
import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor;
import org.springframework.security.authorization.method.Jsr250AuthorizationManager;
import org.springframework.security.config.core.GrantedAuthorityDefaults;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;

/**
Expand All @@ -47,42 +50,64 @@
* @since 5.6
* @see EnableMethodSecurity
*/
@Configuration(proxyBeanMethods = false)
@Configuration(value = "_jsr250MethodSecurityConfiguration", proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
final class Jsr250MethodSecurityConfiguration implements ImportAware, AopInfrastructureBean {

private int interceptorOrderOffset;
private static final Pointcut pointcut = AuthorizationManagerBeforeMethodInterceptor.jsr250().getPointcut();

private final Jsr250AuthorizationManager authorizationManager = new Jsr250AuthorizationManager();

private AuthorizationManagerBeforeMethodInterceptor methodInterceptor = AuthorizationManagerBeforeMethodInterceptor
.jsr250(this.authorizationManager);

@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
static MethodInterceptor jsr250AuthorizationMethodInterceptor(
ObjectProvider<GrantedAuthorityDefaults> defaultsProvider,
ObjectProvider<SecurityContextHolderStrategy> strategyProvider,
ObjectProvider<AuthorizationEventPublisher> eventPublisherProvider,
ObjectProvider<ObservationRegistry> registryProvider, ObjectProvider<RoleHierarchy> roleHierarchyProvider,
Jsr250MethodSecurityConfiguration configuration) {
Jsr250AuthorizationManager jsr250 = new Jsr250AuthorizationManager();
AuthoritiesAuthorizationManager authoritiesAuthorizationManager = new AuthoritiesAuthorizationManager();
RoleHierarchy roleHierarchy = roleHierarchyProvider.getIfAvailable(NullRoleHierarchy::new);
authoritiesAuthorizationManager.setRoleHierarchy(roleHierarchy);
jsr250.setAuthoritiesAuthorizationManager(authoritiesAuthorizationManager);
defaultsProvider.ifAvailable((d) -> jsr250.setRolePrefix(d.getRolePrefix()));
SecurityContextHolderStrategy strategy = strategyProvider
.getIfAvailable(SecurityContextHolder::getContextHolderStrategy);
AuthorizationManager<MethodInvocation> manager = new DeferringObservationAuthorizationManager<>(
registryProvider, jsr250);
AuthorizationManagerBeforeMethodInterceptor interceptor = AuthorizationManagerBeforeMethodInterceptor
.jsr250(manager);
interceptor.setOrder(interceptor.getOrder() + configuration.interceptorOrderOffset);
interceptor.setSecurityContextHolderStrategy(strategy);
eventPublisherProvider.ifAvailable(interceptor::setAuthorizationEventPublisher);
return interceptor;
ObjectProvider<Jsr250MethodSecurityConfiguration> _jsr250MethodSecurityConfiguration) {
Supplier<AuthorizationManagerBeforeMethodInterceptor> supplier = () -> {
Jsr250MethodSecurityConfiguration configuration = _jsr250MethodSecurityConfiguration.getObject();
return configuration.methodInterceptor;
};
return new DeferringMethodInterceptor<>(pointcut, supplier);
}

@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
EnableMethodSecurity annotation = importMetadata.getAnnotations().get(EnableMethodSecurity.class).synthesize();
this.interceptorOrderOffset = annotation.offset();
this.methodInterceptor.setOrder(this.methodInterceptor.getOrder() + annotation.offset());
}

@Autowired(required = false)
void setGrantedAuthorityDefaults(GrantedAuthorityDefaults defaults) {
this.authorizationManager.setRolePrefix(defaults.getRolePrefix());
}

@Autowired(required = false)
void setRoleHierarchy(RoleHierarchy roleHierarchy) {
AuthoritiesAuthorizationManager authoritiesAuthorizationManager = new AuthoritiesAuthorizationManager();
authoritiesAuthorizationManager.setRoleHierarchy(roleHierarchy);
this.authorizationManager.setAuthoritiesAuthorizationManager(authoritiesAuthorizationManager);
}

@Autowired(required = false)
public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
this.methodInterceptor.setSecurityContextHolderStrategy(securityContextHolderStrategy);
}

@Autowired(required = false)
void setObservationRegistry(ObservationRegistry registry) {
if (registry.isNoop()) {
return;
}
AuthorizationManager<MethodInvocation> observed = new ObservationAuthorizationManager<>(registry,
this.authorizationManager);
this.methodInterceptor = AuthorizationManagerBeforeMethodInterceptor.secured(observed);
}

@Autowired(required = false)
void setEventPublisher(AuthorizationEventPublisher eventPublisher) {
this.methodInterceptor.setAuthorizationEventPublisher(eventPublisher);
}

}
Loading

0 comments on commit 982d9da

Please sign in to comment.