mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-07 05:31:22 +00:00
GUACAMOLE-641: Use record service to resolve hostname/username of records for later lookup.
This commit is contained in:
@@ -71,6 +71,12 @@ public class KsmClient {
|
|||||||
@Inject
|
@Inject
|
||||||
private KsmConfigurationService confService;
|
private KsmConfigurationService confService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service for retrieving data from records.
|
||||||
|
*/
|
||||||
|
@Inject
|
||||||
|
private KsmRecordService recordService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The publicly-accessible URL for Keeper's documentation covering Keeper
|
* The publicly-accessible URL for Keeper's documentation covering Keeper
|
||||||
* notation.
|
* notation.
|
||||||
@@ -226,28 +232,17 @@ public class KsmClient {
|
|||||||
cachedRecordsByUsername.clear();
|
cachedRecordsByUsername.clear();
|
||||||
|
|
||||||
// Store all records, sorting each into host-based and login-based
|
// Store all records, sorting each into host-based and login-based
|
||||||
// buckets (note that a single record may be associated with
|
// buckets
|
||||||
// multiple hosts and logins)
|
|
||||||
records.forEach(record -> {
|
records.forEach(record -> {
|
||||||
|
|
||||||
// Store based on UID ...
|
// Store based on UID ...
|
||||||
cachedRecordsByUid.put(record.getRecordUid(), record);
|
cachedRecordsByUid.put(record.getRecordUid(), record);
|
||||||
|
|
||||||
// ... and standard fields ...
|
// ... and hostname/address ...
|
||||||
KeeperRecordData data = record.getData();
|
addRecordForHost(record, recordService.getHostname(record));
|
||||||
addRecordForHosts(record, (Hosts) data.getField(Hosts.class));
|
|
||||||
addRecordForLogin(record, (Login) data.getField(Login.class));
|
|
||||||
|
|
||||||
// ... and custom fields
|
// ... and username
|
||||||
List<KeeperRecordField> custom = data.getCustom();
|
addRecordForLogin(record, recordService.getUsername(record));
|
||||||
if (custom != null) {
|
|
||||||
custom.forEach(field -> {
|
|
||||||
if (field instanceof Hosts)
|
|
||||||
addRecordForHosts(record, (Hosts) field);
|
|
||||||
else if (field instanceof Login)
|
|
||||||
addRecordForLogin(record, (Login) field);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -262,62 +257,51 @@ public class KsmClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Associates the given record with each of the hosts in the given Hosts
|
* Associates the given record with the given hostname. The hostname may be
|
||||||
* field. The given Hosts field may be null. Both {@link #cachedRecordsByHost}
|
* null. Both {@link #cachedRecordsByHost} and {@link #cachedAmbiguousHosts}
|
||||||
* and {@link #cachedAmbiguousHosts} are updated appropriately. The write
|
|
||||||
* lock of {@link #cacheLock} must already be acquired before invoking this
|
|
||||||
* function.
|
|
||||||
*
|
|
||||||
* @param record
|
|
||||||
* The record to associate with the hosts in the given field.
|
|
||||||
*
|
|
||||||
* @param hosts
|
|
||||||
* The Hosts field containing the hosts that the given record should be
|
|
||||||
* associated with. This may be null.
|
|
||||||
*/
|
|
||||||
private void addRecordForHosts(KeeperRecord record, Hosts hosts) {
|
|
||||||
|
|
||||||
if (hosts == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
hosts.getValue().stream().map(host -> host.getHostName())
|
|
||||||
.forEachOrdered(hostname -> {
|
|
||||||
|
|
||||||
KeeperRecord existing = cachedRecordsByHost.putIfAbsent(hostname, record);
|
|
||||||
if (existing != null && record != existing)
|
|
||||||
cachedAmbiguousHosts.add(hostname);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Associates the given record with each of the usernames in the given
|
|
||||||
* Login field. The given Hosts field may be null. Both
|
|
||||||
* {@link #cachedRecordsByUsername} and {@link #cachedAmbiguousUsernames}
|
|
||||||
* are updated appropriately. The write lock of {@link #cacheLock} must
|
* are updated appropriately. The write lock of {@link #cacheLock} must
|
||||||
* already be acquired before invoking this function.
|
* already be acquired before invoking this function.
|
||||||
*
|
*
|
||||||
* @param record
|
* @param record
|
||||||
* The record to associate with the hosts in the given field.
|
* The record to associate with the hosts in the given field.
|
||||||
*
|
*
|
||||||
* @param login
|
* @param hostname
|
||||||
* The Login field containing the usernames that the given record
|
* The hostname/address that the given record should be associated
|
||||||
* should be associated with. This may be null.
|
* with. This may be null.
|
||||||
*/
|
*/
|
||||||
private void addRecordForLogin(KeeperRecord record, Login login) {
|
private void addRecordForHost(KeeperRecord record, String hostname) {
|
||||||
|
|
||||||
if (login == null)
|
if (hostname == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
login.getValue().stream()
|
KeeperRecord existing = cachedRecordsByHost.putIfAbsent(hostname, record);
|
||||||
.forEachOrdered(username -> {
|
if (existing != null && record != existing)
|
||||||
|
cachedAmbiguousHosts.add(hostname);
|
||||||
|
|
||||||
KeeperRecord existing = cachedRecordsByUsername.putIfAbsent(username, record);
|
}
|
||||||
if (existing != null && record != existing)
|
|
||||||
cachedAmbiguousUsernames.add(username);
|
|
||||||
|
|
||||||
});
|
/**
|
||||||
|
* Associates the given record with the given username. The given username
|
||||||
|
* may be null. Both {@link #cachedRecordsByUsername} and
|
||||||
|
* {@link #cachedAmbiguousUsernames} are updated appropriately. The write
|
||||||
|
* lock of {@link #cacheLock} must already be acquired before invoking this
|
||||||
|
* function.
|
||||||
|
*
|
||||||
|
* @param record
|
||||||
|
* The record to associate with the given username.
|
||||||
|
*
|
||||||
|
* @param username
|
||||||
|
* The username that the given record should be associated with. This
|
||||||
|
* may be null.
|
||||||
|
*/
|
||||||
|
private void addRecordForLogin(KeeperRecord record, String username) {
|
||||||
|
|
||||||
|
if (username == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
KeeperRecord existing = cachedRecordsByUsername.putIfAbsent(username, record);
|
||||||
|
if (existing != null && record != existing)
|
||||||
|
cachedAmbiguousUsernames.add(username);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -21,6 +21,8 @@ package org.apache.guacamole.vault.ksm.secret;
|
|||||||
|
|
||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
import com.keepersecurity.secretsManager.core.HiddenField;
|
import com.keepersecurity.secretsManager.core.HiddenField;
|
||||||
|
import com.keepersecurity.secretsManager.core.Host;
|
||||||
|
import com.keepersecurity.secretsManager.core.Hosts;
|
||||||
import com.keepersecurity.secretsManager.core.KeeperRecord;
|
import com.keepersecurity.secretsManager.core.KeeperRecord;
|
||||||
import com.keepersecurity.secretsManager.core.KeeperRecordData;
|
import com.keepersecurity.secretsManager.core.KeeperRecordData;
|
||||||
import com.keepersecurity.secretsManager.core.KeeperRecordField;
|
import com.keepersecurity.secretsManager.core.KeeperRecordField;
|
||||||
@@ -40,6 +42,13 @@ import java.util.regex.Pattern;
|
|||||||
@Singleton
|
@Singleton
|
||||||
public class KsmRecordService {
|
public class KsmRecordService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Regular expression which matches the labels of custom fields containing
|
||||||
|
* hostnames/addresses.
|
||||||
|
*/
|
||||||
|
private static final Pattern HOSTNAME_LABEL_PATTERN =
|
||||||
|
Pattern.compile("hostname|(ip\\s*)?address", Pattern.CASE_INSENSITIVE);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Regular expression which matches the labels of custom fields containing
|
* Regular expression which matches the labels of custom fields containing
|
||||||
* usernames.
|
* usernames.
|
||||||
@@ -225,6 +234,44 @@ public class KsmRecordService {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the single hostname (or address) associated with the given
|
||||||
|
* record. If the record has no associated hostname, or multiple hostnames,
|
||||||
|
* null is returned. Hostnames are retrieved from "Hosts" fields, as well
|
||||||
|
* as "Text" and "Hidden" fields that have the label "hostname", "address",
|
||||||
|
* or "ip address" (case-insensitive, space optional).
|
||||||
|
*
|
||||||
|
* @param record
|
||||||
|
* The record to retrieve the hostname from.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The hostname associated with the given record, or null if the record
|
||||||
|
* has no associated hostname or multiple hostnames.
|
||||||
|
*/
|
||||||
|
public String getHostname(KeeperRecord record) {
|
||||||
|
|
||||||
|
// Prefer standard login field
|
||||||
|
Hosts hostsField = getField(record, Hosts.class, null);
|
||||||
|
if (hostsField != null)
|
||||||
|
return getSingleValue(hostsField.getValue(), Host::getHostName);
|
||||||
|
|
||||||
|
KeeperRecordData data = record.getData();
|
||||||
|
List<KeeperRecordField> custom = data.getCustom();
|
||||||
|
|
||||||
|
// Use text "hostname" custom field as fallback ...
|
||||||
|
Text textField = getField(custom, Text.class, HOSTNAME_LABEL_PATTERN);
|
||||||
|
if (textField != null)
|
||||||
|
return getSingleValue(textField.getValue());
|
||||||
|
|
||||||
|
// ... or hidden "hostname" custom field
|
||||||
|
HiddenField hiddenField = getField(custom, HiddenField.class, HOSTNAME_LABEL_PATTERN);
|
||||||
|
if (hiddenField != null)
|
||||||
|
return getSingleValue(hiddenField.getValue());
|
||||||
|
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the single username associated with the given record. If the
|
* Returns the single username associated with the given record. If the
|
||||||
* record has no associated username, or multiple usernames, null is
|
* record has no associated username, or multiple usernames, null is
|
||||||
|
Reference in New Issue
Block a user