Return-Path: X-Original-To: apmail-guacamole-commits-archive@minotaur.apache.org Delivered-To: apmail-guacamole-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 7E82C19113 for ; Tue, 29 Mar 2016 04:20:22 +0000 (UTC) Received: (qmail 37665 invoked by uid 500); 29 Mar 2016 04:20:22 -0000 Delivered-To: apmail-guacamole-commits-archive@guacamole.apache.org Received: (qmail 37649 invoked by uid 500); 29 Mar 2016 04:20:22 -0000 Mailing-List: contact commits-help@guacamole.incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@guacamole.incubator.apache.org Delivered-To: mailing list commits@guacamole.incubator.apache.org Received: (qmail 37612 invoked by uid 99); 29 Mar 2016 04:20:22 -0000 Received: from pnap-us-west-generic-nat.apache.org (HELO spamd2-us-west.apache.org) (209.188.14.142) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 29 Mar 2016 04:20:22 +0000 Received: from localhost (localhost [127.0.0.1]) by spamd2-us-west.apache.org (ASF Mail Server at spamd2-us-west.apache.org) with ESMTP id BD8301A0783 for ; Tue, 29 Mar 2016 04:20:21 +0000 (UTC) X-Virus-Scanned: Debian amavisd-new at spamd2-us-west.apache.org X-Spam-Flag: NO X-Spam-Score: -3.221 X-Spam-Level: X-Spam-Status: No, score=-3.221 tagged_above=-999 required=6.31 tests=[KAM_ASCII_DIVIDERS=0.8, KAM_LAZY_DOMAIN_SECURITY=1, RCVD_IN_DNSWL_HI=-5, RCVD_IN_MSPIKE_H3=-0.01, RCVD_IN_MSPIKE_WL=-0.01, RP_MATCHES_RCVD=-0.001] autolearn=disabled Received: from mx2-lw-us.apache.org ([10.40.0.8]) by localhost (spamd2-us-west.apache.org [10.40.0.9]) (amavisd-new, port 10024) with ESMTP id EvPgaESMax_1 for ; Tue, 29 Mar 2016 04:20:12 +0000 (UTC) Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by mx2-lw-us.apache.org (ASF Mail Server at mx2-lw-us.apache.org) with SMTP id 3FB9C5FAC9 for ; Tue, 29 Mar 2016 04:20:11 +0000 (UTC) Received: (qmail 37413 invoked by uid 99); 29 Mar 2016 04:20:10 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 29 Mar 2016 04:20:10 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 72BB3E38DC; Tue, 29 Mar 2016 04:20:10 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: jmuehlner@apache.org To: commits@guacamole.incubator.apache.org Date: Tue, 29 Mar 2016 04:20:14 -0000 Message-Id: <5a8e4fb2d67b41339ab26ac11c3bac60@git.apache.org> In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [05/51] [abbrv] incubator-guacamole-client git commit: GUACAMOLE-1: Remove useless .net.basic subpackage, now that everything is being renamed. http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/properties/AuthenticationProviderProperty.java ---------------------------------------------------------------------- diff --git a/guacamole/src/main/java/org/apache/guacamole/properties/AuthenticationProviderProperty.java b/guacamole/src/main/java/org/apache/guacamole/properties/AuthenticationProviderProperty.java new file mode 100644 index 0000000..09f3576 --- /dev/null +++ b/guacamole/src/main/java/org/apache/guacamole/properties/AuthenticationProviderProperty.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.apache.guacamole.properties; + +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.net.auth.AuthenticationProvider; +import org.apache.guacamole.properties.GuacamoleProperty; + +/** + * A GuacamoleProperty whose value is the name of a class to use to + * authenticate users. This class must implement AuthenticationProvider. Use + * of this property type is deprecated in favor of the + * GUACAMOLE_HOME/extensions directory. + * + * @author Michael Jumper + */ +@Deprecated +public abstract class AuthenticationProviderProperty implements GuacamoleProperty> { + + @Override + @SuppressWarnings("unchecked") // Explicitly checked within by isAssignableFrom() + public Class parseValue(String authProviderClassName) throws GuacamoleException { + + // If no property provided, return null. + if (authProviderClassName == null) + return null; + + // Get auth provider instance + try { + + // Get authentication provider class + Class authProviderClass = org.apache.guacamole.GuacamoleClassLoader.getInstance().loadClass(authProviderClassName); + + // Verify the located class is actually a subclass of AuthenticationProvider + if (!AuthenticationProvider.class.isAssignableFrom(authProviderClass)) + throw new GuacamoleException("Specified authentication provider class is not a AuthenticationProvider."); + + // Return located class + return (Class) authProviderClass; + + } + catch (ClassNotFoundException e) { + throw new GuacamoleException("Authentication provider class not found", e); + } + + } + +} http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/properties/BasicGuacamoleProperties.java ---------------------------------------------------------------------- diff --git a/guacamole/src/main/java/org/apache/guacamole/properties/BasicGuacamoleProperties.java b/guacamole/src/main/java/org/apache/guacamole/properties/BasicGuacamoleProperties.java new file mode 100644 index 0000000..9d8d99f --- /dev/null +++ b/guacamole/src/main/java/org/apache/guacamole/properties/BasicGuacamoleProperties.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2013 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.apache.guacamole.properties; + +import org.apache.guacamole.properties.FileGuacamoleProperty; +import org.apache.guacamole.properties.IntegerGuacamoleProperty; +import org.apache.guacamole.properties.StringGuacamoleProperty; + +/** + * Properties used by the default Guacamole web application. + * + * @author Michael Jumper + */ +public class BasicGuacamoleProperties { + + /** + * This class should not be instantiated. + */ + private BasicGuacamoleProperties() {} + + /** + * The authentication provider to user when retrieving the authorized + * configurations of a user. This property is currently supported, but + * deprecated in favor of the GUACAMOLE_HOME/extensions directory. + */ + @Deprecated + public static final AuthenticationProviderProperty AUTH_PROVIDER = new AuthenticationProviderProperty() { + + @Override + public String getName() { return "auth-provider"; } + + }; + + /** + * The directory to search for authentication provider classes. This + * property is currently supported, but deprecated in favor of the + * GUACAMOLE_HOME/lib directory. + */ + @Deprecated + public static final FileGuacamoleProperty LIB_DIRECTORY = new FileGuacamoleProperty() { + + @Override + public String getName() { return "lib-directory"; } + + }; + + /** + * The session timeout for the API, in minutes. + */ + public static final IntegerGuacamoleProperty API_SESSION_TIMEOUT = new IntegerGuacamoleProperty() { + + @Override + public String getName() { return "api-session-timeout"; } + + }; + + /** + * Comma-separated list of all allowed languages, where each language is + * represented by a language key, such as "en" or "en_US". If specified, + * only languages within this list will be listed as available by the REST + * service. + */ + public static final StringSetProperty ALLOWED_LANGUAGES = new StringSetProperty() { + + @Override + public String getName() { return "allowed-languages"; } + + }; + +} http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/properties/StringSetProperty.java ---------------------------------------------------------------------- diff --git a/guacamole/src/main/java/org/apache/guacamole/properties/StringSetProperty.java b/guacamole/src/main/java/org/apache/guacamole/properties/StringSetProperty.java new file mode 100644 index 0000000..5bcd13c --- /dev/null +++ b/guacamole/src/main/java/org/apache/guacamole/properties/StringSetProperty.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.apache.guacamole.properties; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.regex.Pattern; +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.properties.GuacamoleProperty; + +/** + * A GuacamoleProperty whose value is a Set of unique Strings. The string value + * parsed to produce this set is a comma-delimited list. Duplicate values are + * ignored, as is any whitespace following delimiters. To maintain + * compatibility with the behavior of Java properties in general, only + * whitespace at the beginning of each value is ignored; trailing whitespace + * becomes part of the value. + * + * @author Michael Jumper + */ +public abstract class StringSetProperty implements GuacamoleProperty> { + + /** + * A pattern which matches against the delimiters between values. This is + * currently simply a comma and any following whitespace. Parts of the + * input string which match this pattern will not be included in the parsed + * result. + */ + private static final Pattern DELIMITER_PATTERN = Pattern.compile(",\\s*"); + + @Override + public Set parseValue(String values) throws GuacamoleException { + + // If no property provided, return null. + if (values == null) + return null; + + // Split string into a set of individual values + List valueList = Arrays.asList(DELIMITER_PATTERN.split(values)); + return new HashSet(valueList); + + } + +} http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/properties/package-info.java ---------------------------------------------------------------------- diff --git a/guacamole/src/main/java/org/apache/guacamole/properties/package-info.java b/guacamole/src/main/java/org/apache/guacamole/properties/package-info.java new file mode 100644 index 0000000..0640815 --- /dev/null +++ b/guacamole/src/main/java/org/apache/guacamole/properties/package-info.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2013 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/** + * Classes related to the properties which the Guacamole web application + * (and stock parts of it) read from guacamole.properties. + */ +package org.apache.guacamole.properties; + http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/resource/AbstractResource.java ---------------------------------------------------------------------- diff --git a/guacamole/src/main/java/org/apache/guacamole/resource/AbstractResource.java b/guacamole/src/main/java/org/apache/guacamole/resource/AbstractResource.java new file mode 100644 index 0000000..f985361 --- /dev/null +++ b/guacamole/src/main/java/org/apache/guacamole/resource/AbstractResource.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.apache.guacamole.resource; + +/** + * Base abstract resource implementation which provides an associated mimetype, + * and modification time. Classes which extend AbstractResource must provide + * their own InputStream, however. + * + * @author Michael Jumper + */ +public abstract class AbstractResource implements Resource { + + /** + * The mimetype of this resource. + */ + private final String mimetype; + + /** + * The time this resource was last modified, in milliseconds since midnight + * of January 1, 1970 UTC. + */ + private final long lastModified; + + /** + * Initializes this AbstractResource with the given mimetype and + * modification time. + * + * @param mimetype + * The mimetype of this resource. + * + * @param lastModified + * The time this resource was last modified, in milliseconds since + * midnight of January 1, 1970 UTC. + */ + public AbstractResource(String mimetype, long lastModified) { + this.mimetype = mimetype; + this.lastModified = lastModified; + } + + /** + * Initializes this AbstractResource with the given mimetype. The + * modification time of the resource is set to the current system time. + * + * @param mimetype + * The mimetype of this resource. + */ + public AbstractResource(String mimetype) { + this(mimetype, System.currentTimeMillis()); + } + + @Override + public long getLastModified() { + return lastModified; + } + + @Override + public String getMimeType() { + return mimetype; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/resource/ByteArrayResource.java ---------------------------------------------------------------------- diff --git a/guacamole/src/main/java/org/apache/guacamole/resource/ByteArrayResource.java b/guacamole/src/main/java/org/apache/guacamole/resource/ByteArrayResource.java new file mode 100644 index 0000000..2fa8199 --- /dev/null +++ b/guacamole/src/main/java/org/apache/guacamole/resource/ByteArrayResource.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.apache.guacamole.resource; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +/** + * A resource which contains a defined byte array. + * + * @author Michael Jumper + */ +public class ByteArrayResource extends AbstractResource { + + /** + * The bytes contained by this resource. + */ + private final byte[] bytes; + + /** + * Creates a new ByteArrayResource which provides access to the given byte + * array. Changes to the given byte array will affect this resource even + * after the resource is created. Changing the byte array while an input + * stream from this resource is in use has undefined behavior. + * + * @param mimetype + * The mimetype of the resource. + * + * @param bytes + * The bytes that this resource should contain. + */ + public ByteArrayResource(String mimetype, byte[] bytes) { + super(mimetype); + this.bytes = bytes; + } + + @Override + public InputStream asStream() { + return new ByteArrayInputStream(bytes); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/resource/ClassPathResource.java ---------------------------------------------------------------------- diff --git a/guacamole/src/main/java/org/apache/guacamole/resource/ClassPathResource.java b/guacamole/src/main/java/org/apache/guacamole/resource/ClassPathResource.java new file mode 100644 index 0000000..fb81791 --- /dev/null +++ b/guacamole/src/main/java/org/apache/guacamole/resource/ClassPathResource.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.apache.guacamole.resource; + +import java.io.InputStream; + +/** + * A resource which is located within the classpath of an arbitrary + * ClassLoader. + * + * @author Michael Jumper + */ +public class ClassPathResource extends AbstractResource { + + /** + * The classloader to use when reading this resource. + */ + private final ClassLoader classLoader; + + /** + * The path of this resource relative to the classloader. + */ + private final String path; + + /** + * Creates a new ClassPathResource which uses the given ClassLoader to + * read the resource having the given path. + * + * @param classLoader + * The ClassLoader to use when reading the resource. + * + * @param mimetype + * The mimetype of the resource. + * + * @param path + * The path of the resource relative to the given ClassLoader. + */ + public ClassPathResource(ClassLoader classLoader, String mimetype, String path) { + super(mimetype); + this.classLoader = classLoader; + this.path = path; + } + + /** + * Creates a new ClassPathResource which uses the ClassLoader associated + * with the ClassPathResource class to read the resource having the given + * path. + * + * @param mimetype + * The mimetype of the resource. + * + * @param path + * The path of the resource relative to the ClassLoader associated + * with the ClassPathResource class. + */ + public ClassPathResource(String mimetype, String path) { + this(ClassPathResource.class.getClassLoader(), mimetype, path); + } + + @Override + public InputStream asStream() { + return classLoader.getResourceAsStream(path); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/resource/Resource.java ---------------------------------------------------------------------- diff --git a/guacamole/src/main/java/org/apache/guacamole/resource/Resource.java b/guacamole/src/main/java/org/apache/guacamole/resource/Resource.java new file mode 100644 index 0000000..845bd72 --- /dev/null +++ b/guacamole/src/main/java/org/apache/guacamole/resource/Resource.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.apache.guacamole.resource; + +import java.io.InputStream; + +/** + * An arbitrary resource that can be served to a user via HTTP. Resources are + * anonymous but have a defined mimetype and corresponding input stream. + * + * @author Michael Jumper + */ +public interface Resource { + + /** + * Returns the mimetype of this resource. This function MUST always return + * a value. If the type is unknown, return "application/octet-stream". + * + * @return + * The mimetype of this resource. + */ + String getMimeType(); + + /** + * Returns the time the resource was last modified in milliseconds since + * midnight of January 1, 1970 UTC. + * + * @return + * The time the resource was last modified, in milliseconds. + */ + long getLastModified(); + + /** + * Returns an InputStream which reads the contents of this resource, + * starting with the first byte. Reading from the returned InputStream will + * not affect reads from other InputStreams returned by other calls to + * asStream(). The returned InputStream must be manually closed when no + * longer needed. If the resource is unexpectedly unavailable, this will + * return null. + * + * @return + * An InputStream which reads the contents of this resource, starting + * with the first byte, or null if the resource is unavailable. + */ + InputStream asStream(); + +} http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/resource/ResourceServlet.java ---------------------------------------------------------------------- diff --git a/guacamole/src/main/java/org/apache/guacamole/resource/ResourceServlet.java b/guacamole/src/main/java/org/apache/guacamole/resource/ResourceServlet.java new file mode 100644 index 0000000..f1af7c6 --- /dev/null +++ b/guacamole/src/main/java/org/apache/guacamole/resource/ResourceServlet.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.apache.guacamole.resource; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Servlet which serves a given resource for all HTTP GET requests. The HEAD + * method is correctly supported, and HTTP 304 ("Not Modified") responses will + * be properly returned for GET requests depending on the last time the + * resource was modified. + * + * @author Michael Jumper + */ +public class ResourceServlet extends HttpServlet { + + /** + * Logger for this class. + */ + private static final Logger logger = LoggerFactory.getLogger(ResourceServlet.class); + + /** + * The size of the buffer to use when transferring data from the input + * stream of a resource to the output stream of a request. + */ + private static final int BUFFER_SIZE = 10240; + + /** + * The resource to serve for every GET request. + */ + private final Resource resource; + + /** + * Creates a new ResourceServlet which serves the given Resource for all + * HTTP GET requests. + * + * @param resource + * The Resource to serve. + */ + public ResourceServlet(Resource resource) { + this.resource = resource; + } + + @Override + protected void doHead(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + + // Set last modified and content type headers + response.addDateHeader("Last-Modified", resource.getLastModified()); + response.setContentType(resource.getMimeType()); + + } + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + + // Get input stream from resource + InputStream input = resource.asStream(); + + // If resource does not exist, return not found + if (input == null) { + logger.debug("Resource does not exist: \"{}\"", request.getServletPath()); + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + return; + } + + try { + + // Write headers + doHead(request, response); + + // If not modified since "If-Modified-Since" header, return not modified + long ifModifiedSince = request.getDateHeader("If-Modified-Since"); + if (resource.getLastModified() - ifModifiedSince < 1000) { + logger.debug("Resource not modified: \"{}\"", request.getServletPath()); + response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); + return; + } + + int length; + byte[] buffer = new byte[BUFFER_SIZE]; + + // Write resource to response body + OutputStream output = response.getOutputStream(); + while ((length = input.read(buffer)) != -1) + output.write(buffer, 0, length); + + } + + // Ensure input stream is always closed + finally { + input.close(); + } + + } + +} http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/resource/SequenceResource.java ---------------------------------------------------------------------- diff --git a/guacamole/src/main/java/org/apache/guacamole/resource/SequenceResource.java b/guacamole/src/main/java/org/apache/guacamole/resource/SequenceResource.java new file mode 100644 index 0000000..fe407b5 --- /dev/null +++ b/guacamole/src/main/java/org/apache/guacamole/resource/SequenceResource.java @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.apache.guacamole.resource; + +import java.io.InputStream; +import java.io.SequenceInputStream; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.Iterator; + +/** + * A resource which is the logical concatenation of other resources. + * + * @author Michael Jumper + */ +public class SequenceResource extends AbstractResource { + + /** + * The resources to be concatenated. + */ + private final Iterable resources; + + /** + * Returns the mimetype of the first resource in the given Iterable, or + * "application/octet-stream" if no resources are provided. + * + * @param resources + * The resources from which the mimetype should be retrieved. + * + * @return + * The mimetype of the first resource, or "application/octet-stream" + * if no resources were provided. + */ + private static String getMimeType(Iterable resources) { + + // If no resources, just assume application/octet-stream + Iterator resourceIterator = resources.iterator(); + if (!resourceIterator.hasNext()) + return "application/octet-stream"; + + // Return mimetype of first resource + return resourceIterator.next().getMimeType(); + + } + + /** + * Creates a new SequenceResource as the logical concatenation of the + * given resources. Each resource is concatenated in iteration order as + * needed when reading from the input stream of the SequenceResource. + * + * @param mimetype + * The mimetype of the resource. + * + * @param resources + * The resources to concatenate within the InputStream of this + * SequenceResource. + */ + public SequenceResource(String mimetype, Iterable resources) { + super(mimetype); + this.resources = resources; + } + + /** + * Creates a new SequenceResource as the logical concatenation of the + * given resources. Each resource is concatenated in iteration order as + * needed when reading from the input stream of the SequenceResource. The + * mimetype of the resulting concatenation is derived from the first + * resource. + * + * @param resources + * The resources to concatenate within the InputStream of this + * SequenceResource. + */ + public SequenceResource(Iterable resources) { + super(getMimeType(resources)); + this.resources = resources; + } + + /** + * Creates a new SequenceResource as the logical concatenation of the + * given resources. Each resource is concatenated in iteration order as + * needed when reading from the input stream of the SequenceResource. + * + * @param mimetype + * The mimetype of the resource. + * + * @param resources + * The resources to concatenate within the InputStream of this + * SequenceResource. + */ + public SequenceResource(String mimetype, Resource... resources) { + this(mimetype, Arrays.asList(resources)); + } + + /** + * Creates a new SequenceResource as the logical concatenation of the + * given resources. Each resource is concatenated in iteration order as + * needed when reading from the input stream of the SequenceResource. The + * mimetype of the resulting concatenation is derived from the first + * resource. + * + * @param resources + * The resources to concatenate within the InputStream of this + * SequenceResource. + */ + public SequenceResource(Resource... resources) { + this(Arrays.asList(resources)); + } + + @Override + public InputStream asStream() { + return new SequenceInputStream(new Enumeration() { + + /** + * Iterator over all resources associated with this + * SequenceResource. + */ + private final Iterator resourceIterator = resources.iterator(); + + @Override + public boolean hasMoreElements() { + return resourceIterator.hasNext(); + } + + @Override + public InputStream nextElement() { + return resourceIterator.next().asStream(); + } + + }); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/resource/WebApplicationResource.java ---------------------------------------------------------------------- diff --git a/guacamole/src/main/java/org/apache/guacamole/resource/WebApplicationResource.java b/guacamole/src/main/java/org/apache/guacamole/resource/WebApplicationResource.java new file mode 100644 index 0000000..b8aae14 --- /dev/null +++ b/guacamole/src/main/java/org/apache/guacamole/resource/WebApplicationResource.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.apache.guacamole.resource; + +import java.io.InputStream; +import javax.servlet.ServletContext; + +/** + * A resource which is located within the classpath associated with another + * class. + * + * @author Michael Jumper + */ +public class WebApplicationResource extends AbstractResource { + + /** + * The servlet context to use when reading the resource and, if necessary, + * when determining the mimetype of the resource. + */ + private final ServletContext context; + + /** + * The path of this resource relative to the ServletContext. + */ + private final String path; + + /** + * Derives a mimetype from the filename within the given path using the + * given ServletContext, if possible. + * + * @param context + * The ServletContext to use to derive the mimetype. + * + * @param path + * The path to derive the mimetype from. + * + * @return + * An appropriate mimetype based on the name of the file in the path, + * or "application/octet-stream" if no mimetype could be determined. + */ + private static String getMimeType(ServletContext context, String path) { + + // If mimetype is known, use defined mimetype + String mimetype = context.getMimeType(path); + if (mimetype != null) + return mimetype; + + // Otherwise, default to application/octet-stream + return "application/octet-stream"; + + } + + /** + * Creates a new WebApplicationResource which serves the resource at the + * given path relative to the given ServletContext. Rather than deriving + * the mimetype of the resource from the filename within the path, the + * mimetype given is used. + * + * @param context + * The ServletContext to use when reading the resource. + * + * @param mimetype + * The mimetype of the resource. + * + * @param path + * The path of the resource relative to the given ServletContext. + */ + public WebApplicationResource(ServletContext context, String mimetype, String path) { + super(mimetype); + this.context = context; + this.path = path; + } + + /** + * Creates a new WebApplicationResource which serves the resource at the + * given path relative to the given ServletContext. The mimetype of the + * resource is automatically determined based on the filename within the + * path. + * + * @param context + * The ServletContext to use when reading the resource and deriving the + * mimetype. + * + * @param path + * The path of the resource relative to the given ServletContext. + */ + public WebApplicationResource(ServletContext context, String path) { + this(context, getMimeType(context, path), path); + } + + @Override + public InputStream asStream() { + return context.getResourceAsStream(path); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/resource/package-info.java ---------------------------------------------------------------------- diff --git a/guacamole/src/main/java/org/apache/guacamole/resource/package-info.java b/guacamole/src/main/java/org/apache/guacamole/resource/package-info.java new file mode 100644 index 0000000..edbe504 --- /dev/null +++ b/guacamole/src/main/java/org/apache/guacamole/resource/package-info.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/** + * Classes which describe and provide access to arbitrary resources, such as + * the contents of the classpath of a classloader, or files within the web + * application itself. + */ +package org.apache.guacamole.resource; http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/rest/APIError.java ---------------------------------------------------------------------- diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/APIError.java b/guacamole/src/main/java/org/apache/guacamole/rest/APIError.java new file mode 100644 index 0000000..74fa7d2 --- /dev/null +++ b/guacamole/src/main/java/org/apache/guacamole/rest/APIError.java @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.apache.guacamole.rest; + +import java.util.Collection; +import javax.ws.rs.core.Response; +import org.apache.guacamole.form.Field; + +/** + * Describes an error that occurred within a REST endpoint. + * + * @author James Muehlner + * @author Michael Jumper + */ +public class APIError { + + /** + * The error message. + */ + private final String message; + + /** + * All expected request parameters, if any, as a collection of fields. + */ + private final Collection expected; + + /** + * The type of error that occurred. + */ + private final Type type; + + /** + * All possible types of REST API errors. + */ + public enum Type { + + /** + * The requested operation could not be performed because the request + * itself was malformed. + */ + BAD_REQUEST(Response.Status.BAD_REQUEST), + + /** + * The credentials provided were invalid. + */ + INVALID_CREDENTIALS(Response.Status.FORBIDDEN), + + /** + * The credentials provided were not necessarily invalid, but were not + * sufficient to determine validity. + */ + INSUFFICIENT_CREDENTIALS(Response.Status.FORBIDDEN), + + /** + * An internal server error has occurred. + */ + INTERNAL_ERROR(Response.Status.INTERNAL_SERVER_ERROR), + + /** + * An object related to the request does not exist. + */ + NOT_FOUND(Response.Status.NOT_FOUND), + + /** + * Permission was denied to perform the requested operation. + */ + PERMISSION_DENIED(Response.Status.FORBIDDEN); + + /** + * The HTTP status associated with this error type. + */ + private final Response.Status status; + + /** + * Defines a new error type associated with the given HTTP status. + * + * @param status + * The HTTP status to associate with the error type. + */ + Type(Response.Status status) { + this.status = status; + } + + /** + * Returns the HTTP status associated with this error type. + * + * @return + * The HTTP status associated with this error type. + */ + public Response.Status getStatus() { + return status; + } + + } + + /** + * Create a new APIError with the specified error message. + * + * @param type + * The type of error that occurred. + * + * @param message + * The error message. + */ + public APIError(Type type, String message) { + this.type = type; + this.message = message; + this.expected = null; + } + + /** + * Create a new APIError with the specified error message and parameter + * information. + * + * @param type + * The type of error that occurred. + * + * @param message + * The error message. + * + * @param expected + * All parameters expected in the original request, or now required as + * a result of the original request, as a collection of fields. + */ + public APIError(Type type, String message, Collection expected) { + this.type = type; + this.message = message; + this.expected = expected; + } + + /** + * Returns the type of error that occurred. + * + * @return + * The type of error that occurred. + */ + public Type getType() { + return type; + } + + /** + * Returns a collection of all required parameters, where each parameter is + * represented by a field. + * + * @return + * A collection of all required parameters. + */ + public Collection getExpected() { + return expected; + } + + /** + * Returns a human-readable error message describing the error that + * occurred. + * + * @return + * A human-readable error message. + */ + public String getMessage() { + return message; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/rest/APIException.java ---------------------------------------------------------------------- diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/APIException.java b/guacamole/src/main/java/org/apache/guacamole/rest/APIException.java new file mode 100644 index 0000000..7a70fb8 --- /dev/null +++ b/guacamole/src/main/java/org/apache/guacamole/rest/APIException.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2014 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.apache.guacamole.rest; + +import java.util.Collection; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Response; +import org.apache.guacamole.form.Field; + +/** + * An exception that will result in the given error error information being + * returned from the API layer. All error messages have the same format which + * is defined by APIError. + * + * @author James Muehlner + * @author Michael Jumper + */ +public class APIException extends WebApplicationException { + + /** + * Construct a new APIException with the given error. All information + * associated with this new exception will be extracted from the given + * APIError. + * + * @param error + * The error that occurred. + */ + public APIException(APIError error) { + super(Response.status(error.getType().getStatus()).entity(error).build()); + } + + /** + * Creates a new APIException with the given type and message. The + * corresponding APIError will be created from the provided information. + * + * @param type + * The type of error that occurred. + * + * @param message + * A human-readable message describing the error. + */ + public APIException(APIError.Type type, String message) { + this(new APIError(type, message)); + } + + /** + * Creates a new APIException with the given type, message, and parameter + * information. The corresponding APIError will be created from the + * provided information. + * + * @param type + * The type of error that occurred. + * + * @param message + * A human-readable message describing the error. + * + * @param expected + * All parameters expected in the original request, or now required as + * a result of the original request, as a collection of fields. + */ + public APIException(APIError.Type type, String message, Collection expected) { + this(new APIError(type, message, expected)); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/rest/APIPatch.java ---------------------------------------------------------------------- diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/APIPatch.java b/guacamole/src/main/java/org/apache/guacamole/rest/APIPatch.java new file mode 100644 index 0000000..08ee062 --- /dev/null +++ b/guacamole/src/main/java/org/apache/guacamole/rest/APIPatch.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2014 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.apache.guacamole.rest; + +/** + * An object for representing the body of a HTTP PATCH method. + * See https://tools.ietf.org/html/rfc6902 + * + * @author James Muehlner + * @param The type of object being patched. + */ +public class APIPatch { + + /** + * The possible operations for a PATCH request. + */ + public enum Operation { + add, remove, test, copy, replace, move + } + + /** + * The operation to perform for this patch. + */ + private Operation op; + + /** + * The value for this patch. + */ + private T value; + + /** + * The path for this patch. + */ + private String path; + + /** + * Returns the operation for this patch. + * @return the operation for this patch. + */ + public Operation getOp() { + return op; + } + + /** + * Set the operation for this patch. + * @param op The operation for this patch. + */ + public void setOp(Operation op) { + this.op = op; + } + + /** + * Returns the value of this patch. + * @return The value of this patch. + */ + public T getValue() { + return value; + } + + /** + * Sets the value of this patch. + * @param value The value of this patch. + */ + public void setValue(T value) { + this.value = value; + } + + /** + * Returns the path for this patch. + * @return The path for this patch. + */ + public String getPath() { + return path; + } + + /** + * Set the path for this patch. + * @param path The path for this patch. + */ + public void setPath(String path) { + this.path = path; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/rest/APIRequest.java ---------------------------------------------------------------------- diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/APIRequest.java b/guacamole/src/main/java/org/apache/guacamole/rest/APIRequest.java new file mode 100644 index 0000000..cd4fcd5 --- /dev/null +++ b/guacamole/src/main/java/org/apache/guacamole/rest/APIRequest.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.apache.guacamole.rest; + +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import javax.ws.rs.core.MultivaluedMap; + +/** + * Wrapper for HttpServletRequest which uses a given MultivaluedMap to provide + * the values of all request parameters. + * + * @author Michael Jumper + */ +public class APIRequest extends HttpServletRequestWrapper { + + /** + * Map of all request parameter names to their corresponding values. + */ + private final Map parameters; + + /** + * Wraps the given HttpServletRequest, using the given MultivaluedMap to + * provide all request parameters. All HttpServletRequest functions which + * do not deal with parameter names and values are delegated to the wrapped + * request. + * + * @param request + * The HttpServletRequest to wrap. + * + * @param parameters + * All request parameters. + */ + public APIRequest(HttpServletRequest request, + MultivaluedMap parameters) { + + super(request); + + // Copy parameters from given MultivaluedMap + this.parameters = new HashMap(parameters.size()); + for (Map.Entry> entry : parameters.entrySet()) { + + // Get parameter name and all corresponding values + String name = entry.getKey(); + List values = entry.getValue(); + + // Add parameters to map + this.parameters.put(name, values.toArray(new String[values.size()])); + + } + + } + + @Override + public String[] getParameterValues(String name) { + return parameters.get(name); + } + + @Override + public Enumeration getParameterNames() { + return Collections.enumeration(parameters.keySet()); + } + + @Override + public Map getParameterMap() { + return Collections.unmodifiableMap(parameters); + } + + @Override + public String getParameter(String name) { + + // If no such parameter exists, just return null + String[] values = getParameterValues(name); + if (values == null) + return null; + + // Otherwise, return first value + return values[0]; + + } + +} http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/rest/ObjectRetrievalService.java ---------------------------------------------------------------------- diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/ObjectRetrievalService.java b/guacamole/src/main/java/org/apache/guacamole/rest/ObjectRetrievalService.java new file mode 100644 index 0000000..1cf8919 --- /dev/null +++ b/guacamole/src/main/java/org/apache/guacamole/rest/ObjectRetrievalService.java @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.apache.guacamole.rest; + +import java.util.List; +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.GuacamoleResourceNotFoundException; +import org.apache.guacamole.net.auth.AuthenticationProvider; +import org.apache.guacamole.net.auth.Connection; +import org.apache.guacamole.net.auth.ConnectionGroup; +import org.apache.guacamole.net.auth.Directory; +import org.apache.guacamole.net.auth.User; +import org.apache.guacamole.net.auth.UserContext; +import org.apache.guacamole.GuacamoleSession; +import org.apache.guacamole.rest.connectiongroup.APIConnectionGroup; + +/** + * Provides easy access and automatic error handling for retrieval of objects, + * such as users, connections, or connection groups. REST API semantics, such + * as the special root connection group identifier, are also handled + * automatically. + */ +public class ObjectRetrievalService { + + /** + * Retrieves a single UserContext from the given GuacamoleSession, which + * may contain multiple UserContexts. + * + * @param session + * The GuacamoleSession to retrieve the UserContext from. + * + * @param authProviderIdentifier + * The unique identifier of the AuthenticationProvider that created the + * UserContext being retrieved. Only one UserContext per User per + * AuthenticationProvider can exist. + * + * @return + * The UserContext that was created by the AuthenticationProvider + * having the given identifier. + * + * @throws GuacamoleException + * If an error occurs while retrieving the UserContext, or if the + * UserContext does not exist. + */ + public UserContext retrieveUserContext(GuacamoleSession session, + String authProviderIdentifier) throws GuacamoleException { + + // Get list of UserContexts + List userContexts = session.getUserContexts(); + + // Locate and return the UserContext associated with the + // AuthenticationProvider having the given identifier, if any + for (UserContext userContext : userContexts) { + + // Get AuthenticationProvider associated with current UserContext + AuthenticationProvider authProvider = userContext.getAuthenticationProvider(); + + // If AuthenticationProvider identifier matches, done + if (authProvider.getIdentifier().equals(authProviderIdentifier)) + return userContext; + + } + + throw new GuacamoleResourceNotFoundException("Session not associated with authentication provider \"" + authProviderIdentifier + "\"."); + + } + + /** + * Retrieves a single user from the given user context. + * + * @param userContext + * The user context to retrieve the user from. + * + * @param identifier + * The identifier of the user to retrieve. + * + * @return + * The user having the given identifier. + * + * @throws GuacamoleException + * If an error occurs while retrieving the user, or if the + * user does not exist. + */ + public User retrieveUser(UserContext userContext, + String identifier) throws GuacamoleException { + + // Get user directory + Directory directory = userContext.getUserDirectory(); + + // Pull specified user + User user = directory.get(identifier); + if (user == null) + throw new GuacamoleResourceNotFoundException("No such user: \"" + identifier + "\""); + + return user; + + } + + /** + * Retrieves a single user from the given GuacamoleSession. + * + * @param session + * The GuacamoleSession to retrieve the user from. + * + * @param authProviderIdentifier + * The unique identifier of the AuthenticationProvider that created the + * UserContext from which the user should be retrieved. Only one + * UserContext per User per AuthenticationProvider can exist. + * + * @param identifier + * The identifier of the user to retrieve. + * + * @return + * The user having the given identifier. + * + * @throws GuacamoleException + * If an error occurs while retrieving the user, or if the + * user does not exist. + */ + public User retrieveUser(GuacamoleSession session, String authProviderIdentifier, + String identifier) throws GuacamoleException { + + UserContext userContext = retrieveUserContext(session, authProviderIdentifier); + return retrieveUser(userContext, identifier); + + } + + /** + * Retrieves a single connection from the given user context. + * + * @param userContext + * The user context to retrieve the connection from. + * + * @param identifier + * The identifier of the connection to retrieve. + * + * @return + * The connection having the given identifier. + * + * @throws GuacamoleException + * If an error occurs while retrieving the connection, or if the + * connection does not exist. + */ + public Connection retrieveConnection(UserContext userContext, + String identifier) throws GuacamoleException { + + // Get connection directory + Directory directory = userContext.getConnectionDirectory(); + + // Pull specified connection + Connection connection = directory.get(identifier); + if (connection == null) + throw new GuacamoleResourceNotFoundException("No such connection: \"" + identifier + "\""); + + return connection; + + } + + /** + * Retrieves a single connection from the given GuacamoleSession. + * + * @param session + * The GuacamoleSession to retrieve the connection from. + * + * @param authProviderIdentifier + * The unique identifier of the AuthenticationProvider that created the + * UserContext from which the connection should be retrieved. Only one + * UserContext per User per AuthenticationProvider can exist. + * + * @param identifier + * The identifier of the connection to retrieve. + * + * @return + * The connection having the given identifier. + * + * @throws GuacamoleException + * If an error occurs while retrieving the connection, or if the + * connection does not exist. + */ + public Connection retrieveConnection(GuacamoleSession session, + String authProviderIdentifier, String identifier) + throws GuacamoleException { + + UserContext userContext = retrieveUserContext(session, authProviderIdentifier); + return retrieveConnection(userContext, identifier); + + } + + /** + * Retrieves a single connection group from the given user context. If + * the given identifier the REST API root identifier, the root connection + * group will be returned. The underlying authentication provider may + * additionally use a different identifier for root. + * + * @param userContext + * The user context to retrieve the connection group from. + * + * @param identifier + * The identifier of the connection group to retrieve. + * + * @return + * The connection group having the given identifier, or the root + * connection group if the identifier the root identifier. + * + * @throws GuacamoleException + * If an error occurs while retrieving the connection group, or if the + * connection group does not exist. + */ + public ConnectionGroup retrieveConnectionGroup(UserContext userContext, + String identifier) throws GuacamoleException { + + // Use root group if identifier is the standard root identifier + if (identifier != null && identifier.equals(APIConnectionGroup.ROOT_IDENTIFIER)) + return userContext.getRootConnectionGroup(); + + // Pull specified connection group otherwise + Directory directory = userContext.getConnectionGroupDirectory(); + ConnectionGroup connectionGroup = directory.get(identifier); + + if (connectionGroup == null) + throw new GuacamoleResourceNotFoundException("No such connection group: \"" + identifier + "\""); + + return connectionGroup; + + } + + /** + * Retrieves a single connection group from the given GuacamoleSession. If + * the given identifier is the REST API root identifier, the root + * connection group will be returned. The underlying authentication + * provider may additionally use a different identifier for root. + * + * @param session + * The GuacamoleSession to retrieve the connection group from. + * + * @param authProviderIdentifier + * The unique identifier of the AuthenticationProvider that created the + * UserContext from which the connection group should be retrieved. + * Only one UserContext per User per AuthenticationProvider can exist. + * + * @param identifier + * The identifier of the connection group to retrieve. + * + * @return + * The connection group having the given identifier, or the root + * connection group if the identifier is the root identifier. + * + * @throws GuacamoleException + * If an error occurs while retrieving the connection group, or if the + * connection group does not exist. + */ + public ConnectionGroup retrieveConnectionGroup(GuacamoleSession session, + String authProviderIdentifier, String identifier) throws GuacamoleException { + + UserContext userContext = retrieveUserContext(session, authProviderIdentifier); + return retrieveConnectionGroup(userContext, identifier); + + } + +} http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/rest/PATCH.java ---------------------------------------------------------------------- diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/PATCH.java b/guacamole/src/main/java/org/apache/guacamole/rest/PATCH.java new file mode 100644 index 0000000..f87ca98 --- /dev/null +++ b/guacamole/src/main/java/org/apache/guacamole/rest/PATCH.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2014 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +package org.apache.guacamole.rest; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import javax.ws.rs.HttpMethod; + +/** + * An annotation for using the HTTP PATCH method in the REST endpoints. + * + * @author James Muehlner + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@HttpMethod("PATCH") +public @interface PATCH {} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/rest/RESTExceptionWrapper.java ---------------------------------------------------------------------- diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/RESTExceptionWrapper.java b/guacamole/src/main/java/org/apache/guacamole/rest/RESTExceptionWrapper.java new file mode 100644 index 0000000..0193e22 --- /dev/null +++ b/guacamole/src/main/java/org/apache/guacamole/rest/RESTExceptionWrapper.java @@ -0,0 +1,274 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.apache.guacamole.rest; + +import com.google.inject.Inject; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import javax.ws.rs.FormParam; +import javax.ws.rs.QueryParam; +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; +import org.apache.guacamole.GuacamoleClientException; +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.GuacamoleResourceNotFoundException; +import org.apache.guacamole.GuacamoleSecurityException; +import org.apache.guacamole.GuacamoleUnauthorizedException; +import org.apache.guacamole.net.auth.credentials.GuacamoleInsufficientCredentialsException; +import org.apache.guacamole.net.auth.credentials.GuacamoleInvalidCredentialsException; +import org.apache.guacamole.rest.auth.AuthenticationService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A method interceptor which wraps custom exception handling around methods + * which can throw GuacamoleExceptions and which are exposed through the REST + * interface. The various types of GuacamoleExceptions are automatically + * translated into appropriate HTTP responses, including JSON describing the + * error that occurred. + * + * @author James Muehlner + * @author Michael Jumper + */ +public class RESTExceptionWrapper implements MethodInterceptor { + + /** + * Logger for this class. + */ + private final Logger logger = LoggerFactory.getLogger(RESTExceptionWrapper.class); + + /** + * Service for authenticating users and managing their Guacamole sessions. + */ + @Inject + private AuthenticationService authenticationService; + + /** + * Determines whether the given set of annotations describes an HTTP + * request parameter of the given name. For a parameter to be associated + * with an HTTP request parameter, it must be annotated with either the + * @QueryParam or @FormParam annotations. + * + * @param annotations + * The annotations associated with the Java parameter being checked. + * + * @param name + * The name of the HTTP request parameter. + * + * @return + * true if the given set of annotations describes an HTTP request + * parameter having the given name, false otherwise. + */ + private boolean isRequestParameter(Annotation[] annotations, String name) { + + // Search annotations for associated HTTP parameters + for (Annotation annotation : annotations) { + + // Check if parameter is associated with the HTTP query string + if (annotation instanceof QueryParam && name.equals(((QueryParam) annotation).value())) + return true; + + // Failing that, check whether the parameter is associated with the + // HTTP request body + if (annotation instanceof FormParam && name.equals(((FormParam) annotation).value())) + return true; + + } + + // No parameter annotations are present + return false; + + } + + /** + * Returns the authentication token that was passed in the given method + * invocation. If the given method invocation is not associated with an + * HTTP request (it lacks the appropriate JAX-RS annotations) or there is + * no authentication token, null is returned. + * + * @param invocation + * The method invocation whose corresponding authentication token + * should be determined. + * + * @return + * The authentication token passed in the given method invocation, or + * null if there is no such token. + */ + private String getAuthenticationToken(MethodInvocation invocation) { + + Method method = invocation.getMethod(); + + // Get the types and annotations associated with each parameter + Annotation[][] parameterAnnotations = method.getParameterAnnotations(); + Class[] parameterTypes = method.getParameterTypes(); + + // The Java standards require these to be parallel arrays + assert(parameterAnnotations.length == parameterTypes.length); + + // Iterate through all parameters, looking for the authentication token + for (int i = 0; i < parameterTypes.length; i++) { + + // Only inspect String parameters + Class parameterType = parameterTypes[i]; + if (parameterType != String.class) + continue; + + // Parameter must be declared as a REST service parameter + Annotation[] annotations = parameterAnnotations[i]; + if (!isRequestParameter(annotations, "token")) + continue; + + // The token parameter has been found - return its value + Object[] args = invocation.getArguments(); + return (String) args[i]; + + } + + // No token parameter is defined + return null; + + } + + @Override + public Object invoke(MethodInvocation invocation) throws Throwable { + + try { + + // Invoke wrapped method + try { + return invocation.proceed(); + } + + // Ensure any associated session is invalidated if unauthorized + catch (GuacamoleUnauthorizedException e) { + + // Pull authentication token from request + String token = getAuthenticationToken(invocation); + + // If there is an associated auth token, invalidate it + if (authenticationService.destroyGuacamoleSession(token)) + logger.debug("Implicitly invalidated session for token \"{}\".", token); + + // Continue with exception processing + throw e; + + } + + } + + // Additional credentials are needed + catch (GuacamoleInsufficientCredentialsException e) { + + // Generate default message + String message = e.getMessage(); + if (message == null) + message = "Permission denied."; + + throw new APIException( + APIError.Type.INSUFFICIENT_CREDENTIALS, + message, + e.getCredentialsInfo().getFields() + ); + } + + // The provided credentials are wrong + catch (GuacamoleInvalidCredentialsException e) { + + // Generate default message + String message = e.getMessage(); + if (message == null) + message = "Permission denied."; + + throw new APIException( + APIError.Type.INVALID_CREDENTIALS, + message, + e.getCredentialsInfo().getFields() + ); + } + + // Generic permission denied + catch (GuacamoleSecurityException e) { + + // Generate default message + String message = e.getMessage(); + if (message == null) + message = "Permission denied."; + + throw new APIException( + APIError.Type.PERMISSION_DENIED, + message + ); + + } + + // Arbitrary resource not found + catch (GuacamoleResourceNotFoundException e) { + + // Generate default message + String message = e.getMessage(); + if (message == null) + message = "Not found."; + + throw new APIException( + APIError.Type.NOT_FOUND, + message + ); + + } + + // Arbitrary bad requests + catch (GuacamoleClientException e) { + + // Generate default message + String message = e.getMessage(); + if (message == null) + message = "Invalid request."; + + throw new APIException( + APIError.Type.BAD_REQUEST, + message + ); + + } + + // All other errors + catch (GuacamoleException e) { + + // Generate default message + String message = e.getMessage(); + if (message == null) + message = "Unexpected server error."; + + // Ensure internal errors are logged at the debug level + logger.debug("Unexpected exception in REST endpoint.", e); + + throw new APIException( + APIError.Type.INTERNAL_ERROR, + message + ); + + } + + } + +} http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/rest/RESTMethodMatcher.java ---------------------------------------------------------------------- diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/RESTMethodMatcher.java b/guacamole/src/main/java/org/apache/guacamole/rest/RESTMethodMatcher.java new file mode 100644 index 0000000..0283e63 --- /dev/null +++ b/guacamole/src/main/java/org/apache/guacamole/rest/RESTMethodMatcher.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.apache.guacamole.rest; + +import com.google.inject.matcher.AbstractMatcher; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import javax.ws.rs.HttpMethod; +import org.apache.guacamole.GuacamoleException; + +/** + * A Guice Matcher which matches only methods which throw GuacamoleException + * (or a subclass thereof) and are explicitly annotated as with an HTTP method + * annotation like @GET or @POST. Any method which + * throws GuacamoleException and is annotated with an annotation that is + * annotated with @HttpMethod will match. + * + * @author Michael Jumper + */ +public class RESTMethodMatcher extends AbstractMatcher { + + /** + * Returns whether the given method throws the specified exception type, + * including any subclasses of that type. + * + * @param method + * The method to test. + * + * @param exceptionType + * The exception type to test for. + * + * @return + * true if the given method throws an exception of the specified type, + * false otherwise. + */ + private boolean methodThrowsException(Method method, + Class exceptionType) { + + // Check whether the method throws an exception of the specified type + for (Class thrownType : method.getExceptionTypes()) { + if (exceptionType.isAssignableFrom(thrownType)) + return true; + } + + // No such exception is declared to be thrown + return false; + + } + + /** + * Returns whether the given method is annotated as a REST method. A REST + * method is annotated with an annotation which is annotated with + * @HttpMethod. + * + * @param method + * The method to test. + * + * @return + * true if the given method is annotated as a REST method, false + * otherwise. + */ + private boolean isRESTMethod(Method method) { + + // Check whether the required REST annotations are present + for (Annotation annotation : method.getAnnotations()) { + + // A method is a REST method if it is annotated with @HttpMethod + Class annotationType = annotation.annotationType(); + if (annotationType.isAnnotationPresent(HttpMethod.class)) + return true; + + } + + // The method is not an HTTP method + return false; + + } + + @Override + public boolean matches(Method method) { + + // Guacamole REST methods are REST methods which throw + // GuacamoleExceptions + return isRESTMethod(method) + && methodThrowsException(method, GuacamoleException.class); + + } + +}