GUACAMOLE-641: Allow extensions to receive Environment via constructors.

This commit is contained in:
Michael Jumper
2020-08-25 01:31:26 -07:00
parent 6644955fff
commit 9d7b979195
4 changed files with 47 additions and 14 deletions

View File

@@ -23,6 +23,7 @@ import java.util.Set;
import java.util.UUID; import java.util.UUID;
import org.apache.guacamole.GuacamoleClientException; import org.apache.guacamole.GuacamoleClientException;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.environment.Environment;
import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.AuthenticatedUser;
import org.apache.guacamole.net.auth.AuthenticationProvider; import org.apache.guacamole.net.auth.AuthenticationProvider;
import org.apache.guacamole.net.auth.Credentials; import org.apache.guacamole.net.auth.Credentials;
@@ -71,6 +72,9 @@ public class AuthenticationProviderFacade implements AuthenticationProvider {
* facade will still succeed, but its use will result in errors being * facade will still succeed, but its use will result in errors being
* logged, and all authentication attempts will fail. * logged, and all authentication attempts will fail.
* *
* @param environment
* The Guacamole server environment.
*
* @param authProviderClass * @param authProviderClass
* The AuthenticationProvider subclass to instantiate. * The AuthenticationProvider subclass to instantiate.
* *
@@ -83,12 +87,12 @@ public class AuthenticationProviderFacade implements AuthenticationProvider {
* attempt. By default, errors during authentication halt the * attempt. By default, errors during authentication halt the
* authentication process entirely. * authentication process entirely.
*/ */
public AuthenticationProviderFacade( public AuthenticationProviderFacade(Environment environment,
Class<? extends AuthenticationProvider> authProviderClass, Class<? extends AuthenticationProvider> authProviderClass,
Set<String> tolerateFailures) { Set<String> tolerateFailures) {
this.tolerateFailures = tolerateFailures; this.tolerateFailures = tolerateFailures;
this.authProvider = ProviderFactory.newInstance("authentication provider", this.authProvider = ProviderFactory.newInstance(environment,
authProviderClass); "authentication provider", authProviderClass);
} }
@Override @Override

View File

@@ -199,7 +199,7 @@ public class ExtensionModule extends ServletModule {
logger.debug("[{}] Binding AuthenticationProvider \"{}\".", logger.debug("[{}] Binding AuthenticationProvider \"{}\".",
boundAuthenticationProviders.size(), authenticationProvider.getName()); boundAuthenticationProviders.size(), authenticationProvider.getName());
boundAuthenticationProviders.add(new AuthenticationProviderFacade( boundAuthenticationProviders.add(new AuthenticationProviderFacade(
authenticationProvider, tolerateFailures)); environment, authenticationProvider, tolerateFailures));
} }
@@ -255,7 +255,7 @@ public class ExtensionModule extends ServletModule {
logger.debug("[{}] Binding listener \"{}\".", logger.debug("[{}] Binding listener \"{}\".",
boundListeners.size(), providerClass.getName()); boundListeners.size(), providerClass.getName());
boundListeners.addAll(ListenerFactory.createListeners(providerClass)); boundListeners.addAll(ListenerFactory.createListeners(environment, providerClass));
} }

View File

@@ -30,6 +30,7 @@ import org.apache.guacamole.net.event.listener.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import org.apache.guacamole.environment.Environment;
/** /**
* A factory that reflectively instantiates Listener objects for a given * A factory that reflectively instantiates Listener objects for a given
@@ -44,15 +45,20 @@ class ListenerFactory {
* only listener type that will be returned. Otherwise, a list of Listener * only listener type that will be returned. Otherwise, a list of Listener
* objects that adapt the legacy listener interfaces will be returned. * objects that adapt the legacy listener interfaces will be returned.
* *
* @param environment
* The Environment instance that should be passed to the constructor
* of the given class, if a constructor accepting an Environment
* instance is defined.
*
* @param providerClass * @param providerClass
* A class that represents a listener. * A class that represents a listener.
* *
* @return * @return
* The list of listeners represented by the given provider class. * The list of listeners represented by the given provider class.
*/ */
static List<Listener> createListeners(Class<?> providerClass) { static List<Listener> createListeners(Environment environment, Class<?> providerClass) {
Object provider = ProviderFactory.newInstance("listener", providerClass); Object provider = ProviderFactory.newInstance(environment, "listener", providerClass);
if (provider instanceof Listener) { if (provider instanceof Listener) {
return Collections.singletonList((Listener) provider); return Collections.singletonList((Listener) provider);

View File

@@ -24,6 +24,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import org.apache.guacamole.environment.Environment;
/** /**
* A utility for creating provider instances and logging unexpected outcomes * A utility for creating provider instances and logging unexpected outcomes
@@ -37,10 +38,18 @@ class ProviderFactory {
private static final Logger logger = LoggerFactory.getLogger(ProviderFactory.class); private static final Logger logger = LoggerFactory.getLogger(ProviderFactory.class);
/** /**
* Creates an instance of the specified provider class using the no-arg constructor. * Creates an instance of the specified provider class using either the
* constructor accepting an instance of the Environment interface or, if no
* such constructor is defined, the no-arg constructor.
*
* @param environment
* The Environment instance that should be passed to the constructor
* of the given class, if a constructor accepting an Environment
* instance is defined.
* *
* @param typeName * @param typeName
* The provider type name used for log messages; e.g. "authentication provider". * The provider type name used for log messages; e.g. "authentication
* provider".
* *
* @param providerClass * @param providerClass
* The provider class to instantiate. * The provider class to instantiate.
@@ -51,19 +60,33 @@ class ProviderFactory {
* @return * @return
* A provider instance or null if no instance was created due to error. * A provider instance or null if no instance was created due to error.
*/ */
static <T> T newInstance(String typeName, Class<? extends T> providerClass) { static <T> T newInstance(Environment environment, String typeName,
Class<? extends T> providerClass) {
T instance = null; T instance = null;
try { try {
// Attempt to instantiate the provider
instance = providerClass.getConstructor().newInstance(); // Attempt to instantiate the provider while providing the
// Guacamole server's environment
try {
instance = providerClass.getConstructor(Environment.class).newInstance(environment);
}
// Fall back to no-arg constructor if no constructor accepts
// Environment
catch (NoSuchMethodException e) {
logger.debug("{} does not provide a constructor accepting "
+ "Environment. Falling back to no-arg constructor.",
providerClass.getName());
instance = providerClass.getConstructor().newInstance();
}
} }
catch (NoSuchMethodException e) { catch (NoSuchMethodException e) {
logger.error("The {} extension in use is not properly defined. " logger.error("The {} extension in use is not properly defined. "
+ "Please contact the developers of the extension or, if you " + "Please contact the developers of the extension or, if you "
+ "are the developer, turn on debug-level logging.", typeName); + "are the developer, turn on debug-level logging.", typeName);
logger.debug("{} is missing a default constructor.", logger.debug("{} is missing a usable constructor.", providerClass.getName(), e);
providerClass.getName(), e);
} }
catch (SecurityException e) { catch (SecurityException e) {
logger.error("The Java security manager is preventing extensions " logger.error("The Java security manager is preventing extensions "