diff --git a/src/integration/spring/cache/src/main/java/org/geoserver/acl/authorization/cache/CachingAuthorizationService.java b/src/integration/spring/cache/src/main/java/org/geoserver/acl/authorization/cache/CachingAuthorizationService.java index d5e3d93..1aa23b0 100644 --- a/src/integration/spring/cache/src/main/java/org/geoserver/acl/authorization/cache/CachingAuthorizationService.java +++ b/src/integration/spring/cache/src/main/java/org/geoserver/acl/authorization/cache/CachingAuthorizationService.java @@ -95,6 +95,14 @@ public void onAdminRuleEvent(AdminRuleEvent event) { log.debug("evicted all {} admin authorizations upon event {}", evictCount, event); } + public void evictAll() { + int dataAuth = evictAll(ruleAccessCache); + int adminAuth = evictAll(adminRuleAccessCache); + int summaries = evictAll(viewablesCache); + int total = dataAuth + adminAuth + summaries; + log.info("evicted {} cached ACL authorizations", total); + } + private int evictAll(Map, ?> cache) { int size = cache.size(); cache.clear(); diff --git a/src/integration/spring/cache/src/main/java/org/geoserver/acl/authorization/cache/CachingAuthorizationServiceConfiguration.java b/src/integration/spring/cache/src/main/java/org/geoserver/acl/authorization/cache/CachingAuthorizationServiceConfiguration.java index 90a3045..53b88dd 100644 --- a/src/integration/spring/cache/src/main/java/org/geoserver/acl/authorization/cache/CachingAuthorizationServiceConfiguration.java +++ b/src/integration/spring/cache/src/main/java/org/geoserver/acl/authorization/cache/CachingAuthorizationServiceConfiguration.java @@ -7,6 +7,8 @@ import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; +import lombok.extern.slf4j.Slf4j; + import org.geoserver.acl.authorization.AccessInfo; import org.geoserver.acl.authorization.AccessRequest; import org.geoserver.acl.authorization.AccessSummary; @@ -14,22 +16,85 @@ import org.geoserver.acl.authorization.AdminAccessInfo; import org.geoserver.acl.authorization.AdminAccessRequest; import org.geoserver.acl.authorization.AuthorizationService; +import org.springframework.beans.factory.BeanInitializationException; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.cache.CacheManager; -import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.caffeine.CaffeineCacheManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; +import org.springframework.core.env.PropertyResolver; +import java.time.Duration; +import java.time.format.DateTimeParseException; +import java.util.Optional; import java.util.concurrent.ConcurrentMap; /** * @since 2.0 */ @Configuration -@EnableCaching +@Slf4j(topic = "org.geoserver.acl.authorization.cache") public class CachingAuthorizationServiceConfiguration { + private static final Duration DEFAULT_CACHE_TTL = Duration.ofSeconds(30); + + /** + * Defines the ACL Auth cache time-to-live from the {@code geoserver.acl.client.cache.ttl} + * config property, which only applies if there's no {@link CacheManager} in the application + * context or if it's not a {@link CaffeineCacheManager}. + * + *
The {@code geoserver.acl.client.cache.ttl} expects a {@link Duration} string, for example: + * + *
+ *
+ * {@literal PT20.345S} -- parses as "20.345 seconds"
+ * {@literal PT15M} -- parses as "15 minutes" (where a minute is 60 seconds)
+ * {@literal PT10H} -- parses as "10 hours" (where an hour is 3600 seconds)
+ * {@literal P2D} -- parses as "2 days" (where a day is 24 hours or 86400 seconds)
+ * {@literal P2DT3H4M} -- parses as "2 days, 3 hours and 4 minutes"
+ *
+ *
+ *
+ * Defaults to 30 seconds otherwise.
+ */
+ @Bean
+ Duration aclAuthCacheTTL(
+ OptionalFor plain Spring (without spring boot auto configuration support), {@link + * AclEnabledCondition @Conditional(AclEnabledCondition.class)} is to be used on plain {@link + * Configuration @Configuration} classes + */ @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented diff --git a/src/plugin/plugin/src/main/java/org/geoserver/acl/plugin/autoconfigure/webui/AclWebUIAutoConfiguration.java b/src/plugin/plugin/src/main/java/org/geoserver/acl/plugin/autoconfigure/webui/AclWebUIAutoConfiguration.java index 1b6e4f4..9a7ac90 100644 --- a/src/plugin/plugin/src/main/java/org/geoserver/acl/plugin/autoconfigure/webui/AclWebUIAutoConfiguration.java +++ b/src/plugin/plugin/src/main/java/org/geoserver/acl/plugin/autoconfigure/webui/AclWebUIAutoConfiguration.java @@ -4,7 +4,7 @@ */ package org.geoserver.acl.plugin.autoconfigure.webui; -import org.geoserver.acl.plugin.autoconfigure.accessmanager.ConditionalOnAclEnabled; +import org.geoserver.acl.plugin.autoconfigure.conditionals.ConditionalOnAclEnabled; import org.geoserver.acl.plugin.config.webui.ACLWebUIConfiguration; import org.geoserver.security.web.SecuritySettingsPage; import org.geoserver.web.GeoServerBasePage; diff --git a/src/plugin/plugin/src/main/java/org/geoserver/acl/plugin/autoconfigure/wps/AclWpsAutoConfiguration.java b/src/plugin/plugin/src/main/java/org/geoserver/acl/plugin/autoconfigure/wps/AclWpsAutoConfiguration.java index 40df828..51c3385 100644 --- a/src/plugin/plugin/src/main/java/org/geoserver/acl/plugin/autoconfigure/wps/AclWpsAutoConfiguration.java +++ b/src/plugin/plugin/src/main/java/org/geoserver/acl/plugin/autoconfigure/wps/AclWpsAutoConfiguration.java @@ -4,7 +4,7 @@ */ package org.geoserver.acl.plugin.autoconfigure.wps; -import org.geoserver.acl.plugin.autoconfigure.accessmanager.ConditionalOnAclEnabled; +import org.geoserver.acl.plugin.autoconfigure.conditionals.ConditionalOnAclEnabled; import org.geoserver.acl.plugin.config.wps.AclWpsIntegrationConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; diff --git a/src/plugin/plugin/src/main/java/org/geoserver/acl/plugin/config/accessmanager/AclAccessManagerConfiguration.java b/src/plugin/plugin/src/main/java/org/geoserver/acl/plugin/config/accessmanager/AclAccessManagerConfiguration.java new file mode 100644 index 0000000..3b589af --- /dev/null +++ b/src/plugin/plugin/src/main/java/org/geoserver/acl/plugin/config/accessmanager/AclAccessManagerConfiguration.java @@ -0,0 +1,32 @@ +/* (c) 2023 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.acl.plugin.config.accessmanager; + +import org.geoserver.acl.plugin.accessmanager.ACLResourceAccessManager; +import org.geoserver.acl.plugin.config.configmanager.AclConfigurationManagerConfiguration; +import org.geoserver.acl.plugin.config.domain.client.ApiClientAclDomainServicesConfiguration; +import org.geoserver.security.ResourceAccessManager; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +/** + * {@link Configuration @Configuration} for the GeoServer Access Control List {@link + * ACLResourceAccessManager}. + * + *
{@link ACLResourceAccessManager} implements GeoServer {@link ResourceAccessManager} by
+ * delegating resource access requests to the GeoServer ACL service.
+ *
+ * @since 1.0
+ * @see AclConfigurationManagerConfiguration
+ * @see ApiClientAclDomainServicesConfiguration
+ * @see AccessManagerSpringConfig
+ */
+@Configuration
+@Import({ //
+ AclConfigurationManagerConfiguration.class, //
+ ApiClientAclDomainServicesConfiguration.class, //
+ AccessManagerSpringConfig.class
+})
+public class AclAccessManagerConfiguration {}
diff --git a/src/plugin/plugin/src/main/java/org/geoserver/acl/plugin/config/cache/CachingAuthorizationServicePluginConfiguration.java b/src/plugin/plugin/src/main/java/org/geoserver/acl/plugin/config/cache/CachingAuthorizationServicePluginConfiguration.java
new file mode 100644
index 0000000..170c923
--- /dev/null
+++ b/src/plugin/plugin/src/main/java/org/geoserver/acl/plugin/config/cache/CachingAuthorizationServicePluginConfiguration.java
@@ -0,0 +1,68 @@
+/* (c) 2023 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.acl.plugin.config.cache;
+
+import lombok.extern.slf4j.Slf4j;
+
+import org.geoserver.acl.authorization.cache.CachingAuthorizationService;
+import org.geoserver.acl.authorization.cache.CachingAuthorizationServiceConfiguration;
+import org.geoserver.config.impl.GeoServerLifecycleHandler;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+
+import javax.annotation.PostConstruct;
+
+/**
+ * Plugin-specific extension for {@link CachingAuthorizationServiceConfiguration} to support
+ * GeoServer without spring boot enabling and disabling through ConditionalOnAclEnabled.
+ *
+ * @since 2.3
+ * @see CachingAuthorizationServiceConfiguration
+ */
+@Configuration
+@Import(CachingAuthorizationServiceConfiguration.class)
+@Slf4j(topic = "org.geoserver.acl.plugin.config.cache")
+public class CachingAuthorizationServicePluginConfiguration {
+
+ @PostConstruct
+ void logUsing() {
+ log.info("Caching ACL AuthorizationService enabled");
+ }
+
+ @Bean
+ CachingAclAuthorizationCleanupService cachingAclAuthorizationCleanupService(
+ CachingAuthorizationService cachingService) {
+ return new CachingAclAuthorizationCleanupService(cachingService);
+ }
+
+ static class CachingAclAuthorizationCleanupService implements GeoServerLifecycleHandler {
+ private CachingAuthorizationService cachingService;
+
+ public CachingAclAuthorizationCleanupService(CachingAuthorizationService cachingService) {
+ this.cachingService = cachingService;
+ }
+
+ @Override
+ public void onReset() {
+ cachingService.evictAll();
+ }
+
+ @Override
+ public void onDispose() {
+ // no=op
+ }
+
+ @Override
+ public void beforeReload() {
+ // no=op
+ }
+
+ @Override
+ public void onReload() {
+ // no=op
+ }
+ }
+}
diff --git a/src/plugin/plugin/src/main/java/org/geoserver/acl/plugin/config/condition/AclEnabledCondition.java b/src/plugin/plugin/src/main/java/org/geoserver/acl/plugin/config/condition/AclEnabledCondition.java
new file mode 100644
index 0000000..cae0f9b
--- /dev/null
+++ b/src/plugin/plugin/src/main/java/org/geoserver/acl/plugin/config/condition/AclEnabledCondition.java
@@ -0,0 +1,28 @@
+/* (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.acl.plugin.config.condition;
+
+import org.springframework.context.annotation.Condition;
+import org.springframework.context.annotation.ConditionContext;
+import org.springframework.context.annotation.ConfigurationCondition;
+import org.springframework.core.type.AnnotatedTypeMetadata;
+
+/**
+ * {@link Condition} to apply to plain-spring configuration classes to the same effect as
+ * {@code @ConditionalOnAclEnabled} when spring-boot is not available.
+ */
+public class AclEnabledCondition implements ConfigurationCondition {
+
+ @Override
+ public ConfigurationPhase getConfigurationPhase() {
+ return ConfigurationPhase.PARSE_CONFIGURATION;
+ }
+
+ @Override
+ public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
+ return context.getEnvironment()
+ .getProperty("geoserver.acl.enabled", Boolean.class, Boolean.TRUE);
+ }
+}
diff --git a/src/plugin/plugin/src/main/java/org/geoserver/acl/plugin/config/spring/AclPluginSpringConfiguration.java b/src/plugin/plugin/src/main/java/org/geoserver/acl/plugin/config/spring/AclPluginSpringConfiguration.java
new file mode 100644
index 0000000..2d32411
--- /dev/null
+++ b/src/plugin/plugin/src/main/java/org/geoserver/acl/plugin/config/spring/AclPluginSpringConfiguration.java
@@ -0,0 +1,27 @@
+/* (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.acl.plugin.config.spring;
+
+import org.geoserver.acl.plugin.config.accessmanager.AclAccessManagerConfiguration;
+import org.geoserver.acl.plugin.config.cache.CachingAuthorizationServicePluginConfiguration;
+import org.geoserver.acl.plugin.config.condition.AclEnabledCondition;
+import org.geoserver.acl.plugin.config.webui.ACLWebUIConfiguration;
+import org.geoserver.acl.plugin.config.wps.AclWpsIntegrationConfiguration;
+import org.springframework.context.annotation.Conditional;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+
+/**
+ * @since 2.3
+ */
+@Configuration
+@Conditional(AclEnabledCondition.class)
+@Import({
+ AclAccessManagerConfiguration.class,
+ ACLWebUIConfiguration.class,
+ AclWpsIntegrationConfiguration.class,
+ CachingAuthorizationServicePluginConfiguration.class
+})
+public class AclPluginSpringConfiguration {}
diff --git a/src/plugin/web/src/main/resources/applicationContext.xml b/src/plugin/plugin/src/main/resources/applicationContext.xml
similarity index 93%
rename from src/plugin/web/src/main/resources/applicationContext.xml
rename to src/plugin/plugin/src/main/resources/applicationContext.xml
index ad72304..55187b4 100644
--- a/src/plugin/web/src/main/resources/applicationContext.xml
+++ b/src/plugin/plugin/src/main/resources/applicationContext.xml
@@ -13,7 +13,6 @@
directory.
-->
-
-
-