From 1ec5e266818325bec4e76b1496b5ffd96d3caee2 Mon Sep 17 00:00:00 2001 From: Gabriel Roldan Date: Fri, 5 Jul 2024 17:11:07 -0300 Subject: [PATCH] Allow to disable gateway-shared-auth global filter in the gateway The config property `geoserver.security.gateway-shared-auth.enabled` only allowed to disable the gateway/webui shared auth in the gs services. This patch makes it possible to also disable the global filter in the gateway. --- config | 2 +- .../GatewayApplicationAutoconfiguration.java | 79 +++++++++++++++++++ .../SharedAuthConfigurationProperties.java | 25 ++++++ .../cloud/gateway/GatewayApplication.java | 46 ++--------- .../main/resources/META-INF/spring.factories | 3 + .../gateway/src/main/resources/bootstrap.yml | 7 -- ...tewayApplicationAutoconfigurationTest.java | 46 +++++++++++ .../src/test/resources/logback-test.xml | 13 +++ .../resources/gs_cloud_bootstrap_profiles.yml | 2 +- 9 files changed, 174 insertions(+), 49 deletions(-) create mode 100644 src/apps/infrastructure/gateway/src/main/java/org/geoserver/cloud/autoconfigure/gateway/GatewayApplicationAutoconfiguration.java create mode 100644 src/apps/infrastructure/gateway/src/main/java/org/geoserver/cloud/autoconfigure/gateway/SharedAuthConfigurationProperties.java create mode 100644 src/apps/infrastructure/gateway/src/main/resources/META-INF/spring.factories create mode 100644 src/apps/infrastructure/gateway/src/test/java/org/geoserver/cloud/autoconfigure/gateway/GatewayApplicationAutoconfigurationTest.java create mode 100644 src/apps/infrastructure/gateway/src/test/resources/logback-test.xml diff --git a/config b/config index 35ca78050..ad3c285b0 160000 --- a/config +++ b/config @@ -1 +1 @@ -Subproject commit 35ca780506358321367d4fd0a04554e6d715d4d0 +Subproject commit ad3c285b06572f8c7eb1d68ed9e94d0de86e96b0 diff --git a/src/apps/infrastructure/gateway/src/main/java/org/geoserver/cloud/autoconfigure/gateway/GatewayApplicationAutoconfiguration.java b/src/apps/infrastructure/gateway/src/main/java/org/geoserver/cloud/autoconfigure/gateway/GatewayApplicationAutoconfiguration.java new file mode 100644 index 000000000..81b9cd7ec --- /dev/null +++ b/src/apps/infrastructure/gateway/src/main/java/org/geoserver/cloud/autoconfigure/gateway/GatewayApplicationAutoconfiguration.java @@ -0,0 +1,79 @@ +/* + * (c) 2020 Open Source Geospatial Foundation - all rights reserved This code is licensed under the + * GPL 2.0 license, available at the root application directory. + */ +package org.geoserver.cloud.autoconfigure.gateway; + +import lombok.extern.slf4j.Slf4j; + +import org.geoserver.cloud.gateway.filter.GatewaySharedAuhenticationGlobalFilter; +import org.geoserver.cloud.gateway.filter.RouteProfileGatewayFilterFactory; +import org.geoserver.cloud.gateway.filter.StripBasePathGatewayFilterFactory; +import org.geoserver.cloud.gateway.predicate.RegExpQueryRoutePredicateFactory; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.core.env.Environment; + +@AutoConfiguration +@Slf4j +public class GatewayApplicationAutoconfiguration { + + /** + * Custom gateway predicate factory to support matching by regular expressions on both name and + * value of query parameters + * + *

E.g.: + * + *

{@code
+     * - id: wms_ows
+     *   uri: http://wms-service:8080
+     *   predicates:
+     *     # match service=wms case insensitively
+     *     - RegExpQuery=(?i:service),(?i:wms)
+     * }
+ */ + @Bean + RegExpQueryRoutePredicateFactory regExpQueryRoutePredicateFactory() { + return new RegExpQueryRoutePredicateFactory(); + } + + /** + * Allows to enable routes only if a given spring profile is enabled + * + *

Since the `spring.cloud.gateway.routes` is a list and not a map/dictionary, routes can't + * be added in profiles, because the list is overritten fully. This filter allows to enable + * routes based on profiles from a single list of routes. + * + *

E.g.: + * + *

{@code
+     * - id: catalog
+     *   uri: ...
+     *   predicates:
+     *     - Path=${geoserver.base-path}/api/v1/**
+     *   filters:
+     *     # Expose the catalog and configuration API only if the dev profile is active
+     *     - RouteProfile=dev,403
+     * }
+ */ + @Bean + RouteProfileGatewayFilterFactory routeProfileGatewayFilterFactory(Environment environment) { + return new RouteProfileGatewayFilterFactory(environment); + } + + @Bean + StripBasePathGatewayFilterFactory stripBasePathGatewayFilterFactory() { + return new StripBasePathGatewayFilterFactory(); + } + + @Bean + @ConditionalOnProperty( + name = "geoserver.security.gateway-shared-auth.enabled", + havingValue = "true", + matchIfMissing = true) + GatewaySharedAuhenticationGlobalFilter gatewaySharedAuhenticationGlobalFilter() { + log.info("gateway-shared-auth is enabled"); + return new GatewaySharedAuhenticationGlobalFilter(); + } +} diff --git a/src/apps/infrastructure/gateway/src/main/java/org/geoserver/cloud/autoconfigure/gateway/SharedAuthConfigurationProperties.java b/src/apps/infrastructure/gateway/src/main/java/org/geoserver/cloud/autoconfigure/gateway/SharedAuthConfigurationProperties.java new file mode 100644 index 000000000..04b39f6d2 --- /dev/null +++ b/src/apps/infrastructure/gateway/src/main/java/org/geoserver/cloud/autoconfigure/gateway/SharedAuthConfigurationProperties.java @@ -0,0 +1,25 @@ +/* + * (c) 2024 Open Source Geospatial Foundation - all rights reserved This code is licensed under the + * GPL 2.0 license, available at the root application directory. + */ +package org.geoserver.cloud.autoconfigure.gateway; + +import lombok.Data; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * For automatic documentation purposes only, as used by the {@literal + * spring-boot-configuration-processor} + */ +@ConfigurationProperties(prefix = "geoserver.security.gateway-shared-auth") +@Data +class SharedAuthConfigurationProperties { + + /** + * Enable or disable the Gateway/WebUI Shared Authentication mechanism, where the Gateway works + * as mediator to share the authentication from the GeoServer WebUI with the rest of the + * services. + */ + private boolean enabled = true; +} diff --git a/src/apps/infrastructure/gateway/src/main/java/org/geoserver/cloud/gateway/GatewayApplication.java b/src/apps/infrastructure/gateway/src/main/java/org/geoserver/cloud/gateway/GatewayApplication.java index 350b51b23..5318af96c 100644 --- a/src/apps/infrastructure/gateway/src/main/java/org/geoserver/cloud/gateway/GatewayApplication.java +++ b/src/apps/infrastructure/gateway/src/main/java/org/geoserver/cloud/gateway/GatewayApplication.java @@ -4,53 +4,19 @@ */ package org.geoserver.cloud.gateway; -import org.geoserver.cloud.gateway.filter.GatewaySharedAuhenticationGlobalFilter; -import org.geoserver.cloud.gateway.filter.RouteProfileGatewayFilterFactory; -import org.geoserver.cloud.gateway.filter.StripBasePathGatewayFilterFactory; -import org.geoserver.cloud.gateway.predicate.RegExpQueryRoutePredicateFactory; +import org.geoserver.cloud.autoconfigure.gateway.GatewayApplicationAutoconfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; -import org.springframework.cloud.gateway.route.RouteLocator; -import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.env.Environment; +/** + * Spring Cloud Gateway application for GeoServer Cloud + * + * @see GatewayApplicationAutoconfiguration + */ @SpringBootApplication -@Configuration(proxyBeanMethods = false) public class GatewayApplication { public static void main(String[] args) { new SpringApplicationBuilder(GatewayApplication.class).run(args); } - - @Bean - RouteLocator customRouteLocator(RouteLocatorBuilder builder) { - return builder.routes().build(); - } - - /** - * Custom gateway predicate factory to support matching by regular expressions on both name and - * value of query parameters - */ - @Bean - RegExpQueryRoutePredicateFactory regExpQueryRoutePredicateFactory() { - return new RegExpQueryRoutePredicateFactory(); - } - - /** Allows to enable routes only if a given spring profile is enabled */ - @Bean - RouteProfileGatewayFilterFactory routeProfileGatewayFilterFactory(Environment environment) { - return new RouteProfileGatewayFilterFactory(environment); - } - - @Bean - StripBasePathGatewayFilterFactory stripBasePathGatewayFilterFactory() { - return new StripBasePathGatewayFilterFactory(); - } - - @Bean - GatewaySharedAuhenticationGlobalFilter gatewaySharedAuhenticationGlobalFilter() { - return new GatewaySharedAuhenticationGlobalFilter(); - } } diff --git a/src/apps/infrastructure/gateway/src/main/resources/META-INF/spring.factories b/src/apps/infrastructure/gateway/src/main/resources/META-INF/spring.factories new file mode 100644 index 000000000..e8e6264bc --- /dev/null +++ b/src/apps/infrastructure/gateway/src/main/resources/META-INF/spring.factories @@ -0,0 +1,3 @@ +# Auto Configure +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +org.geoserver.cloud.autoconfigure.gateway.GatewayApplicationAutoconfiguration \ No newline at end of file diff --git a/src/apps/infrastructure/gateway/src/main/resources/bootstrap.yml b/src/apps/infrastructure/gateway/src/main/resources/bootstrap.yml index 9eb93161d..484dbb77e 100644 --- a/src/apps/infrastructure/gateway/src/main/resources/bootstrap.yml +++ b/src/apps/infrastructure/gateway/src/main/resources/bootstrap.yml @@ -15,13 +15,6 @@ spring: application: name: gateway-service jmx.enabled: false -# autoconfigure: -# exclude: -# - org.springframework.cloud.loadbalancer.config.LoadBalancerAutoConfiguration -# - org.springframework.cloud.loadbalancer.config.BlockingLoadBalancerClientAutoConfiguration -# - org.springframework.cloud.loadbalancer.config.LoadBalancerCacheAutoConfiguration -# - org.springframework.cloud.loadbalancer.security.OAuth2LoadBalancerClientAutoConfiguration -# - org.springframework.cloud.loadbalancer.config.LoadBalancerStatsAutoConfiguration # this service uses the registry (when eureka client is enabled) eureka.client: diff --git a/src/apps/infrastructure/gateway/src/test/java/org/geoserver/cloud/autoconfigure/gateway/GatewayApplicationAutoconfigurationTest.java b/src/apps/infrastructure/gateway/src/test/java/org/geoserver/cloud/autoconfigure/gateway/GatewayApplicationAutoconfigurationTest.java new file mode 100644 index 000000000..a9a2c2949 --- /dev/null +++ b/src/apps/infrastructure/gateway/src/test/java/org/geoserver/cloud/autoconfigure/gateway/GatewayApplicationAutoconfigurationTest.java @@ -0,0 +1,46 @@ +/* + * (c) 2020 Open Source Geospatial Foundation - all rights reserved This code is licensed under the + * GPL 2.0 license, available at the root application directory. + */ +package org.geoserver.cloud.autoconfigure.gateway; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.geoserver.cloud.gateway.filter.GatewaySharedAuhenticationGlobalFilter; +import org.geoserver.cloud.gateway.filter.RouteProfileGatewayFilterFactory; +import org.geoserver.cloud.gateway.filter.StripBasePathGatewayFilterFactory; +import org.geoserver.cloud.gateway.predicate.RegExpQueryRoutePredicateFactory; +import org.junit.jupiter.api.Test; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner; + +class GatewayApplicationAutoconfigurationTest { + + private ReactiveWebApplicationContextRunner runner = + new ReactiveWebApplicationContextRunner() + .withConfiguration( + AutoConfigurations.of(GatewayApplicationAutoconfiguration.class)); + + @Test + void testDefaultAppContextContributions() { + runner.run( + context -> + assertThat(context) + .hasNotFailed() + .hasSingleBean(RegExpQueryRoutePredicateFactory.class) + .hasSingleBean(RouteProfileGatewayFilterFactory.class) + .hasSingleBean(StripBasePathGatewayFilterFactory.class) + .hasSingleBean(GatewaySharedAuhenticationGlobalFilter.class)); + } + + @Test + void disableGatewaySharedAuhenticationGlobalFilter() { + runner.withPropertyValues("geoserver.security.gateway-shared-auth.enabled: false") + .run( + context -> + assertThat(context) + .hasNotFailed() + .doesNotHaveBean( + GatewaySharedAuhenticationGlobalFilter.class)); + } +} diff --git a/src/apps/infrastructure/gateway/src/test/resources/logback-test.xml b/src/apps/infrastructure/gateway/src/test/resources/logback-test.xml new file mode 100644 index 000000000..63cfbdb48 --- /dev/null +++ b/src/apps/infrastructure/gateway/src/test/resources/logback-test.xml @@ -0,0 +1,13 @@ + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n + + + + + + + + + \ No newline at end of file diff --git a/src/starters/spring-boot/src/main/resources/gs_cloud_bootstrap_profiles.yml b/src/starters/spring-boot/src/main/resources/gs_cloud_bootstrap_profiles.yml index 6dd398396..f846e8328 100644 --- a/src/starters/spring-boot/src/main/resources/gs_cloud_bootstrap_profiles.yml +++ b/src/starters/spring-boot/src/main/resources/gs_cloud_bootstrap_profiles.yml @@ -64,7 +64,7 @@ eureka: #all Dockerfile files have the default config under that directory spring.config.activate.on-profile: bootstrap_standalone spring: - config.location: file:/etc/geoserver/ + config.location: ${standalone.config.location:file:/etc/geoserver/} cloud.config: enabled: false ---