GUACAMOLE-2130: Merge support for for "linked records" in KSM integration.
This commit is contained in:
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) -->
|
||||
|
||||
+117
-1
@@ -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
|
||||
|
||||
+18
-6
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user