mirror of
				https://github.com/gyurix1968/guacamole-client.git
				synced 2025-10-30 00:23: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.glyptodon.guacamole.GuacamoleException; | ||||
| 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.Resource; | ||||
|  | ||||
| @@ -74,6 +75,125 @@ public class Extension { | ||||
|      */ | ||||
|     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 | ||||
|      * 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); | ||||
|         } | ||||
|  | ||||
|         // 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(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 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 | ||||
|      * extension. JavaScript resources are declared within the extension | ||||
| @@ -224,7 +320,7 @@ public class Extension { | ||||
|      *     All declared JavaScript resources associated with this extension. | ||||
|      */ | ||||
|     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. | ||||
|      */ | ||||
|     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; | ||||
|  | ||||
|     /** | ||||
|      * 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 | ||||
|      * name is human-readable, for display purposes only, and is defined within | ||||
| @@ -169,4 +175,32 @@ public class ExtensionManifest { | ||||
|         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; | ||||
|  | ||||
| import com.google.inject.Singleton; | ||||
| import com.google.inject.servlet.ServletModule; | ||||
| import java.io.File; | ||||
| import java.io.FileFilter; | ||||
| @@ -29,6 +30,7 @@ import java.util.ArrayList; | ||||
| import java.util.Collection; | ||||
| import org.glyptodon.guacamole.GuacamoleException; | ||||
| 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.ResourceServlet; | ||||
| import org.glyptodon.guacamole.net.basic.resource.SequenceResource; | ||||
| @@ -118,6 +120,13 @@ public class ExtensionModule extends ServletModule { | ||||
|                 javaScriptResources.addAll(extension.getJavaScriptResources()); | ||||
|                 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 | ||||
|                 logger.info("Extension \"{}\" loaded.", extension.getName()); | ||||
|  | ||||
|   | ||||
| @@ -84,15 +84,20 @@ public class RESTAuthModule extends AbstractModule { | ||||
|         bind(AuthenticationService.class); | ||||
|         bind(AuthTokenGenerator.class).to(SecureRandomAuthTokenGenerator.class); | ||||
|  | ||||
|         // Get and bind auth provider instance | ||||
|         // Get and bind auth provider instance, if defined via property | ||||
|         try { | ||||
|             AuthenticationProvider authProvider = environment.getRequiredProperty(BasicGuacamoleProperties.AUTH_PROVIDER); | ||||
|             bind(AuthenticationProvider.class).toInstance(authProvider); | ||||
|  | ||||
|             // 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); | ||||
|             } | ||||
|  | ||||
|         } | ||||
|         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); | ||||
|             throw new RuntimeException(e); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user