mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-07 21:51:23 +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);
|
|
||||||
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) {
|
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