Merge changes from patch branch back to main.

This commit is contained in:
Michael Jumper committed 2025-09-04 10:33:23 -07:00
commit 4a7ee78b12
11 files changed
+142 -14

No files matched your search

@@ -60,7 +60,7 @@
<dependency>
<groupId>com.keepersecurity.secrets-manager</groupId>
<artifactId>core</artifactId>
<version>17.0.0</version>
<version>17.1.1</version>
<!-- Correct version conflict (different versions across transitive
dependencies) -->
@@ -24,9 +24,11 @@ import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;
import com.keepersecurity.secretsManager.core.Hosts;
import com.keepersecurity.secretsManager.core.KeeperRecord;
import com.keepersecurity.secretsManager.core.KeeperRecordLink;
import com.keepersecurity.secretsManager.core.KeeperSecrets;
import com.keepersecurity.secretsManager.core.Login;
import com.keepersecurity.secretsManager.core.Notation;
import com.keepersecurity.secretsManager.core.QueryOptions;
import com.keepersecurity.secretsManager.core.SecretsManager;
import com.keepersecurity.secretsManager.core.SecretsManagerOptions;
@@ -156,6 +158,22 @@ public class KsmClient {
*/
private final Map<String, KeeperRecord> cachedRecordsByHost = new HashMap<>();
/**
* All linked admin records retrieved from Keeper Secrets Manager, where each key is a
* KeeperRecord and the value is its associated linked admin KeeperRecord. The contents
* of this Map are automatically updated if {@link #validateCache()} refreshes the cache.
* This Map must not be accessed without {@link #cacheLock} acquired appropriately.
*/
private final Map<KeeperRecord, KeeperRecord> cachedLinkedAdminRecords = new HashMap<>();
/**
* All linked launch records retrieved from Keeper Secrets Manager, where each key is a
* KeeperRecord and the value is its associated linked launch KeeperRecord. The contents
* of this Map are automatically updated if {@link #validateCache()} refreshes the cache.
* This Map must not be accessed without {@link #cacheLock} acquired appropriately.
*/
private final Map<KeeperRecord, KeeperRecord> cachedLinkedLaunchRecords = new HashMap<>();
/**
* The set of all hostnames or IP addresses that are associated with
* multiple records, and thus cannot uniquely identify a record. The
@@ -264,9 +282,16 @@ public class KsmClient {
if (currentTime - cacheTimestamp < cacheInterval)
return;
// Enable GraphSync
QueryOptions queryOptions = new QueryOptions(
Collections.emptyList(),
Collections.emptyList(),
true
);
// Attempt to pull all records first, allowing that operation to
// succeed/fail BEFORE we clear out the last cached success
KeeperSecrets secrets = SecretsManager.getSecrets(ksmConfig);
KeeperSecrets secrets = SecretsManager.getSecrets2(ksmConfig, queryOptions);
List<KeeperRecord> records = secrets.getRecords();
// Store all secrets within cache
@@ -275,6 +300,10 @@ public class KsmClient {
// Clear unambiguous cache of all records by UID
cachedRecordsByUid.clear();
// Clear cache of all linked records
cachedLinkedAdminRecords.clear();
cachedLinkedLaunchRecords.clear();
// Clear cache of host-based records
cachedAmbiguousHosts.clear();
cachedRecordsByHost.clear();
@@ -339,6 +368,9 @@ public class KsmClient {
});
// Run through again and build a cache of linked records
records.forEach(record -> cacheLinkedRecords(record));
// Cache has been refreshed
this.cacheTimestamp = System.currentTimeMillis();
@@ -397,6 +429,42 @@ public class KsmClient {
}
/**
* Populates {@link #cachedLinkedAdminRecords} and {@link #cachedLinkedLaunchRecords}
* with any linked admin or launch records from the provided record. The write lock of
* {@link #cacheLock} must already be acquired before invoking this function.
*
* @param record
* The record whose linked records should be processed and cached.
*/
private void cacheLinkedRecords(KeeperRecord record) {
List<KeeperRecordLink> links = record.getLinks();
if (links != null && !links.isEmpty()) {
for (KeeperRecordLink link : links) {
KeeperRecord linkedRecord = cachedRecordsByUid.get(link.getRecordUid());
if (linkedRecord != null && link.isAdminUser()) {
if (cachedLinkedAdminRecords.containsKey(record)) {
logger.warn("Multiple 'admin' linked records exist "
+ "for record UID: {}", record.getRecordUid());
}
cachedLinkedAdminRecords.put(record, linkedRecord);
}
if (linkedRecord != null && link.isLaunchCredential()) {
if (cachedLinkedLaunchRecords.containsKey(record)) {
logger.warn("Multiple 'launch' linked records exist "
+ "for record UID: {}", record.getRecordUid());
}
cachedLinkedLaunchRecords.put(record, linkedRecord);
}
}
}
}
/**
* Associates the given record with the given user, and optional domain.
* The given username or domain may be null. Both {@link #cachedRecordsByUser}
@@ -587,6 +655,54 @@ public class KsmClient {
}
}
/**
* Returns the linked admin record for the given Keeper record, if one exists.
* If no such linked admin record exists, null is returned.
*
* @param record
* The KeeperRecord for which to retrieve the linked admin record.
*
* @return
* The linked KeeperRecord, or null if there is no such record.
*
* @throws GuacamoleException
* If an error occurs that prevents the linked record from being retrieved.
*/
public KeeperRecord getLinkedAdminRecord(KeeperRecord record) throws GuacamoleException {
validateCache();
cacheLock.readLock().lock();
try {
return cachedLinkedAdminRecords.get(record);
}
finally {
cacheLock.readLock().unlock();
}
}
/**
* Returns the linked launch record for the given Keeper record, if one exists.
* If no such linked launch record exists, null is returned.
*
* @param record
* The KeeperRecord for which to retrieve the linked launch record.
*
* @return
* The linked KeeperRecord, or null if there is no such record.
*
* @throws GuacamoleException
* If an error occurs that prevents the linked record from being retrieved.
*/
public KeeperRecord getLinkedLaunchRecord(KeeperRecord record) throws GuacamoleException {
validateCache();
cacheLock.readLock().lock();
try {
return cachedLinkedLaunchRecords.get(record);
}
finally {
cacheLock.readLock().unlock();
}
}
/**
* Returns the value of the secret stored within Keeper Secrets Manager and
* represented by the given Keeper notation. Keeper notation locates the
@@ -370,7 +370,7 @@ public class KsmSecretService implements VaultSecretService {
*
* @param connectable
* The connectable to which the connection is being established. This
* is the conneciton which will be checked to see if user KSM configs
* is the connection which will be checked to see if user KSM configs
* are enabled.
*
* @return
@@ -435,18 +435,30 @@ public class KsmSecretService implements VaultSecretService {
// Retrieve and define server-specific tokens, if any
String hostname = parameters.get("hostname");
if (hostname != null && !hostname.isEmpty())
if (hostname != null && !hostname.isEmpty()) {
KeeperRecord record = ksm.getRecordByHost(filter.filter(hostname));
KeeperRecord adminRecord = ksm.getLinkedAdminRecord(record);
KeeperRecord launchRecord = ksm.getLinkedLaunchRecord(record);
addRecordTokens(tokens, "KEEPER_SERVER_",
ksm.getRecordByHost(filter.filter(hostname)));
adminRecord != null ? adminRecord : record);
addRecordTokens(tokens, "KEEPER_SERVER_ADMIN_", adminRecord);
addRecordTokens(tokens, "KEEPER_SERVER_LAUNCH_", launchRecord);
}
// Tokens specific to RDP
if ("rdp".equals(config.getProtocol())) {
// Retrieve and define gateway server-specific tokens, if any
String gatewayHostname = parameters.get("gateway-hostname");
if (gatewayHostname != null && !gatewayHostname.isEmpty())
if (gatewayHostname != null && !gatewayHostname.isEmpty()) {
KeeperRecord record = ksm.getRecordByHost(filter.filter(gatewayHostname));
KeeperRecord adminRecord = ksm.getLinkedAdminRecord(record);
KeeperRecord launchRecord = ksm.getLinkedLaunchRecord(record);
addRecordTokens(tokens, "KEEPER_GATEWAY_",
ksm.getRecordByHost(filter.filter(gatewayHostname)));
adminRecord != null ? adminRecord : record);
addRecordTokens(tokens, "KEEPER_GATEWAY_ADMIN_", adminRecord);
addRecordTokens(tokens, "KEEPER_GATEWAY_LAUNCH_", launchRecord);
}
// Retrieve and define domain tokens, if any
String domain = parameters.get("domain");
@@ -518,7 +530,7 @@ public class KsmSecretService implements VaultSecretService {
config, getClient(userKsmConfig), tokens, parameters, filter);
// Add connection group or globally defined tokens after the user-specific
// ones to ensure that the user config will be overriden on collision
// ones to ensure that the user config will be overridden on collision
String ksmConfig = getConnectionGroupKsmConfig(userContext, connectable);
addConnectableTokens(
config, getClient(ksmConfig), tokens, parameters, filter);