From 600002531e3f7b166fd02f8c5c88056204d5ab17 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Thu, 28 Jul 2016 11:20:19 -0700 Subject: [PATCH] GUACAMOLE-5: Use singleton Guice Injector via common base class. --- .../auth/jdbc/JDBCAuthenticationProvider.java | 101 ++++++++++++++++++ .../auth/jdbc/JDBCInjectorProvider.java | 90 ++++++++++++++++ .../mysql/MySQLAuthenticationProvider.java | 78 +------------- .../auth/mysql/MySQLInjectorProvider.java | 51 +++++++++ .../PostgreSQLAuthenticationProvider.java | 85 +-------------- .../PostgreSQLInjectorProvider.java | 51 +++++++++ 6 files changed, 301 insertions(+), 155 deletions(-) create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProvider.java create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCInjectorProvider.java create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLInjectorProvider.java create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLInjectorProvider.java diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProvider.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProvider.java new file mode 100644 index 000000000..ebacd13ce --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProvider.java @@ -0,0 +1,101 @@ +/* + * 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.Injector; +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.net.auth.AuthenticationProvider; +import org.apache.guacamole.net.auth.Credentials; +import org.apache.guacamole.net.auth.UserContext; +import org.apache.guacamole.auth.jdbc.user.AuthenticationProviderService; +import org.apache.guacamole.net.auth.AuthenticatedUser; + +/** + * Provides a base implementation of an AuthenticationProvider which is backed + * by an arbitrary underlying database. It is up to the subclass implementation + * to configure the underlying database appropriately via Guice. + * + * @author James Muehlner + * @author Michael Jumper + */ +public abstract class JDBCAuthenticationProvider implements AuthenticationProvider { + + /** + * Provider of the singleton Injector instance which will manage the object + * graph of this authentication provider. + */ + private final JDBCInjectorProvider injectorProvider; + + /** + * Creates a new AuthenticationProvider that is backed by an arbitrary + * underlying database. + * + * @param injectorProvider + * A JDBCInjectorProvider instance which provides singleton instances + * of a Guice Injector, pre-configured to set up all injections and + * access to the underlying database via MyBatis. + */ + public JDBCAuthenticationProvider(JDBCInjectorProvider injectorProvider) { + this.injectorProvider = injectorProvider; + } + + @Override + public AuthenticatedUser authenticateUser(Credentials credentials) + throws GuacamoleException { + + Injector injector = injectorProvider.get(); + + // Create AuthenticatedUser based on credentials, if valid + AuthenticationProviderService authProviderService = injector.getInstance(AuthenticationProviderService.class); + return authProviderService.authenticateUser(this, credentials); + + } + + @Override + public AuthenticatedUser updateAuthenticatedUser(AuthenticatedUser authenticatedUser, + Credentials credentials) throws GuacamoleException { + + // No need to update authenticated users + return authenticatedUser; + + } + + @Override + public UserContext getUserContext(AuthenticatedUser authenticatedUser) + throws GuacamoleException { + + Injector injector = injectorProvider.get(); + + // Create UserContext based on credentials, if valid + AuthenticationProviderService authProviderService = injector.getInstance(AuthenticationProviderService.class); + return authProviderService.getUserContext(authenticatedUser); + + } + + @Override + public UserContext updateUserContext(UserContext context, + AuthenticatedUser authenticatedUser) throws GuacamoleException { + + // No need to update the context + return context; + + } + +} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCInjectorProvider.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCInjectorProvider.java new file mode 100644 index 000000000..839616e85 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCInjectorProvider.java @@ -0,0 +1,90 @@ +/* + * 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.Injector; +import java.util.concurrent.atomic.AtomicReference; +import org.apache.guacamole.GuacamoleException; + +/** + * A caching provider of singleton Guice Injector instances. The first call to + * get() will return a new instance of the Guice Injector, while all subsequent + * calls will return that same instance. It is up to implementations of this + * class to define how the Guice Injector will be created through defining the + * create() function. + * + * IMPORTANT: Because the Injector returned by get() is cached statically, only + * ONE implementation of this class may be used within any individual + * classloader. Within the context of the JDBC extension, as long as each built + * extension only provides one subclass of this class, things should work + * properly, as each extension is given its own classloader by Guacamole. + * + * @author Michael Jumper + */ +public abstract class JDBCInjectorProvider { + + /** + * An AtomicReference wrapping the cached Guice Injector. If the Injector + * has not yet been created, null will be wrapped instead. + */ + private static final AtomicReference injector = new AtomicReference(null); + + /** + * Creates a new instance of the Guice Injector which should be used + * across the entire JDBC authentication extension. This function will + * generally only be called once, but multiple invocations are possible if + * get() is invoked several times concurrently prior to the Injector being + * cached. + * + * @return + * @throws GuacamoleException + */ + protected abstract Injector create() throws GuacamoleException; + + /** + * Returns a common, singleton instance of a Guice Injector, configured for + * the injections required by the JDBC authentication extension. The result + * of the first call to this function will be cached statically within this + * class, and will be returned for all subsequent calls. + * + * @return + * A singleton instance of the Guice Injector used across the entire + * JDBC authentication extension. + * + * @throws GuacamoleException + * If the Injector cannot be created due to an error. + */ + public Injector get() throws GuacamoleException { + + // Return existing Injector if already created + Injector value = injector.get(); + if (value != null) + return value; + + // Explicitly create and store new Injector only if necessary + injector.compareAndSet(null, create()); + + // Consistently return the same Injector, even if two create operations + // happen concurrently + return injector.get(); + + } + +} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLAuthenticationProvider.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLAuthenticationProvider.java index 8db48b7ac..e7521633b 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLAuthenticationProvider.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLAuthenticationProvider.java @@ -19,15 +19,7 @@ package org.apache.guacamole.auth.mysql; -import com.google.inject.Guice; -import com.google.inject.Injector; -import org.apache.guacamole.GuacamoleException; -import org.apache.guacamole.net.auth.AuthenticationProvider; -import org.apache.guacamole.net.auth.Credentials; -import org.apache.guacamole.net.auth.UserContext; -import org.apache.guacamole.auth.jdbc.JDBCAuthenticationProviderModule; -import org.apache.guacamole.auth.jdbc.user.AuthenticationProviderService; -import org.apache.guacamole.net.auth.AuthenticatedUser; +import org.apache.guacamole.auth.jdbc.JDBCAuthenticationProvider; /** * Provides a MySQL based implementation of the AuthenticationProvider @@ -36,39 +28,15 @@ import org.apache.guacamole.net.auth.AuthenticatedUser; * @author James Muehlner * @author Michael Jumper */ -public class MySQLAuthenticationProvider implements AuthenticationProvider { - - /** - * Injector which will manage the object graph of this authentication - * provider. - */ - private final Injector injector; +public class MySQLAuthenticationProvider extends JDBCAuthenticationProvider { /** * Creates a new MySQLAuthenticationProvider that reads and writes * authentication data to a MySQL database defined by properties in * guacamole.properties. - * - * @throws GuacamoleException - * If a required property is missing, or an error occurs while parsing - * a property. */ - public MySQLAuthenticationProvider() throws GuacamoleException { - - // Get local environment - MySQLEnvironment environment = new MySQLEnvironment(); - - // Set up Guice injector. - injector = Guice.createInjector( - - // Configure MySQL-specific authentication - new MySQLAuthenticationProviderModule(environment), - - // Configure JDBC authentication core - new JDBCAuthenticationProviderModule(environment) - - ); - + public MySQLAuthenticationProvider() { + super(new MySQLInjectorProvider()); } @Override @@ -76,42 +44,4 @@ public class MySQLAuthenticationProvider implements AuthenticationProvider { return "mysql"; } - @Override - public AuthenticatedUser authenticateUser(Credentials credentials) - throws GuacamoleException { - - // Create AuthenticatedUser based on credentials, if valid - AuthenticationProviderService authProviderService = injector.getInstance(AuthenticationProviderService.class); - return authProviderService.authenticateUser(this, credentials); - - } - - @Override - public AuthenticatedUser updateAuthenticatedUser(AuthenticatedUser authenticatedUser, - Credentials credentials) throws GuacamoleException { - - // No need to update authenticated users - return authenticatedUser; - - } - - @Override - public UserContext getUserContext(AuthenticatedUser authenticatedUser) - throws GuacamoleException { - - // Create UserContext based on credentials, if valid - AuthenticationProviderService authProviderService = injector.getInstance(AuthenticationProviderService.class); - return authProviderService.getUserContext(authenticatedUser); - - } - - @Override - public UserContext updateUserContext(UserContext context, - AuthenticatedUser authenticatedUser) throws GuacamoleException { - - // No need to update the context - return context; - - } - } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLInjectorProvider.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLInjectorProvider.java new file mode 100644 index 000000000..09c40be7c --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLInjectorProvider.java @@ -0,0 +1,51 @@ +/* + * 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.mysql; + +import com.google.inject.Guice; +import com.google.inject.Injector; +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.auth.jdbc.JDBCAuthenticationProviderModule; +import org.apache.guacamole.auth.jdbc.JDBCInjectorProvider; + +/** + * JDBCInjectorProvider implementation which configures Guice injections for + * connecting to a MySQL database based on MySQL-specific options provided via + * guacamole.properties. + * + * @author Michael Jumper + */ +public class MySQLInjectorProvider extends JDBCInjectorProvider { + + @Override + protected Injector create() throws GuacamoleException { + + // Get local environment + MySQLEnvironment environment = new MySQLEnvironment(); + + // Set up Guice injector + return Guice.createInjector( + new JDBCAuthenticationProviderModule(environment), + new MySQLAuthenticationProviderModule(environment) + ); + + } + +} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLAuthenticationProvider.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLAuthenticationProvider.java index cd37d0598..1c4b816ca 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLAuthenticationProvider.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLAuthenticationProvider.java @@ -19,17 +19,7 @@ package org.apache.guacamole.auth.postgresql; -import com.google.inject.Guice; -import com.google.inject.Injector; -import org.apache.guacamole.GuacamoleException; -import org.apache.guacamole.net.auth.AuthenticationProvider; -import org.apache.guacamole.net.auth.Credentials; -import org.apache.guacamole.net.auth.UserContext; -import org.apache.guacamole.auth.jdbc.JDBCAuthenticationProviderModule; -import org.apache.guacamole.auth.jdbc.user.AuthenticationProviderService; -import org.apache.guacamole.net.auth.AuthenticatedUser; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.guacamole.auth.jdbc.JDBCAuthenticationProvider; /** * Provides a PostgreSQL-based implementation of the AuthenticationProvider @@ -38,44 +28,15 @@ import org.slf4j.LoggerFactory; * @author James Muehlner * @author Michael Jumper */ -public class PostgreSQLAuthenticationProvider implements AuthenticationProvider { - - /** - * Logger for this class. - */ - private static final Logger logger = LoggerFactory.getLogger(PostgreSQLAuthenticationProvider.class); - - /** - * Injector which will manage the object graph of this authentication - * provider. - */ - private final Injector injector; +public class PostgreSQLAuthenticationProvider extends JDBCAuthenticationProvider { /** * Creates a new PostgreSQLAuthenticationProvider that reads and writes * authentication data to a PostgreSQL database defined by properties in * guacamole.properties. - * - * @throws GuacamoleException - * If a required property is missing, or an error occurs while parsing - * a property. */ - public PostgreSQLAuthenticationProvider() throws GuacamoleException { - - // Get local environment - PostgreSQLEnvironment environment = new PostgreSQLEnvironment(); - - // Set up Guice injector. - injector = Guice.createInjector( - - // Configure PostgreSQL-specific authentication - new PostgreSQLAuthenticationProviderModule(environment), - - // Configure JDBC authentication core - new JDBCAuthenticationProviderModule(environment) - - ); - + public PostgreSQLAuthenticationProvider() { + super(new PostgreSQLInjectorProvider()); } @Override @@ -83,42 +44,4 @@ public class PostgreSQLAuthenticationProvider implements AuthenticationProvider return "postgresql"; } - @Override - public AuthenticatedUser authenticateUser(Credentials credentials) - throws GuacamoleException { - - // Create AuthenticatedUser based on credentials, if valid - AuthenticationProviderService authProviderService = injector.getInstance(AuthenticationProviderService.class); - return authProviderService.authenticateUser(this, credentials); - - } - - @Override - public AuthenticatedUser updateAuthenticatedUser(AuthenticatedUser authenticatedUser, - Credentials credentials) throws GuacamoleException { - - // No need to update authenticated users - return authenticatedUser; - - } - - @Override - public UserContext getUserContext(AuthenticatedUser authenticatedUser) - throws GuacamoleException { - - // Create UserContext based on credentials, if valid - AuthenticationProviderService authProviderService = injector.getInstance(AuthenticationProviderService.class); - return authProviderService.getUserContext(authenticatedUser); - - } - - @Override - public UserContext updateUserContext(UserContext context, - AuthenticatedUser authenticatedUser) throws GuacamoleException { - - // No need to update the context - return context; - - } - } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLInjectorProvider.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLInjectorProvider.java new file mode 100644 index 000000000..ff34399c0 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLInjectorProvider.java @@ -0,0 +1,51 @@ +/* + * 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.postgresql; + +import com.google.inject.Guice; +import com.google.inject.Injector; +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.auth.jdbc.JDBCAuthenticationProviderModule; +import org.apache.guacamole.auth.jdbc.JDBCInjectorProvider; + +/** + * JDBCInjectorProvider implementation which configures Guice injections for + * connecting to a PostgreSQL database based on PostgreSQL-specific options + * provided via guacamole.properties. + * + * @author Michael Jumper + */ +public class PostgreSQLInjectorProvider extends JDBCInjectorProvider { + + @Override + protected Injector create() throws GuacamoleException { + + // Get local environment + PostgreSQLEnvironment environment = new PostgreSQLEnvironment(); + + // Set up Guice injector + return Guice.createInjector( + new JDBCAuthenticationProviderModule(environment), + new PostgreSQLAuthenticationProviderModule(environment) + ); + + } + +}