diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/BasicServletContextListener.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/BasicServletContextListener.java index e6f342f2c..60eeffdbb 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/BasicServletContextListener.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/BasicServletContextListener.java @@ -85,7 +85,7 @@ public class BasicServletContextListener extends GuiceServletContextListener { new EnvironmentModule(environment), new LogModule(environment), new ExtensionModule(environment), - new RESTAuthModule(environment, sessionMap), + new RESTAuthModule(sessionMap), new RESTServletModule(), new TunnelModule() ); diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/GuacamoleClassLoader.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/GuacamoleClassLoader.java index 1dcb37048..8c3f40c94 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/GuacamoleClassLoader.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/GuacamoleClassLoader.java @@ -39,10 +39,13 @@ import org.glyptodon.guacamole.net.basic.properties.BasicGuacamoleProperties; /** * A ClassLoader implementation which finds classes within a configurable - * directory. This directory is set within guacamole.properties. + * directory. This directory is set within guacamole.properties. This class + * is deprecated in favor of DirectoryClassLoader, which is automatically + * configured based on the presence/absence of GUACAMOLE_HOME/lib. * * @author Michael Jumper */ +@Deprecated public class GuacamoleClassLoader extends ClassLoader { /** 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 c2defbafb..e7cbf13c0 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 @@ -28,9 +28,11 @@ import java.io.File; import java.io.FileFilter; import java.util.ArrayList; import java.util.Collection; +import net.sourceforge.guacamole.net.basic.BasicFileAuthenticationProvider; import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.environment.Environment; import org.glyptodon.guacamole.net.auth.AuthenticationProvider; +import org.glyptodon.guacamole.net.basic.properties.BasicGuacamoleProperties; import org.glyptodon.guacamole.net.basic.resource.Resource; import org.glyptodon.guacamole.net.basic.resource.ResourceServlet; import org.glyptodon.guacamole.net.basic.resource.SequenceResource; @@ -74,6 +76,12 @@ public class ExtensionModule extends ServletModule { */ private final Environment environment; + /** + * The currently-bound authentication provider, if any. At the moment, we + * only support one authentication provider loaded at any one time. + */ + private Class boundAuthenticationProvider = null; + /** * Returns the classloader that should be used as the parent classloader * for all extensions. If the GUACAMOLE_HOME/lib directory exists, this @@ -113,9 +121,81 @@ public class ExtensionModule extends ServletModule { this.environment = environment; } + /** + * Reads the value of the now-deprecated "auth-provider" property from + * guacamole.properties, returning the corresponding AuthenticationProvider + * class. If no authentication provider could be read, or the property is + * not present, null is returned. + * + * As this property is deprecated, this function will also log warning + * messages if the property is actually specified. + * + * @return + * The value of the deprecated "auth-provider" property, or null if the + * property is not present. + */ + @SuppressWarnings("deprecation") // We must continue to use this property until it is truly no longer supported + private Class getAuthProviderProperty() { + + // Get and bind auth provider instance, if defined via property + try { + + // Use "auth-provider" property if present, but warn about deprecation + Class authenticationProvider = environment.getProperty(BasicGuacamoleProperties.AUTH_PROVIDER); + if (authenticationProvider != null) + logger.warn("The \"auth-provider\" and \"lib-directory\" properties are now deprecated. Please use the \"extensions\" and \"lib\" directories within GUACAMOLE_HOME instead."); + + return authenticationProvider; + + } + catch (GuacamoleException e) { + logger.warn("Value of deprecated \"auth-provider\" property within guacamole.properties is not valid: {}", e.getMessage()); + logger.debug("Error reading authentication provider from guacamole.properties.", e); + } + + return null; + + } + + /** + * Binds the given AuthenticationProvider class such that any service + * requiring access to the AuthenticationProvider can obtain it via + * injection. + * + * @param authenticationProvider + * The AuthenticationProvider class to bind. + */ + private void bindAuthenticationProvider(Class authenticationProvider) { + + // Choose auth provider for binding if not already chosen + if (boundAuthenticationProvider != null) + boundAuthenticationProvider = authenticationProvider; + + // If an auth provider is already chosen, skip and warn + else { + logger.debug("Ignoring AuthenticationProvider \"{}\".", authenticationProvider); + logger.warn("Only one authentication extension may be used at a time. Please " + + "make sure that only one authentication extension is present " + + "within the GUACAMOLE_HOME/" + EXTENSIONS_DIRECTORY + " " + + "directory, and that you are not also specifying the deprecated " + + "\"auth-provider\" property within guacamole.properties."); + return; + } + + // Bind authentication provider + logger.debug("Binding AuthenticationProvider \"{}\".", authenticationProvider); + bind(AuthenticationProvider.class).to(authenticationProvider).in(Singleton.class); + + } + @Override protected void configureServlets() { + // Load authentication provider from guacamole.properties for sake of backwards compatibility + Class authProviderProperty = getAuthProviderProperty(); + if (authProviderProperty != null) + bindAuthenticationProvider(authProviderProperty); + // Retrieve and validate extensions directory File extensionsDir = new File(environment.getGuacamoleHome(), EXTENSIONS_DIRECTORY); if (!extensionsDir.isDirectory()) @@ -153,12 +233,10 @@ public class ExtensionModule extends ServletModule { javaScriptResources.addAll(extension.getJavaScriptResources()); cssResources.addAll(extension.getCSSResources()); - // Load all authentication providers as singletons + // Attempt to load all authentication providers Collection> authenticationProviders = extension.getAuthenticationProviderClasses(); - for (Class authenticationProvider : authenticationProviders) { - logger.debug("Binding AuthenticationProvider \"{}\".", authenticationProvider); - bind(AuthenticationProvider.class).to(authenticationProvider).in(Singleton.class); - } + for (Class authenticationProvider : authenticationProviders) + bindAuthenticationProvider(authenticationProvider); // Log successful loading of extension by name logger.info("Extension \"{}\" loaded.", extension.getName()); @@ -171,6 +249,12 @@ public class ExtensionModule extends ServletModule { } + // Default to basic auth if nothing else chosen/provided + if (boundAuthenticationProvider == null) { + logger.info("Using default, \"basic\", XML-driven authentication."); + bindAuthenticationProvider(BasicFileAuthenticationProvider.class); + } + // Dynamically generate app.js and app.css from extensions serve("/app.js").with(new ResourceServlet(new SequenceResource(javaScriptResources))); serve("/app.css").with(new ResourceServlet(new SequenceResource(cssResources))); diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/properties/AuthenticationProviderProperty.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/properties/AuthenticationProviderProperty.java index dd633ed29..1714bb1e0 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/properties/AuthenticationProviderProperty.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/properties/AuthenticationProviderProperty.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Glyptodon LLC + * 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 @@ -22,7 +22,6 @@ package org.glyptodon.guacamole.net.basic.properties; -import java.lang.reflect.InvocationTargetException; import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.net.auth.AuthenticationProvider; import org.glyptodon.guacamole.net.basic.GuacamoleClassLoader; @@ -30,14 +29,18 @@ import org.glyptodon.guacamole.properties.GuacamoleProperty; /** * A GuacamoleProperty whose value is the name of a class to use to - * authenticate users. This class must implement AuthenticationProvider. + * authenticate users. This class must implement AuthenticationProvider. Use + * of this property type is deprecated in favor of the + * GUACAMOLE_HOME/extensions directory. * * @author Michael Jumper */ -public abstract class AuthenticationProviderProperty implements GuacamoleProperty { +@Deprecated +public abstract class AuthenticationProviderProperty implements GuacamoleProperty> { @Override - public AuthenticationProvider parseValue(String authProviderClassName) throws GuacamoleException { + @SuppressWarnings("unchecked") // Explicitly checked within by isAssignableFrom() + public Class parseValue(String authProviderClassName) throws GuacamoleException { // If no property provided, return null. if (authProviderClassName == null) @@ -46,35 +49,21 @@ public abstract class AuthenticationProviderProperty implements GuacamolePropert // Get auth provider instance try { - Object obj = GuacamoleClassLoader.getInstance().loadClass(authProviderClassName) - .getConstructor().newInstance(); + // Get authentication provider class + Class authProviderClass = GuacamoleClassLoader.getInstance().loadClass(authProviderClassName); - if (!(obj instanceof AuthenticationProvider)) + // Verify the located class is actually a subclass of AuthenticationProvider + if (!AuthenticationProvider.class.isAssignableFrom(authProviderClass)) throw new GuacamoleException("Specified authentication provider class is not a AuthenticationProvider."); - return (AuthenticationProvider) obj; + // Return located class + return (Class) authProviderClass; } catch (ClassNotFoundException e) { throw new GuacamoleException("Authentication provider class not found", e); } - catch (NoSuchMethodException e) { - throw new GuacamoleException("Default constructor for authentication provider not present", e); - } - catch (SecurityException e) { - throw new GuacamoleException("Creation of authentication provider disallowed; check your security settings", e); - } - catch (InstantiationException e) { - throw new GuacamoleException("Unable to instantiate authentication provider", e); - } - catch (IllegalAccessException e) { - throw new GuacamoleException("Unable to access default constructor of authentication provider", e); - } - catch (InvocationTargetException e) { - throw new GuacamoleException("Internal error in constructor of authentication provider", e.getTargetException()); - } } } - diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/properties/BasicGuacamoleProperties.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/properties/BasicGuacamoleProperties.java index f2de45e3b..05bcb8d49 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/properties/BasicGuacamoleProperties.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/properties/BasicGuacamoleProperties.java @@ -22,7 +22,6 @@ package org.glyptodon.guacamole.net.basic.properties; -import org.glyptodon.guacamole.properties.BooleanGuacamoleProperty; import org.glyptodon.guacamole.properties.FileGuacamoleProperty; import org.glyptodon.guacamole.properties.IntegerGuacamoleProperty; @@ -40,8 +39,10 @@ public class BasicGuacamoleProperties { /** * The authentication provider to user when retrieving the authorized - * configurations of a user. + * configurations of a user. This property is currently supported, but + * deprecated in favor of the GUACAMOLE_HOME/extensions directory. */ + @Deprecated public static final AuthenticationProviderProperty AUTH_PROVIDER = new AuthenticationProviderProperty() { @Override @@ -50,8 +51,11 @@ public class BasicGuacamoleProperties { }; /** - * The directory to search for authentication provider classes. + * The directory to search for authentication provider classes. This + * property is currently supported, but deprecated in favor of the + * GUACAMOLE_HOME/lib directory. */ + @Deprecated public static final FileGuacamoleProperty LIB_DIRECTORY = new FileGuacamoleProperty() { @Override @@ -60,7 +64,9 @@ public class BasicGuacamoleProperties { }; /** - * The comma-separated list of all classes to use as event listeners. + * The comma-separated list of all classes to use as event listeners. This + * property is currently supported, but deprecated in favor of declared + * event listeners within extension manifests. */ public static final EventListenersProperty EVENT_LISTENERS = new EventListenersProperty() { diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/properties/EventListenersProperty.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/properties/EventListenersProperty.java index 5b7e9a4b5..0046faa1d 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/properties/EventListenersProperty.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/properties/EventListenersProperty.java @@ -30,10 +30,13 @@ import org.glyptodon.guacamole.properties.GuacamoleProperty; /** * A GuacamoleProperty whose value is a comma-separated list of class names, - * where each class will be used as a listener for events. + * where each class will be used as a listener for events. This type of + * property is deprecated in favor of declaring event listeners within + * extension manifests. * * @author Michael Jumper */ +@SuppressWarnings("deprecation") public abstract class EventListenersProperty implements GuacamoleProperty> { @Override diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/RESTAuthModule.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/RESTAuthModule.java index 68bc669a4..ddc5fff78 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/RESTAuthModule.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/RESTAuthModule.java @@ -23,10 +23,6 @@ package org.glyptodon.guacamole.net.basic.rest; import com.google.inject.AbstractModule; -import org.glyptodon.guacamole.GuacamoleException; -import org.glyptodon.guacamole.environment.Environment; -import org.glyptodon.guacamole.net.auth.AuthenticationProvider; -import org.glyptodon.guacamole.net.basic.properties.BasicGuacamoleProperties; import org.glyptodon.guacamole.net.basic.rest.auth.AuthTokenGenerator; import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService; import org.glyptodon.guacamole.net.basic.rest.auth.SecureRandomAuthTokenGenerator; @@ -47,11 +43,6 @@ public class RESTAuthModule extends AbstractModule { */ private final Logger logger = LoggerFactory.getLogger(RESTAuthModule.class); - /** - * The Guacamole server environment. - */ - private final Environment environment; - /** * Singleton instance of TokenSessionMap. */ @@ -61,16 +52,11 @@ public class RESTAuthModule extends AbstractModule { * Creates a module which handles binding of authentication-related * objects, including the singleton TokenSessionMap. * - * @param environment - * The environment to use when configuring authentication. - * * @param tokenSessionMap * An instance of TokenSessionMap to inject as a singleton wherever * needed. */ - public RESTAuthModule(Environment environment, - TokenSessionMap tokenSessionMap) { - this.environment = environment; + public RESTAuthModule(TokenSessionMap tokenSessionMap) { this.tokenSessionMap = tokenSessionMap; } @@ -84,22 +70,6 @@ public class RESTAuthModule extends AbstractModule { bind(AuthenticationService.class); bind(AuthTokenGenerator.class).to(SecureRandomAuthTokenGenerator.class); - // Get and bind auth provider instance, if defined via property - try { - - // Use "auth-provider" property if present, but warn about deprecation - AuthenticationProvider authProvider = environment.getProperty(BasicGuacamoleProperties.AUTH_PROVIDER); - if (authProvider != null) { - logger.warn("The \"auth-provider\" and \"lib-directory\" properties are now deprecated. Please use the \"extensions\" and \"lib\" directories within GUACAMOLE_HOME instead."); - bind(AuthenticationProvider.class).toInstance(authProvider); - } - - } - catch (GuacamoleException e) { - logger.warn("Value of deprecated \"auth-provider\" property within guacamole.properties is not valid: {}", e.getMessage()); - logger.debug("Error reading authentication provider from guacamole.properties.", e); - } - } }