GUACAMOLE-2219: Fix vault token resolution for BALANCING groups#1163
GUACAMOLE-2219: Fix vault token resolution for BALANCING groups#1163subbareddyalamur wants to merge 1 commit intoapache:mainfrom
Conversation
98e3ee3 to
8998fca
Compare
| for (String childId : childIds) { | ||
| try { | ||
|
|
||
| Connection child = getPrivileged() | ||
| .getConnectionDirectory().get(childId); | ||
| if (child == null) | ||
| continue; | ||
|
|
||
| GuacamoleConfiguration childConfig = | ||
| child.getConfiguration(); | ||
| if (childConfig == null) | ||
| continue; | ||
|
|
||
| logger.debug("Resolving vault tokens for BALANCING " | ||
| + "child connection \"{}\" (\"{}\").", | ||
| child.getIdentifier(), child.getName()); | ||
|
|
||
| TokenFilter childFilter = createFilter(); | ||
| childFilter.setToken(CONNECTION_NAME_TOKEN, | ||
| child.getName()); | ||
| childFilter.setToken(CONNECTION_IDENTIFIER_TOKEN, | ||
| child.getIdentifier()); | ||
|
|
||
| Map<String, String> parameters = | ||
| childConfig.getParameters(); | ||
|
|
||
| String hostname = parameters.get("hostname"); | ||
| if (hostname != null && !hostname.isEmpty()) | ||
| childFilter.setToken(CONNECTION_HOSTNAME_TOKEN, | ||
| hostname); | ||
|
|
||
| String username = parameters.get("username"); | ||
| if (username != null && !username.isEmpty()) | ||
| childFilter.setToken(CONNECTION_USERNAME_TOKEN, | ||
| username); | ||
|
|
||
| tokens.putAll(resolve(getTokens(child, | ||
| confService.getTokenMapping(), childFilter, | ||
| childConfig, new TokenFilter(tokens)))); | ||
|
|
||
| } |
There was a problem hiding this comment.
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...
|
@necouchman Thank you for the review. I've refactored the approach based on your feedback. Instead of manually building tokens for each BALANCING child (which duplicated the logic in for (String childId : childIds) {
Connection child = getPrivileged()
.getConnectionDirectory().get(childId);
if (child == null) continue;
addTokens(child, tokens);
}This eliminates the code duplication entirely — the same Regarding other extensions' tokens (LDAP attributes, SSO tokens): this is a deeper issue in the JDBC BALANCING pipeline itself — |
8998fca to
d12222a
Compare
|
@subbareddyalamur I certainly like the new approach better - I think calling the existing functions is preferable to rewriting all of the logic within that block. That said, I'm still a little unsure as to whether or not we want to preload the data for all of the connections? It seems like there ought to be a way to have the resolution of these tokens done after the connection is selected? |
@necouchman Not feasible without changes to the JDBC tunnel layer. The resolution would require introducing a new hook in AbstractGuacamoleTunnelService (JDBC layer), which is out of scope for a vault-only fix. The pre-resolution approach is a tradeoff — slightly more work upfront, but it stays within the vault extension's boundaries without touching the core tunnel service |
Summary
When connecting through a BALANCING connection group, the JDBC layer internally selects and connects a child connection, bypassing the vault extension's
TokenInjectingConnectionwrapper. This meansaddTokens(Connection)is never called for the selected child, and vault-managed tokens (e.g.KEEPER_USER_PASSWORD) are not resolved — causing authentication failures on the child connection.This PR fixes two related issues:
VaultUserContext.addTokens(ConnectionGroup)now detects BALANCING groups and pre-resolves vault tokens for all child connections, ensuring tokens are available when the JDBC layer applies them to the selected child's configurationKsmSecretService.getTokens()now guards againstnullGuacamoleConfiguration, which is always null for connection groups (they have no protocol configuration). Previously this caused aNullPointerExceptionRoot Cause
TokenInjectingConnectionGroup.connect()callsaddTokens(ConnectionGroup)and then delegates to the underlying JDBC connection group. For BALANCING groups,AbstractGuacamoleTunnelServiceacquires the child connection internally and connects it directly — the child is a rawModeledConnection, NOT wrapped byTokenInjectingConnection. ThereforeaddTokens(Connection)is never invoked for the child, and vault tokens that depend on connection parameters (hostname, username) are never resolved.Changes
VaultUserContext.javaaddTokens(ConnectionGroup)and resolve vault tokens for each child using privileged access to connection configurationKsmSecretService.javagetTokens()whenconfigis null (connection groups have noGuacamoleConfiguration)Test Plan
NullPointerExceptionin logs when connecting through any connection group type