From 6853d2dad4832fc574a9ca822dbbced701a821f4 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Mon, 24 Feb 2025 16:23:43 +0000 Subject: [PATCH] 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). --- .../grpc/server/security/GrpcSecurity.java | 6 +++++- .../server/security/GrpcSecurityAutoConfiguration.java | 7 ++++++- .../security/GrpcSecurityAutoConfigurationTests.java | 8 +++++--- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/spring-grpc-core/src/main/java/org/springframework/grpc/server/security/GrpcSecurity.java b/spring-grpc-core/src/main/java/org/springframework/grpc/server/security/GrpcSecurity.java index d0ee2be..5ead14d 100644 --- a/spring-grpc-core/src/main/java/org/springframework/grpc/server/security/GrpcSecurity.java +++ b/spring-grpc-core/src/main/java/org/springframework/grpc/server/security/GrpcSecurity.java @@ -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; diff --git a/spring-grpc-spring-boot-autoconfigure/src/main/java/org/springframework/grpc/autoconfigure/server/security/GrpcSecurityAutoConfiguration.java b/spring-grpc-spring-boot-autoconfigure/src/main/java/org/springframework/grpc/autoconfigure/server/security/GrpcSecurityAutoConfiguration.java index 1a7cef1..f4f9a2e 100644 --- a/spring-grpc-spring-boot-autoconfigure/src/main/java/org/springframework/grpc/autoconfigure/server/security/GrpcSecurityAutoConfiguration.java +++ b/spring-grpc-spring-boot-autoconfigure/src/main/java/org/springframework/grpc/autoconfigure/server/security/GrpcSecurityAutoConfiguration.java @@ -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 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); } diff --git a/spring-grpc-spring-boot-autoconfigure/src/test/java/org/springframework/grpc/autoconfigure/server/security/GrpcSecurityAutoConfigurationTests.java b/spring-grpc-spring-boot-autoconfigure/src/test/java/org/springframework/grpc/autoconfigure/server/security/GrpcSecurityAutoConfigurationTests.java index 8595179..d5df78c 100644 --- a/spring-grpc-spring-boot-autoconfigure/src/test/java/org/springframework/grpc/autoconfigure/server/security/GrpcSecurityAutoConfigurationTests.java +++ b/spring-grpc-spring-boot-autoconfigure/src/test/java/org/springframework/grpc/autoconfigure/server/security/GrpcSecurityAutoConfigurationTests.java @@ -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(); + }); } }