From 741cf481d648ed1a1e3cd8c4815ac775b6cd6040 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Wed, 27 Apr 2022 19:22:04 +0000 Subject: [PATCH 1/2] GUACAMOLE-641: Ensure empty strings within KSM record fields are handled as if the field value is absent. --- .../vault/ksm/secret/KsmRecordService.java | 81 +++++++++++++++---- 1 file changed, 67 insertions(+), 14 deletions(-) diff --git a/extensions/guacamole-vault/modules/guacamole-vault-ksm/src/main/java/org/apache/guacamole/vault/ksm/secret/KsmRecordService.java b/extensions/guacamole-vault/modules/guacamole-vault-ksm/src/main/java/org/apache/guacamole/vault/ksm/secret/KsmRecordService.java index 9528ad7d6..1bb3311fa 100644 --- a/extensions/guacamole-vault/modules/guacamole-vault-ksm/src/main/java/org/apache/guacamole/vault/ksm/secret/KsmRecordService.java +++ b/extensions/guacamole-vault/modules/guacamole-vault-ksm/src/main/java/org/apache/guacamole/vault/ksm/secret/KsmRecordService.java @@ -112,6 +112,29 @@ public class KsmRecordService { } + /** + * Returns the single value stored in the given list of strings. If the + * list is empty, contains multiple values, or contains only a single empty + * string, null is returned. + * + * @param values + * The list to retrieve a single value from. + * + * @return + * The single value stored in the given list, or null if the list is + * empty, contains multiple values, or contains only a single empty + * string. + */ + private String getSingleStringValue(List values) { + + String value = getSingleValue(values); + if (value != null && !value.isEmpty()) + return value; + + return null; + + } + /** * Returns the single value stored in the given list, additionally * performing a mapping transformation on the single value. If the list is @@ -144,6 +167,36 @@ public class KsmRecordService { } + /** + * Returns the single value stored in the given list of strings, + * additionally performing a mapping transformation on the single value. If + * the list is empty, contains multiple values, or contains only a single + * empty string, null is returned. + * + * @param + * The type of object stored in the list. + * + * @param values + * The list to retrieve a single value from. + * + * @param mapper + * The function to use to map the single object of type T to type R. + * + * @return + * The single value stored in the given list, transformed using the + * provided mapping function, or null if the list is empty, contains + * multiple values, or contains only a single empty string. + */ + private String getSingleStringValue(List values, Function mapper) { + + String value = getSingleValue(values, mapper); + if (value != null && !value.isEmpty()) + return value; + + return null; + + } + /** * Returns the instance of the only field that has the given type and * matches the given label pattern. If there are no such fields, or @@ -329,7 +382,7 @@ public class KsmRecordService { // Prefer standard login field Hosts hostsField = getField(record, Hosts.class, null); if (hostsField != null) - return getSingleValue(hostsField.getValue(), Host::getHostName); + return getSingleStringValue(hostsField.getValue(), Host::getHostName); KeeperRecordData data = record.getData(); List custom = data.getCustom(); @@ -337,12 +390,12 @@ public class KsmRecordService { // Use text "hostname" custom field as fallback ... Text textField = getField(custom, Text.class, HOSTNAME_LABEL_PATTERN); if (textField != null) - return getSingleValue(textField.getValue()); + return getSingleStringValue(textField.getValue()); // ... or hidden "hostname" custom field HiddenField hiddenField = getField(custom, HiddenField.class, HOSTNAME_LABEL_PATTERN); if (hiddenField != null) - return getSingleValue(hiddenField.getValue()); + return getSingleStringValue(hiddenField.getValue()); return null; @@ -367,7 +420,7 @@ public class KsmRecordService { // Prefer standard login field Login loginField = getField(record, Login.class, null); if (loginField != null) - return getSingleValue(loginField.getValue()); + return getSingleStringValue(loginField.getValue()); KeeperRecordData data = record.getData(); List custom = data.getCustom(); @@ -375,12 +428,12 @@ public class KsmRecordService { // Use text "username" custom field as fallback ... Text textField = getField(custom, Text.class, USERNAME_LABEL_PATTERN); if (textField != null) - return getSingleValue(textField.getValue()); + return getSingleStringValue(textField.getValue()); // ... or hidden "username" custom field HiddenField hiddenField = getField(custom, HiddenField.class, USERNAME_LABEL_PATTERN); if (hiddenField != null) - return getSingleValue(hiddenField.getValue()); + return getSingleStringValue(hiddenField.getValue()); return null; @@ -403,11 +456,11 @@ public class KsmRecordService { Password passwordField = getField(record, Password.class, PASSWORD_LABEL_PATTERN); if (passwordField != null) - return getSingleValue(passwordField.getValue()); + return getSingleStringValue(passwordField.getValue()); HiddenField hiddenField = getField(record, HiddenField.class, PASSWORD_LABEL_PATTERN); if (hiddenField != null) - return getSingleValue(hiddenField.getValue()); + return getSingleStringValue(hiddenField.getValue()); return null; @@ -435,7 +488,7 @@ public class KsmRecordService { // Attempt to find single matching keypair field KeyPairs keyPairsField = getField(record, KeyPairs.class, PRIVATE_KEY_LABEL_PATTERN); if (keyPairsField != null) { - String privateKey = getSingleValue(keyPairsField.getValue(), KeyPair::getPrivateKey); + String privateKey = getSingleStringValue(keyPairsField.getValue(), KeyPair::getPrivateKey); if (privateKey != null && !privateKey.isEmpty()) return CompletableFuture.completedFuture(privateKey); } @@ -451,12 +504,12 @@ public class KsmRecordService { // Use password "private key" custom field as fallback ... Password passwordField = getField(custom, Password.class, PRIVATE_KEY_LABEL_PATTERN); if (passwordField != null) - return CompletableFuture.completedFuture(getSingleValue(passwordField.getValue())); + return CompletableFuture.completedFuture(getSingleStringValue(passwordField.getValue())); // ... or hidden "private key" custom field HiddenField hiddenField = getField(custom, HiddenField.class, PRIVATE_KEY_LABEL_PATTERN); if (hiddenField != null) - return CompletableFuture.completedFuture(getSingleValue(hiddenField.getValue())); + return CompletableFuture.completedFuture(getSingleStringValue(hiddenField.getValue())); return CompletableFuture.completedFuture(null); @@ -488,7 +541,7 @@ public class KsmRecordService { if (getField(fields, KeyPairs.class, null) != null) { Password passwordField = getField(fields, Password.class, null); if (passwordField != null) - return getSingleValue(passwordField.getValue()); + return getSingleStringValue(passwordField.getValue()); } // For records WITHOUT a standard keypair field, the passphrase can @@ -500,12 +553,12 @@ public class KsmRecordService { // Use password "private key" custom field as fallback ... Password passwordField = getField(custom, Password.class, PASSPHRASE_LABEL_PATTERN); if (passwordField != null) - return getSingleValue(passwordField.getValue()); + return getSingleStringValue(passwordField.getValue()); // ... or hidden "private key" custom field HiddenField hiddenField = getField(custom, HiddenField.class, PASSPHRASE_LABEL_PATTERN); if (hiddenField != null) - return getSingleValue(hiddenField.getValue()); + return getSingleStringValue(hiddenField.getValue()); return null; From 837a0360bebb95dce8b27c147f3e39a5fb9a3db2 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Wed, 27 Apr 2022 22:01:01 +0000 Subject: [PATCH 2/2] GUACAMOLE-641: Clarify that null will also be returned if the List actually contains null. --- .../vault/ksm/secret/KsmRecordService.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/extensions/guacamole-vault/modules/guacamole-vault-ksm/src/main/java/org/apache/guacamole/vault/ksm/secret/KsmRecordService.java b/extensions/guacamole-vault/modules/guacamole-vault-ksm/src/main/java/org/apache/guacamole/vault/ksm/secret/KsmRecordService.java index 1bb3311fa..d67b5816a 100644 --- a/extensions/guacamole-vault/modules/guacamole-vault-ksm/src/main/java/org/apache/guacamole/vault/ksm/secret/KsmRecordService.java +++ b/extensions/guacamole-vault/modules/guacamole-vault-ksm/src/main/java/org/apache/guacamole/vault/ksm/secret/KsmRecordService.java @@ -91,7 +91,8 @@ public class KsmRecordService { /** * Returns the single value stored in the given list. If the list is empty - * or contains multiple values, null is returned. + * or contains multiple values, null is returned. Note that null will also + * be returned if the single value stored in the list is itself null. * * @param * The type of object stored in the list. @@ -115,7 +116,8 @@ public class KsmRecordService { /** * Returns the single value stored in the given list of strings. If the * list is empty, contains multiple values, or contains only a single empty - * string, null is returned. + * string, null is returned. Note that null will also be returned if the + * single value stored in the list is itself null. * * @param values * The list to retrieve a single value from. @@ -138,7 +140,9 @@ public class KsmRecordService { /** * Returns the single value stored in the given list, additionally * performing a mapping transformation on the single value. If the list is - * empty or contains multiple values, null is returned. + * empty or contains multiple values, null is returned. Note that null will + * also be returned if the mapping transformation returns null for the + * single value stored in the list. * * @param * The type of object stored in the list. @@ -171,7 +175,9 @@ public class KsmRecordService { * Returns the single value stored in the given list of strings, * additionally performing a mapping transformation on the single value. If * the list is empty, contains multiple values, or contains only a single - * empty string, null is returned. + * empty string, null is returned. Note that null will also be returned if + * the mapping transformation returns null for the single value stored in + * the list. * * @param * The type of object stored in the list.