There may be more than one security configuration

In an app with servlets *and* a native gRPC server for instance,
the global AuthenticationManagerBuilder (the @Bean) should be
treated as a parent for the one used by GrpcSecurity. It's the
same in HttpSecurity. Slightly more complicated than necessary
when there is only native gRPC security, but at least it now
works, and makes it easier to introduce multiple GrpcSecurity
instances in future if necessary (like with HttpSecurity it
could be a prototype).
This commit is contained in:
Dave Syer
2025-02-24 16:23:43 +00:00
parent dee423953f
commit 6853d2dad4
3 changed files with 16 additions and 5 deletions

View File

@@ -106,7 +106,7 @@ public final class GrpcSecurity
}
else {
ObservationRegistry registry = getObservationRegistry();
AuthenticationManager manager = getAuthenticationRegistry().build();
AuthenticationManager manager = getAuthenticationManager();
if (!registry.isNoop() && manager != null) {
setSharedObject(AuthenticationManager.class, new ObservationAuthenticationManager(registry, manager));
}
@@ -119,6 +119,10 @@ public final class GrpcSecurity
new CompositeAuthenticationExtractor(this.authenticationExtractors), this.authorizationManager);
}
private AuthenticationManager getAuthenticationManager() throws Exception {
return getAuthenticationRegistry().getOrBuild();
}
public GrpcSecurity authenticationProvider(AuthenticationProvider authenticationProvider) {
getAuthenticationRegistry().authenticationProvider(authenticationProvider);
return this;

View File

@@ -35,6 +35,7 @@ import org.springframework.grpc.server.security.SecurityGrpcExceptionHandler;
import org.springframework.security.concurrent.DelegatingSecurityContextExecutor;
import org.springframework.security.config.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.web.SecurityFilterChain;
import io.grpc.ServerBuilder;
@@ -62,7 +63,11 @@ public class GrpcSecurityAutoConfiguration {
@Bean
public GrpcSecurity grpcSecurity(ObjectPostProcessor<Object> objectPostProcessor,
AuthenticationManagerBuilder authenticationManagerBuilder, ApplicationContext context) {
AuthenticationConfiguration authenticationConfiguration, ApplicationContext context) throws Exception {
AuthenticationManagerBuilder authenticationManagerBuilder = authenticationConfiguration
.authenticationManagerBuilder(objectPostProcessor, context);
authenticationManagerBuilder
.parentAuthenticationManager(authenticationConfiguration.getAuthenticationManager());
return new GrpcSecurity(objectPostProcessor, authenticationManagerBuilder, context);
}

View File

@@ -27,6 +27,7 @@ import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.grpc.autoconfigure.server.GrpcServerAutoConfiguration;
import org.springframework.grpc.server.exception.GrpcExceptionHandler;
import org.springframework.grpc.server.lifecycle.GrpcServerLifecycle;
import org.springframework.grpc.server.security.AuthenticationProcessInterceptor;
import org.springframework.grpc.server.security.SecurityGrpcExceptionHandler;
import org.springframework.security.config.ObjectPostProcessor;
@@ -72,9 +73,10 @@ class GrpcSecurityAutoConfigurationTests {
@Test
void grpcSecurityAutoConfiguredAsExpected() {
this.contextRunner()
.run((context) -> assertThat(context).getBean(GrpcExceptionHandler.class)
.isInstanceOf(SecurityGrpcExceptionHandler.class));
this.contextRunner().run((context) -> {
assertThat(context).getBean(GrpcExceptionHandler.class).isInstanceOf(SecurityGrpcExceptionHandler.class);
assertThat(context).getBean(AuthenticationProcessInterceptor.class).isNull();
});
}
}