diff --git a/extensions/guacamole-auth-quickconnect/pom.xml b/extensions/guacamole-auth-quickconnect/pom.xml
index 9d2bcfb17..fdf04c75a 100644
--- a/extensions/guacamole-auth-quickconnect/pom.xml
+++ b/extensions/guacamole-auth-quickconnect/pom.xml
@@ -185,6 +185,13 @@
provided
+
+
+ com.sun.jersey
+ jersey-server
+ 1.17.1
+
+
com.google.inject
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 c2ca355e4..d56df95ad 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
@@ -21,9 +21,11 @@ package org.apache.guacamole.auth.quickconnect;
import java.util.Collection;
import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.auth.quickconnect.utility.QCParser;
import org.apache.guacamole.net.auth.ConnectionGroup;
import org.apache.guacamole.net.auth.simple.SimpleConnectionDirectory;
import org.apache.guacamole.net.auth.Connection;
+import org.apache.guacamole.protocol.GuacamoleConfiguration;
/**
* Implementation of the Connection Directory, stored
@@ -89,6 +91,75 @@ public class QuickConnectDirectory extends SimpleConnectionDirectory {
this.rootGroup.addConnectionIdentifier(connectionId);
}
+ /**
+ * Create a connection object on the tree using an existing
+ * QuickConnection connection, after setting the identifier
+ * and parent object.
+ *
+ * @param object
+ * The QuickConnection object to add to the tree.
+ *
+ * @returns
+ * The connectionId of the object added to the directory.
+ *
+ * @throws GuacamoleException
+ * If an error is encountered adding the object to the
+ * directory.
+ */
+ public String put(QuickConnection object) throws GuacamoleException {
+
+ // Get the next connection ID.
+ String connectionId = getNextConnectionID().toString();
+
+ // Set up identifier and parent on object.
+ object.setIdentifier(connectionId);
+ object.setParentIdentifier(ROOT_IDENTIFIER);
+
+ // Add connection to the directory
+ putConnection(object);
+
+ // Add connection to the tree
+ this.rootGroup.addConnectionIdentifier(connectionId);
+
+ return connectionId;
+
+ }
+
+ /**
+ * Create a QuickConnection object from a GuacamoleConfiguration
+ * and get an ID and place it on the tree.
+ *
+ * @param config
+ * The GuacamoleConfiguration to use to create the
+ * QuickConnection object.
+ *
+ * @returns
+ * The connectionId of the object creation in the directory.
+ *
+ * @throws GuacamoleException
+ * If an error occurs adding the object to the tree.
+ */
+ public String create(GuacamoleConfiguration config) throws GuacamoleException {
+
+ // Get the next connection ID
+ String connectionId = getNextConnectionID().toString();
+
+ // Generate a name for the configuration
+ String name = QCParser.getName(config);
+
+ // Create a new connection and set parent identifier.
+ Connection connection = new QuickConnection(name, connectionId, config);
+ connection.setParentIdentifier(ROOT_IDENTIFIER);
+
+ // Place the object in directory
+ putConnection(connection);
+
+ // Add connection to the tree.
+ this.rootGroup.addConnectionIdentifier(connectionId);
+
+ return connectionId;
+ }
+
@Override
public void update(Connection object) throws GuacamoleException {
putConnection(object);
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 bc9754cad..b1a2752ca 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
@@ -21,6 +21,7 @@ package org.apache.guacamole.auth.quickconnect;
import java.util.Collection;
import java.util.Collections;
+import org.apache.guacamole.auth.quickconnect.rest.QuickConnectREST;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.form.Form;
import org.apache.guacamole.net.auth.ActiveConnection;
@@ -50,7 +51,7 @@ public class QuickConnectUserContext implements UserContext {
/**
* The unique identifier of the root connection group.
*/
- private static final String ROOT_IDENTIFIER = "ROOT";
+ public static final String ROOT_IDENTIFIER = "ROOT";
/**
* The AuthenticationProvider that created this UserContext.
@@ -129,7 +130,7 @@ public class QuickConnectUserContext implements UserContext {
@Override
public Object getResource() throws GuacamoleException {
- return null;
+ return new QuickConnectREST(this);
}
@Override
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
new file mode 100644
index 000000000..d494eb883
--- /dev/null
+++ b/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/rest/QuickConnectREST.java
@@ -0,0 +1,103 @@
+/*
+ * 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.rest;
+
+import com.google.inject.Inject;
+import java.util.List;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.POST;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.GuacamoleServerException;
+import org.apache.guacamole.protocol.GuacamoleConfiguration;
+import org.apache.guacamole.auth.quickconnect.QuickConnection;
+import org.apache.guacamole.auth.quickconnect.QuickConnectDirectory;
+import org.apache.guacamole.auth.quickconnect.QuickConnectUserContext;
+import org.apache.guacamole.auth.quickconnect.utility.QCParser;
+import org.apache.guacamole.net.auth.Connection;
+import org.apache.guacamole.net.auth.Directory;
+
+/**
+ * A class to create and manage REST endpoints for the
+ * QuickConnect extension.
+ */
+@Produces(MediaType.APPLICATION_JSON)
+public class QuickConnectREST {
+
+ /**
+ * The connection directory for this REST endpoint.
+ */
+ private QuickConnectDirectory directory;
+
+ /**
+ * The UserContext object for this REST endpoint.
+ */
+ private QuickConnectUserContext userContext;
+
+ /**
+ * Construct a new QuickConnectREST class, taking in the UserContext
+ * object that calls this constructor.
+ *
+ * @param userContext
+ * The UserContext object associated with this REST endpoint
+ *
+ * @throws GuacamoleException
+ * If the UserContext is unavailable or the directory object
+ * cannot be retrieved.
+ */
+ public QuickConnectREST(QuickConnectUserContext userContext)
+ throws GuacamoleException {
+ this.userContext = userContext;
+ this.directory = (QuickConnectDirectory)this.userContext.getConnectionDirectory();
+ }
+
+ /**
+ * Parse the URI read from the POST input, add the connection
+ * to the directory, and return the ID of the newly-created
+ * connection.
+ *
+ * @param uri
+ * The URI to parse into a connection.
+ *
+ * @returns
+ * The ID of the connection in the directory.
+ *
+ * @throws
+ * Throws a GuacamoleException if an error is encountered
+ * parsing the URI.
+ */
+ @POST
+ @Path("create")
+ public String create(@FormParam("uri") String uri)
+ throws GuacamoleException {
+
+ if (directory == null)
+ throw new GuacamoleServerException("No connection directory available.");
+
+ return directory.create(QCParser.getConfiguration(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
new file mode 100644
index 000000000..afe272adb
--- /dev/null
+++ b/extensions/guacamole-auth-quickconnect/src/main/java/org/apache/guacamole/auth/quickconnect/utility/QCParser.java
@@ -0,0 +1,169 @@
+/*
+ * 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.utility;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.List;
+import org.apache.guacamole.GuacamoleClientException;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.protocol.GuacamoleConfiguration;
+
+public class QCParser {
+
+ /**
+ * The default protocol to parse to if one is undefined.
+ */
+ public static final String DEFAULT_URI_PROTOCOL = "ssh";
+
+ /**
+ * The default host to use if one is not defined.
+ */
+ public static final String DEFAULT_URI_HOST = "localhost";
+
+ /**
+ * The default port to use if one is not defined.
+ */
+ public static final Integer DEFAULT_URI_PORT = 22;
+
+ /**
+ * Parse out a URI string and get a connection from that string,
+ * or an exception if the parsing fails.
+ *
+ * @param uri
+ * The string form of the URI to be parsed.
+ *
+ * @returns
+ * A GuacamoleConfiguration using a combination of the parsed
+ * URI values and default values when not specified in the
+ * URI.
+ *
+ * @throws GuacamoleException
+ * When an error occurs parsing the URI.
+ */
+ public static GuacamoleConfiguration getConfiguration(String uri)
+ throws GuacamoleException {
+
+ URI qcUri;
+ try {
+ qcUri = new URI(uri);
+ }
+ catch (URISyntaxException e) {
+ throw new GuacamoleClientException("Invalid URI Syntax", e);
+ }
+ String protocol = qcUri.getScheme();
+ String host = qcUri.getHost();
+ Integer port = qcUri.getPort();
+ String userInfo = qcUri.getUserInfo();
+ String query = qcUri.getQuery();
+ String username = null;
+ String password = null;
+ List paramList = null;
+
+ if (protocol == null || protocol.equals(""))
+ protocol = DEFAULT_URI_PROTOCOL;
+
+ if (host == null || host.equals(""))
+ host = DEFAULT_URI_HOST;
+
+ if (port == -1 || port < 1)
+ port = DEFAULT_URI_PORT;
+
+ if (query != null && !query.equals(""))
+ paramList = Arrays.asList(query.split("&"));
+
+ if (userInfo != null && !userInfo.equals("")) {
+ String[] authenticators = userInfo.split(":");
+ if (authenticators[0] != null)
+ username = authenticators[0];
+ if (authenticators[1] != null)
+ password = authenticators[1];
+ }
+
+ GuacamoleConfiguration qcConfig = new GuacamoleConfiguration();
+ qcConfig.setProtocol(protocol);
+ qcConfig.setParameter("hostname",host);
+ qcConfig.setParameter("port", port.toString());
+
+ if (username != null)
+ qcConfig.setParameter("username", username);
+
+ if (password != null)
+ qcConfig.setParameter("password", password);
+
+ if (paramList != null) {
+ for (String parameter : paramList) {
+ String[] paramArray = parameter.split("=");
+ qcConfig.setParameter(paramArray[0],paramArray[1]);
+ }
+ }
+
+ return qcConfig;
+
+ }
+
+ /**
+ * Given a GuacamoleConfiguration object, generate a name
+ * for the configuration based on the protocol, host, user
+ * and port in the configuration, and return the string value.
+ *
+ * @param config
+ * The GuacamoleConfiguration object to use to generate
+ * the name.
+ *
+ * @return
+ * The String value of the name that is generated, or
+ * null if no config is provided.
+ *
+ * @throws GuacamoleException
+ * If an error occurs getting items in the configuration.
+ */
+ public static String getName(GuacamoleConfiguration config)
+ throws GuacamoleException {
+
+ if (config == null)
+ return null;
+
+ String protocol = config.getProtocol();
+ String host = config.getParameter("hostname");
+ String port = config.getParameter("port");
+ String user = config.getParameter("username");
+
+ String name = "";
+
+ if (protocol != null && !protocol.equals(""))
+ name += protocol + "://";
+
+ if (user != null && !user.equals(""))
+ name += user + "@";
+
+ if (host != null && !host.equals(""))
+ name += host;
+
+ if (port != null && !port.equals(""))
+ name += ":" + port;
+
+ name += "/";
+
+ return name;
+ }
+
+}