diff --git a/extensions/guacamole-auth-quickconnect/pom.xml b/extensions/guacamole-auth-quickconnect/pom.xml
index 166f98fec..75132925b 100644
--- a/extensions/guacamole-auth-quickconnect/pom.xml
+++ b/extensions/guacamole-auth-quickconnect/pom.xml
@@ -191,6 +191,18 @@
1.3.0
provided
+
+
+
+ com.google.inject
+ guice
+ 3.0
+
+
+ com.google.inject.extensions
+ guice-multibindings
+ 3.0
+
diff --git a/extensions/guacamole-auth-quickconnect/src/licenses/LICENSE b/extensions/guacamole-auth-quickconnect/src/licenses/LICENSE
index d64569567..0c50ec07c 100644
--- a/extensions/guacamole-auth-quickconnect/src/licenses/LICENSE
+++ b/extensions/guacamole-auth-quickconnect/src/licenses/LICENSE
@@ -200,3 +200,15 @@
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.
+
+
+==============================================================================
+
+
+Google Guice (https://github.com/google/guice)
+----------------------------------------------
+
+ Version: 3.0
+ From: 'Google Inc.' (http://www.google.com/)
+ License(s):
+ Apache v2.0 (bundled/guice-3.0/COPYING)
\ No newline at end of file
diff --git a/extensions/guacamole-auth-quickconnect/src/licenses/guice-3.0/COPYING b/extensions/guacamole-auth-quickconnect/src/licenses/guice-3.0/COPYING
new file mode 100644
index 000000000..d64569567
--- /dev/null
+++ b/extensions/guacamole-auth-quickconnect/src/licenses/guice-3.0/COPYING
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed 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.
diff --git a/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/QuickConnectAuthenticationProvider.java b/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/QuickConnectAuthenticationProvider.java
index 090c5e7f7..41346cc75 100644
--- a/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/QuickConnectAuthenticationProvider.java
+++ b/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/QuickConnectAuthenticationProvider.java
@@ -19,6 +19,8 @@
package org.apache.guacamole.auth.quickconnect;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.AuthenticatedUser;
import org.apache.guacamole.net.auth.AbstractAuthenticationProvider;
@@ -31,6 +33,20 @@ import org.apache.guacamole.net.auth.UserContext;
*/
public class QuickConnectAuthenticationProvider extends AbstractAuthenticationProvider {
+ /**
+ * Injector which will manage the object graph of this authentication
+ * provider.
+ */
+ private final Injector injector;
+
+ public QuickConnectAuthenticationProvider() throws GuacamoleException {
+
+ // Set up Guice injector.
+ injector = Guice.createInjector(
+ new QuickConnectAuthenticationProviderModule(this)
+ );
+ }
+
@Override
public String getIdentifier() {
return "quickconnect";
@@ -40,9 +56,13 @@ public class QuickConnectAuthenticationProvider extends AbstractAuthenticationPr
public UserContext getUserContext(AuthenticatedUser authenticatedUser)
throws GuacamoleException {
- return new QuickConnectUserContext(this,
- authenticatedUser.getIdentifier());
-
+ QuickConnectUserContext userContext =
+ injector.getInstance(QuickConnectUserContext.class);
+
+ userContext.init(authenticatedUser.getIdentifier());
+
+ return userContext;
+
}
}
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
new file mode 100644
index 000000000..7841316be
--- /dev/null
+++ b/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/QuickConnectAuthenticationProviderModule.java
@@ -0,0 +1,81 @@
+/*
+ * 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.quickconnect;
+
+import com.google.inject.AbstractModule;
+import org.apache.guacamole.auth.quickconnect.conf.ConfigurationService;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.environment.Environment;
+import org.apache.guacamole.environment.LocalEnvironment;
+import org.apache.guacamole.net.auth.AuthenticationProvider;
+
+/**
+ * Guice module which configures QuickConnect-specific injections.
+ */
+public class QuickConnectAuthenticationProviderModule extends AbstractModule {
+
+ /**
+ * Guacamole server environment.
+ */
+ private final Environment environment;
+
+ /**
+ * A reference to the QuickConnectAuthenticationProvider on behalf of which
+ * this module has configured injection.
+ */
+ private final AuthenticationProvider authProvider;
+
+ /**
+ * Creates a new QuickConnect authentication provider module which
+ * configures injection for the QuickConnectAuthenticationProvider.
+ *
+ * @param authProvider
+ * The AuthenticationProvider for which injection is being configured.
+ *
+ * @throws GuacamoleException
+ * If an error occurs while retrieving the Guacamole server
+ * environment.
+ */
+ public QuickConnectAuthenticationProviderModule(
+ AuthenticationProvider authProvider) throws GuacamoleException {
+
+ // Get local environment
+ this.environment = new LocalEnvironment();
+
+ // Store associated auth provider
+ this.authProvider = authProvider;
+
+ }
+
+ @Override
+ protected void configure() {
+
+ // Bind core implementations of guacamole-ext classes
+ bind(AuthenticationProvider.class).toInstance(authProvider);
+ bind(Environment.class).toInstance(environment);
+
+ // Bind QuickConnect-specific services
+ bind(ConfigurationService.class);
+ bind(QuickConnectUserContext.class);
+ bind(QuickConnectDirectory.class);
+
+ }
+
+}
diff --git a/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/QuickConnectDirectory.java b/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/QuickConnectDirectory.java
index cec0432b2..b677fb195 100644
--- a/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/QuickConnectDirectory.java
+++ b/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/QuickConnectDirectory.java
@@ -19,11 +19,13 @@
package org.apache.guacamole.auth.quickconnect;
+import com.google.inject.Inject;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.quickconnect.utility.QCParser;
+import org.apache.guacamole.auth.quickconnect.conf.ConfigurationService;
import org.apache.guacamole.net.auth.ConnectionGroup;
import org.apache.guacamole.net.auth.simple.SimpleConnection;
import org.apache.guacamole.net.auth.simple.SimpleDirectory;
@@ -35,40 +37,46 @@ import org.apache.guacamole.protocol.GuacamoleConfiguration;
* completely in memory.
*/
public class QuickConnectDirectory extends SimpleDirectory {
-
+
+ /**
+ * The configuration service for the QuickConnect module.
+ */
+ @Inject
+ private ConfigurationService confService;
+
/**
* The connections to store.
*/
private final Map connections =
- new ConcurrentHashMap();
+ new ConcurrentHashMap<>();
/**
* The root connection group for this directory.
*/
- private final QuickConnectionGroup rootGroup;
+ private QuickConnectionGroup rootGroup;
/**
* The internal counter for connection IDs.
*/
- private final AtomicInteger connectionId;
+ private AtomicInteger connectionId;
/**
- * Creates a new QuickConnectDirectory with the default
- * empty Map for Connection objects, and the specified
- * ConnectionGroup at the root of the directory.
+ * Initialize the QuickConnectDirectory with the default empty Map for
+ * Connection objects, and the specified ConnectionGroup at the root of
+ * the directory.
*
* @param rootGroup
* A group that should be at the root of this directory.
*/
- public QuickConnectDirectory(ConnectionGroup rootGroup) {
+ public void init(ConnectionGroup rootGroup) {
this.rootGroup = (QuickConnectionGroup)rootGroup;
this.connectionId = new AtomicInteger();
super.setObjects(this.connections);
+
}
/**
- * Returns the current connection identifier counter and
- * then increments it.
+ * Returns the current connection identifier counter and then increments it.
*
* @return
* An int representing the next available connection
@@ -84,13 +92,14 @@ public class QuickConnectDirectory extends SimpleDirectory {
}
/**
- * Create a SimpleConnection object from a GuacamoleConfiguration,
- * obtain an identifier, and place it on the tree, returning the
- * identifier value of the new connection.
+ * Taking a URI, parse the URI into a GuacamoleConfiguration object and
+ * then use the configuration to create a SimpleConnection object, obtain
+ * an identifier, and place it on the tree, returning the identifier value
+ * of the new connection.
*
- * @param config
- * The GuacamoleConfiguration object to use to create the
- * SimpleConnection object.
+ * @param uri
+ * The URI to parse into a GuacamoleConfiguration, which will then be
+ * used to generate the SimpleConnection.
*
* @return
* The identifier of the connection created in the directory.
@@ -98,13 +107,20 @@ public class QuickConnectDirectory extends SimpleDirectory {
* @throws GuacamoleException
* If an error occurs adding the object to the tree.
*/
- public String create(GuacamoleConfiguration config) throws GuacamoleException {
+ public String create(String uri) throws GuacamoleException {
// Get the next available connection identifier.
String newConnectionId = Integer.toString(getNextConnectionID());
+ // Get a new QCParser
+ QCParser parser = new QCParser(confService.getAllowedParameters(),
+ confService.getDeniedParameters());
+
+ // Parse the URI into a configuration
+ GuacamoleConfiguration config = parser.getConfiguration(uri);
+
// Generate a name for the configuration.
- String name = QCParser.getName(config);
+ String name = parser.getName(config);
// Create a new connection and set the parent identifier.
Connection connection = new SimpleConnection(name, newConnectionId, config, true);
diff --git a/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/QuickConnectUserContext.java b/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/QuickConnectUserContext.java
index dad050556..21b2d48de 100644
--- a/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/QuickConnectUserContext.java
+++ b/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/QuickConnectUserContext.java
@@ -19,6 +19,7 @@
package org.apache.guacamole.auth.quickconnect;
+import com.google.inject.Inject;
import java.util.Collections;
import org.apache.guacamole.auth.quickconnect.rest.QuickConnectREST;
import org.apache.guacamole.GuacamoleException;
@@ -45,32 +46,29 @@ public class QuickConnectUserContext extends AbstractUserContext {
/**
* The AuthenticationProvider that created this UserContext.
*/
- private final AuthenticationProvider authProvider;
+ @Inject
+ private AuthenticationProvider authProvider;
/**
* Reference to the user whose permissions dictate the configurations
* accessible within this UserContext.
*/
- private final User self;
+ private User self;
/**
* The Directory with access to all connections within the root group
* associated with this UserContext.
*/
- private final QuickConnectDirectory connectionDirectory;
+ @Inject
+ private QuickConnectDirectory connectionDirectory;
/**
* The root connection group.
*/
- private final ConnectionGroup rootGroup;
+ private ConnectionGroup rootGroup;
/**
- * Construct a QuickConnectUserContext using the authProvider and
- * the username.
- *
- * @param authProvider
- * The authentication provider module instantiating this
- * this class.
+ * Initialize a QuickConnectUserContext using the provided username.
*
* @param username
* The name of the user logging in that will be associated
@@ -80,8 +78,7 @@ public class QuickConnectUserContext extends AbstractUserContext {
* If errors occur initializing the ConnectionGroup,
* ConnectionDirectory, or User.
*/
- public QuickConnectUserContext(AuthenticationProvider authProvider,
- String username) throws GuacamoleException {
+ public void init(String username) throws GuacamoleException {
// Initialize the rootGroup to a QuickConnectionGroup with a
// single root identifier.
@@ -91,7 +88,7 @@ public class QuickConnectUserContext extends AbstractUserContext {
);
// Initialize the connection directory
- this.connectionDirectory = new QuickConnectDirectory(this.rootGroup);
+ this.connectionDirectory.init(this.rootGroup);
// Initialize the user to a SimpleUser with the provided username,
// no connections, and the single root group.
@@ -109,9 +106,6 @@ public class QuickConnectUserContext extends AbstractUserContext {
};
- // Set the authProvider to the calling authProvider object.
- this.authProvider = authProvider;
-
}
@Override
diff --git a/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/conf/ConfigurationService.java b/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/conf/ConfigurationService.java
new file mode 100644
index 000000000..11f11f3f8
--- /dev/null
+++ b/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/conf/ConfigurationService.java
@@ -0,0 +1,97 @@
+/*
+ * 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.quickconnect.conf;
+
+import com.google.inject.Inject;
+import java.util.List;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.environment.Environment;
+import org.apache.guacamole.properties.StringListProperty;
+
+/**
+ * Configuration options to control the QuickConnect module.
+ */
+public class ConfigurationService {
+
+ /**
+ * The environment of the Guacamole Server.
+ */
+ @Inject
+ private Environment environment;
+
+ /**
+ * A list of parameters that, if set, will limit the parameters allowed to
+ * be defined by connections created using the QuickConnect module to only
+ * the parameters defined in this list. Defaults to null (all parameters
+ * are allowed).
+ */
+ public static final StringListProperty QUICKCONNECT_ALLOWED_PARAMETERS = new StringListProperty() {
+
+ @Override
+ public String getName() { return "quickconnect-allowed-parameters"; }
+
+ };
+
+ /**
+ * A list of parameters that, if set, will limit the parameters allowed to
+ * be defined by connections created using the QuickConnect module to any
+ * except the ones defined in this list. Defaults to null (all parameters
+ * are allowed).
+ */
+ public static final StringListProperty QUICKCONNECT_DENIED_PARAMETERS = new StringListProperty() {
+
+ @Override
+ public String getName() { return "quickconnect-denied-parameters"; }
+
+ };
+
+ /**
+ * Return the list of allowed parameters to be set by connections created
+ * using the QuickConnect module, or null if none are defined (thereby
+ * allowing all parameters to be set).
+ *
+ * @return
+ * The list of allowed parameters to be set by connections crated using
+ * the QuickConnect module.
+ *
+ * @throws GuacamoleException
+ * If guacamole.properties cannot be parsed.
+ */
+ public List getAllowedParameters() throws GuacamoleException {
+ return environment.getProperty(QUICKCONNECT_ALLOWED_PARAMETERS);
+ }
+
+ /**
+ * Return the list of denied parameters for connections created using the
+ * QuickConnect module, or null if none are defined (thereby allowing all
+ * parameters to be set).
+ *
+ * @return
+ * The list of parameters that cannot be set by connections created
+ * using the QuickConnect module.
+ *
+ * @throws GuacamoleException
+ * If guacamole.properties cannot be parsed.
+ */
+ public List getDeniedParameters() throws GuacamoleException {
+ return environment.getProperty(QUICKCONNECT_DENIED_PARAMETERS);
+ }
+
+}
diff --git a/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/rest/QuickConnectREST.java b/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/rest/QuickConnectREST.java
index 4cced071c..eec1c641a 100644
--- a/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/rest/QuickConnectREST.java
+++ b/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/rest/QuickConnectREST.java
@@ -36,7 +36,7 @@ import org.apache.guacamole.auth.quickconnect.utility.QCParser;
*/
@Produces(MediaType.APPLICATION_JSON)
public class QuickConnectREST {
-
+
/**
* The connection directory for this REST endpoint.
*/
@@ -74,8 +74,7 @@ public class QuickConnectREST {
public Map create(@FormParam("uri") String uri)
throws GuacamoleException {
- return Collections.singletonMap("identifier",
- directory.create(QCParser.getConfiguration(uri)));
+ return Collections.singletonMap("identifier", directory.create(uri));
}
diff --git a/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/utility/QCParser.java b/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/utility/QCParser.java
index e5fc8ec0b..32df74297 100644
--- a/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/utility/QCParser.java
+++ b/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/utility/QCParser.java
@@ -25,9 +25,8 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.util.Arrays;
-import java.util.HashMap;
+import java.util.Collections;
import java.util.List;
-import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.guacamole.GuacamoleServerException;
@@ -55,7 +54,48 @@ public class QCParser {
* THe regex group of the password.
*/
private static final int PASSWORD_GROUP = 2;
-
+
+ /**
+ * The list of parameters that are allowed to be placed into a configuration
+ * by this parser. If not defined, all parameters will be allowed unless
+ * explicitly denied.
+ */
+ private final List allowedParams;
+
+ /**
+ * The list of parameters that are explicitly denied from being placed into
+ * a configuration by this parser.
+ */
+ private final List deniedParams;
+
+ /**
+ * Create a new instance of the QCParser class, with the provided allowed
+ * and denied parameter lists, if any.
+ *
+ * @param allowedParams
+ * A list of parameters that are allowed to be parsed and placed into
+ * a connection configuration, or null or empty if all parameters are
+ * allowed.
+ *
+ * @param deniedParams
+ * A list of parameters, if any, that should be explicitly denied from
+ * being placed into a connection configuration.
+ */
+ public QCParser(List allowedParams, List deniedParams) {
+ this.allowedParams = allowedParams;
+ this.deniedParams = deniedParams;
+ }
+
+ /**
+ * Create a new instance of the QCParser class, initializing the allowed
+ * and denied parameter lists to empty lists, which means all parameters
+ * will be allowed and none will be denied.
+ */
+ public QCParser() {
+ this.allowedParams = Collections.emptyList();
+ this.deniedParams = Collections.emptyList();
+ }
+
/**
* Parse out a URI string and get a GuacamoleConfiguration
* from that string, or an exception if the parsing fails.
@@ -70,7 +110,7 @@ public class QCParser {
* @throws GuacamoleException
* If an error occurs parsing the URI.
*/
- public static GuacamoleConfiguration getConfiguration(String uri)
+ public GuacamoleConfiguration getConfiguration(String uri)
throws GuacamoleException {
// Parse the provided String into a URI object.
@@ -104,77 +144,68 @@ public class QCParser {
"QUICKCONNECT.ERROR_NO_PROTOCOL");
// Check for provided port number
- if (port > 0)
+ if (port > 0 && paramIsAllowed("port"))
qcConfig.setParameter("port", Integer.toString(port));
// Check for provided host, or throw an error if not present
- if (host != null && !host.isEmpty())
+ if (host != null && !host.isEmpty() && paramIsAllowed("hostname"))
qcConfig.setParameter("hostname", host);
else
throw new TranslatableGuacamoleClientException("No host specified.",
"QUICKCONNECT.ERROR_NO_HOST");
// Look for extra query parameters and parse them out.
- if (query != null && !query.isEmpty()) {
- try {
- Map queryParams = parseQueryString(query);
- if (queryParams != null)
- for (Map.Entry entry: queryParams.entrySet())
- qcConfig.setParameter(entry.getKey(), entry.getValue());
- }
- catch (UnsupportedEncodingException e) {
- throw new GuacamoleServerException("Unexpected lack of UTF-8 encoding support.", e);
- }
- }
+ if (query != null && !query.isEmpty())
+ parseQueryString(query, qcConfig);
// Look for the username and password and parse them out.
- if (userInfo != null && !userInfo.isEmpty()) {
-
- try {
+ if (userInfo != null && !userInfo.isEmpty())
parseUserInfo(userInfo, qcConfig);
- }
- catch (UnsupportedEncodingException e) {
- throw new GuacamoleServerException("Unexpected lack of UTF-8 encoding support.", e);
- }
- }
return qcConfig;
}
/**
- * Parse the given string for parameter key/value pairs and return
- * a map with the parameters.
+ * Parse the given string for parameter key/value pairs and update the
+ * provided GuacamoleConfiguration object with the parsed values, checking
+ * to make sure that the parser is allowed to provide the requested
+ * parameters.
*
* @param queryStr
* The query string to parse for key/value pairs.
*
- * @return
- * A map with the key/value pairs.
+ * @param config
+ * The GuacamoleConfiguration object that should be updated with the
+ * parsed parameters.
*
- * @throws UnsupportedEncodingException
- * If Java lacks UTF-8 support.
+ * @throws GuacamoleException
+ * If Java unexpectedly lacks UTF-8 support.
*/
- public static Map parseQueryString(String queryStr)
- throws UnsupportedEncodingException {
+ private void parseQueryString(String queryStr, GuacamoleConfiguration config)
+ throws GuacamoleException {
// Split the query string into the pairs
List paramList = Arrays.asList(queryStr.split("&"));
- Map parameters = new HashMap();
// Loop through key/value pairs and put them in the Map.
for (String param : paramList) {
String[] paramArray = param.split("=", 2);
- parameters.put(URLDecoder.decode(paramArray[0], "UTF-8"),
- URLDecoder.decode(paramArray[1], "UTF-8"));
+ try {
+ String paramName = URLDecoder.decode(paramArray[0], "UTF-8");
+ String paramValue = URLDecoder.decode(paramArray[1], "UTF-8");
+ if (paramIsAllowed(paramName))
+ config.setParameter(paramName, paramValue);
+ }
+ catch (UnsupportedEncodingException e) {
+ throw new GuacamoleServerException("Unexpected lack of UTF-8 encoding support.", e);
+ }
}
-
- return parameters;
}
/**
- * Parse the given string for username and password values,
- * and, if values are present, decode them and set them in
+ * Parse the given string for username and password values, and, if values
+ * are present and allowed by the configuration, decode them and set them in
* the provided GuacamoleConfiguration object.
*
* @param userInfo
@@ -184,12 +215,12 @@ public class QCParser {
* The GuacamoleConfiguration object to store the username
* and password in.
*
- * @throws UnsupportedEncodingException
- * If Java lacks UTF-8 support.
+ * @throws GuacamoleException
+ * If Java unexpectedly lacks UTF-8 support.
*/
- public static void parseUserInfo(String userInfo,
+ private void parseUserInfo(String userInfo,
GuacamoleConfiguration config)
- throws UnsupportedEncodingException {
+ throws GuacamoleException {
Matcher userinfoMatcher = userinfoPattern.matcher(userInfo);
@@ -197,13 +228,25 @@ public class QCParser {
String username = userinfoMatcher.group(USERNAME_GROUP);
String password = userinfoMatcher.group(PASSWORD_GROUP);
- if (username != null && !username.isEmpty())
- config.setParameter("username",
- URLDecoder.decode(username, "UTF-8"));
+ if (username != null && !username.isEmpty() && paramIsAllowed("username")) {
+ try {
+ config.setParameter("username",
+ URLDecoder.decode(username, "UTF-8"));
+ }
+ catch (UnsupportedEncodingException e) {
+ throw new GuacamoleServerException("Unexpected lack of UTF-8 encoding support.", e);
+ }
+ }
- if (password != null && !password.isEmpty())
- config.setParameter("password",
- URLDecoder.decode(password, "UTF-8"));
+ if (password != null && !password.isEmpty() && paramIsAllowed("password")) {
+ try {
+ config.setParameter("password",
+ URLDecoder.decode(password, "UTF-8"));
+ }
+ catch (UnsupportedEncodingException e) {
+ throw new GuacamoleServerException("Unexpected lack of UTF-8 encoding support.", e);
+ }
+ }
}
}
@@ -223,7 +266,7 @@ public class QCParser {
* @throws GuacamoleException
* If an error occurs getting items in the configuration.
*/
- public static String getName(GuacamoleConfiguration config)
+ public String getName(GuacamoleConfiguration config)
throws GuacamoleException {
if (config == null)
@@ -252,5 +295,36 @@ public class QCParser {
return name.toString();
}
+
+ /**
+ * For a given parameter, check to make sure the parameter is allowed to be
+ * used in the connection configuration, first by checking to see if
+ * allowed parameters are defined and the given parameter is present, then
+ * by checking for explicitly denied parameters. Returns false if the
+ * configuration prevents the parameter from being used, otherwise true.
+ *
+ * @param param
+ * The name of the parameter to check.
+ *
+ * @return
+ * False if the configuration prevents the parameter from being used,
+ * otherwise true.
+ */
+ private boolean paramIsAllowed(String param) {
+
+ // If allowed parameters are defined and not empty,
+ // check to see if this parameter is allowed.
+ if (allowedParams != null && !allowedParams.isEmpty() && !allowedParams.contains(param))
+ return false;
+
+ // If denied parameters are defined and not empty,
+ // check to see if this parameter is denied.
+ if (deniedParams != null && !deniedParams.isEmpty() && deniedParams.contains(param))
+ return false;
+
+ // By default, the parameter is allowed.
+ return true;
+
+ }
}
diff --git a/extensions/guacamole-auth-quickconnect/src/test/java/org/apache/guacamole/auth/quickconnect/utility/QCParserTest.java b/extensions/guacamole-auth-quickconnect/src/test/java/org/apache/guacamole/auth/quickconnect/utility/QCParserTest.java
index 50ad7d6f2..2b7bf78af 100644
--- a/extensions/guacamole-auth-quickconnect/src/test/java/org/apache/guacamole/auth/quickconnect/utility/QCParserTest.java
+++ b/extensions/guacamole-auth-quickconnect/src/test/java/org/apache/guacamole/auth/quickconnect/utility/QCParserTest.java
@@ -19,8 +19,8 @@
package org.apache.guacamole.auth.quickconnect.utility;
-import java.io.UnsupportedEncodingException;
-import java.util.Map;
+import java.util.Arrays;
+import java.util.Collections;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.protocol.GuacamoleConfiguration;
import org.junit.Test;
@@ -32,90 +32,86 @@ import static org.junit.Assert.assertNull;
*/
public class QCParserTest {
- /**
- * Verify that the parseQueryString() method functions as designed.
- *
- * @throws UnsupportedEncodingException
- * If Java lacks UTF-8 support.
- */
- @Test
- public void testParseQueryString() throws UnsupportedEncodingException {
-
- final String queryString = "param1=value1¶m2=value2=3¶m3=value%3D3¶m4=value%264";
- Map queryMap = QCParser.parseQueryString(queryString);
-
- assertEquals("value1", queryMap.get("param1"));
- assertEquals("value2=3", queryMap.get("param2"));
- assertEquals("value=3", queryMap.get("param3"));
- assertEquals("value&4", queryMap.get("param4"));
-
- }
-
- /**
- * Verify that the parseUserInfo() method functions as designed.
- *
- * @throws UnsupportedEncodingException
- * If Java lacks UTF-8 support.
- */
- @Test
- public void testParseUserInfo() throws UnsupportedEncodingException {
-
- Map userInfoMap;
-
- GuacamoleConfiguration config1 = new GuacamoleConfiguration();
- QCParser.parseUserInfo("guacuser:secretpw", config1);
- assertEquals("guacuser", config1.getParameter("username"));
- assertEquals("secretpw", config1.getParameter("password"));
-
- GuacamoleConfiguration config2 = new GuacamoleConfiguration();
- QCParser.parseUserInfo("guacuser", config2);
- assertEquals("guacuser", config2.getParameter("username"));
- assertNull(config2.getParameter("password"));
-
- GuacamoleConfiguration config3 = new GuacamoleConfiguration();
- QCParser.parseUserInfo("guacuser:P%40ssw0rd%21", config3);
- assertEquals("guacuser", config3.getParameter("username"));
- assertEquals("P@ssw0rd!", config3.getParameter("password"));
-
- GuacamoleConfiguration config4 = new GuacamoleConfiguration();
- QCParser.parseUserInfo("domain%5cguacuser:domain%2fpassword", config4);
- assertEquals("domain\\guacuser", config4.getParameter("username"));
- assertEquals("domain/password", config4.getParameter("password"));
-
- }
-
/**
* Verify that the getConfiguration() method returns the expected
* GuacamoleConfiguration object.
*
* @throws GuacamoleException
- * If the configuration cannot be parsed from the given URI.
+ * If the configuration cannot be parsed from the given URI or Java
+ * unexpectedly lacks UTF-8 support.
*/
@Test
public void testGetConfiguration() throws GuacamoleException {
- String uri1 = "ssh://guacuser:guacpassword@hostname1.domain.local/?param1=value1¶m2=value2";
- GuacamoleConfiguration config1 = QCParser.getConfiguration(uri1);
- assertEquals("ssh", config1.getProtocol());
- assertEquals("hostname1.domain.local", config1.getParameter("hostname"));
- assertEquals("guacuser", config1.getParameter("username"));
- assertEquals("guacpassword", config1.getParameter("password"));
- assertEquals("value1", config1.getParameter("param1"));
- assertEquals("value2", config1.getParameter("param2"));
+ // Initialize the parser, first with no lists so all parameters are allowed
+ QCParser parser = new QCParser();
+
+ // Create some empty objects to test
+ GuacamoleConfiguration guacConfig;
+ String uri;
+
+ // Test a standard SSH URI, with username and password, and parameters and values
+ uri = "ssh://guacuser:guacpassword@hostname1.domain.local/?param1=value1¶m2=value2";
+ guacConfig = parser.getConfiguration(uri);
+ assertEquals("ssh", guacConfig.getProtocol());
+ assertEquals("hostname1.domain.local", guacConfig.getParameter("hostname"));
+ assertEquals("guacuser", guacConfig.getParameter("username"));
+ assertEquals("guacpassword", guacConfig.getParameter("password"));
+ assertEquals("value1", guacConfig.getParameter("param1"));
+ assertEquals("value2", guacConfig.getParameter("param2"));
- String uri2 = "rdp://domain%5cguacuser:adPassword123@windows1.domain.tld/?enable-sftp=true";
- GuacamoleConfiguration config2 = QCParser.getConfiguration(uri2);
- assertEquals("rdp", config2.getProtocol());
- assertEquals("windows1.domain.tld", config2.getParameter("hostname"));
- assertEquals("domain\\guacuser", config2.getParameter("username"));
- assertEquals("adPassword123", config2.getParameter("password"));
- assertEquals("true", config2.getParameter("enable-sftp"));
+ // Test a standard RDP URI, with username/password and a parameter/value pair.
+ uri = "rdp://domain%5cguacuser:adPassword123@windows1.domain.tld/?enable-sftp=true";
+ guacConfig = parser.getConfiguration(uri);
+ assertEquals("rdp", guacConfig.getProtocol());
+ assertEquals("windows1.domain.tld", guacConfig.getParameter("hostname"));
+ assertEquals("domain\\guacuser", guacConfig.getParameter("username"));
+ assertEquals("adPassword123", guacConfig.getParameter("password"));
+ assertEquals("true", guacConfig.getParameter("enable-sftp"));
- String uri3 = "vnc://mirror1.example.com:5910/";
- GuacamoleConfiguration config3 = QCParser.getConfiguration(uri3);
- assertEquals("vnc", config3.getProtocol());
- assertEquals("mirror1.example.com", config3.getParameter("hostname"));
- assertEquals("5910", config3.getParameter("port"));
+ // Test a VNC URI with no parameters/values
+ uri = "vnc://mirror1.example.com:5910/";
+ guacConfig = parser.getConfiguration(uri);
+ assertEquals("vnc", guacConfig.getProtocol());
+ assertEquals("mirror1.example.com", guacConfig.getParameter("hostname"));
+ assertEquals("5910", guacConfig.getParameter("port"));
+
+ // Test a telnet URI with no parameters/values
+ uri = "telnet://old1.example.com:23/";
+ guacConfig = parser.getConfiguration(uri);
+ assertEquals("telnet", guacConfig.getProtocol());
+ assertEquals("old1.example.com", guacConfig.getParameter("hostname"));
+ assertEquals("23", guacConfig.getParameter("port"));
+
+ // Re-initialize parser with only allowed parameters, and test
+ parser = new QCParser(Arrays.asList("hostname", "username", "password", "port"), Collections.emptyList());
+ uri = "rdp://domain%5cguacuser:adPassword123@windows1.domain.tld/?enable-sftp=true";
+ guacConfig = parser.getConfiguration(uri);
+ assertEquals("rdp", guacConfig.getProtocol());
+ assertEquals("windows1.domain.tld", guacConfig.getParameter("hostname"));
+ assertEquals("domain\\guacuser", guacConfig.getParameter("username"));
+ assertEquals("adPassword123", guacConfig.getParameter("password"));
+ assertNull(guacConfig.getParameter("enable-sftp"));
+
+ // Re-initialize parser with denied parameters, and test
+ parser = new QCParser(Collections.emptyList(), Arrays.asList("password"));
+ uri = "rdp://domain%5cguacuser:adPassword123@windows1.domain.tld/?enable-sftp=true";
+ guacConfig = parser.getConfiguration(uri);
+ assertEquals("rdp", guacConfig.getProtocol());
+ assertEquals("windows1.domain.tld", guacConfig.getParameter("hostname"));
+ assertEquals("domain\\guacuser", guacConfig.getParameter("username"));
+ assertNull(guacConfig.getParameter("password"));
+ assertEquals("true", guacConfig.getParameter("enable-sftp"));
+
+ // Re-initialize parser with both allowed and denied parameters, and test
+ parser = new QCParser(Arrays.asList("hostname", "username", "password", "port"), Arrays.asList("password"));
+ uri = "rdp://domain%5cguacuser:adPassword123@windows1.domain.tld/?enable-sftp=true";
+ guacConfig = parser.getConfiguration(uri);
+ assertEquals("rdp", guacConfig.getProtocol());
+ assertEquals("windows1.domain.tld", guacConfig.getParameter("hostname"));
+ assertEquals("domain\\guacuser", guacConfig.getParameter("username"));
+ assertNull(guacConfig.getParameter("password"));
+ assertNull(guacConfig.getParameter("enable-sftp"));
}