mirror of
				https://github.com/gyurix1968/guacamole-client.git
				synced 2025-10-31 09:03:21 +00:00 
			
		
		
		
	GUAC-587: Load authentication providers from extensions.
This commit is contained in:
		| @@ -40,6 +40,7 @@ import org.codehaus.jackson.JsonParseException; | |||||||
| import org.codehaus.jackson.map.ObjectMapper; | import org.codehaus.jackson.map.ObjectMapper; | ||||||
| import org.glyptodon.guacamole.GuacamoleException; | import org.glyptodon.guacamole.GuacamoleException; | ||||||
| import org.glyptodon.guacamole.GuacamoleServerException; | import org.glyptodon.guacamole.GuacamoleServerException; | ||||||
|  | import org.glyptodon.guacamole.net.auth.AuthenticationProvider; | ||||||
| import org.glyptodon.guacamole.net.basic.resource.ClassPathResource; | import org.glyptodon.guacamole.net.basic.resource.ClassPathResource; | ||||||
| import org.glyptodon.guacamole.net.basic.resource.Resource; | import org.glyptodon.guacamole.net.basic.resource.Resource; | ||||||
|  |  | ||||||
| @@ -74,6 +75,125 @@ public class Extension { | |||||||
|      */ |      */ | ||||||
|     private final ClassLoader classLoader; |     private final ClassLoader classLoader; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The collection of all JavaScript resources defined within the extension. | ||||||
|  |      */ | ||||||
|  |     private final Collection<Resource> javaScriptResources; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The collection of all CSS resources defined within the extension. | ||||||
|  |      */ | ||||||
|  |     private final Collection<Resource> cssResources; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The collection of all AuthenticationProvider classes defined within the | ||||||
|  |      * extension. | ||||||
|  |      */ | ||||||
|  |     private final Collection<Class<AuthenticationProvider>> authenticationProviderClasses; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns a new collection of resources corresponding to the collection of | ||||||
|  |      * paths provided. Each resource will be associated with the given | ||||||
|  |      * mimetype. | ||||||
|  |      * | ||||||
|  |      * @param mimetype | ||||||
|  |      *     The mimetype to associate with each resource. | ||||||
|  |      * | ||||||
|  |      * @param paths | ||||||
|  |      *     The paths corresponding to the resources desired. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      *     A new, unmodifiable collection of resources corresponding to the | ||||||
|  |      *     collection of paths provided. | ||||||
|  |      */ | ||||||
|  |     private Collection<Resource> getClassPathResources(String mimetype, Collection<String> paths) { | ||||||
|  |  | ||||||
|  |         // If no paths are provided, just return an empty list | ||||||
|  |         if (paths == null) | ||||||
|  |             return Collections.<Resource>emptyList(); | ||||||
|  |  | ||||||
|  |         // Add classpath resource for each path provided | ||||||
|  |         Collection<Resource> resources = new ArrayList<Resource>(paths.size()); | ||||||
|  |         for (String path : paths) | ||||||
|  |             resources.add(new ClassPathResource(classLoader, mimetype, path)); | ||||||
|  |  | ||||||
|  |         // Callers should not rely on modifying the result | ||||||
|  |         return Collections.unmodifiableCollection(resources); | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Retrieve the AuthenticationProvider subclass having the given name. If | ||||||
|  |      * the class having the given name does not exist or isn't actually a | ||||||
|  |      * subclass of AuthenticationProvider, an exception will be thrown. | ||||||
|  |      * | ||||||
|  |      * @param name | ||||||
|  |      *     The name of the AuthenticationProvider class to retrieve. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      *     The subclass of AuthenticationProvider having the given name. | ||||||
|  |      * | ||||||
|  |      * @throws GuacamoleException | ||||||
|  |      *     If no such class exists, or if the class with the given name is not | ||||||
|  |      *     a subclass of AuthenticationProvider. | ||||||
|  |      */ | ||||||
|  |     @SuppressWarnings("unchecked") // We check this ourselves with isAssignableFrom() | ||||||
|  |     private Class<AuthenticationProvider> getAuthenticationProviderClass(String name) | ||||||
|  |             throws GuacamoleException { | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |  | ||||||
|  |             // Get authentication provider class | ||||||
|  |             Class<?> authenticationProviderClass = classLoader.loadClass(name); | ||||||
|  |  | ||||||
|  |             // Verify the located class is actually a subclass of AuthenticationProvider | ||||||
|  |             if (!AuthenticationProvider.class.isAssignableFrom(authenticationProviderClass)) | ||||||
|  |                 throw new GuacamoleServerException("Authentication providers MUST extend the AuthenticationProvider class."); | ||||||
|  |  | ||||||
|  |             // Return located class | ||||||
|  |             return (Class<AuthenticationProvider>) authenticationProviderClass; | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |         catch (ClassNotFoundException e) { | ||||||
|  |             throw new GuacamoleException("Authentication provider class not found.", e); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns a new collection of all AuthenticationProvider subclasses having | ||||||
|  |      * the given names. If any class does not exist or isn't actually a | ||||||
|  |      * subclass of AuthenticationProvider, an exception will be thrown, and | ||||||
|  |      * no further AuthenticationProvider classes will be loaded. | ||||||
|  |      * | ||||||
|  |      * @param names | ||||||
|  |      *     The names of the AuthenticationProvider classes to retrieve. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      *     A new collection of all AuthenticationProvider subclasses having the | ||||||
|  |      *     given names. | ||||||
|  |      * | ||||||
|  |      * @throws GuacamoleException | ||||||
|  |      *     If any given class does not exist, or if any given class is not a | ||||||
|  |      *     subclass of AuthenticationProvider. | ||||||
|  |      */ | ||||||
|  |     private Collection<Class<AuthenticationProvider>> getAuthenticationProviderClasses(Collection<String> names) | ||||||
|  |             throws GuacamoleException { | ||||||
|  |  | ||||||
|  |         // If no classnames are provided, just return an empty list | ||||||
|  |         if (names == null) | ||||||
|  |             return Collections.<Class<AuthenticationProvider>>emptyList(); | ||||||
|  |  | ||||||
|  |         // Define all auth provider classes | ||||||
|  |         Collection<Class<AuthenticationProvider>> classes = new ArrayList<Class<AuthenticationProvider>>(names.size()); | ||||||
|  |         for (String name : names) | ||||||
|  |             classes.add(getAuthenticationProviderClass(name)); | ||||||
|  |  | ||||||
|  |         // Callers should not rely on modifying the result | ||||||
|  |         return Collections.unmodifiableCollection(classes); | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Loads the given file as an extension, which must be a .jar containing |      * Loads the given file as an extension, which must be a .jar containing | ||||||
|      * a guac-manifest.json file describing its contents. |      * a guac-manifest.json file describing its contents. | ||||||
| @@ -160,6 +280,13 @@ public class Extension { | |||||||
|             throw new GuacamoleServerException("Unable to read extension: " + file.getName(), e); |             throw new GuacamoleServerException("Unable to read extension: " + file.getName(), e); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         // Define static resources | ||||||
|  |         cssResources = getClassPathResources("text/css", manifest.getCSSPaths()); | ||||||
|  |         javaScriptResources = getClassPathResources("text/javascript", manifest.getJavaScriptPaths()); | ||||||
|  |  | ||||||
|  |         // Define authentication providers | ||||||
|  |         authenticationProviderClasses = getAuthenticationProviderClasses(manifest.getAuthProviders()); | ||||||
|  |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -184,37 +311,6 @@ public class Extension { | |||||||
|         return manifest.getNamespace(); |         return manifest.getNamespace(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Returns a new collection of resources corresponding to the collection of |  | ||||||
|      * paths provided. Each resource will be associated with the given |  | ||||||
|      * mimetype. |  | ||||||
|      * |  | ||||||
|      * @param mimetype |  | ||||||
|      *     The mimetype to associate with each resource. |  | ||||||
|      * |  | ||||||
|      * @param paths |  | ||||||
|      *     The paths corresponding to the resources desired. |  | ||||||
|      * |  | ||||||
|      * @return |  | ||||||
|      *     A new, unmodifiable collection of resources corresponding to the |  | ||||||
|      *     collection of paths provided. |  | ||||||
|      */ |  | ||||||
|     private Collection<Resource> getClassPathResources(String mimetype, Collection<String> paths) { |  | ||||||
|  |  | ||||||
|         // If no paths are provided, just return an empty list |  | ||||||
|         if (paths == null) |  | ||||||
|             return Collections.<Resource>emptyList(); |  | ||||||
|  |  | ||||||
|         // Add classpath resource for each path provided |  | ||||||
|         Collection<Resource> resources = new ArrayList<Resource>(paths.size()); |  | ||||||
|         for (String path : paths) |  | ||||||
|             resources.add(new ClassPathResource(classLoader, mimetype, path)); |  | ||||||
|  |  | ||||||
|         // Callers should not rely on modifying the result |  | ||||||
|         return Collections.unmodifiableCollection(resources); |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Returns all declared JavaScript resources associated with this |      * Returns all declared JavaScript resources associated with this | ||||||
|      * extension. JavaScript resources are declared within the extension |      * extension. JavaScript resources are declared within the extension | ||||||
| @@ -224,7 +320,7 @@ public class Extension { | |||||||
|      *     All declared JavaScript resources associated with this extension. |      *     All declared JavaScript resources associated with this extension. | ||||||
|      */ |      */ | ||||||
|     public Collection<Resource> getJavaScriptResources() { |     public Collection<Resource> getJavaScriptResources() { | ||||||
|         return getClassPathResources("text/javascript", manifest.getJavaScriptPaths()); |         return javaScriptResources; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
| @@ -235,7 +331,19 @@ public class Extension { | |||||||
|      *     All declared CSS resources associated with this extension. |      *     All declared CSS resources associated with this extension. | ||||||
|      */ |      */ | ||||||
|     public Collection<Resource> getCSSResources() { |     public Collection<Resource> getCSSResources() { | ||||||
|         return getClassPathResources("text/css", manifest.getCSSPaths()); |         return cssResources; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns all declared authentication providers classes associated with | ||||||
|  |      * this extension. Authentication providers are declared within the | ||||||
|  |      * extension manifest. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      *     All declared authentication provider classes with this extension. | ||||||
|  |      */ | ||||||
|  |     public Collection<Class<AuthenticationProvider>> getAuthenticationProviderClasses() { | ||||||
|  |         return authenticationProviderClasses; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -59,6 +59,12 @@ public class ExtensionManifest { | |||||||
|      */ |      */ | ||||||
|     private Collection<String> cssPaths; |     private Collection<String> cssPaths; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The names of all authentication provider classes within this extension, | ||||||
|  |      * if any. | ||||||
|  |      */ | ||||||
|  |     private Collection<String> authProviders; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Returns the name of the extension associated with this manifest. The |      * Returns the name of the extension associated with this manifest. The | ||||||
|      * name is human-readable, for display purposes only, and is defined within |      * name is human-readable, for display purposes only, and is defined within | ||||||
| @@ -169,4 +175,32 @@ public class ExtensionManifest { | |||||||
|         this.cssPaths = cssPaths; |         this.cssPaths = cssPaths; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns the classnames of all authentication provider classes within the | ||||||
|  |      * extension. These classnames are defined within the manifest by the | ||||||
|  |      * "authProviders" property as an array of strings, where each string is an | ||||||
|  |      * authentication provider classname. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      *     A collection of classnames of all authentication providers within | ||||||
|  |      *     the extension. | ||||||
|  |      */ | ||||||
|  |     public Collection<String> getAuthProviders() { | ||||||
|  |         return authProviders; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Sets the classnames of all authentication provider classes within the | ||||||
|  |      * extension. These classnames are defined within the manifest by the | ||||||
|  |      * "authProviders" property as an array of strings, where each string is an | ||||||
|  |      * authentication provider classname. | ||||||
|  |      * | ||||||
|  |      * @param authProviders | ||||||
|  |      *     A collection of classnames of all authentication providers within | ||||||
|  |      *     the extension. | ||||||
|  |      */ | ||||||
|  |     public void setAuthProviders(Collection<String> authProviders) { | ||||||
|  |         this.authProviders = authProviders; | ||||||
|  |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -22,6 +22,7 @@ | |||||||
|  |  | ||||||
| package org.glyptodon.guacamole.net.basic.extension; | package org.glyptodon.guacamole.net.basic.extension; | ||||||
|  |  | ||||||
|  | import com.google.inject.Singleton; | ||||||
| import com.google.inject.servlet.ServletModule; | import com.google.inject.servlet.ServletModule; | ||||||
| import java.io.File; | import java.io.File; | ||||||
| import java.io.FileFilter; | import java.io.FileFilter; | ||||||
| @@ -29,6 +30,7 @@ import java.util.ArrayList; | |||||||
| import java.util.Collection; | import java.util.Collection; | ||||||
| import org.glyptodon.guacamole.GuacamoleException; | import org.glyptodon.guacamole.GuacamoleException; | ||||||
| import org.glyptodon.guacamole.environment.Environment; | import org.glyptodon.guacamole.environment.Environment; | ||||||
|  | import org.glyptodon.guacamole.net.auth.AuthenticationProvider; | ||||||
| import org.glyptodon.guacamole.net.basic.resource.Resource; | import org.glyptodon.guacamole.net.basic.resource.Resource; | ||||||
| import org.glyptodon.guacamole.net.basic.resource.ResourceServlet; | import org.glyptodon.guacamole.net.basic.resource.ResourceServlet; | ||||||
| import org.glyptodon.guacamole.net.basic.resource.SequenceResource; | import org.glyptodon.guacamole.net.basic.resource.SequenceResource; | ||||||
| @@ -118,6 +120,13 @@ public class ExtensionModule extends ServletModule { | |||||||
|                 javaScriptResources.addAll(extension.getJavaScriptResources()); |                 javaScriptResources.addAll(extension.getJavaScriptResources()); | ||||||
|                 cssResources.addAll(extension.getCSSResources()); |                 cssResources.addAll(extension.getCSSResources()); | ||||||
|  |  | ||||||
|  |                 // Load all authentication providers as singletons | ||||||
|  |                 Collection<Class<AuthenticationProvider>> authenticationProviders = extension.getAuthenticationProviderClasses(); | ||||||
|  |                 for (Class<AuthenticationProvider> authenticationProvider : authenticationProviders) { | ||||||
|  |                     logger.debug("Binding AuthenticationProvider \"{}\".", authenticationProvider); | ||||||
|  |                     bind(AuthenticationProvider.class).to(authenticationProvider).in(Singleton.class); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|                 // Log successful loading of extension by name |                 // Log successful loading of extension by name | ||||||
|                 logger.info("Extension \"{}\" loaded.", extension.getName()); |                 logger.info("Extension \"{}\" loaded.", extension.getName()); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -84,15 +84,20 @@ public class RESTAuthModule extends AbstractModule { | |||||||
|         bind(AuthenticationService.class); |         bind(AuthenticationService.class); | ||||||
|         bind(AuthTokenGenerator.class).to(SecureRandomAuthTokenGenerator.class); |         bind(AuthTokenGenerator.class).to(SecureRandomAuthTokenGenerator.class); | ||||||
|  |  | ||||||
|         // Get and bind auth provider instance |         // Get and bind auth provider instance, if defined via property | ||||||
|         try { |         try { | ||||||
|             AuthenticationProvider authProvider = environment.getRequiredProperty(BasicGuacamoleProperties.AUTH_PROVIDER); |  | ||||||
|  |             // 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\" is now deprecated. Please use the \"extensions\" directory within GUACAMOLE_HOME instead."); | ||||||
|                 bind(AuthenticationProvider.class).toInstance(authProvider); |                 bind(AuthenticationProvider.class).toInstance(authProvider); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |         } | ||||||
|         catch (GuacamoleException e) { |         catch (GuacamoleException e) { | ||||||
|             logger.error("Unable to read authentication provider from guacamole.properties: {}", e.getMessage()); |             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); |             logger.debug("Error reading authentication provider from guacamole.properties.", e); | ||||||
|             throw new RuntimeException(e); |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|     } |     } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user