From abd3d381f939a6bb76496583c4eeb239be5ebf26 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 12 May 2015 13:31:18 -0700 Subject: [PATCH] GUAC-587: Include and validate Guacamole version in manifest. --- .../tunnel/ManagedSSLGuacamoleSocket.java | 71 +++++++++++++++++++ .../src/main/resources/guac-manifest.json | 2 + .../src/main/resources/guac-manifest.json | 2 + .../src/main/resources/guac-manifest.json | 2 + .../src/main/resources/guac-manifest.json | 2 + .../net/basic/extension/Extension.java | 12 ++++ .../basic/extension/ExtensionManifest.java | 31 ++++++++ .../net/basic/extension/ExtensionModule.java | 36 ++++++++++ 8 files changed, 158 insertions(+) create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/ManagedSSLGuacamoleSocket.java diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/ManagedSSLGuacamoleSocket.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/ManagedSSLGuacamoleSocket.java new file mode 100644 index 000000000..739b4776e --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/ManagedSSLGuacamoleSocket.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.glyptodon.guacamole.auth.jdbc.tunnel; + +import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.net.InetGuacamoleSocket; + +/** + * Implementation of GuacamoleSocket which connects via TCP to a given hostname + * and port. If the socket is closed for any reason, a given task is run. + * + * @author Michael Jumper + */ +public class ManagedInetGuacamoleSocket extends InetGuacamoleSocket { + + /** + * The task to run when the socket is closed. + */ + private final Runnable socketClosedTask; + + /** + * Creates a new socket which connects via TCP to a given hostname and + * port. If the socket is closed for any reason, the given task is run. + * + * @param hostname + * The hostname of the Guacamole proxy server to connect to. + * + * @param port + * The port of the Guacamole proxy server to connect to. + * + * @param socketClosedTask + * The task to run when the socket is closed. This task will NOT be + * run if an exception occurs during connection, and this + * ManagedInetGuacamoleSocket instance is ultimately not created. + * + * @throws GuacamoleException + * If an error occurs while connecting to the Guacamole proxy server. + */ + public ManagedInetGuacamoleSocket(String hostname, int port, + Runnable socketClosedTask) throws GuacamoleException { + super(hostname, port); + this.socketClosedTask = socketClosedTask; + } + + @Override + public void close() throws GuacamoleException { + super.close(); + socketClosedTask.run(); + } + +} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/guac-manifest.json index d9aad44f3..3c7deb865 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/guac-manifest.json +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/guac-manifest.json @@ -1,5 +1,7 @@ { + "guacamoleVersion" : "0.9.6", + "name" : "MySQL Authentication", "namespace" : "guac-mysql", diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/guac-manifest.json index 59b5ed7ca..2be870f25 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/guac-manifest.json +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/guac-manifest.json @@ -1,5 +1,7 @@ { + "guacamoleVersion" : "0.9.6", + "name" : "PostgreSQL Authentication", "namespace" : "guac-postgresql", diff --git a/extensions/guacamole-auth-ldap/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-ldap/src/main/resources/guac-manifest.json index b2633a170..e8d9a9e7b 100644 --- a/extensions/guacamole-auth-ldap/src/main/resources/guac-manifest.json +++ b/extensions/guacamole-auth-ldap/src/main/resources/guac-manifest.json @@ -1,5 +1,7 @@ { + "guacamoleVersion" : "0.9.6", + "name" : "LDAP Authentication", "namespace" : "guac-ldap", diff --git a/extensions/guacamole-auth-noauth/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-noauth/src/main/resources/guac-manifest.json index 588855a70..03fd29916 100644 --- a/extensions/guacamole-auth-noauth/src/main/resources/guac-manifest.json +++ b/extensions/guacamole-auth-noauth/src/main/resources/guac-manifest.json @@ -1,5 +1,7 @@ { + "guacamoleVersion" : "0.9.6", + "name" : "Disabled Authentication", "namespace" : "guac-noauth", diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/extension/Extension.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/extension/Extension.java index 61eb16c17..2f3aa17c4 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/extension/Extension.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/extension/Extension.java @@ -289,6 +289,18 @@ public class Extension { } + /** + * Returns the version of the Guacamole web application for which this + * extension was built. + * + * @return + * The version of the Guacamole web application for which this + * extension was built. + */ + public String getGuacamoleVersion() { + return manifest.getGuacamoleVersion(); + } + /** * Returns the name of this extension, as declared in the extension's * manifest. diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/extension/ExtensionManifest.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/extension/ExtensionManifest.java index c593865d0..093af3b0d 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/extension/ExtensionManifest.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/extension/ExtensionManifest.java @@ -33,6 +33,13 @@ import org.codehaus.jackson.annotate.JsonProperty; */ public class ExtensionManifest { + /** + * The version of Guacamole for which this extension was built. + * Compatibility rules built into the web application will guard against + * incompatible extensions being loaded. + */ + private String guacamoleVersion; + /** * The name of the extension associated with this manifest. The extension * name is human-readable, and used for display purposes only. @@ -65,6 +72,30 @@ public class ExtensionManifest { */ private Collection authProviders; + /** + * Returns the version of the Guacamole web application for which the + * extension was built, such as "0.9.6". + * + * @return + * The version of the Guacamole web application for which the extension + * was built. + */ + public String getGuacamoleVersion() { + return guacamoleVersion; + } + + /** + * Sets the version of the Guacamole web application for which the + * extension was built, such as "0.9.6". + * + * @param guacamoleVersion + * The version of the Guacamole web application for which the extension + * was built. + */ + public void setGuacamoleVersion(String guacamoleVersion) { + this.guacamoleVersion = guacamoleVersion; + } + /** * Returns the name of the extension associated with this manifest. The * name is human-readable, for display purposes only, and is defined within diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/extension/ExtensionModule.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/extension/ExtensionModule.java index 84a4484d7..e2bae9bdf 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/extension/ExtensionModule.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/extension/ExtensionModule.java @@ -27,9 +27,13 @@ import com.google.inject.servlet.ServletModule; import java.io.File; import java.io.FileFilter; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; +import java.util.Collections; +import java.util.List; import net.sourceforge.guacamole.net.basic.BasicFileAuthenticationProvider; import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.GuacamoleServerException; import org.glyptodon.guacamole.environment.Environment; import org.glyptodon.guacamole.net.auth.AuthenticationProvider; import org.glyptodon.guacamole.net.basic.properties.BasicGuacamoleProperties; @@ -53,6 +57,15 @@ public class ExtensionModule extends ServletModule { */ private final Logger logger = LoggerFactory.getLogger(ExtensionModule.class); + /** + * The version strings of all Guacamole versions whose extensions are + * compatible with this release. + */ + private static final List ALLOWED_GUACAMOLE_VERSIONS = + Collections.unmodifiableList(Arrays.asList( + "0.9.6" + )); + /** * The name of the directory within GUACAMOLE_HOME containing any .jars * which should be included in the classpath of all extensions. @@ -188,6 +201,21 @@ public class ExtensionModule extends ServletModule { } + /** + * Returns whether the given version of Guacamole is compatible with this + * version of Guacamole as far as extensions are concerned. + * + * @param guacamoleVersion + * The version of Guacamole the extension was built for. + * + * @return + * true if the given version of Guacamole is compatible with this + * version of Guacamole, false otherwise. + */ + private boolean isCompatible(String guacamoleVersion) { + return ALLOWED_GUACAMOLE_VERSIONS.contains(guacamoleVersion); + } + @Override protected void configureServlets() { @@ -229,6 +257,14 @@ public class ExtensionModule extends ServletModule { // Load extension from file Extension extension = new Extension(getParentClassLoader(), extensionFile); + // Validate Guacamole version of extension + if (!isCompatible(extension.getGuacamoleVersion())) { + logger.debug("Declared Guacamole version \"{}\" of extension \"{}\" is not compatible with this version of Guacamole.", + extension.getGuacamoleVersion(), extensionFile.getName()); + throw new GuacamoleServerException("Extension \"" + extension.getName() + "\" is not " + + "compatible with this version of Guacamole."); + } + // Add any JavaScript / CSS resources javaScriptResources.addAll(extension.getJavaScriptResources()); cssResources.addAll(extension.getCSSResources());