From b9044caf65f8d56a77dd994823a50eb7dfb48cef Mon Sep 17 00:00:00 2001 From: James Muehlner Date: Tue, 29 Nov 2022 20:58:51 +0000 Subject: [PATCH] GUACAMOLE-1772: Allow user configuration of KSM API call timeout. --- .../ksm/conf/KsmConfigurationService.java | 32 +++++++++++++++++++ .../guacamole/vault/ksm/secret/KsmClient.java | 31 +++++++++++------- .../vault/ksm/secret/KsmClientFactory.java | 9 ++++-- .../vault/ksm/secret/KsmSecretService.java | 3 +- 4 files changed, 61 insertions(+), 14 deletions(-) diff --git a/extensions/guacamole-vault/modules/guacamole-vault-ksm/src/main/java/org/apache/guacamole/vault/ksm/conf/KsmConfigurationService.java b/extensions/guacamole-vault/modules/guacamole-vault-ksm/src/main/java/org/apache/guacamole/vault/ksm/conf/KsmConfigurationService.java index 5571ef9df..197b979e2 100644 --- a/extensions/guacamole-vault/modules/guacamole-vault-ksm/src/main/java/org/apache/guacamole/vault/ksm/conf/KsmConfigurationService.java +++ b/extensions/guacamole-vault/modules/guacamole-vault-ksm/src/main/java/org/apache/guacamole/vault/ksm/conf/KsmConfigurationService.java @@ -28,6 +28,7 @@ import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleServerException; import org.apache.guacamole.environment.Environment; import org.apache.guacamole.properties.BooleanGuacamoleProperty; +import org.apache.guacamole.properties.LongGuacamoleProperty; import org.apache.guacamole.properties.StringGuacamoleProperty; import org.apache.guacamole.vault.conf.VaultConfigurationService; @@ -120,6 +121,17 @@ public class KsmConfigurationService extends VaultConfigurationService { } }; + /** + * The minimum number of milliseconds between KSM API calls. + */ + private static final LongGuacamoleProperty KSM_API_CALL_INTERVAL = new LongGuacamoleProperty() { + + @Override + public String getName() { + return "ksm-api-call-interval"; + } + }; + /** * Creates a new KsmConfigurationService which reads the configuration * from "ksm-token-mapping.yml" and properties from @@ -176,6 +188,20 @@ public class KsmConfigurationService extends VaultConfigurationService { return environment.getProperty(MATCH_USER_DOMAINS, false); } + /** + * Return the minimum number of milliseconds between KSM API calls. If not + * otherwise configured, this value will be 10 seconds. + * + * @return + * The minimum number of milliseconds between KSM API calls. + * + * @throws GuacamoleException + * If the value specified within guacamole.properties cannot be + * parsed or does not exist. + */ + public long getKsmApiInterval() throws GuacamoleException { + return environment.getProperty(KSM_API_CALL_INTERVAL, 10000L); + } /** * Return the globally-defined base-64-encoded JSON KSM configuration blob @@ -189,7 +215,12 @@ public class KsmConfigurationService extends VaultConfigurationService { * If the value specified within guacamole.properties cannot be * parsed or does not exist. */ + @Nonnull + @SuppressWarnings("null") public String getKsmConfig() throws GuacamoleException { + + // This will always return a non-null value; an exception would be + // thrown if the required value is not set return environment.getRequiredProperty(KSM_CONFIG); } @@ -235,6 +266,7 @@ public class KsmConfigurationService extends VaultConfigurationService { * @throws GuacamoleException * If an invalid ksmConfig parameter is provided. */ + @Nonnull public SecretsManagerOptions getSecretsManagerOptions(@Nonnull String ksmConfig) throws GuacamoleException { return new SecretsManagerOptions( diff --git a/extensions/guacamole-vault/modules/guacamole-vault-ksm/src/main/java/org/apache/guacamole/vault/ksm/secret/KsmClient.java b/extensions/guacamole-vault/modules/guacamole-vault-ksm/src/main/java/org/apache/guacamole/vault/ksm/secret/KsmClient.java index 3aa436f69..1dbcd73a8 100644 --- a/extensions/guacamole-vault/modules/guacamole-vault-ksm/src/main/java/org/apache/guacamole/vault/ksm/secret/KsmClient.java +++ b/extensions/guacamole-vault/modules/guacamole-vault-ksm/src/main/java/org/apache/guacamole/vault/ksm/secret/KsmClient.java @@ -95,12 +95,6 @@ public class KsmClient { */ private static final Pattern KEEPER_FILE_NOTATION = Pattern.compile("^(keeper://)?[^/]*/file/.+"); - /** - * The maximum amount of time that an entry will be stored in the cache - * before being refreshed, in milliseconds. - */ - private static final long CACHE_INTERVAL = 5000; - /** * The KSM configuration associated with this client instance. */ @@ -115,6 +109,13 @@ public class KsmClient { */ private final ReadWriteLock cacheLock = new ReentrantReadWriteLock(); + /** + * The maximum amount of time that an entry will be stored in the cache + * before being refreshed, in milliseconds. This is also the shortest + * possible interval between API calls to KSM. + */ + private final long cacheInterval; + /** * The timestamp that the cache was last refreshed, in milliseconds, as * returned by System.currentTimeMillis(). This value is automatically @@ -215,19 +216,27 @@ public class KsmClient { private final Set cachedAmbiguousDomains = new HashSet<>(); /** - * Create a new KSM client based around the provided KSM configuration. + * Create a new KSM client based around the provided KSM configuration and + * API timeout setting. * * @param ksmConfig * The KSM configuration to use when retrieving properties from KSM. + * + * @param apiInterval + * The minimum number of milliseconds that must elapse between KSM API + * calls. */ @AssistedInject - public KsmClient(@Assisted SecretsManagerOptions ksmConfig) { + public KsmClient( + @Assisted SecretsManagerOptions ksmConfig, + @Assisted long apiInterval) { this.ksmConfig = ksmConfig; + this.cacheInterval = apiInterval; } /** * Validates that all cached data is current with respect to - * {@link #CACHE_INTERVAL}, refreshing data from the server as needed. + * {@link #cacheInterval}, refreshing data from the server as needed. * * @throws GuacamoleException * If an error occurs preventing the cached data from being refreshed. @@ -240,7 +249,7 @@ public class KsmClient { // continuing cacheLock.readLock().lock(); try { - if (currentTime - cacheTimestamp < CACHE_INTERVAL) + if (currentTime - cacheTimestamp < cacheInterval) return; } finally { @@ -252,7 +261,7 @@ public class KsmClient { // Cache may have been updated since the read-only check. Re-verify // that the cache has expired before continuing with a full refresh - if (currentTime - cacheTimestamp < CACHE_INTERVAL) + if (currentTime - cacheTimestamp < cacheInterval) return; // Attempt to pull all records first, allowing that operation to diff --git a/extensions/guacamole-vault/modules/guacamole-vault-ksm/src/main/java/org/apache/guacamole/vault/ksm/secret/KsmClientFactory.java b/extensions/guacamole-vault/modules/guacamole-vault-ksm/src/main/java/org/apache/guacamole/vault/ksm/secret/KsmClientFactory.java index f8220c16f..d97711893 100644 --- a/extensions/guacamole-vault/modules/guacamole-vault-ksm/src/main/java/org/apache/guacamole/vault/ksm/secret/KsmClientFactory.java +++ b/extensions/guacamole-vault/modules/guacamole-vault-ksm/src/main/java/org/apache/guacamole/vault/ksm/secret/KsmClientFactory.java @@ -30,16 +30,21 @@ public interface KsmClientFactory { /** * Returns a new instance of a KsmClient instance associated with - * the provided KSM configuration options. + * the provided KSM configuration options and API interval. * * @param ksmConfigOptions * The KSM config options to use when constructing the KsmClient * object. * + * @param apiInterval + * The minimum number of milliseconds that must elapse between KSM API + * calls. + * * @return * A new KsmClient instance associated with the provided KSM config * options. */ - KsmClient create(@Nonnull SecretsManagerOptions ksmConfigOptions); + KsmClient create( + @Nonnull SecretsManagerOptions ksmConfigOptions, long apiInterval); } diff --git a/extensions/guacamole-vault/modules/guacamole-vault-ksm/src/main/java/org/apache/guacamole/vault/ksm/secret/KsmSecretService.java b/extensions/guacamole-vault/modules/guacamole-vault-ksm/src/main/java/org/apache/guacamole/vault/ksm/secret/KsmSecretService.java index f4d3c0626..717a125e3 100644 --- a/extensions/guacamole-vault/modules/guacamole-vault-ksm/src/main/java/org/apache/guacamole/vault/ksm/secret/KsmSecretService.java +++ b/extensions/guacamole-vault/modules/guacamole-vault-ksm/src/main/java/org/apache/guacamole/vault/ksm/secret/KsmSecretService.java @@ -124,7 +124,7 @@ public class KsmSecretService implements VaultSecretService { // Create and store a new KSM client instance for the provided KSM config blob SecretsManagerOptions options = confService.getSecretsManagerOptions(ksmConfig); - ksmClient = ksmClientFactory.create(options); + ksmClient = ksmClientFactory.create(options, confService.getKsmApiInterval()); KsmClient prevClient = ksmClientMap.putIfAbsent(ksmConfig, ksmClient); // If the client was already set before this thread got there, use the existing one @@ -274,6 +274,7 @@ public class KsmSecretService implements VaultSecretService { * no KSM config is found in the connection group tree, and the value is also not * defined in the config file. */ + @Nonnull private String getConnectionGroupKsmConfig( UserContext userContext, Connectable connectable) throws GuacamoleException {