diff --git a/extensions/guacamole-vault/modules/guacamole-vault-base/src/main/java/org/apache/guacamole/vault/user/VaultUserContext.java b/extensions/guacamole-vault/modules/guacamole-vault-base/src/main/java/org/apache/guacamole/vault/user/VaultUserContext.java index eeddbe8d1c..954b7eed2b 100644 --- a/extensions/guacamole-vault/modules/guacamole-vault-base/src/main/java/org/apache/guacamole/vault/user/VaultUserContext.java +++ b/extensions/guacamole-vault/modules/guacamole-vault-base/src/main/java/org/apache/guacamole/vault/user/VaultUserContext.java @@ -27,6 +27,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.stream.Collectors; @@ -357,6 +358,50 @@ protected void addTokens(ConnectionGroup connectionGroup, connectionGroup, confService.getTokenMapping(), filter, null, new TokenFilter(tokens)))); + // For BALANCING groups, the JDBC layer selects and connects a child + // connection internally, bypassing the vault's addTokens(Connection). + // Pre-resolve vault tokens for child connections here so they are + // available when the JDBC layer applies tokens to the child's config. + if (connectionGroup.getType() == ConnectionGroup.Type.BALANCING) { + + Set childIds; + try { + childIds = connectionGroup.getConnectionIdentifiers(); + } + catch (GuacamoleException e) { + logger.debug("Unable to retrieve child connection identifiers " + + "for BALANCING group \"{}\": {}", identifier, + e.getMessage()); + return; + } + + for (String childId : childIds) { + try { + + Connection child = getPrivileged() + .getConnectionDirectory().get(childId); + if (child == null) + continue; + + logger.debug("Resolving vault tokens for BALANCING " + + "child connection \"{}\" (\"{}\").", + child.getIdentifier(), child.getName()); + + // Delegate to addTokens(Connection) to reuse the + // same token resolution logic used for direct + // connections, avoiding duplication and ensuring + // all extension-contributed tokens are included + addTokens(child, tokens); + + } + catch (GuacamoleException e) { + logger.debug("Unable to resolve vault tokens for " + + "child connection \"{}\": {}", + childId, e.getMessage()); + } + } + } + } /** diff --git a/extensions/guacamole-vault/modules/guacamole-vault-ksm/src/main/java/org/apache/guacamole/vault/ksm/secret/KsmSecretService.java b/extensions/guacamole-vault/modules/guacamole-vault-ksm/src/main/java/org/apache/guacamole/vault/ksm/secret/KsmSecretService.java index 9ed606cd77..5276aad90e 100644 --- a/extensions/guacamole-vault/modules/guacamole-vault-ksm/src/main/java/org/apache/guacamole/vault/ksm/secret/KsmSecretService.java +++ b/extensions/guacamole-vault/modules/guacamole-vault-ksm/src/main/java/org/apache/guacamole/vault/ksm/secret/KsmSecretService.java @@ -520,6 +520,11 @@ public Map> getTokens(UserContext userContext, Connectabl GuacamoleConfiguration config, TokenFilter filter) throws GuacamoleException { Map> tokens = new HashMap<>(); + + // Connection groups have no GuacamoleConfiguration — nothing to resolve + if (config == null) + return tokens; + Map parameters = config.getParameters(); // Only use the user-specific KSM config if explicitly enabled in the global