GUACAMOLE-1772: Merge support for configuring KSM API call interval.

This commit is contained in:
Mike Jumper
2022-11-30 09:31:52 -08:00
committed by GitHub
4 changed files with 61 additions and 14 deletions

View File

@@ -28,6 +28,7 @@ import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleServerException; import org.apache.guacamole.GuacamoleServerException;
import org.apache.guacamole.environment.Environment; import org.apache.guacamole.environment.Environment;
import org.apache.guacamole.properties.BooleanGuacamoleProperty; import org.apache.guacamole.properties.BooleanGuacamoleProperty;
import org.apache.guacamole.properties.LongGuacamoleProperty;
import org.apache.guacamole.properties.StringGuacamoleProperty; import org.apache.guacamole.properties.StringGuacamoleProperty;
import org.apache.guacamole.vault.conf.VaultConfigurationService; 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 * Creates a new KsmConfigurationService which reads the configuration
* from "ksm-token-mapping.yml" and properties from * 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 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 * 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 * If the value specified within guacamole.properties cannot be
* parsed or does not exist. * parsed or does not exist.
*/ */
@Nonnull
@SuppressWarnings("null")
public String getKsmConfig() throws GuacamoleException { 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); return environment.getRequiredProperty(KSM_CONFIG);
} }
@@ -235,6 +266,7 @@ public class KsmConfigurationService extends VaultConfigurationService {
* @throws GuacamoleException * @throws GuacamoleException
* If an invalid ksmConfig parameter is provided. * If an invalid ksmConfig parameter is provided.
*/ */
@Nonnull
public SecretsManagerOptions getSecretsManagerOptions(@Nonnull String ksmConfig) throws GuacamoleException { public SecretsManagerOptions getSecretsManagerOptions(@Nonnull String ksmConfig) throws GuacamoleException {
return new SecretsManagerOptions( return new SecretsManagerOptions(

View File

@@ -95,12 +95,6 @@ public class KsmClient {
*/ */
private static final Pattern KEEPER_FILE_NOTATION = Pattern.compile("^(keeper://)?[^/]*/file/.+"); 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. * The KSM configuration associated with this client instance.
*/ */
@@ -115,6 +109,13 @@ public class KsmClient {
*/ */
private final ReadWriteLock cacheLock = new ReentrantReadWriteLock(); 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 * The timestamp that the cache was last refreshed, in milliseconds, as
* returned by System.currentTimeMillis(). This value is automatically * returned by System.currentTimeMillis(). This value is automatically
@@ -215,19 +216,27 @@ public class KsmClient {
private final Set<String> cachedAmbiguousDomains = new HashSet<>(); private final Set<String> 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 * @param ksmConfig
* The KSM configuration to use when retrieving properties from KSM. * 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 @AssistedInject
public KsmClient(@Assisted SecretsManagerOptions ksmConfig) { public KsmClient(
@Assisted SecretsManagerOptions ksmConfig,
@Assisted long apiInterval) {
this.ksmConfig = ksmConfig; this.ksmConfig = ksmConfig;
this.cacheInterval = apiInterval;
} }
/** /**
* Validates that all cached data is current with respect to * 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 * @throws GuacamoleException
* If an error occurs preventing the cached data from being refreshed. * If an error occurs preventing the cached data from being refreshed.
@@ -240,7 +249,7 @@ public class KsmClient {
// continuing // continuing
cacheLock.readLock().lock(); cacheLock.readLock().lock();
try { try {
if (currentTime - cacheTimestamp < CACHE_INTERVAL) if (currentTime - cacheTimestamp < cacheInterval)
return; return;
} }
finally { finally {
@@ -252,7 +261,7 @@ public class KsmClient {
// Cache may have been updated since the read-only check. Re-verify // Cache may have been updated since the read-only check. Re-verify
// that the cache has expired before continuing with a full refresh // that the cache has expired before continuing with a full refresh
if (currentTime - cacheTimestamp < CACHE_INTERVAL) if (currentTime - cacheTimestamp < cacheInterval)
return; return;
// Attempt to pull all records first, allowing that operation to // Attempt to pull all records first, allowing that operation to

View File

@@ -30,16 +30,21 @@ public interface KsmClientFactory {
/** /**
* Returns a new instance of a KsmClient instance associated with * 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 * @param ksmConfigOptions
* The KSM config options to use when constructing the KsmClient * The KSM config options to use when constructing the KsmClient
* object. * object.
* *
* @param apiInterval
* The minimum number of milliseconds that must elapse between KSM API
* calls.
*
* @return * @return
* A new KsmClient instance associated with the provided KSM config * A new KsmClient instance associated with the provided KSM config
* options. * options.
*/ */
KsmClient create(@Nonnull SecretsManagerOptions ksmConfigOptions); KsmClient create(
@Nonnull SecretsManagerOptions ksmConfigOptions, long apiInterval);
} }

View File

@@ -124,7 +124,7 @@ public class KsmSecretService implements VaultSecretService {
// Create and store a new KSM client instance for the provided KSM config blob // Create and store a new KSM client instance for the provided KSM config blob
SecretsManagerOptions options = confService.getSecretsManagerOptions(ksmConfig); SecretsManagerOptions options = confService.getSecretsManagerOptions(ksmConfig);
ksmClient = ksmClientFactory.create(options); ksmClient = ksmClientFactory.create(options, confService.getKsmApiInterval());
KsmClient prevClient = ksmClientMap.putIfAbsent(ksmConfig, ksmClient); KsmClient prevClient = ksmClientMap.putIfAbsent(ksmConfig, ksmClient);
// If the client was already set before this thread got there, use the existing one // 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 * no KSM config is found in the connection group tree, and the value is also not
* defined in the config file. * defined in the config file.
*/ */
@Nonnull
private String getConnectionGroupKsmConfig( private String getConnectionGroupKsmConfig(
UserContext userContext, Connectable connectable) throws GuacamoleException { UserContext userContext, Connectable connectable) throws GuacamoleException {