Skip to content

GUACAMOLE-524: Update connect() API changes for backward compatibility with 1.0.0.#360

Merged
necouchman merged 10 commits intoapache:masterfrom
mike-jumper:backward-compat
Jan 23, 2019
Merged

GUACAMOLE-524: Update connect() API changes for backward compatibility with 1.0.0.#360
necouchman merged 10 commits intoapache:masterfrom
mike-jumper:backward-compat

Conversation

@mike-jumper
Copy link
Copy Markdown
Contributor

As discussed on dev@, these changes modify the Connectable interface such that implementations of the previous version of the connect() function will continue to work, even if those implementations extended SimpleConnection and overrode the old, now-deprecated function. This is achieved through:

  1. Continuing to use the old connect() as the basis for the implementation.
  2. Using a ThreadLocal to make the additional Map<String, String> parameter available to the old connect() within a strict context.

The SimpleConnection class and related classes are also modified to provide the same behavior as past releases, particularly for downstream subclasses.

With these changes, things are ABI-compatible with 1.0.0. Things are also API-compatible with 1.0.0, though continuing to use/override the old connect() will result in compiler warnings. Behavior of the relevant classes should now be as follows:

Class Behavior in 1.0.0 and older New behavior
SimpleAuthenticationProvider Tokens are applied and "baked-in" when the user authenticates. Tokens are applied dynamically when connecting.
SimpleUserContext Tokens are applied only if explicitly implemented. Tokens are applied only if explicitly implemented or if requested via the constructor.
SimpleConnection Tokens are applied only if explicitly implemented. Tokens are applied only if explicitly implemented or if requested via the constructor.

Overall, behavior should be identical to 1.0.0 with the following exceptions:

  • Subclasses of SimpleAuthenticationProvider will now handle additional tokens and apply those tokens in context of the connection, not at time of authentication.
  • The result of calling getConfiguration() on a connection accessed via a subclass of SimpleAuthenticationProvider will now contain any tokens in uninterpreted form.

…sions of connect() for sake of compatibility.
…uacamoleConfiguration within SimpleConnection.

While raw, internal access to the GuacamoleConfiguration was originally
present in older versions of SimpleConnection, this access was
undocumented and could result in unexpected behavior if the default
constructor was used, getConfiguration() was overridden, or
setConfiguration() was called.
…deprecated connect() function to have the expected effect within subclasses of SimpleConnection.
…st automatic interpretation of parameter tokens. Do not enable by default.

Previous implementations of SimpleConnection did not interpret parameter
tokens automatically. Adding that behavior now could have security
implications for downstream users of the class if parameter values may
unexpectedly contain substrings which would be interpreted as tokens,
particularly if parameter values are built from untrusted input.
Copy link
Copy Markdown
Contributor

@necouchman necouchman left a comment

Choose a reason for hiding this comment

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

Just a couple of quick questions, but looking pretty good.

Map<String, String> tokens) throws GuacamoleException {

// Allow old implementations of Connectable to continue to work
return this.connect(info);
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.

Is there a reason supplying a default of this particular instance of this method is necessary or valuable? Won't the old implementations already be calling the other default method, without the tokens parameter? And doesn't this introduce the possibility that an implementing class could end up recursively calling these parameters (if they don't actually implement either of them)? Or will that get caught at compile time?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Is there a reason supplying a default of this particular instance of this method is necessary or valuable? Won't the old implementations already be calling the other default method, without the tokens parameter?

Some sort of default is necessary to bridge the implementations, as it's the webapp that ultimately calls connect(), and in this case will be calling the version which has tokens.

In the general case, defaults are needed to bridge in both directions to allow extensions of different versions to interoperate. An older extension (compatible with 1.0.0) which decorates the connections of other extensions will need to be able to invoke connect(), even though it will be calling the older version. A newer extension and the webapp need the same ability but in the other direction.

And doesn't this introduce the possibility that an implementing class could end up recursively calling these parameters (if they don't actually implement either of them)?

Yes, and that's definitely a bad thing. I think I may have a route around this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

OK - I'm rearranging things a bit such that the interface defined within guacamole-ext is still strictly as defined before: one connect() definition which accepts tokens.

Within the webapp, I'm adding another version of Connectable in the same package which defines both connect() versions as well as defaults, and thus an ABI-compatible redefinition of both versions of the interface. Because of the way servlet containers handle classes bundled with the webapp vs. within dependencies, the webapp version of Connectable takes priority.


// Add as simple connection
Connection connection = new SimpleConnection(identifier, identifier, config);
Connection connection = new SimpleConnection(identifier, identifier, config, true);
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.

Should this be true, or should this be passing the value of interpretTokens?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch - we should pass through interpretTokens.

…version.

Defining an ABI-compatible version of Connectable at the guacamole-ext
level is problematic as concrete implementations of the interface will
suddenly compile despite having no implementation of connect() at all.

We can instead rely on the web application to ensure binary
compatibility, leaving guacamole-ext to define the interface that new
code should use.
@mike-jumper
Copy link
Copy Markdown
Contributor Author

Reading through things again, I think we might need to also update SimpleConnectionGroup, DelegatingConnection, DelegatingConnectionGroup, etc.

…) use the old connect() as their basis. Overriding the old connect() will not have the expected effect otherwise.
@mike-jumper
Copy link
Copy Markdown
Contributor Author

OK - I've gone through and made sure that any guacamole-ext class which provides a concrete implementation of connect() does so using the old connect() as a basis for the sake of compatibility (same approach as SimpleConnection), with the exception of the new token injecting classes that did not exist before.

@necouchman necouchman merged commit 7e7b6fd into apache:master Jan 23, 2019
@mike-jumper mike-jumper deleted the backward-compat branch February 3, 2019 23:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants