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/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-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..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 @@ -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()); } /** @@ -168,4 +166,30 @@ public abstract class JDBCEnvironment extends LocalEnvironment { */ 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..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.getMySQLUsername()); - myBatisProperties.setProperty("JDBC.password", environment.getMySQLPassword()); 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..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.getPostgreSQLUsername()); - myBatisProperties.setProperty("JDBC.password", environment.getPostgreSQLPassword()); 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..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.getSQLServerUsername()); - myBatisProperties.setProperty("JDBC.password", environment.getSQLServerPassword()); 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); } 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/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); + } + +} 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/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-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-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..cd81572ec 100644 --- a/guacamole/src/main/java/org/apache/guacamole/GuacamoleServletContextListener.java +++ b/guacamole/src/main/java/org/apache/guacamole/GuacamoleServletContextListener.java @@ -24,6 +24,7 @@ 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; @@ -33,6 +34,8 @@ 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 +89,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 +126,38 @@ public class GuacamoleServletContextListener extends GuiceServletContextListener @Override public void contextInitialized(ServletContextEvent servletContextEvent) { + environment = LocalEnvironment.getInstance(); + + // Read configuration information from GUACAMOLE_HOME/guacamole.properties try { - environment = new LocalEnvironment(); - sessionMap = new HashTokenSessionMap(environment); + 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()); 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()); + 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()); + 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/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(); }