Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<String> 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);

}
Comment on lines +378 to +396
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see what you're trying to do, but I'm not sure this is the best way to go about it. It looks to me like the code, here, basically duplicates code elsewhere, processing a handful of standard tokens (connection name/identifier, username, etc.). This creates two problems:

  • What if other extensions provide other tokens? For example, the LDAP extension provides the ability to use LDAP attributes as tokens in the connection data, as do the various SSO providers. I think the implementation, here, would not capture those correctly?
  • What happens if other tokens are added in the future? Whether processing these standard ones or all of the ones from all of the extensions, creating a location, here, where we have to maintain all of the tokens we want available and process them seems cumbersome and destined to get out-of-sync with the rest of the code.

There has to be a better way...

catch (GuacamoleException e) {
logger.debug("Unable to resolve vault tokens for "
+ "child connection \"{}\": {}",
childId, e.getMessage());
}
}
}

}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,11 @@ public Map<String, Future<String>> getTokens(UserContext userContext, Connectabl
GuacamoleConfiguration config, TokenFilter filter) throws GuacamoleException {

Map<String, Future<String>> tokens = new HashMap<>();

// Connection groups have no GuacamoleConfiguration — nothing to resolve
if (config == null)
return tokens;

Map<String, String> parameters = config.getParameters();

// Only use the user-specific KSM config if explicitly enabled in the global
Expand Down