From 9d7b9791954f91354078b6809923a3a8c9b34688 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 25 Aug 2020 01:31:26 -0700 Subject: [PATCH 1/8] GUACAMOLE-641: Allow extensions to receive Environment via constructors. --- .../AuthenticationProviderFacade.java | 10 +++-- .../guacamole/extension/ExtensionModule.java | 4 +- .../guacamole/extension/ListenerFactory.java | 10 ++++- .../guacamole/extension/ProviderFactory.java | 37 +++++++++++++++---- 4 files changed, 47 insertions(+), 14 deletions(-) diff --git a/guacamole/src/main/java/org/apache/guacamole/extension/AuthenticationProviderFacade.java b/guacamole/src/main/java/org/apache/guacamole/extension/AuthenticationProviderFacade.java index 9855cd6fd..87e9e39d3 100644 --- a/guacamole/src/main/java/org/apache/guacamole/extension/AuthenticationProviderFacade.java +++ b/guacamole/src/main/java/org/apache/guacamole/extension/AuthenticationProviderFacade.java @@ -23,6 +23,7 @@ import java.util.Set; import java.util.UUID; import org.apache.guacamole.GuacamoleClientException; import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.environment.Environment; import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.AuthenticationProvider; 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 * logged, and all authentication attempts will fail. * + * @param environment + * The Guacamole server environment. + * * @param authProviderClass * The AuthenticationProvider subclass to instantiate. * @@ -83,12 +87,12 @@ public class AuthenticationProviderFacade implements AuthenticationProvider { * attempt. By default, errors during authentication halt the * authentication process entirely. */ - public AuthenticationProviderFacade( + public AuthenticationProviderFacade(Environment environment, Class authProviderClass, Set tolerateFailures) { this.tolerateFailures = tolerateFailures; - this.authProvider = ProviderFactory.newInstance("authentication provider", - authProviderClass); + this.authProvider = ProviderFactory.newInstance(environment, + "authentication provider", authProviderClass); } @Override diff --git a/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java b/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java index 58f124e6a..d7e266d2a 100644 --- a/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java +++ b/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java @@ -199,7 +199,7 @@ public class ExtensionModule extends ServletModule { logger.debug("[{}] Binding AuthenticationProvider \"{}\".", boundAuthenticationProviders.size(), authenticationProvider.getName()); boundAuthenticationProviders.add(new AuthenticationProviderFacade( - authenticationProvider, tolerateFailures)); + environment, authenticationProvider, tolerateFailures)); } @@ -255,7 +255,7 @@ public class ExtensionModule extends ServletModule { logger.debug("[{}] Binding listener \"{}\".", boundListeners.size(), providerClass.getName()); - boundListeners.addAll(ListenerFactory.createListeners(providerClass)); + boundListeners.addAll(ListenerFactory.createListeners(environment, providerClass)); } diff --git a/guacamole/src/main/java/org/apache/guacamole/extension/ListenerFactory.java b/guacamole/src/main/java/org/apache/guacamole/extension/ListenerFactory.java index 8aa6babb4..ef8d22d5b 100644 --- a/guacamole/src/main/java/org/apache/guacamole/extension/ListenerFactory.java +++ b/guacamole/src/main/java/org/apache/guacamole/extension/ListenerFactory.java @@ -30,6 +30,7 @@ import org.apache.guacamole.net.event.listener.*; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import org.apache.guacamole.environment.Environment; /** * 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 * 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 * A class that represents a listener. * * @return * The list of listeners represented by the given provider class. */ - static List createListeners(Class providerClass) { + static List createListeners(Environment environment, Class providerClass) { - Object provider = ProviderFactory.newInstance("listener", providerClass); + Object provider = ProviderFactory.newInstance(environment, "listener", providerClass); if (provider instanceof Listener) { return Collections.singletonList((Listener) provider); diff --git a/guacamole/src/main/java/org/apache/guacamole/extension/ProviderFactory.java b/guacamole/src/main/java/org/apache/guacamole/extension/ProviderFactory.java index 01fda5719..8f85093bd 100644 --- a/guacamole/src/main/java/org/apache/guacamole/extension/ProviderFactory.java +++ b/guacamole/src/main/java/org/apache/guacamole/extension/ProviderFactory.java @@ -24,6 +24,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.reflect.InvocationTargetException; +import org.apache.guacamole.environment.Environment; /** * 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); /** - * 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 - * 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 * The provider class to instantiate. @@ -51,19 +60,33 @@ class ProviderFactory { * @return * A provider instance or null if no instance was created due to error. */ - static T newInstance(String typeName, Class providerClass) { + static T newInstance(Environment environment, String typeName, + Class providerClass) { T instance = null; 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) { logger.error("The {} extension in use is not properly defined. " + "Please contact the developers of the extension or, if you " + "are the developer, turn on debug-level logging.", typeName); - logger.debug("{} is missing a default constructor.", - providerClass.getName(), e); + logger.debug("{} is missing a usable constructor.", providerClass.getName(), e); } catch (SecurityException e) { logger.error("The Java security manager is preventing extensions " From 61a3ec1331ba815365991a1cdfdedff572c96601 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 25 Aug 2020 02:25:08 -0700 Subject: [PATCH 2/8] GUACAMOLE-641: Allow extensions to add arbitrary sources of Guacamole properties. --- .../guacamole/environment/Environment.java | 22 ++ .../properties/FileGuacamoleProperties.java | 85 ++++ .../properties/GuacamoleProperties.java | 49 +++ .../PropertiesGuacamoleProperties.java | 54 +++ .../GuacamoleServletContextListener.java | 40 +- .../SystemEnvironmentGuacamoleProperties.java | 38 ++ .../guacamole/WebApplicationEnvironment.java | 364 ++++++++++++++++++ 7 files changed, 648 insertions(+), 4 deletions(-) create mode 100644 guacamole-ext/src/main/java/org/apache/guacamole/properties/FileGuacamoleProperties.java create mode 100644 guacamole-ext/src/main/java/org/apache/guacamole/properties/GuacamoleProperties.java create mode 100644 guacamole-ext/src/main/java/org/apache/guacamole/properties/PropertiesGuacamoleProperties.java create mode 100644 guacamole/src/main/java/org/apache/guacamole/SystemEnvironmentGuacamoleProperties.java create mode 100644 guacamole/src/main/java/org/apache/guacamole/WebApplicationEnvironment.java diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/environment/Environment.java b/guacamole-ext/src/main/java/org/apache/guacamole/environment/Environment.java index 43f8f7560..16f8f58d3 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/environment/Environment.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/environment/Environment.java @@ -19,9 +19,11 @@ package org.apache.guacamole.environment; +import org.apache.guacamole.properties.GuacamoleProperties; import java.io.File; import java.util.Map; import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.GuacamoleUnsupportedException; import org.apache.guacamole.net.auth.GuacamoleProxyConfiguration; import org.apache.guacamole.properties.BooleanGuacamoleProperty; import org.apache.guacamole.properties.GuacamoleProperty; @@ -162,4 +164,24 @@ public interface Environment { public GuacamoleProxyConfiguration getDefaultGuacamoleProxyConfiguration() throws GuacamoleException; + /** + * Adds another possible source of Guacamole configuration properties to + * this Environment. Properties not already defined by other sources of + * Guacamole configuration properties will alternatively be read from the + * given {@link GuacamoleProperties}. + * + * @param properties + * The GuacamoleProperties to add to this Environment. + * + * @throws GuacamoleException + * If the given GuacamoleProperties cannot be added, or if this + * Environment does not support this operation. + */ + public default void addGuacamoleProperties(GuacamoleProperties properties) + throws GuacamoleException { + throw new GuacamoleUnsupportedException(String.format("%s does not " + + "support dynamic definition of Guacamole properties.", + getClass())); + } + } diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/properties/FileGuacamoleProperties.java b/guacamole-ext/src/main/java/org/apache/guacamole/properties/FileGuacamoleProperties.java new file mode 100644 index 000000000..8be0b4e25 --- /dev/null +++ b/guacamole-ext/src/main/java/org/apache/guacamole/properties/FileGuacamoleProperties.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.guacamole.properties; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.GuacamoleServerException; + +/** + * GuacamoleProperties implementation which reads all properties from a + * standard Java properties file. + */ +public class FileGuacamoleProperties extends PropertiesGuacamoleProperties { + + /** + * Reads the given Java properties file, storing all property name/value + * pairs in a new {@link Properties} object. + * + * @param propertiesFile + * The Java properties file to read. + * + * @return + * A new Properties containing all property name/value pairs defined in + * the given file. + * + * @throws GuacamoleException + * If an error prevents reading the given Java properties file. + */ + private static Properties read(File propertiesFile) throws GuacamoleException { + + // Fail early if file simply does not exist + if (!propertiesFile.exists()) + throw new GuacamoleServerException(String.format("\"%s\" does not " + + "exist.", propertiesFile)); + + // Load properties from stream, if any, always closing stream when done + Properties properties = new Properties(); + try (InputStream stream = new FileInputStream(propertiesFile)) { + properties.load(stream); + } + catch (IOException e) { + throw new GuacamoleServerException(String.format("\"%s\" cannot " + + "be read: %s", propertiesFile, e.getMessage()), e); + } + + return properties; + + } + + /** + * Creates a new FileGuacamoleProperties which reads all properties from + * the given standard Java properties file. + * + * @param propertiesFile + * The Java properties file to read. + * + * @throws GuacamoleException + * If an error prevents reading the given Java properties file. + */ + public FileGuacamoleProperties(File propertiesFile) throws GuacamoleException { + super(read(propertiesFile)); + } + +} diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/properties/GuacamoleProperties.java b/guacamole-ext/src/main/java/org/apache/guacamole/properties/GuacamoleProperties.java new file mode 100644 index 000000000..d77512687 --- /dev/null +++ b/guacamole-ext/src/main/java/org/apache/guacamole/properties/GuacamoleProperties.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.guacamole.properties; + +import java.util.Properties; +import org.apache.guacamole.GuacamoleException; + +/** + * An arbitrary set of Guacamole configuration property name/value pairs. This + * interface is similar in concept to {@link Properties} except that + * implementations are not required to allow properties to be enumerated or + * iterated. Properties may simply be retrieved by their names, if known. + */ +public interface GuacamoleProperties { + + /** + * Returns the value of the property having the given name, if defined. If + * no such property exists, null is returned. + * + * @param name + * The name of the property to retrieve. + * + * @return + * The value of the given property, or null if no such property is + * defined. + * + * @throws GuacamoleException + * If an error prevents the given property from being read. + */ + String getProperty(String name) throws GuacamoleException; + +} diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/properties/PropertiesGuacamoleProperties.java b/guacamole-ext/src/main/java/org/apache/guacamole/properties/PropertiesGuacamoleProperties.java new file mode 100644 index 000000000..263f7ee3e --- /dev/null +++ b/guacamole-ext/src/main/java/org/apache/guacamole/properties/PropertiesGuacamoleProperties.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.guacamole.properties; + +import java.util.Properties; +import org.apache.guacamole.GuacamoleException; + +/** + * GuacamoleProperties implementation which reads all properties from a + * {@link Properties} object. + */ +public class PropertiesGuacamoleProperties implements GuacamoleProperties { + + /** + * The Properties from which all property values should be read. + */ + private final Properties properties; + + /** + * Creates a new PropertiesGuacamoleProperties which wraps the given + * {@link Properties}, providing access to the values of any properties + * defined therein. + * + * @param properties + * The Properties that should be used as the source of all property + * values exposed by this instance of PropertiesGuacamoleProperties. + */ + public PropertiesGuacamoleProperties(Properties properties) { + this.properties = properties; + } + + @Override + public String getProperty(String name) throws GuacamoleException { + return properties.getProperty(name); + } + +} diff --git a/guacamole/src/main/java/org/apache/guacamole/GuacamoleServletContextListener.java b/guacamole/src/main/java/org/apache/guacamole/GuacamoleServletContextListener.java index f793575e6..efe6943e3 100644 --- a/guacamole/src/main/java/org/apache/guacamole/GuacamoleServletContextListener.java +++ b/guacamole/src/main/java/org/apache/guacamole/GuacamoleServletContextListener.java @@ -24,15 +24,17 @@ import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.Stage; import com.google.inject.servlet.GuiceServletContextListener; +import java.io.File; import java.util.List; import java.util.concurrent.atomic.AtomicReference; import javax.inject.Inject; import javax.servlet.ServletContextEvent; import org.apache.guacamole.environment.Environment; -import org.apache.guacamole.environment.LocalEnvironment; import org.apache.guacamole.extension.ExtensionModule; import org.apache.guacamole.log.LogModule; import org.apache.guacamole.net.auth.AuthenticationProvider; +import org.apache.guacamole.properties.BooleanGuacamoleProperty; +import org.apache.guacamole.properties.FileGuacamoleProperties; import org.apache.guacamole.rest.RESTServiceModule; import org.apache.guacamole.rest.auth.HashTokenSessionMap; import org.apache.guacamole.rest.auth.TokenSessionMap; @@ -86,6 +88,18 @@ public class GuacamoleServletContextListener extends GuiceServletContextListener */ private final Logger logger = LoggerFactory.getLogger(GuacamoleServletContextListener.class); + /** + * A property that determines whether environment variables are evaluated + * to override properties specified in guacamole.properties. + */ + private static final BooleanGuacamoleProperty ENABLE_ENVIRONMENT_PROPERTIES = + new BooleanGuacamoleProperty() { + @Override + public String getName() { + return "enable-environment-properties"; + } + }; + /** * The Guacamole server environment. */ @@ -111,16 +125,34 @@ public class GuacamoleServletContextListener extends GuiceServletContextListener @Override public void contextInitialized(ServletContextEvent servletContextEvent) { + environment = new WebApplicationEnvironment(); + + // Read configuration information from GUACAMOLE_HOME/guacamole.properties try { - environment = new LocalEnvironment(); - sessionMap = new HashTokenSessionMap(environment); + environment.addGuacamoleProperties(new FileGuacamoleProperties( + new File(environment.getGuacamoleHome(), "guacamole.properties"))); } catch (GuacamoleException e) { logger.error("Unable to read guacamole.properties: {}", e.getMessage()); logger.debug("Error reading guacamole.properties.", e); - throw new RuntimeException(e); } + // For any values not defined in GUACAMOLE_HOME/guacamole.properties, + // read from system environment if "enable-environment-properties" is + // set to "true" + try { + if (environment.getProperty(ENABLE_ENVIRONMENT_PROPERTIES, false)) + environment.addGuacamoleProperties(new SystemEnvironmentGuacamoleProperties()); + } + catch (GuacamoleException e) { + logger.error("Unable to configure support for environment properties: {}", e.getMessage()); + logger.debug("Error reading \"{}\" property from guacamole.properties.", ENABLE_ENVIRONMENT_PROPERTIES.getName(), e); + } + + // Now that at least the main guacamole.properties source of + // configuration information is available, initialize the session map + sessionMap = new HashTokenSessionMap(environment); + // NOTE: The superclass implementation of contextInitialized() is // expected to invoke getInjector(), hence the need to call AFTER // setting up the environment and session map diff --git a/guacamole/src/main/java/org/apache/guacamole/SystemEnvironmentGuacamoleProperties.java b/guacamole/src/main/java/org/apache/guacamole/SystemEnvironmentGuacamoleProperties.java new file mode 100644 index 000000000..7ad2fd466 --- /dev/null +++ b/guacamole/src/main/java/org/apache/guacamole/SystemEnvironmentGuacamoleProperties.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.guacamole; + +import org.apache.guacamole.properties.GuacamoleProperties; +import org.apache.guacamole.token.TokenName; + +/** + * GuacamoleProperties implementation which reads all properties from + * environment variables. The name of the environment variable corresponding to + * any particular property is determined using + * {@link TokenName#canonicalize(java.lang.String)}. + */ +public class SystemEnvironmentGuacamoleProperties implements GuacamoleProperties { + + @Override + public String getProperty(String name) { + return System.getenv(TokenName.canonicalize(name)); + } + +} diff --git a/guacamole/src/main/java/org/apache/guacamole/WebApplicationEnvironment.java b/guacamole/src/main/java/org/apache/guacamole/WebApplicationEnvironment.java new file mode 100644 index 000000000..9f33a8136 --- /dev/null +++ b/guacamole/src/main/java/org/apache/guacamole/WebApplicationEnvironment.java @@ -0,0 +1,364 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.guacamole; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CopyOnWriteArrayList; +import org.codehaus.jackson.map.ObjectMapper; +import org.apache.guacamole.environment.Environment; +import org.apache.guacamole.net.auth.GuacamoleProxyConfiguration; +import org.apache.guacamole.properties.GuacamoleProperties; +import org.apache.guacamole.properties.GuacamoleProperty; +import org.apache.guacamole.protocols.ProtocolInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The environment of the locally-running instance of the Guacamole web + * application. + */ +public class WebApplicationEnvironment implements Environment { + + /** + * Logger for this class. + */ + private static final Logger logger = LoggerFactory.getLogger(WebApplicationEnvironment.class); + + /** + * Array of all known protocol names. + */ + private static final String[] KNOWN_PROTOCOLS = new String[] { + "kubernetes", + "rdp", + "ssh", + "telnet", + "vnc", + }; + + /** + * The hostname to use when connecting to guacd if no hostname is provided + * within guacamole.properties. + */ + private static final String DEFAULT_GUACD_HOSTNAME = "localhost"; + + /** + * The port to use when connecting to guacd if no port is provided within + * guacamole.properties. + */ + private static final int DEFAULT_GUACD_PORT = 4822; + + /** + * Whether SSL/TLS is enabled for connections to guacd if not specified + * within guacamole.properties. + */ + private static final boolean DEFAULT_GUACD_SSL = false; + + /** + * The location of GUACAMOLE_HOME, which may not truly exist. + */ + private final File guacHome; + + /** + * The map of all available protocols. + */ + private final Map availableProtocols; + + /** + * All GuacamoleProperties instances added via addGuacamoleProperties(), in + * the order that they were added. + */ + private final List availableProperties = new CopyOnWriteArrayList<>(); + + /** + * The Jackson parser for parsing JSON files. + */ + private static final ObjectMapper mapper = new ObjectMapper(); + + /** + * Creates a new Environment, initializing that environment based on the + * location of GUACAMOLE_HOME and the contents of guacamole.properties. + */ + public WebApplicationEnvironment() { + + // Determine location of GUACAMOLE_HOME + guacHome = findGuacamoleHome(); + logger.info("GUACAMOLE_HOME is \"{}\".", guacHome.getAbsolutePath()); + + // Read all protocols + availableProtocols = readProtocols(); + + } + + /** + * Locates the Guacamole home directory by checking, in order: + * the guacamole.home system property, the GUACAMOLE_HOME environment + * variable, and finally the .guacamole directory in the home directory of + * the user running the servlet container. If even the .guacamole directory + * doesn't exist, then /etc/guacamole will be used. + * + * @return The File representing the Guacamole home directory, which may + * or may not exist, and may turn out to not be a directory. + */ + private static File findGuacamoleHome() { + + // Attempt to find Guacamole home + File guacHome; + + // Use system property by default + String desiredDir = System.getProperty("guacamole.home"); + + // Failing that, try the GUACAMOLE_HOME environment variable + if (desiredDir == null) desiredDir = System.getenv("GUACAMOLE_HOME"); + + // If successful, use explicitly specified directory + if (desiredDir != null) + guacHome = new File(desiredDir); + + // If not explicitly specified, use standard locations + else { + + // Try ~/.guacamole first + guacHome = new File(System.getProperty("user.home"), ".guacamole"); + + // If that doesn't exist, try /etc/guacamole if the /etc directory + // exists on this system + if (!guacHome.exists() && new File("/etc").exists()) + guacHome = new File("/etc/guacamole"); + + } + + // Return discovered directory + return guacHome; + + } + + /** + * Parses the given JSON file, returning the parsed ProtocolInfo. The JSON + * format is conveniently and intentionally identical to a serialized + * ProtocolInfo object, which is identical to the JSON format used by the + * protocol REST service built into the Guacamole web application. + * + * @param input + * An input stream containing JSON describing the forms and parameters + * associated with a protocol supported by Guacamole. + * + * @return + * A new ProtocolInfo object which contains the forms and parameters + * described by the JSON file parsed. + * + * @throws IOException + * If an error occurs while parsing the JSON file. + */ + private ProtocolInfo readProtocol(InputStream input) + throws IOException { + return mapper.readValue(input, ProtocolInfo.class); + } + + /** + * Reads through all pre-defined protocols and any protocols within the + * "protocols" subdirectory of GUACAMOLE_HOME, returning a map containing + * each of these protocols. The key of each entry will be the name of that + * protocol, as would be passed to guacd during connection. + * + * @return + * A map of all available protocols. + */ + private Map readProtocols() { + + // Map of all available protocols + Map protocols = new HashMap(); + + // Get protcols directory + File protocol_directory = new File(getGuacamoleHome(), "protocols"); + + // Read protocols from directory if it exists + if (protocol_directory.isDirectory()) { + + // Get all JSON files + File[] files = protocol_directory.listFiles( + new FilenameFilter() { + + @Override + public boolean accept(File file, String string) { + return string.endsWith(".json"); + } + + } + ); + + // Warn if directory contents are not available + if (files == null) { + logger.error("Unable to read contents of \"{}\".", protocol_directory.getAbsolutePath()); + files = new File[0]; + } + + // Load each protocol from each file + for (File file : files) { + + try { + + // Parse protocol + FileInputStream stream = new FileInputStream(file); + ProtocolInfo protocol = readProtocol(stream); + stream.close(); + + // Store protocol + protocols.put(protocol.getName(), protocol); + + } + catch (IOException e) { + logger.error("Unable to read connection parameter information from \"{}\": {}", file.getAbsolutePath(), e.getMessage()); + logger.debug("Error reading protocol JSON.", e); + } + + } + + } + + // If known protocols are not already defined, read from classpath + for (String protocol : KNOWN_PROTOCOLS) { + + // If protocol not defined yet, attempt to load from classpath + if (!protocols.containsKey(protocol)) { + + InputStream stream = WebApplicationEnvironment.class.getResourceAsStream( + "/org/apache/guacamole/protocols/" + + protocol + ".json"); + + // Parse JSON if available + if (stream != null) { + try { + protocols.put(protocol, readProtocol(stream)); + } + catch (IOException e) { + logger.error("Unable to read pre-defined connection parameter information for protocol \"{}\": {}", protocol, e.getMessage()); + logger.debug("Error reading pre-defined protocol JSON.", e); + } + } + + } + + } + + // Protocols map now fully populated + return protocols; + + } + + @Override + public File getGuacamoleHome() { + return guacHome; + } + + /** + * Returns the string value of the property having the given name, trying + * each source of properties added with addGuacamoleProperties() until a + * value is found. If no such property is defined, null is returned. + * + * @param name + * The name of the property value to retrieve. + * + * @return + * The value of the property having the given name, or null if no such + * property is defined. + * + * @throws GuacamoleException + * If an error occurs retrieving a property from a GuacamoleProperties + * implementation added via addGuacamoleProperties(). + */ + private String getPropertyValue(String name) throws GuacamoleException { + + // Search all provided GuacamoleProperties implementations, in order + for (GuacamoleProperties properties : availableProperties) { + String value = properties.getProperty(name); + if (value != null) + return value; + } + + // No such property + return null; + + } + + @Override + public Type getProperty(GuacamoleProperty property) throws GuacamoleException { + return property.parseValue(getPropertyValue(property.getName())); + } + + @Override + public Type getProperty(GuacamoleProperty property, + Type defaultValue) throws GuacamoleException { + + Type value = getProperty(property); + if (value == null) + return defaultValue; + + return value; + + } + + @Override + public Type getRequiredProperty(GuacamoleProperty property) + throws GuacamoleException { + + Type value = getProperty(property); + if (value == null) + throw new GuacamoleServerException("Property " + property.getName() + " is required."); + + return value; + + } + + @Override + public Map getProtocols() { + return availableProtocols; + } + + @Override + public ProtocolInfo getProtocol(String name) { + return availableProtocols.get(name); + } + + @Override + public GuacamoleProxyConfiguration getDefaultGuacamoleProxyConfiguration() + throws GuacamoleException { + + // Parse guacd hostname/port/ssl properties + return new GuacamoleProxyConfiguration( + getProperty(Environment.GUACD_HOSTNAME, DEFAULT_GUACD_HOSTNAME), + getProperty(Environment.GUACD_PORT, DEFAULT_GUACD_PORT), + getProperty(Environment.GUACD_SSL, DEFAULT_GUACD_SSL) + ); + + } + + @Override + public void addGuacamoleProperties(GuacamoleProperties properties) { + availableProperties.add(properties); + } + +} From 30ddd7a092d55ce4dc1640e54f5f9fb3bc4777a1 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 25 Aug 2020 02:31:31 -0700 Subject: [PATCH 3/8] GUACAMOLE-641: Provide DelegatingEnvironment convenience class. --- .../environment/DelegatingEnvironment.java | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 guacamole-ext/src/main/java/org/apache/guacamole/environment/DelegatingEnvironment.java diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/environment/DelegatingEnvironment.java b/guacamole-ext/src/main/java/org/apache/guacamole/environment/DelegatingEnvironment.java new file mode 100644 index 000000000..cdaa924ea --- /dev/null +++ b/guacamole-ext/src/main/java/org/apache/guacamole/environment/DelegatingEnvironment.java @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.guacamole.environment; + +import java.io.File; +import java.util.Map; +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.net.auth.GuacamoleProxyConfiguration; +import org.apache.guacamole.properties.GuacamoleProperties; +import org.apache.guacamole.properties.GuacamoleProperty; +import org.apache.guacamole.protocols.ProtocolInfo; + +/** + * Environment implementation which simply delegates all function calls to a + * wrapped Environment instance. + */ +public class DelegatingEnvironment implements Environment { + + /** + * The Environment instance that all function calls should be delegated to. + */ + private final Environment environment; + + /** + * Creates a new DelegatingEnvironment which delegates all function calls + * to the given Environment. + * + * @param environment + * The Environment that all function calls should be delegated to. + */ + public DelegatingEnvironment(Environment environment) { + this.environment = environment; + } + + @Override + public File getGuacamoleHome() { + return environment.getGuacamoleHome(); + } + + @Override + public Map getProtocols() { + return environment.getProtocols(); + } + + @Override + public ProtocolInfo getProtocol(String name) { + return environment.getProtocol(name); + } + + @Override + public Type getProperty(GuacamoleProperty property) throws GuacamoleException { + return environment.getProperty(property); + } + + @Override + public Type getProperty(GuacamoleProperty property, Type defaultValue) throws GuacamoleException { + return environment.getProperty(property, defaultValue); + } + + @Override + public Type getRequiredProperty(GuacamoleProperty property) throws GuacamoleException { + return environment.getRequiredProperty(property); + } + + @Override + public GuacamoleProxyConfiguration getDefaultGuacamoleProxyConfiguration() throws GuacamoleException { + return environment.getDefaultGuacamoleProxyConfiguration(); + } + + @Override + public void addGuacamoleProperties(GuacamoleProperties properties) throws GuacamoleException { + environment.addGuacamoleProperties(properties); + } + +} From fc7c7b7966194db99e49c8fe603c8659660dd70c Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 25 Aug 2020 16:01:13 -0700 Subject: [PATCH 4/8] GUACAMOLE-641: Leverage singleton instance of LocalEnvironment. --- .../environment/LocalEnvironment.java | 186 ++++----- .../GuacamoleServletContextListener.java | 3 +- .../guacamole/WebApplicationEnvironment.java | 364 ------------------ 3 files changed, 74 insertions(+), 479 deletions(-) delete mode 100644 guacamole/src/main/java/org/apache/guacamole/WebApplicationEnvironment.java diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/environment/LocalEnvironment.java b/guacamole-ext/src/main/java/org/apache/guacamole/environment/LocalEnvironment.java index eecfdfcac..caf1c418e 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/environment/LocalEnvironment.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/environment/LocalEnvironment.java @@ -26,12 +26,13 @@ import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; +import java.util.List; import java.util.Map; -import java.util.Properties; +import java.util.concurrent.CopyOnWriteArrayList; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleServerException; import org.apache.guacamole.net.auth.GuacamoleProxyConfiguration; -import org.apache.guacamole.properties.BooleanGuacamoleProperty; +import org.apache.guacamole.properties.GuacamoleProperties; import org.apache.guacamole.properties.GuacamoleProperty; import org.apache.guacamole.protocols.ProtocolInfo; import org.slf4j.Logger; @@ -40,7 +41,10 @@ import org.slf4j.LoggerFactory; /** * The environment of the locally-running Guacamole instance, describing * available protocols, configuration parameters, and the GUACAMOLE_HOME - * directory. + * directory. Sources of configuration properties like guacamole.properties and + * environment variables will be automatically added by the Guacamole web + * application and may also be added by extensions using + * {@link #addGuacamoleProperties(org.apache.guacamole.properties.GuacamoleProperties)}. */ public class LocalEnvironment implements Environment { @@ -52,8 +56,13 @@ public class LocalEnvironment implements Environment { /** * Array of all known protocol names. */ - private static final String[] KNOWN_PROTOCOLS = new String[]{ - "vnc", "rdp", "ssh", "telnet", "kubernetes"}; + private static final String[] KNOWN_PROTOCOLS = new String[] { + "kubernetes", + "rdp", + "ssh", + "telnet", + "vnc", + }; /** * The hostname to use when connecting to guacd if no hostname is provided @@ -73,23 +82,6 @@ public class LocalEnvironment implements Environment { */ private static final boolean DEFAULT_GUACD_SSL = false; - /** - * A property that determines whether environment variables are evaluated - * to override properties specified in guacamole.properties. - */ - private static final BooleanGuacamoleProperty ENABLE_ENVIRONMENT_PROPERTIES = - new BooleanGuacamoleProperty() { - @Override - public String getName() { - return "enable-environment-properties"; - } - }; - - /** - * All properties read from guacamole.properties. - */ - private final Properties properties; - /** * The location of GUACAMOLE_HOME, which may not truly exist. */ @@ -101,9 +93,13 @@ public class LocalEnvironment implements Environment { private final Map availableProtocols; /** - * Flag indicating whether environment variables can override properties. + * All GuacamoleProperties instances added via addGuacamoleProperties(), in + * the order that they were added. This storage has been made static to + * allow addGuacamoleProperties() to work as expected even if extensions + * continue to use the deprecated constructor to create non-singleton + * instances. */ - private final boolean environmentPropertiesEnabled; + private static final List availableProperties = new CopyOnWriteArrayList<>(); /** * The Jackson parser for parsing JSON files. @@ -111,56 +107,43 @@ public class LocalEnvironment implements Environment { private static final ObjectMapper mapper = new ObjectMapper(); /** - * Creates a new Environment, initializing that environment based on the - * location of GUACAMOLE_HOME and the contents of guacamole.properties. - * - * @throws GuacamoleException If an error occurs while determining the - * environment of this Guacamole instance. + * Singleton instance of this environment, to be returned by calls to + * getInstance(). */ - public LocalEnvironment() throws GuacamoleException { + private static final LocalEnvironment instance = new LocalEnvironment(); + + /** + * Returns a singleton instance of LocalEnvironment which may be shared by + * the Guacamole web application and all extensions. + * + * @return + * A singleton instance of this class. + */ + public static LocalEnvironment getInstance() { + return instance; + } + + /** + * Creates a new LocalEnvironment, initializing that environment based on + * the contents of GUACAMOLE_HOME. Sources of configuration properties like + * guacamole.properties and environment variables will be automatically + * added by the Guacamole web application and/or any installed extensions. + * + * @deprecated + * Extensions leveraging LocalEnvironment should instead use + * LocalEnvironment.getInstance() to obtain a singleton instance of the + * environment. + */ + @Deprecated + public LocalEnvironment() { // Determine location of GUACAMOLE_HOME guacHome = findGuacamoleHome(); logger.info("GUACAMOLE_HOME is \"{}\".", guacHome.getAbsolutePath()); - // Read properties - properties = new Properties(); - try { - - InputStream stream = null; - - // If not a directory, load from classpath - if (!guacHome.isDirectory()) - stream = LocalEnvironment.class.getResourceAsStream("/guacamole.properties"); - - // Otherwise, try to load from file - else { - File propertiesFile = new File(guacHome, "guacamole.properties"); - if (propertiesFile.exists()) - stream = new FileInputStream(propertiesFile); - } - - // Load properties from stream, if any, always closing stream when done - if (stream != null) { - try { properties.load(stream); } - finally { stream.close(); } - } - - // Notify if we're proceeding without guacamole.properties - else - logger.info("No guacamole.properties file found within GUACAMOLE_HOME or the classpath. Using defaults."); - - } - catch (IOException e) { - logger.warn("The guacamole.properties file within GUACAMOLE_HOME cannot be read: {}", e.getMessage()); - logger.debug("Error reading guacamole.properties.", e); - } - // Read all protocols availableProtocols = readProtocols(); - // Should environment variables override configuration properties? - environmentPropertiesEnabled = environmentPropertiesEnabled(properties); } /** @@ -265,7 +248,7 @@ public class LocalEnvironment implements Environment { logger.error("Unable to read contents of \"{}\".", protocol_directory.getAbsolutePath()); files = new File[0]; } - + // Load each protocol from each file for (File file : files) { @@ -319,69 +302,39 @@ public class LocalEnvironment implements Environment { } - /** - * Checks for the presence of the {@link #ENABLE_ENVIRONMENT_PROPERTIES} - * property in the given properties collection. - * - * @param properties - * The properties collection to check. - * - * @return - * true if the property is present in the given properties collection - * and its parsed value is true - * - * @throws GuacamoleException If the value specified for the property - * cannot be successfully parsed as a Boolean - * - */ - private static boolean environmentPropertiesEnabled(Properties properties) - throws GuacamoleException { - - final Boolean enabled = ENABLE_ENVIRONMENT_PROPERTIES.parseValue( - properties.getProperty(ENABLE_ENVIRONMENT_PROPERTIES.getName())); - - return enabled != null && enabled; - } - @Override public File getGuacamoleHome() { return guacHome; } /** - * Gets the string value for a property name. - * - * The value may come from either the OS environment (if property override - * is enabled) or the Properties collection that was loaded from - * guacamole.properties. When checking the environment for the named - * property, the name is first transformed by converting all hyphens to - * underscores and converting the string to upper case letter, in accordance - * with common convention for environment strings. + * Returns the string value of the property having the given name, trying + * each source of properties added with addGuacamoleProperties() until a + * value is found. If no such property is defined, null is returned. * * @param name * The name of the property value to retrieve. * * @return - * The corresponding value for the property. If property override - * is enabled and the value is found in the OS environment, the value - * from the environment is returned. Otherwise, the value from - * guacamole.properties, if any, is returned. + * The value of the property having the given name, or null if no such + * property is defined. + * + * @throws GuacamoleException + * If an error occurs retrieving a property from a GuacamoleProperties + * implementation added via addGuacamoleProperties(). */ - private String getPropertyValue(String name) { + private String getPropertyValue(String name) throws GuacamoleException { - // Check for corresponding environment variable if overrides enabled - if (environmentPropertiesEnabled) { - - // Transform the name according to common convention - final String envName = name.replace('-', '_').toUpperCase(); - final String envValue = System.getenv(envName); - - if (envValue != null) { - return envValue; - } + // Search all provided GuacamoleProperties implementations, in order + for (GuacamoleProperties properties : availableProperties) { + String value = properties.getProperty(name); + if (value != null) + return value; } - return properties.getProperty(name); + // No such property + return null; + } @Override @@ -436,4 +389,9 @@ public class LocalEnvironment implements Environment { } + @Override + public void addGuacamoleProperties(GuacamoleProperties properties) { + availableProperties.add(properties); + } + } diff --git a/guacamole/src/main/java/org/apache/guacamole/GuacamoleServletContextListener.java b/guacamole/src/main/java/org/apache/guacamole/GuacamoleServletContextListener.java index efe6943e3..b33c65d99 100644 --- a/guacamole/src/main/java/org/apache/guacamole/GuacamoleServletContextListener.java +++ b/guacamole/src/main/java/org/apache/guacamole/GuacamoleServletContextListener.java @@ -30,6 +30,7 @@ import java.util.concurrent.atomic.AtomicReference; import javax.inject.Inject; import javax.servlet.ServletContextEvent; import org.apache.guacamole.environment.Environment; +import org.apache.guacamole.environment.LocalEnvironment; import org.apache.guacamole.extension.ExtensionModule; import org.apache.guacamole.log.LogModule; import org.apache.guacamole.net.auth.AuthenticationProvider; @@ -125,7 +126,7 @@ public class GuacamoleServletContextListener extends GuiceServletContextListener @Override public void contextInitialized(ServletContextEvent servletContextEvent) { - environment = new WebApplicationEnvironment(); + environment = LocalEnvironment.getInstance(); // Read configuration information from GUACAMOLE_HOME/guacamole.properties try { diff --git a/guacamole/src/main/java/org/apache/guacamole/WebApplicationEnvironment.java b/guacamole/src/main/java/org/apache/guacamole/WebApplicationEnvironment.java deleted file mode 100644 index 9f33a8136..000000000 --- a/guacamole/src/main/java/org/apache/guacamole/WebApplicationEnvironment.java +++ /dev/null @@ -1,364 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.guacamole; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FilenameFilter; -import java.io.IOException; -import java.io.InputStream; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CopyOnWriteArrayList; -import org.codehaus.jackson.map.ObjectMapper; -import org.apache.guacamole.environment.Environment; -import org.apache.guacamole.net.auth.GuacamoleProxyConfiguration; -import org.apache.guacamole.properties.GuacamoleProperties; -import org.apache.guacamole.properties.GuacamoleProperty; -import org.apache.guacamole.protocols.ProtocolInfo; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * The environment of the locally-running instance of the Guacamole web - * application. - */ -public class WebApplicationEnvironment implements Environment { - - /** - * Logger for this class. - */ - private static final Logger logger = LoggerFactory.getLogger(WebApplicationEnvironment.class); - - /** - * Array of all known protocol names. - */ - private static final String[] KNOWN_PROTOCOLS = new String[] { - "kubernetes", - "rdp", - "ssh", - "telnet", - "vnc", - }; - - /** - * The hostname to use when connecting to guacd if no hostname is provided - * within guacamole.properties. - */ - private static final String DEFAULT_GUACD_HOSTNAME = "localhost"; - - /** - * The port to use when connecting to guacd if no port is provided within - * guacamole.properties. - */ - private static final int DEFAULT_GUACD_PORT = 4822; - - /** - * Whether SSL/TLS is enabled for connections to guacd if not specified - * within guacamole.properties. - */ - private static final boolean DEFAULT_GUACD_SSL = false; - - /** - * The location of GUACAMOLE_HOME, which may not truly exist. - */ - private final File guacHome; - - /** - * The map of all available protocols. - */ - private final Map availableProtocols; - - /** - * All GuacamoleProperties instances added via addGuacamoleProperties(), in - * the order that they were added. - */ - private final List availableProperties = new CopyOnWriteArrayList<>(); - - /** - * The Jackson parser for parsing JSON files. - */ - private static final ObjectMapper mapper = new ObjectMapper(); - - /** - * Creates a new Environment, initializing that environment based on the - * location of GUACAMOLE_HOME and the contents of guacamole.properties. - */ - public WebApplicationEnvironment() { - - // Determine location of GUACAMOLE_HOME - guacHome = findGuacamoleHome(); - logger.info("GUACAMOLE_HOME is \"{}\".", guacHome.getAbsolutePath()); - - // Read all protocols - availableProtocols = readProtocols(); - - } - - /** - * Locates the Guacamole home directory by checking, in order: - * the guacamole.home system property, the GUACAMOLE_HOME environment - * variable, and finally the .guacamole directory in the home directory of - * the user running the servlet container. If even the .guacamole directory - * doesn't exist, then /etc/guacamole will be used. - * - * @return The File representing the Guacamole home directory, which may - * or may not exist, and may turn out to not be a directory. - */ - private static File findGuacamoleHome() { - - // Attempt to find Guacamole home - File guacHome; - - // Use system property by default - String desiredDir = System.getProperty("guacamole.home"); - - // Failing that, try the GUACAMOLE_HOME environment variable - if (desiredDir == null) desiredDir = System.getenv("GUACAMOLE_HOME"); - - // If successful, use explicitly specified directory - if (desiredDir != null) - guacHome = new File(desiredDir); - - // If not explicitly specified, use standard locations - else { - - // Try ~/.guacamole first - guacHome = new File(System.getProperty("user.home"), ".guacamole"); - - // If that doesn't exist, try /etc/guacamole if the /etc directory - // exists on this system - if (!guacHome.exists() && new File("/etc").exists()) - guacHome = new File("/etc/guacamole"); - - } - - // Return discovered directory - return guacHome; - - } - - /** - * Parses the given JSON file, returning the parsed ProtocolInfo. The JSON - * format is conveniently and intentionally identical to a serialized - * ProtocolInfo object, which is identical to the JSON format used by the - * protocol REST service built into the Guacamole web application. - * - * @param input - * An input stream containing JSON describing the forms and parameters - * associated with a protocol supported by Guacamole. - * - * @return - * A new ProtocolInfo object which contains the forms and parameters - * described by the JSON file parsed. - * - * @throws IOException - * If an error occurs while parsing the JSON file. - */ - private ProtocolInfo readProtocol(InputStream input) - throws IOException { - return mapper.readValue(input, ProtocolInfo.class); - } - - /** - * Reads through all pre-defined protocols and any protocols within the - * "protocols" subdirectory of GUACAMOLE_HOME, returning a map containing - * each of these protocols. The key of each entry will be the name of that - * protocol, as would be passed to guacd during connection. - * - * @return - * A map of all available protocols. - */ - private Map readProtocols() { - - // Map of all available protocols - Map protocols = new HashMap(); - - // Get protcols directory - File protocol_directory = new File(getGuacamoleHome(), "protocols"); - - // Read protocols from directory if it exists - if (protocol_directory.isDirectory()) { - - // Get all JSON files - File[] files = protocol_directory.listFiles( - new FilenameFilter() { - - @Override - public boolean accept(File file, String string) { - return string.endsWith(".json"); - } - - } - ); - - // Warn if directory contents are not available - if (files == null) { - logger.error("Unable to read contents of \"{}\".", protocol_directory.getAbsolutePath()); - files = new File[0]; - } - - // Load each protocol from each file - for (File file : files) { - - try { - - // Parse protocol - FileInputStream stream = new FileInputStream(file); - ProtocolInfo protocol = readProtocol(stream); - stream.close(); - - // Store protocol - protocols.put(protocol.getName(), protocol); - - } - catch (IOException e) { - logger.error("Unable to read connection parameter information from \"{}\": {}", file.getAbsolutePath(), e.getMessage()); - logger.debug("Error reading protocol JSON.", e); - } - - } - - } - - // If known protocols are not already defined, read from classpath - for (String protocol : KNOWN_PROTOCOLS) { - - // If protocol not defined yet, attempt to load from classpath - if (!protocols.containsKey(protocol)) { - - InputStream stream = WebApplicationEnvironment.class.getResourceAsStream( - "/org/apache/guacamole/protocols/" - + protocol + ".json"); - - // Parse JSON if available - if (stream != null) { - try { - protocols.put(protocol, readProtocol(stream)); - } - catch (IOException e) { - logger.error("Unable to read pre-defined connection parameter information for protocol \"{}\": {}", protocol, e.getMessage()); - logger.debug("Error reading pre-defined protocol JSON.", e); - } - } - - } - - } - - // Protocols map now fully populated - return protocols; - - } - - @Override - public File getGuacamoleHome() { - return guacHome; - } - - /** - * Returns the string value of the property having the given name, trying - * each source of properties added with addGuacamoleProperties() until a - * value is found. If no such property is defined, null is returned. - * - * @param name - * The name of the property value to retrieve. - * - * @return - * The value of the property having the given name, or null if no such - * property is defined. - * - * @throws GuacamoleException - * If an error occurs retrieving a property from a GuacamoleProperties - * implementation added via addGuacamoleProperties(). - */ - private String getPropertyValue(String name) throws GuacamoleException { - - // Search all provided GuacamoleProperties implementations, in order - for (GuacamoleProperties properties : availableProperties) { - String value = properties.getProperty(name); - if (value != null) - return value; - } - - // No such property - return null; - - } - - @Override - public Type getProperty(GuacamoleProperty property) throws GuacamoleException { - return property.parseValue(getPropertyValue(property.getName())); - } - - @Override - public Type getProperty(GuacamoleProperty property, - Type defaultValue) throws GuacamoleException { - - Type value = getProperty(property); - if (value == null) - return defaultValue; - - return value; - - } - - @Override - public Type getRequiredProperty(GuacamoleProperty property) - throws GuacamoleException { - - Type value = getProperty(property); - if (value == null) - throw new GuacamoleServerException("Property " + property.getName() + " is required."); - - return value; - - } - - @Override - public Map getProtocols() { - return availableProtocols; - } - - @Override - public ProtocolInfo getProtocol(String name) { - return availableProtocols.get(name); - } - - @Override - public GuacamoleProxyConfiguration getDefaultGuacamoleProxyConfiguration() - throws GuacamoleException { - - // Parse guacd hostname/port/ssl properties - return new GuacamoleProxyConfiguration( - getProperty(Environment.GUACD_HOSTNAME, DEFAULT_GUACD_HOSTNAME), - getProperty(Environment.GUACD_PORT, DEFAULT_GUACD_PORT), - getProperty(Environment.GUACD_SSL, DEFAULT_GUACD_SSL) - ); - - } - - @Override - public void addGuacamoleProperties(GuacamoleProperties properties) { - availableProperties.add(properties); - } - -} From 3a24b2f556d87edcf431f1d3023cd5c4a8c1424c Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 25 Aug 2020 16:02:28 -0700 Subject: [PATCH 5/8] GUACAMOLE-641: Revert support for passing Environment via extension constructors. This reverts commit 1f0b855ea4a39f4c41979ad9d59297f02f188b82. --- .../AuthenticationProviderFacade.java | 10 ++--- .../guacamole/extension/ExtensionModule.java | 4 +- .../guacamole/extension/ListenerFactory.java | 10 +---- .../guacamole/extension/ProviderFactory.java | 37 ++++--------------- 4 files changed, 14 insertions(+), 47 deletions(-) diff --git a/guacamole/src/main/java/org/apache/guacamole/extension/AuthenticationProviderFacade.java b/guacamole/src/main/java/org/apache/guacamole/extension/AuthenticationProviderFacade.java index 87e9e39d3..9855cd6fd 100644 --- a/guacamole/src/main/java/org/apache/guacamole/extension/AuthenticationProviderFacade.java +++ b/guacamole/src/main/java/org/apache/guacamole/extension/AuthenticationProviderFacade.java @@ -23,7 +23,6 @@ import java.util.Set; import java.util.UUID; import org.apache.guacamole.GuacamoleClientException; import org.apache.guacamole.GuacamoleException; -import org.apache.guacamole.environment.Environment; import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.AuthenticationProvider; import org.apache.guacamole.net.auth.Credentials; @@ -72,9 +71,6 @@ public class AuthenticationProviderFacade implements AuthenticationProvider { * facade will still succeed, but its use will result in errors being * logged, and all authentication attempts will fail. * - * @param environment - * The Guacamole server environment. - * * @param authProviderClass * The AuthenticationProvider subclass to instantiate. * @@ -87,12 +83,12 @@ public class AuthenticationProviderFacade implements AuthenticationProvider { * attempt. By default, errors during authentication halt the * authentication process entirely. */ - public AuthenticationProviderFacade(Environment environment, + public AuthenticationProviderFacade( Class authProviderClass, Set tolerateFailures) { this.tolerateFailures = tolerateFailures; - this.authProvider = ProviderFactory.newInstance(environment, - "authentication provider", authProviderClass); + this.authProvider = ProviderFactory.newInstance("authentication provider", + authProviderClass); } @Override diff --git a/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java b/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java index d7e266d2a..58f124e6a 100644 --- a/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java +++ b/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java @@ -199,7 +199,7 @@ public class ExtensionModule extends ServletModule { logger.debug("[{}] Binding AuthenticationProvider \"{}\".", boundAuthenticationProviders.size(), authenticationProvider.getName()); boundAuthenticationProviders.add(new AuthenticationProviderFacade( - environment, authenticationProvider, tolerateFailures)); + authenticationProvider, tolerateFailures)); } @@ -255,7 +255,7 @@ public class ExtensionModule extends ServletModule { logger.debug("[{}] Binding listener \"{}\".", boundListeners.size(), providerClass.getName()); - boundListeners.addAll(ListenerFactory.createListeners(environment, providerClass)); + boundListeners.addAll(ListenerFactory.createListeners(providerClass)); } diff --git a/guacamole/src/main/java/org/apache/guacamole/extension/ListenerFactory.java b/guacamole/src/main/java/org/apache/guacamole/extension/ListenerFactory.java index ef8d22d5b..8aa6babb4 100644 --- a/guacamole/src/main/java/org/apache/guacamole/extension/ListenerFactory.java +++ b/guacamole/src/main/java/org/apache/guacamole/extension/ListenerFactory.java @@ -30,7 +30,6 @@ import org.apache.guacamole.net.event.listener.*; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import org.apache.guacamole.environment.Environment; /** * A factory that reflectively instantiates Listener objects for a given @@ -45,20 +44,15 @@ class ListenerFactory { * only listener type that will be returned. Otherwise, a list of Listener * 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 * A class that represents a listener. * * @return * The list of listeners represented by the given provider class. */ - static List createListeners(Environment environment, Class providerClass) { + static List createListeners(Class providerClass) { - Object provider = ProviderFactory.newInstance(environment, "listener", providerClass); + Object provider = ProviderFactory.newInstance("listener", providerClass); if (provider instanceof Listener) { return Collections.singletonList((Listener) provider); diff --git a/guacamole/src/main/java/org/apache/guacamole/extension/ProviderFactory.java b/guacamole/src/main/java/org/apache/guacamole/extension/ProviderFactory.java index 8f85093bd..01fda5719 100644 --- a/guacamole/src/main/java/org/apache/guacamole/extension/ProviderFactory.java +++ b/guacamole/src/main/java/org/apache/guacamole/extension/ProviderFactory.java @@ -24,7 +24,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.reflect.InvocationTargetException; -import org.apache.guacamole.environment.Environment; /** * A utility for creating provider instances and logging unexpected outcomes @@ -38,18 +37,10 @@ class ProviderFactory { private static final Logger logger = LoggerFactory.getLogger(ProviderFactory.class); /** - * 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. + * Creates an instance of the specified provider class using the no-arg constructor. * * @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 * The provider class to instantiate. @@ -60,33 +51,19 @@ class ProviderFactory { * @return * A provider instance or null if no instance was created due to error. */ - static T newInstance(Environment environment, String typeName, - Class providerClass) { + static T newInstance(String typeName, Class providerClass) { T instance = null; try { - - // 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(); - } - + // Attempt to instantiate the provider + instance = providerClass.getConstructor().newInstance(); } catch (NoSuchMethodException e) { logger.error("The {} extension in use is not properly defined. " + "Please contact the developers of the extension or, if you " + "are the developer, turn on debug-level logging.", typeName); - logger.debug("{} is missing a usable constructor.", providerClass.getName(), e); + logger.debug("{} is missing a default constructor.", + providerClass.getName(), e); } catch (SecurityException e) { logger.error("The Java security manager is preventing extensions " From 4d651056950e39f63f49a4a6cdc27135c47093e3 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 25 Aug 2020 16:25:42 -0700 Subject: [PATCH 6/8] GUACAMOLE-641: Migrate existing extensions to singleton LocalEnvironment. --- .../auth/cas/CASAuthenticationProviderModule.java | 2 +- .../auth/duo/DuoAuthenticationProviderModule.java | 2 +- .../HTTPHeaderAuthenticationProviderModule.java | 2 +- .../guacamole/auth/jdbc/JDBCEnvironment.java | 12 +++++------- .../json/JSONAuthenticationProviderModule.java | 2 +- .../ldap/LDAPAuthenticationProviderModule.java | 2 +- .../openid/OpenIDAuthenticationProviderModule.java | 2 +- .../QuickConnectAuthenticationProviderModule.java | 2 +- .../radius/RadiusAuthenticationProviderModule.java | 2 +- .../saml/SAMLAuthenticationProviderModule.java | 2 +- .../totp/TOTPAuthenticationProviderModule.java | 2 +- .../net/auth/simple/SimpleConnection.java | 2 +- .../auth/file/FileAuthenticationProvider.java | 14 +------------- .../guacamole/rest/schema/SchemaResource.java | 2 +- 14 files changed, 18 insertions(+), 32 deletions(-) diff --git a/extensions/guacamole-auth-cas/src/main/java/org/apache/guacamole/auth/cas/CASAuthenticationProviderModule.java b/extensions/guacamole-auth-cas/src/main/java/org/apache/guacamole/auth/cas/CASAuthenticationProviderModule.java index 329aeae13..a259e449d 100644 --- a/extensions/guacamole-auth-cas/src/main/java/org/apache/guacamole/auth/cas/CASAuthenticationProviderModule.java +++ b/extensions/guacamole-auth-cas/src/main/java/org/apache/guacamole/auth/cas/CASAuthenticationProviderModule.java @@ -58,7 +58,7 @@ public class CASAuthenticationProviderModule extends AbstractModule { throws GuacamoleException { // Get local environment - this.environment = new LocalEnvironment(); + this.environment = LocalEnvironment.getInstance(); // Store associated auth provider this.authProvider = authProvider; diff --git a/extensions/guacamole-auth-duo/src/main/java/org/apache/guacamole/auth/duo/DuoAuthenticationProviderModule.java b/extensions/guacamole-auth-duo/src/main/java/org/apache/guacamole/auth/duo/DuoAuthenticationProviderModule.java index 705e37dec..a60523bf8 100644 --- a/extensions/guacamole-auth-duo/src/main/java/org/apache/guacamole/auth/duo/DuoAuthenticationProviderModule.java +++ b/extensions/guacamole-auth-duo/src/main/java/org/apache/guacamole/auth/duo/DuoAuthenticationProviderModule.java @@ -58,7 +58,7 @@ public class DuoAuthenticationProviderModule extends AbstractModule { throws GuacamoleException { // Get local environment - this.environment = new LocalEnvironment(); + this.environment = LocalEnvironment.getInstance(); // Store associated auth provider this.authProvider = authProvider; diff --git a/extensions/guacamole-auth-header/src/main/java/org/apache/guacamole/auth/header/HTTPHeaderAuthenticationProviderModule.java b/extensions/guacamole-auth-header/src/main/java/org/apache/guacamole/auth/header/HTTPHeaderAuthenticationProviderModule.java index b0e755a2a..a31d633f8 100644 --- a/extensions/guacamole-auth-header/src/main/java/org/apache/guacamole/auth/header/HTTPHeaderAuthenticationProviderModule.java +++ b/extensions/guacamole-auth-header/src/main/java/org/apache/guacamole/auth/header/HTTPHeaderAuthenticationProviderModule.java @@ -56,7 +56,7 @@ public class HTTPHeaderAuthenticationProviderModule extends AbstractModule { throws GuacamoleException { // Get local environment - this.environment = new LocalEnvironment(); + this.environment = LocalEnvironment.getInstance(); // Store associated auth provider this.authProvider = authProvider; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCEnvironment.java index 838ad4d58..ea4bcd959 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCEnvironment.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCEnvironment.java @@ -20,25 +20,23 @@ package org.apache.guacamole.auth.jdbc; import org.apache.guacamole.GuacamoleException; -import org.apache.guacamole.environment.LocalEnvironment; import org.apache.guacamole.auth.jdbc.security.PasswordPolicy; +import org.apache.guacamole.environment.DelegatingEnvironment; +import org.apache.guacamole.environment.LocalEnvironment; import org.apache.ibatis.session.SqlSession; /** * A JDBC-specific implementation of Environment that defines generic properties * intended for use within JDBC based authentication providers. */ -public abstract class JDBCEnvironment extends LocalEnvironment { +public abstract class JDBCEnvironment extends DelegatingEnvironment { /** * Constructs a new JDBCEnvironment using an underlying LocalEnviroment to * read properties from the file system. - * - * @throws GuacamoleException - * If an error occurs while setting up the underlying LocalEnvironment. */ - public JDBCEnvironment() throws GuacamoleException { - super(); + public JDBCEnvironment() { + super(LocalEnvironment.getInstance()); } /** diff --git a/extensions/guacamole-auth-json/src/main/java/org/apache/guacamole/auth/json/JSONAuthenticationProviderModule.java b/extensions/guacamole-auth-json/src/main/java/org/apache/guacamole/auth/json/JSONAuthenticationProviderModule.java index ba12edc79..325b31e43 100644 --- a/extensions/guacamole-auth-json/src/main/java/org/apache/guacamole/auth/json/JSONAuthenticationProviderModule.java +++ b/extensions/guacamole-auth-json/src/main/java/org/apache/guacamole/auth/json/JSONAuthenticationProviderModule.java @@ -59,7 +59,7 @@ public class JSONAuthenticationProviderModule extends AbstractModule { throws GuacamoleException { // Get local environment - this.environment = new LocalEnvironment(); + this.environment = LocalEnvironment.getInstance(); // Store associated auth provider this.authProvider = authProvider; diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/LDAPAuthenticationProviderModule.java b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/LDAPAuthenticationProviderModule.java index 9cfaadf63..fb6f915cf 100644 --- a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/LDAPAuthenticationProviderModule.java +++ b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/LDAPAuthenticationProviderModule.java @@ -60,7 +60,7 @@ public class LDAPAuthenticationProviderModule extends AbstractModule { throws GuacamoleException { // Get local environment - this.environment = new LocalEnvironment(); + this.environment = LocalEnvironment.getInstance(); // Store associated auth provider this.authProvider = authProvider; diff --git a/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/OpenIDAuthenticationProviderModule.java b/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/OpenIDAuthenticationProviderModule.java index 17510cbe5..83e8c3777 100644 --- a/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/OpenIDAuthenticationProviderModule.java +++ b/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/OpenIDAuthenticationProviderModule.java @@ -59,7 +59,7 @@ public class OpenIDAuthenticationProviderModule extends AbstractModule { throws GuacamoleException { // Get local environment - this.environment = new LocalEnvironment(); + this.environment = LocalEnvironment.getInstance(); // Store associated auth provider this.authProvider = authProvider; diff --git a/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/QuickConnectAuthenticationProviderModule.java b/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/QuickConnectAuthenticationProviderModule.java index 7841316be..5243e5371 100644 --- a/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/QuickConnectAuthenticationProviderModule.java +++ b/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/QuickConnectAuthenticationProviderModule.java @@ -57,7 +57,7 @@ public class QuickConnectAuthenticationProviderModule extends AbstractModule { AuthenticationProvider authProvider) throws GuacamoleException { // Get local environment - this.environment = new LocalEnvironment(); + this.environment = LocalEnvironment.getInstance(); // Store associated auth provider this.authProvider = authProvider; diff --git a/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/RadiusAuthenticationProviderModule.java b/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/RadiusAuthenticationProviderModule.java index fa8b1cf88..82b9c408e 100644 --- a/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/RadiusAuthenticationProviderModule.java +++ b/extensions/guacamole-auth-radius/src/main/java/org/apache/guacamole/auth/radius/RadiusAuthenticationProviderModule.java @@ -63,7 +63,7 @@ public class RadiusAuthenticationProviderModule extends AbstractModule { throws GuacamoleException { // Get local environment - this.environment = new LocalEnvironment(); + this.environment = LocalEnvironment.getInstance(); // Check for MD4 requirement RadiusAuthenticationProtocol authProtocol = environment.getProperty(RadiusGuacamoleProperties.RADIUS_AUTH_PROTOCOL); diff --git a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProviderModule.java b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProviderModule.java index faa093550..9405b1e86 100644 --- a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProviderModule.java +++ b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProviderModule.java @@ -57,7 +57,7 @@ public class SAMLAuthenticationProviderModule extends AbstractModule { throws GuacamoleException { // Get local environment - this.environment = new LocalEnvironment(); + this.environment = LocalEnvironment.getInstance(); // Store associated auth provider this.authProvider = authProvider; diff --git a/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/TOTPAuthenticationProviderModule.java b/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/TOTPAuthenticationProviderModule.java index d1f7f9616..51650d8ed 100644 --- a/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/TOTPAuthenticationProviderModule.java +++ b/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/TOTPAuthenticationProviderModule.java @@ -59,7 +59,7 @@ public class TOTPAuthenticationProviderModule extends AbstractModule { throws GuacamoleException { // Get local environment - this.environment = new LocalEnvironment(); + this.environment = LocalEnvironment.getInstance(); // Store associated auth provider this.authProvider = authProvider; diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleConnection.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleConnection.java index ba61f7a7c..aa7e74853 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleConnection.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleConnection.java @@ -202,7 +202,7 @@ public class SimpleConnection extends AbstractConnection { throws GuacamoleException { // Retrieve proxy configuration from environment - Environment environment = new LocalEnvironment(); + Environment environment = LocalEnvironment.getInstance(); GuacamoleProxyConfiguration proxyConfig = environment.getDefaultGuacamoleProxyConfiguration(); // Get guacd connection parameters diff --git a/guacamole/src/main/java/org/apache/guacamole/auth/file/FileAuthenticationProvider.java b/guacamole/src/main/java/org/apache/guacamole/auth/file/FileAuthenticationProvider.java index 53ae7ebe9..3099b3b92 100644 --- a/guacamole/src/main/java/org/apache/guacamole/auth/file/FileAuthenticationProvider.java +++ b/guacamole/src/main/java/org/apache/guacamole/auth/file/FileAuthenticationProvider.java @@ -63,25 +63,13 @@ public class FileAuthenticationProvider extends SimpleAuthenticationProvider { /** * Guacamole server environment. */ - private final Environment environment; + private final Environment environment = LocalEnvironment.getInstance(); /** * The filename to use for the user mapping. */ public static final String USER_MAPPING_FILENAME = "user-mapping.xml"; - /** - * Creates a new FileAuthenticationProvider that authenticates users against - * simple, monolithic XML file. - * - * @throws GuacamoleException - * If a required property is missing, or an error occurs while parsing - * a property. - */ - public FileAuthenticationProvider() throws GuacamoleException { - environment = new LocalEnvironment(); - } - @Override public String getIdentifier() { return "default"; diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/schema/SchemaResource.java b/guacamole/src/main/java/org/apache/guacamole/rest/schema/SchemaResource.java index 211885def..9086ac93e 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/schema/SchemaResource.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/schema/SchemaResource.java @@ -171,7 +171,7 @@ public class SchemaResource { public Map getProtocols() throws GuacamoleException { // Get and return a map of all protocols. - Environment env = new LocalEnvironment(); + Environment env = LocalEnvironment.getInstance(); return env.getProtocols(); } From c54f126824b5f6feb8a128405aa8165f32f23a5f Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 25 Aug 2020 16:30:42 -0700 Subject: [PATCH 7/8] GUACAMOLE-641: Standardize database username/password retrieval via JDBCEnvironment. --- .../guacamole/auth/jdbc/JDBCEnvironment.java | 26 +++++++++++++++ .../MySQLAuthenticationProviderModule.java | 4 +-- .../auth/mysql/conf/MySQLEnvironment.java | 30 +++-------------- ...ostgreSQLAuthenticationProviderModule.java | 4 +-- .../conf/PostgreSQLEnvironment.java | 32 ++++--------------- ...SQLServerAuthenticationProviderModule.java | 4 +-- .../sqlserver/conf/SQLServerEnvironment.java | 28 +++------------- 7 files changed, 47 insertions(+), 81 deletions(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCEnvironment.java index ea4bcd959..a6313a965 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCEnvironment.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCEnvironment.java @@ -166,4 +166,30 @@ public abstract class JDBCEnvironment extends DelegatingEnvironment { */ public abstract boolean autoCreateAbsentAccounts() throws GuacamoleException; + /** + * Returns the username that should be used when authenticating with the + * database containing the Guacamole authentication tables. + * + * @return + * The username for the database. + * + * @throws GuacamoleException + * If an error occurs while retrieving the property value, or if the + * value was not set, as this property is required. + */ + public abstract String getUsername() throws GuacamoleException; + + /** + * Returns the password that should be used authenticating with the + * database containing the Guacamole authentication tables. + * + * @return + * The password for the database. + * + * @throws GuacamoleException + * If an error occurs while retrieving the property value, or if the + * value was not set, as this property is required. + */ + public abstract String getPassword() throws GuacamoleException; + } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLAuthenticationProviderModule.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLAuthenticationProviderModule.java index d1fc93d40..a4e1ef2e0 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLAuthenticationProviderModule.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLAuthenticationProviderModule.java @@ -72,8 +72,8 @@ public class MySQLAuthenticationProviderModule implements Module { myBatisProperties.setProperty("JDBC.host", environment.getMySQLHostname()); myBatisProperties.setProperty("JDBC.port", String.valueOf(environment.getMySQLPort())); myBatisProperties.setProperty("JDBC.schema", environment.getMySQLDatabase()); - myBatisProperties.setProperty("JDBC.username", environment.getMySQLUsername()); - myBatisProperties.setProperty("JDBC.password", environment.getMySQLPassword()); + myBatisProperties.setProperty("JDBC.username", environment.getUsername()); + myBatisProperties.setProperty("JDBC.password", environment.getPassword()); myBatisProperties.setProperty("JDBC.autoCommit", "false"); myBatisProperties.setProperty("mybatis.pooled.pingEnabled", "true"); myBatisProperties.setProperty("mybatis.pooled.pingQuery", "SELECT 1"); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/conf/MySQLEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/conf/MySQLEnvironment.java index 31f04e559..f4aa645b1 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/conf/MySQLEnvironment.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/conf/MySQLEnvironment.java @@ -241,34 +241,14 @@ public class MySQLEnvironment extends JDBCEnvironment { public String getMySQLDatabase() throws GuacamoleException { return getRequiredProperty(MySQLGuacamoleProperties.MYSQL_DATABASE); } - - /** - * Returns the username that should be used when authenticating with the - * MySQL database containing the Guacamole authentication tables. - * - * @return - * The username for the MySQL database. - * - * @throws GuacamoleException - * If an error occurs while retrieving the property value, or if the - * value was not set, as this property is required. - */ - public String getMySQLUsername() throws GuacamoleException { + + @Override + public String getUsername() throws GuacamoleException { return getRequiredProperty(MySQLGuacamoleProperties.MYSQL_USERNAME); } - /** - * Returns the password that should be used when authenticating with the - * MySQL database containing the Guacamole authentication tables. - * - * @return - * The password for the MySQL database. - * - * @throws GuacamoleException - * If an error occurs while retrieving the property value, or if the - * value was not set, as this property is required. - */ - public String getMySQLPassword() throws GuacamoleException { + @Override + public String getPassword() throws GuacamoleException { return getRequiredProperty(MySQLGuacamoleProperties.MYSQL_PASSWORD); } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLAuthenticationProviderModule.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLAuthenticationProviderModule.java index 280cead71..0b285f100 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLAuthenticationProviderModule.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLAuthenticationProviderModule.java @@ -64,8 +64,8 @@ public class PostgreSQLAuthenticationProviderModule implements Module { myBatisProperties.setProperty("JDBC.host", environment.getPostgreSQLHostname()); myBatisProperties.setProperty("JDBC.port", String.valueOf(environment.getPostgreSQLPort())); myBatisProperties.setProperty("JDBC.schema", environment.getPostgreSQLDatabase()); - myBatisProperties.setProperty("JDBC.username", environment.getPostgreSQLUsername()); - myBatisProperties.setProperty("JDBC.password", environment.getPostgreSQLPassword()); + myBatisProperties.setProperty("JDBC.username", environment.getUsername()); + myBatisProperties.setProperty("JDBC.password", environment.getPassword()); myBatisProperties.setProperty("JDBC.autoCommit", "false"); myBatisProperties.setProperty("mybatis.pooled.pingEnabled", "true"); myBatisProperties.setProperty("mybatis.pooled.pingQuery", "SELECT 1"); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLEnvironment.java index 012877cf6..2ead15b6e 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLEnvironment.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/conf/PostgreSQLEnvironment.java @@ -232,34 +232,14 @@ public class PostgreSQLEnvironment extends JDBCEnvironment { public String getPostgreSQLDatabase() throws GuacamoleException { return getRequiredProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_DATABASE); } - - /** - * Returns the username that should be used when authenticating with the - * PostgreSQL database containing the Guacamole authentication tables. - * - * @return - * The username for the PostgreSQL database. - * - * @throws GuacamoleException - * If an error occurs while retrieving the property value, or if the - * value was not set, as this property is required. - */ - public String getPostgreSQLUsername() throws GuacamoleException { + + @Override + public String getUsername() throws GuacamoleException { return getRequiredProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_USERNAME); } - - /** - * Returns the password that should be used when authenticating with the - * PostgreSQL database containing the Guacamole authentication tables. - * - * @return - * The password for the PostgreSQL database. - * - * @throws GuacamoleException - * If an error occurs while retrieving the property value, or if the - * value was not set, as this property is required. - */ - public String getPostgreSQLPassword() throws GuacamoleException { + + @Override + public String getPassword() throws GuacamoleException { return getRequiredProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_PASSWORD); } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/SQLServerAuthenticationProviderModule.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/SQLServerAuthenticationProviderModule.java index bcd4bc94c..ead21066d 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/SQLServerAuthenticationProviderModule.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/SQLServerAuthenticationProviderModule.java @@ -69,8 +69,8 @@ public class SQLServerAuthenticationProviderModule implements Module { myBatisProperties.setProperty("JDBC.host", environment.getSQLServerHostname()); myBatisProperties.setProperty("JDBC.port", String.valueOf(environment.getSQLServerPort())); myBatisProperties.setProperty("JDBC.schema", environment.getSQLServerDatabase()); - myBatisProperties.setProperty("JDBC.username", environment.getSQLServerUsername()); - myBatisProperties.setProperty("JDBC.password", environment.getSQLServerPassword()); + myBatisProperties.setProperty("JDBC.username", environment.getUsername()); + myBatisProperties.setProperty("JDBC.password", environment.getPassword()); myBatisProperties.setProperty("JDBC.autoCommit", "false"); myBatisProperties.setProperty("mybatis.pooled.pingEnabled", "true"); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/conf/SQLServerEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/conf/SQLServerEnvironment.java index 563db0ea2..0e1554371 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/conf/SQLServerEnvironment.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/conf/SQLServerEnvironment.java @@ -222,33 +222,13 @@ public class SQLServerEnvironment extends JDBCEnvironment { return getRequiredProperty(SQLServerGuacamoleProperties.SQLSERVER_DATABASE); } - /** - * Returns the username that should be used when authenticating with the - * SQLServer database containing the Guacamole authentication tables. - * - * @return - * The username for the SQLServer database. - * - * @throws GuacamoleException - * If an error occurs while retrieving the property value, or if the - * value was not set, as this property is required. - */ - public String getSQLServerUsername() throws GuacamoleException { + @Override + public String getUsername() throws GuacamoleException { return getRequiredProperty(SQLServerGuacamoleProperties.SQLSERVER_USERNAME); } - /** - * Returns the password that should be used when authenticating with the - * SQLServer database containing the Guacamole authentication tables. - * - * @return - * The password for the SQLServer database. - * - * @throws GuacamoleException - * If an error occurs while retrieving the property value, or if the - * value was not set, as this property is required. - */ - public String getSQLServerPassword() throws GuacamoleException { + @Override + public String getPassword() throws GuacamoleException { return getRequiredProperty(SQLServerGuacamoleProperties.SQLSERVER_PASSWORD); } From 4dd2a80c84af08b10535743e7e0d19c4994deb5e Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 25 Aug 2020 17:25:27 -0700 Subject: [PATCH 8/8] GUACAMOLE-641: Log primary sources of configuration information. --- .../DynamicallyAuthenticatedDataSource.java | 76 +++++++++++++++++++ .../JDBCAuthenticationProviderModule.java | 4 +- .../MySQLAuthenticationProviderModule.java | 2 - ...ostgreSQLAuthenticationProviderModule.java | 2 - ...SQLServerAuthenticationProviderModule.java | 2 - .../GuacamoleServletContextListener.java | 10 ++- 6 files changed, 85 insertions(+), 11 deletions(-) create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/DynamicallyAuthenticatedDataSource.java diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/DynamicallyAuthenticatedDataSource.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/DynamicallyAuthenticatedDataSource.java new file mode 100644 index 000000000..4c804a6ca --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/DynamicallyAuthenticatedDataSource.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.guacamole.auth.jdbc; + +import com.google.inject.Inject; +import com.google.inject.Singleton; +import com.google.inject.name.Named; +import java.sql.Connection; +import java.sql.SQLException; +import org.apache.guacamole.GuacamoleException; +import org.apache.ibatis.datasource.pooled.PooledDataSource; +import org.apache.ibatis.datasource.unpooled.UnpooledDataSource; + +/** + * Pooled DataSource implementation which dynamically retrieves the database + * username and password from the Guacamole server environment each time a + * new database connection is created. + */ +@Singleton +public class DynamicallyAuthenticatedDataSource extends PooledDataSource { + + /** + * Creates a new DynamicallyAuthenticatedDataSource which dynamically + * retrieves database credentials from the given JDBCEnvironment each time + * a new database connection is needed. + * + * @param environment + * The JDBCEnvironment that should be used to retrieve database + * credentials. + * + * @param driverClassLoader + * @param driver + * @param url + */ + @Inject + public DynamicallyAuthenticatedDataSource(JDBCEnvironment environment, + @Named(value="JDBC.driverClassLoader") ClassLoader driverClassLoader, + @Named(value="JDBC.driver") String driver, + @Named(value="JDBC.url") String url) { + + // Wrap unpooled DataSource, overriding the connection process such + // that credentials are dynamically retrieved from the JDBCEnvironment + super(new UnpooledDataSource(driverClassLoader, driver, url, null, null) { + + @Override + public Connection getConnection() throws SQLException { + try { + return super.getConnection(environment.getUsername(), environment.getPassword()); + } + catch (GuacamoleException e) { + throw new SQLException("Retrieval of database credentials failed.", e); + } + } + + }); + + } + +} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java index 5203cfee7..5ae0ea53f 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java @@ -20,6 +20,7 @@ package org.apache.guacamole.auth.jdbc; import com.google.inject.Scopes; +import javax.sql.DataSource; import org.apache.guacamole.auth.jdbc.user.ModeledUserContext; import org.apache.guacamole.auth.jdbc.connectiongroup.RootConnectionGroup; import org.apache.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup; @@ -90,7 +91,6 @@ import org.apache.guacamole.auth.jdbc.usergroup.UserGroupMemberUserMapper; import org.apache.guacamole.auth.jdbc.usergroup.UserGroupParentUserGroupMapper; import org.apache.guacamole.auth.jdbc.usergroup.UserGroupService; import org.mybatis.guice.MyBatisModule; -import org.mybatis.guice.datasource.builtin.PooledDataSourceProvider; import org.apache.guacamole.auth.jdbc.user.UserParentUserGroupMapper; /** @@ -121,7 +121,7 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule { protected void initialize() { // Datasource - bindDataSourceProviderType(PooledDataSourceProvider.class); + bind(DataSource.class).to(DynamicallyAuthenticatedDataSource.class); // Transaction factory bindTransactionFactoryType(JdbcTransactionFactory.class); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLAuthenticationProviderModule.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLAuthenticationProviderModule.java index a4e1ef2e0..658c08a3a 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLAuthenticationProviderModule.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLAuthenticationProviderModule.java @@ -72,8 +72,6 @@ public class MySQLAuthenticationProviderModule implements Module { myBatisProperties.setProperty("JDBC.host", environment.getMySQLHostname()); myBatisProperties.setProperty("JDBC.port", String.valueOf(environment.getMySQLPort())); myBatisProperties.setProperty("JDBC.schema", environment.getMySQLDatabase()); - myBatisProperties.setProperty("JDBC.username", environment.getUsername()); - myBatisProperties.setProperty("JDBC.password", environment.getPassword()); myBatisProperties.setProperty("JDBC.autoCommit", "false"); myBatisProperties.setProperty("mybatis.pooled.pingEnabled", "true"); myBatisProperties.setProperty("mybatis.pooled.pingQuery", "SELECT 1"); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLAuthenticationProviderModule.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLAuthenticationProviderModule.java index 0b285f100..cdb0b8a94 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLAuthenticationProviderModule.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLAuthenticationProviderModule.java @@ -64,8 +64,6 @@ public class PostgreSQLAuthenticationProviderModule implements Module { myBatisProperties.setProperty("JDBC.host", environment.getPostgreSQLHostname()); myBatisProperties.setProperty("JDBC.port", String.valueOf(environment.getPostgreSQLPort())); myBatisProperties.setProperty("JDBC.schema", environment.getPostgreSQLDatabase()); - myBatisProperties.setProperty("JDBC.username", environment.getUsername()); - myBatisProperties.setProperty("JDBC.password", environment.getPassword()); myBatisProperties.setProperty("JDBC.autoCommit", "false"); myBatisProperties.setProperty("mybatis.pooled.pingEnabled", "true"); myBatisProperties.setProperty("mybatis.pooled.pingQuery", "SELECT 1"); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/SQLServerAuthenticationProviderModule.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/SQLServerAuthenticationProviderModule.java index ead21066d..74d3c950f 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/SQLServerAuthenticationProviderModule.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/SQLServerAuthenticationProviderModule.java @@ -69,8 +69,6 @@ public class SQLServerAuthenticationProviderModule implements Module { myBatisProperties.setProperty("JDBC.host", environment.getSQLServerHostname()); myBatisProperties.setProperty("JDBC.port", String.valueOf(environment.getSQLServerPort())); myBatisProperties.setProperty("JDBC.schema", environment.getSQLServerDatabase()); - myBatisProperties.setProperty("JDBC.username", environment.getUsername()); - myBatisProperties.setProperty("JDBC.password", environment.getPassword()); myBatisProperties.setProperty("JDBC.autoCommit", "false"); myBatisProperties.setProperty("mybatis.pooled.pingEnabled", "true"); diff --git a/guacamole/src/main/java/org/apache/guacamole/GuacamoleServletContextListener.java b/guacamole/src/main/java/org/apache/guacamole/GuacamoleServletContextListener.java index b33c65d99..cd81572ec 100644 --- a/guacamole/src/main/java/org/apache/guacamole/GuacamoleServletContextListener.java +++ b/guacamole/src/main/java/org/apache/guacamole/GuacamoleServletContextListener.java @@ -130,8 +130,9 @@ public class GuacamoleServletContextListener extends GuiceServletContextListener // Read configuration information from GUACAMOLE_HOME/guacamole.properties try { - environment.addGuacamoleProperties(new FileGuacamoleProperties( - new File(environment.getGuacamoleHome(), "guacamole.properties"))); + File guacProperties = new File(environment.getGuacamoleHome(), "guacamole.properties"); + environment.addGuacamoleProperties(new FileGuacamoleProperties(guacProperties)); + logger.info("Read configuration parameters from \"{}\".", guacProperties); } catch (GuacamoleException e) { logger.error("Unable to read guacamole.properties: {}", e.getMessage()); @@ -142,8 +143,11 @@ public class GuacamoleServletContextListener extends GuiceServletContextListener // read from system environment if "enable-environment-properties" is // set to "true" try { - if (environment.getProperty(ENABLE_ENVIRONMENT_PROPERTIES, false)) + if (environment.getProperty(ENABLE_ENVIRONMENT_PROPERTIES, false)) { environment.addGuacamoleProperties(new SystemEnvironmentGuacamoleProperties()); + logger.info("Additional configuration parameters may be read " + + "from environment variables."); + } } catch (GuacamoleException e) { logger.error("Unable to configure support for environment properties: {}", e.getMessage());