You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@guacamole.apache.org by jm...@apache.org on 2016/03/29 06:20:23 UTC
[14/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/auth/Authorization.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/auth/Authorization.java b/guacamole/src/main/java/org/apache/guacamole/auth/Authorization.java
new file mode 100644
index 0000000..9ff1c79
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/auth/Authorization.java
@@ -0,0 +1,255 @@
+/*
+ * 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.auth;
+
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Map;
+import java.util.TreeMap;
+import org.apache.guacamole.protocol.GuacamoleConfiguration;
+
+/**
+ * Mapping of username/password pair to configuration set. In addition to basic
+ * storage of the username, password, and configurations, this class also
+ * provides password validation functions.
+ *
+ * @author Mike Jumper
+ */
+public class Authorization {
+
+ /**
+ * All supported password encodings.
+ */
+ public static enum Encoding {
+
+ /**
+ * Plain-text password (not hashed at all).
+ */
+ PLAIN_TEXT,
+
+ /**
+ * Password hashed with MD5.
+ */
+ MD5
+
+ }
+
+ /**
+ * The username being authorized.
+ */
+ private String username;
+
+ /**
+ * The password corresponding to the username being authorized, which may
+ * be hashed.
+ */
+ private String password;
+
+ /**
+ * The encoding used when the password was hashed.
+ */
+ private Encoding encoding = Encoding.PLAIN_TEXT;
+
+ /**
+ * Map of all authorized configurations, indexed by configuration name.
+ */
+ private Map<String, GuacamoleConfiguration> configs = new
+ TreeMap<String, GuacamoleConfiguration>();
+
+ /**
+ * Lookup table of hex bytes characters by value.
+ */
+ private static final char HEX_CHARS[] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+ };
+
+ /**
+ * Produces a String containing the bytes provided in hexadecimal notation.
+ *
+ * @param bytes The bytes to convert into hex.
+ * @return A String containing the hex representation of the given bytes.
+ */
+ private static String getHexString(byte[] bytes) {
+
+ // If null byte array given, return null
+ if (bytes == null)
+ return null;
+
+ // Create string builder for holding the hex representation,
+ // pre-calculating the exact length
+ StringBuilder hex = new StringBuilder(2 * bytes.length);
+
+ // Convert each byte into a pair of hex digits
+ for (byte b : bytes) {
+ hex.append(HEX_CHARS[(b & 0xF0) >> 4])
+ .append(HEX_CHARS[ b & 0x0F ]);
+ }
+
+ // Return the string produced
+ return hex.toString();
+
+ }
+
+ /**
+ * Returns the username associated with this authorization.
+ *
+ * @return The username associated with this authorization.
+ */
+ public String getUsername() {
+ return username;
+ }
+
+ /**
+ * Sets the username associated with this authorization.
+ *
+ * @param username The username to associate with this authorization.
+ */
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ /**
+ * Returns the password associated with this authorization, which may be
+ * encoded or hashed.
+ *
+ * @return The password associated with this authorization.
+ */
+ public String getPassword() {
+ return password;
+ }
+
+ /**
+ * Sets the password associated with this authorization, which must be
+ * encoded using the encoding specified with setEncoding(). By default,
+ * passwords are plain text.
+ *
+ * @param password Sets the password associated with this authorization.
+ */
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ /**
+ * Returns the encoding used to hash the password, if any.
+ *
+ * @return The encoding used to hash the password.
+ */
+ public Encoding getEncoding() {
+ return encoding;
+ }
+
+ /**
+ * Sets the encoding which will be used to hash the password or when
+ * comparing a given password for validation.
+ *
+ * @param encoding The encoding to use for password hashing.
+ */
+ public void setEncoding(Encoding encoding) {
+ this.encoding = encoding;
+ }
+
+ /**
+ * Returns whether a given username/password pair is authorized based on
+ * the stored username and password. The password given must be plain text.
+ * It will be hashed as necessary to perform the validation.
+ *
+ * @param username The username to validate.
+ * @param password The password to validate.
+ * @return true if the username/password pair given is authorized, false
+ * otherwise.
+ */
+ public boolean validate(String username, String password) {
+
+ // If username matches
+ if (username != null && password != null
+ && username.equals(this.username)) {
+
+ switch (encoding) {
+
+ // If plain text, just compare
+ case PLAIN_TEXT:
+
+ // Compare plaintext
+ return password.equals(this.password);
+
+ // If hased with MD5, hash password and compare
+ case MD5:
+
+ // Compare hashed password
+ try {
+ MessageDigest digest = MessageDigest.getInstance("MD5");
+ String hashedPassword = getHexString(digest.digest(password.getBytes("UTF-8")));
+ return hashedPassword.equals(this.password.toUpperCase());
+ }
+ catch (UnsupportedEncodingException e) {
+ throw new UnsupportedOperationException("Unexpected lack of UTF-8 support.", e);
+ }
+ catch (NoSuchAlgorithmException e) {
+ throw new UnsupportedOperationException("Unexpected lack of MD5 support.", e);
+ }
+
+ }
+
+ } // end validation check
+
+ return false;
+
+ }
+
+ /**
+ * Returns the GuacamoleConfiguration having the given name and associated
+ * with the username/password pair stored within this authorization.
+ *
+ * @param name The name of the GuacamoleConfiguration to return.
+ * @return The GuacamoleConfiguration having the given name, or null if no
+ * such GuacamoleConfiguration exists.
+ */
+ public GuacamoleConfiguration getConfiguration(String name) {
+ return configs.get(name);
+ }
+
+ /**
+ * Adds the given GuacamoleConfiguration to the set of stored configurations
+ * under the given name.
+ *
+ * @param name The name to associate this GuacamoleConfiguration with.
+ * @param config The GuacamoleConfiguration to store.
+ */
+ public void addConfiguration(String name, GuacamoleConfiguration config) {
+ configs.put(name, config);
+ }
+
+ /**
+ * Returns a Map of all stored GuacamoleConfigurations associated with the
+ * username/password pair stored within this authorization, indexed by
+ * configuration name.
+ *
+ * @return A Map of all stored GuacamoleConfigurations.
+ */
+ public Map<String, GuacamoleConfiguration> getConfigurations() {
+ return configs;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/auth/UserMapping.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/auth/UserMapping.java b/guacamole/src/main/java/org/apache/guacamole/auth/UserMapping.java
new file mode 100644
index 0000000..7f86b1e
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/auth/UserMapping.java
@@ -0,0 +1,62 @@
+/*
+ * 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.auth;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Mapping of all usernames to corresponding authorizations.
+ *
+ * @author Mike Jumper
+ */
+public class UserMapping {
+
+ /**
+ * All authorizations, indexed by username.
+ */
+ private Map<String, Authorization> authorizations =
+ new HashMap<String, Authorization>();
+
+ /**
+ * Adds the given authorization to the user mapping.
+ *
+ * @param authorization The authorization to add to the user mapping.
+ */
+ public void addAuthorization(Authorization authorization) {
+ authorizations.put(authorization.getUsername(), authorization);
+ }
+
+ /**
+ * Returns the authorization corresponding to the user having the given
+ * username, if any.
+ *
+ * @param username The username to find the authorization for.
+ * @return The authorization corresponding to the user having the given
+ * username, or null if no such authorization exists.
+ */
+ public Authorization getAuthorization(String username) {
+ return authorizations.get(username);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/auth/basic/AuthorizeTagHandler.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/auth/basic/AuthorizeTagHandler.java b/guacamole/src/main/java/org/apache/guacamole/auth/basic/AuthorizeTagHandler.java
new file mode 100644
index 0000000..bdd9c9a
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/auth/basic/AuthorizeTagHandler.java
@@ -0,0 +1,151 @@
+/*
+ * 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.auth.basic;
+
+import org.apache.guacamole.auth.Authorization;
+import org.apache.guacamole.auth.UserMapping;
+import org.apache.guacamole.xml.TagHandler;
+import org.apache.guacamole.protocol.GuacamoleConfiguration;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+/**
+ * TagHandler for the "authorize" element.
+ *
+ * @author Mike Jumper
+ */
+public class AuthorizeTagHandler implements TagHandler {
+
+ /**
+ * The Authorization corresponding to the "authorize" tag being handled
+ * by this tag handler. The data of this Authorization will be populated
+ * as the tag is parsed.
+ */
+ private Authorization authorization = new Authorization();
+
+ /**
+ * The default GuacamoleConfiguration to use if "param" or "protocol"
+ * tags occur outside a "connection" tag.
+ */
+ private GuacamoleConfiguration default_config = null;
+
+ /**
+ * The UserMapping this authorization belongs to.
+ */
+ private UserMapping parent;
+
+ /**
+ * Creates a new AuthorizeTagHandler that parses an Authorization owned
+ * by the given UserMapping.
+ *
+ * @param parent The UserMapping that owns the Authorization this handler
+ * will parse.
+ */
+ public AuthorizeTagHandler(UserMapping parent) {
+ this.parent = parent;
+ }
+
+ @Override
+ public void init(Attributes attributes) throws SAXException {
+
+ // Init username and password
+ authorization.setUsername(attributes.getValue("username"));
+ authorization.setPassword(attributes.getValue("password"));
+
+ // Get encoding
+ String encoding = attributes.getValue("encoding");
+ if (encoding != null) {
+
+ // If "md5", use MD5 encoding
+ if (encoding.equals("md5"))
+ authorization.setEncoding(Authorization.Encoding.MD5);
+
+ // If "plain", use plain text
+ else if (encoding.equals("plain"))
+ authorization.setEncoding(Authorization.Encoding.PLAIN_TEXT);
+
+ // Otherwise, bad encoding
+ else
+ throw new SAXException(
+ "Invalid encoding: '" + encoding + "'");
+
+ }
+
+ parent.addAuthorization(this.asAuthorization());
+
+ }
+
+ @Override
+ public TagHandler childElement(String localName) throws SAXException {
+
+ // "connection" tag
+ if (localName.equals("connection"))
+ return new ConnectionTagHandler(authorization);
+
+ // "param" tag
+ if (localName.equals("param")) {
+
+ // Create default config if it doesn't exist
+ if (default_config == null) {
+ default_config = new GuacamoleConfiguration();
+ authorization.addConfiguration("DEFAULT", default_config);
+ }
+
+ return new ParamTagHandler(default_config);
+ }
+
+ // "protocol" tag
+ if (localName.equals("protocol")) {
+
+ // Create default config if it doesn't exist
+ if (default_config == null) {
+ default_config = new GuacamoleConfiguration();
+ authorization.addConfiguration("DEFAULT", default_config);
+ }
+
+ return new ProtocolTagHandler(default_config);
+ }
+
+ return null;
+
+ }
+
+ @Override
+ public void complete(String textContent) throws SAXException {
+ // Do nothing
+ }
+
+ /**
+ * Returns an Authorization backed by the data of this authorize tag
+ * handler. This Authorization is guaranteed to at least have the username,
+ * password, and encoding available. Any associated configurations will be
+ * added dynamically as the authorize tag is parsed.
+ *
+ * @return An Authorization backed by the data of this authorize tag
+ * handler.
+ */
+ public Authorization asAuthorization() {
+ return authorization;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/auth/basic/BasicFileAuthenticationProvider.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/auth/basic/BasicFileAuthenticationProvider.java b/guacamole/src/main/java/org/apache/guacamole/auth/basic/BasicFileAuthenticationProvider.java
new file mode 100644
index 0000000..be3fd1a
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/auth/basic/BasicFileAuthenticationProvider.java
@@ -0,0 +1,218 @@
+/*
+ * 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.auth.basic;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.environment.Environment;
+import org.apache.guacamole.environment.LocalEnvironment;
+import org.apache.guacamole.net.auth.Credentials;
+import org.apache.guacamole.net.auth.simple.SimpleAuthenticationProvider;
+import org.apache.guacamole.auth.Authorization;
+import org.apache.guacamole.auth.UserMapping;
+import org.apache.guacamole.xml.DocumentHandler;
+import org.apache.guacamole.properties.FileGuacamoleProperty;
+import org.apache.guacamole.protocol.GuacamoleConfiguration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.XMLReaderFactory;
+
+/**
+ * Authenticates users against a static list of username/password pairs.
+ * Each username/password may be associated with multiple configurations.
+ * This list is stored in an XML file which is reread if modified.
+ *
+ * @author Michael Jumper, Michal Kotas
+ */
+public class BasicFileAuthenticationProvider extends SimpleAuthenticationProvider {
+
+ /**
+ * Logger for this class.
+ */
+ private final Logger logger = LoggerFactory.getLogger(BasicFileAuthenticationProvider.class);
+
+ /**
+ * The time the user mapping file was last modified. If the file has never
+ * been read, and thus no modification time exists, this will be
+ * Long.MIN_VALUE.
+ */
+ private long lastModified = Long.MIN_VALUE;
+
+ /**
+ * The parsed UserMapping read when the user mapping file was last parsed.
+ */
+ private UserMapping cachedUserMapping;
+
+ /**
+ * Guacamole server environment.
+ */
+ private final Environment environment;
+
+ /**
+ * The XML file to read the user mapping from.
+ */
+ public static final FileGuacamoleProperty BASIC_USER_MAPPING = new FileGuacamoleProperty() {
+
+ @Override
+ public String getName() { return "basic-user-mapping"; }
+
+ };
+
+ /**
+ * The default filename to use for the user mapping, if not defined within
+ * guacamole.properties.
+ */
+ public static final String DEFAULT_USER_MAPPING = "user-mapping.xml";
+
+ /**
+ * Creates a new BasicFileAuthenticationProvider that authenticates users
+ * against simple, monolithic XML file.
+ *
+ * @throws GuacamoleException
+ * If a required property is missing, or an error occurs while parsing
+ * a property.
+ */
+ public BasicFileAuthenticationProvider() throws GuacamoleException {
+ environment = new LocalEnvironment();
+ }
+
+ @Override
+ public String getIdentifier() {
+ return "default";
+ }
+
+ /**
+ * Returns a UserMapping containing all authorization data given within
+ * the XML file specified by the "basic-user-mapping" property in
+ * guacamole.properties. If the XML file has been modified or has not yet
+ * been read, this function may reread the file.
+ *
+ * @return
+ * A UserMapping containing all authorization data within the user
+ * mapping XML file, or null if the file cannot be found/parsed.
+ */
+ private UserMapping getUserMapping() {
+
+ // Get user mapping file, defaulting to GUACAMOLE_HOME/user-mapping.xml
+ File userMappingFile;
+ try {
+ userMappingFile = environment.getProperty(BASIC_USER_MAPPING);
+ if (userMappingFile == null)
+ userMappingFile = new File(environment.getGuacamoleHome(), DEFAULT_USER_MAPPING);
+ }
+
+ // Abort if property cannot be parsed
+ catch (GuacamoleException e) {
+ logger.warn("Unable to read user mapping filename from properties: {}", e.getMessage());
+ logger.debug("Error parsing user mapping property.", e);
+ return null;
+ }
+
+ // Abort if user mapping does not exist
+ if (!userMappingFile.exists()) {
+ logger.debug("User mapping file \"{}\" does not exist and will not be read.", userMappingFile);
+ return null;
+ }
+
+ // Refresh user mapping if file has changed
+ if (lastModified < userMappingFile.lastModified()) {
+
+ logger.debug("Reading user mapping file: \"{}\"", userMappingFile);
+
+ // Parse document
+ try {
+
+ // Get handler for root element
+ UserMappingTagHandler userMappingHandler =
+ new UserMappingTagHandler();
+
+ // Set up document handler
+ DocumentHandler contentHandler = new DocumentHandler(
+ "user-mapping", userMappingHandler);
+
+ // Set up XML parser
+ XMLReader parser = XMLReaderFactory.createXMLReader();
+ parser.setContentHandler(contentHandler);
+
+ // Read and parse file
+ InputStream input = new BufferedInputStream(new FileInputStream(userMappingFile));
+ parser.parse(new InputSource(input));
+ input.close();
+
+ // Store mod time and user mapping
+ lastModified = userMappingFile.lastModified();
+ cachedUserMapping = userMappingHandler.asUserMapping();
+
+ }
+
+ // If the file is unreadable, return no mapping
+ catch (IOException e) {
+ logger.warn("Unable to read user mapping file \"{}\": {}", userMappingFile, e.getMessage());
+ logger.debug("Error reading user mapping file.", e);
+ return null;
+ }
+
+ // If the file cannot be parsed, return no mapping
+ catch (SAXException e) {
+ logger.warn("User mapping file \"{}\" is not valid: {}", userMappingFile, e.getMessage());
+ logger.debug("Error parsing user mapping file.", e);
+ return null;
+ }
+
+ }
+
+ // Return (possibly cached) user mapping
+ return cachedUserMapping;
+
+ }
+
+ @Override
+ public Map<String, GuacamoleConfiguration>
+ getAuthorizedConfigurations(Credentials credentials)
+ throws GuacamoleException {
+
+ // Abort authorization if no user mapping exists
+ UserMapping userMapping = getUserMapping();
+ if (userMapping == null)
+ return null;
+
+ // Validate and return info for given user and pass
+ Authorization auth = userMapping.getAuthorization(credentials.getUsername());
+ if (auth != null && auth.validate(credentials.getUsername(), credentials.getPassword()))
+ return auth.getConfigurations();
+
+ // Unauthorized
+ return null;
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/auth/basic/ConnectionTagHandler.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/auth/basic/ConnectionTagHandler.java b/guacamole/src/main/java/org/apache/guacamole/auth/basic/ConnectionTagHandler.java
new file mode 100644
index 0000000..f9acabb
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/auth/basic/ConnectionTagHandler.java
@@ -0,0 +1,110 @@
+/*
+ * 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.auth.basic;
+
+import org.apache.guacamole.auth.Authorization;
+import org.apache.guacamole.xml.TagHandler;
+import org.apache.guacamole.protocol.GuacamoleConfiguration;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+/**
+ * TagHandler for the "connection" element.
+ *
+ * @author Mike Jumper
+ */
+public class ConnectionTagHandler implements TagHandler {
+
+ /**
+ * The GuacamoleConfiguration backing this tag handler.
+ */
+ private GuacamoleConfiguration config = new GuacamoleConfiguration();
+
+ /**
+ * The name associated with the connection being parsed.
+ */
+ private String name;
+
+ /**
+ * The Authorization this connection belongs to.
+ */
+ private Authorization parent;
+
+ /**
+ * Creates a new ConnectionTagHandler that parses a Connection owned by
+ * the given Authorization.
+ *
+ * @param parent The Authorization that will own this Connection once
+ * parsed.
+ */
+ public ConnectionTagHandler(Authorization parent) {
+ this.parent = parent;
+ }
+
+ @Override
+ public void init(Attributes attributes) throws SAXException {
+ name = attributes.getValue("name");
+ parent.addConfiguration(name, this.asGuacamoleConfiguration());
+ }
+
+ @Override
+ public TagHandler childElement(String localName) throws SAXException {
+
+ if (localName.equals("param"))
+ return new ParamTagHandler(config);
+
+ if (localName.equals("protocol"))
+ return new ProtocolTagHandler(config);
+
+ return null;
+
+ }
+
+ @Override
+ public void complete(String textContent) throws SAXException {
+ // Do nothing
+ }
+
+ /**
+ * Returns a GuacamoleConfiguration whose contents are populated from data
+ * within this connection element and child elements. This
+ * GuacamoleConfiguration will continue to be modified as the user mapping
+ * is parsed.
+ *
+ * @return A GuacamoleConfiguration whose contents are populated from data
+ * within this connection element.
+ */
+ public GuacamoleConfiguration asGuacamoleConfiguration() {
+ return config;
+ }
+
+ /**
+ * Returns the name associated with this connection.
+ *
+ * @return The name associated with this connection.
+ */
+ public String getName() {
+ return name;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/auth/basic/ParamTagHandler.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/auth/basic/ParamTagHandler.java b/guacamole/src/main/java/org/apache/guacamole/auth/basic/ParamTagHandler.java
new file mode 100644
index 0000000..5d3d804
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/auth/basic/ParamTagHandler.java
@@ -0,0 +1,74 @@
+/*
+ * 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.auth.basic;
+
+import org.apache.guacamole.xml.TagHandler;
+import org.apache.guacamole.protocol.GuacamoleConfiguration;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+/**
+ * TagHandler for the "param" element.
+ *
+ * @author Mike Jumper
+ */
+public class ParamTagHandler implements TagHandler {
+
+ /**
+ * The GuacamoleConfiguration which will be populated with data from
+ * the tag handled by this tag handler.
+ */
+ private GuacamoleConfiguration config;
+
+ /**
+ * The name of the parameter.
+ */
+ private String name;
+
+ /**
+ * Creates a new handler for an "param" tag having the given
+ * attributes.
+ *
+ * @param config The GuacamoleConfiguration to update with the data parsed
+ * from the "protocol" tag.
+ */
+ public ParamTagHandler(GuacamoleConfiguration config) {
+ this.config = config;
+ }
+
+ @Override
+ public void init(Attributes attributes) throws SAXException {
+ this.name = attributes.getValue("name");
+ }
+
+ @Override
+ public TagHandler childElement(String localName) throws SAXException {
+ throw new SAXException("The 'param' tag can contain no elements.");
+ }
+
+ @Override
+ public void complete(String textContent) throws SAXException {
+ config.setParameter(name, textContent);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/auth/basic/ProtocolTagHandler.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/auth/basic/ProtocolTagHandler.java b/guacamole/src/main/java/org/apache/guacamole/auth/basic/ProtocolTagHandler.java
new file mode 100644
index 0000000..3fc5f12
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/auth/basic/ProtocolTagHandler.java
@@ -0,0 +1,70 @@
+/*
+ * 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.auth.basic;
+
+import org.apache.guacamole.xml.TagHandler;
+import org.apache.guacamole.protocol.GuacamoleConfiguration;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+/**
+ * TagHandler for the "protocol" element.
+ *
+ * @author Mike Jumper
+ */
+public class ProtocolTagHandler implements TagHandler {
+
+ /**
+ * The GuacamoleConfiguration which will be populated with data from
+ * the tag handled by this tag handler.
+ */
+ private GuacamoleConfiguration config;
+
+ /**
+ * Creates a new handler for a "protocol" tag having the given
+ * attributes.
+ *
+ * @param config The GuacamoleConfiguration to update with the data parsed
+ * from the "protocol" tag.
+ * @throws SAXException If the attributes given are not valid.
+ */
+ public ProtocolTagHandler(GuacamoleConfiguration config) throws SAXException {
+ this.config = config;
+ }
+
+ @Override
+ public void init(Attributes attributes) throws SAXException {
+ // Do nothing
+ }
+
+ @Override
+ public TagHandler childElement(String localName) throws SAXException {
+ throw new SAXException("The 'protocol' tag can contain no elements.");
+ }
+
+ @Override
+ public void complete(String textContent) throws SAXException {
+ config.setProtocol(textContent);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/auth/basic/UserMappingTagHandler.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/auth/basic/UserMappingTagHandler.java b/guacamole/src/main/java/org/apache/guacamole/auth/basic/UserMappingTagHandler.java
new file mode 100644
index 0000000..f0bb6fa
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/auth/basic/UserMappingTagHandler.java
@@ -0,0 +1,78 @@
+/*
+ * 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.auth.basic;
+
+import org.apache.guacamole.auth.UserMapping;
+import org.apache.guacamole.xml.TagHandler;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+/**
+ * TagHandler for the "user-mapping" element.
+ *
+ * @author Mike Jumper
+ */
+public class UserMappingTagHandler implements TagHandler {
+
+ /**
+ * The UserMapping which will contain all data parsed by this tag handler.
+ */
+ private UserMapping user_mapping = new UserMapping();
+
+ @Override
+ public void init(Attributes attributes) throws SAXException {
+ // Do nothing
+ }
+
+ @Override
+ public TagHandler childElement(String localName) throws SAXException {
+
+ // Start parsing of authorize tags, add to list of all authorizations
+ if (localName.equals("authorize"))
+ return new AuthorizeTagHandler(user_mapping);
+
+ return null;
+
+ }
+
+ @Override
+ public void complete(String textContent) throws SAXException {
+ // Do nothing
+ }
+
+ /**
+ * Returns a user mapping containing all authorizations and configurations
+ * parsed so far. This user mapping will be backed by the data being parsed,
+ * thus any additional authorizations or configurations will be available
+ * in the object returned by this function even after this function has
+ * returned, once the data corresponding to those authorizations or
+ * configurations has been parsed.
+ *
+ * @return A user mapping containing all authorizations and configurations
+ * parsed so far.
+ */
+ public UserMapping asUserMapping() {
+ return user_mapping;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/auth/basic/package-info.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/auth/basic/package-info.java b/guacamole/src/main/java/org/apache/guacamole/auth/basic/package-info.java
new file mode 100644
index 0000000..d5f8fb7
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/auth/basic/package-info.java
@@ -0,0 +1,27 @@
+/*
+ * 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 parsing the user-mapping.xml file.
+ */
+package org.apache.guacamole.auth.basic;
+
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/auth/package-info.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/auth/package-info.java b/guacamole/src/main/java/org/apache/guacamole/auth/package-info.java
new file mode 100644
index 0000000..d1ac69e
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/auth/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 which drive the default, basic authentication of the Guacamole
+ * web application.
+ */
+package org.apache.guacamole.auth;
+
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/extension/AuthenticationProviderFacade.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/extension/AuthenticationProviderFacade.java b/guacamole/src/main/java/org/apache/guacamole/extension/AuthenticationProviderFacade.java
new file mode 100644
index 0000000..b244255
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/extension/AuthenticationProviderFacade.java
@@ -0,0 +1,203 @@
+/*
+ * 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.extension;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.UUID;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.net.auth.AuthenticatedUser;
+import org.apache.guacamole.net.auth.AuthenticationProvider;
+import org.apache.guacamole.net.auth.Credentials;
+import org.apache.guacamole.net.auth.UserContext;
+import org.apache.guacamole.net.auth.credentials.CredentialsInfo;
+import org.apache.guacamole.net.auth.credentials.GuacamoleInvalidCredentialsException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Provides a safe wrapper around an AuthenticationProvider subclass, such that
+ * authentication attempts can cleanly fail, and errors can be properly logged,
+ * even if the AuthenticationProvider cannot be instantiated.
+ *
+ * @author Michael Jumper
+ */
+public class AuthenticationProviderFacade implements AuthenticationProvider {
+
+ /**
+ * Logger for this class.
+ */
+ private Logger logger = LoggerFactory.getLogger(AuthenticationProviderFacade.class);
+
+ /**
+ * The underlying authentication provider, or null if the authentication
+ * provider could not be instantiated.
+ */
+ private final AuthenticationProvider authProvider;
+
+ /**
+ * The identifier to provide for the underlying authentication provider if
+ * the authentication provider could not be loaded.
+ */
+ private final String facadeIdentifier = UUID.randomUUID().toString();
+
+ /**
+ * Creates a new AuthenticationProviderFacade which delegates all function
+ * calls to an instance of the given AuthenticationProvider subclass. If
+ * an instance of the given class cannot be created, creation of this
+ * facade will still succeed, but its use will result in errors being
+ * logged, and all authentication attempts will fail.
+ *
+ * @param authProviderClass
+ * The AuthenticationProvider subclass to instantiate.
+ */
+ public AuthenticationProviderFacade(Class<? extends AuthenticationProvider> authProviderClass) {
+
+ AuthenticationProvider instance = null;
+
+ try {
+ // Attempt to instantiate the authentication provider
+ instance = authProviderClass.getConstructor().newInstance();
+ }
+ catch (NoSuchMethodException e) {
+ logger.error("The authentication extension in use is not properly defined. "
+ + "Please contact the developers of the extension or, if you "
+ + "are the developer, turn on debug-level logging.");
+ logger.debug("AuthenticationProvider is missing a default constructor.", e);
+ }
+ catch (SecurityException e) {
+ logger.error("The Java security mananager is preventing authentication extensions "
+ + "from being loaded. Please check the configuration of Java or your "
+ + "servlet container.");
+ logger.debug("Creation of AuthenticationProvider disallowed by security manager.", e);
+ }
+ catch (InstantiationException e) {
+ logger.error("The authentication extension in use is not properly defined. "
+ + "Please contact the developers of the extension or, if you "
+ + "are the developer, turn on debug-level logging.");
+ logger.debug("AuthenticationProvider cannot be instantiated.", e);
+ }
+ catch (IllegalAccessException e) {
+ logger.error("The authentication extension in use is not properly defined. "
+ + "Please contact the developers of the extension or, if you "
+ + "are the developer, turn on debug-level logging.");
+ logger.debug("Default constructor of AuthenticationProvider is not public.", e);
+ }
+ catch (IllegalArgumentException e) {
+ logger.error("The authentication extension in use is not properly defined. "
+ + "Please contact the developers of the extension or, if you "
+ + "are the developer, turn on debug-level logging.");
+ logger.debug("Default constructor of AuthenticationProvider cannot accept zero arguments.", e);
+ }
+ catch (InvocationTargetException e) {
+
+ // Obtain causing error - create relatively-informative stub error if cause is unknown
+ Throwable cause = e.getCause();
+ if (cause == null)
+ cause = new GuacamoleException("Error encountered during initialization.");
+
+ logger.error("Authentication extension failed to start: {}", cause.getMessage());
+ logger.debug("AuthenticationProvider instantiation failed.", e);
+
+ }
+
+ // Associate instance, if any
+ authProvider = instance;
+
+ }
+
+ @Override
+ public String getIdentifier() {
+
+ // Ignore auth attempts if no auth provider could be loaded
+ if (authProvider == null) {
+ logger.warn("The authentication system could not be loaded. Please check for errors earlier in the logs.");
+ return facadeIdentifier;
+ }
+
+ // Delegate to underlying auth provider
+ return authProvider.getIdentifier();
+
+ }
+
+ @Override
+ public AuthenticatedUser authenticateUser(Credentials credentials)
+ throws GuacamoleException {
+
+ // Ignore auth attempts if no auth provider could be loaded
+ if (authProvider == null) {
+ logger.warn("Authentication attempt denied because the authentication system could not be loaded. Please check for errors earlier in the logs.");
+ throw new GuacamoleInvalidCredentialsException("Permission denied.", CredentialsInfo.USERNAME_PASSWORD);
+ }
+
+ // Delegate to underlying auth provider
+ return authProvider.authenticateUser(credentials);
+
+ }
+
+ @Override
+ public AuthenticatedUser updateAuthenticatedUser(AuthenticatedUser authenticatedUser,
+ Credentials credentials) throws GuacamoleException {
+
+ // Ignore auth attempts if no auth provider could be loaded
+ if (authProvider == null) {
+ logger.warn("Reauthentication attempt denied because the authentication system could not be loaded. Please check for errors earlier in the logs.");
+ throw new GuacamoleInvalidCredentialsException("Permission denied.", CredentialsInfo.USERNAME_PASSWORD);
+ }
+
+ // Delegate to underlying auth provider
+ return authProvider.updateAuthenticatedUser(authenticatedUser, credentials);
+
+ }
+
+ @Override
+ public UserContext getUserContext(AuthenticatedUser authenticatedUser)
+ throws GuacamoleException {
+
+ // Ignore auth attempts if no auth provider could be loaded
+ if (authProvider == null) {
+ logger.warn("User data retrieval attempt denied because the authentication system could not be loaded. Please check for errors earlier in the logs.");
+ return null;
+ }
+
+ // Delegate to underlying auth provider
+ return authProvider.getUserContext(authenticatedUser);
+
+ }
+
+ @Override
+ public UserContext updateUserContext(UserContext context,
+ AuthenticatedUser authenticatedUser)
+ throws GuacamoleException {
+
+ // Ignore auth attempts if no auth provider could be loaded
+ if (authProvider == null) {
+ logger.warn("User data refresh attempt denied because the authentication system could not be loaded. Please check for errors earlier in the logs.");
+ return null;
+ }
+
+ // Delegate to underlying auth provider
+ return authProvider.updateUserContext(context, authenticatedUser);
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/extension/DirectoryClassLoader.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/extension/DirectoryClassLoader.java b/guacamole/src/main/java/org/apache/guacamole/extension/DirectoryClassLoader.java
new file mode 100644
index 0000000..1d1ac54
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/extension/DirectoryClassLoader.java
@@ -0,0 +1,154 @@
+/*
+ * 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.extension;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.ArrayList;
+import java.util.Collection;
+import org.apache.guacamole.GuacamoleException;
+
+/**
+ * A ClassLoader implementation which finds classes within .jar files within a
+ * given directory.
+ *
+ * @author Michael Jumper
+ */
+public class DirectoryClassLoader extends URLClassLoader {
+
+ /**
+ * Returns an instance of DirectoryClassLoader configured to load .jar
+ * files from the given directory. Calling this function multiple times
+ * will not affect previously-returned instances of DirectoryClassLoader.
+ *
+ * @param dir
+ * The directory from which .jar files should be read.
+ *
+ * @return
+ * A DirectoryClassLoader instance which loads classes from the .jar
+ * files in the given directory.
+ *
+ * @throws GuacamoleException
+ * If the given file is not a directory, or the contents of the given
+ * directory cannot be read.
+ */
+ public static DirectoryClassLoader getInstance(final File dir)
+ throws GuacamoleException {
+
+ try {
+ // Attempt to create singleton classloader which loads classes from
+ // all .jar's in the lib directory defined in guacamole.properties
+ return AccessController.doPrivileged(new PrivilegedExceptionAction<DirectoryClassLoader>() {
+
+ @Override
+ public DirectoryClassLoader run() throws GuacamoleException {
+ return new DirectoryClassLoader(dir);
+ }
+
+ });
+ }
+
+ catch (PrivilegedActionException e) {
+ throw (GuacamoleException) e.getException();
+ }
+
+ }
+
+ /**
+ * Returns all .jar files within the given directory as an array of URLs.
+ *
+ * @param dir
+ * The directory to retrieve all .jar files from.
+ *
+ * @return
+ * An array of the URLs of all .jar files within the given directory.
+ *
+ * @throws GuacamoleException
+ * If the given file is not a directory, or the contents of the given
+ * directory cannot be read.
+ */
+ private static URL[] getJarURLs(File dir) throws GuacamoleException {
+
+ // Validate directory is indeed a directory
+ if (!dir.isDirectory())
+ throw new GuacamoleException(dir + " is not a directory.");
+
+ // Get list of URLs for all .jar's in the lib directory
+ Collection<URL> jarURLs = new ArrayList<URL>();
+ File[] files = dir.listFiles(new FilenameFilter() {
+
+ @Override
+ public boolean accept(File dir, String name) {
+
+ // If it ends with .jar, accept the file
+ return name.endsWith(".jar");
+
+ }
+
+ });
+
+ // Verify directory was successfully read
+ if (files == null)
+ throw new GuacamoleException("Unable to read contents of directory " + dir);
+
+ // Add the URL for each .jar to the jar URL list
+ for (File file : files) {
+
+ try {
+ jarURLs.add(file.toURI().toURL());
+ }
+ catch (MalformedURLException e) {
+ throw new GuacamoleException(e);
+ }
+
+ }
+
+ // Set delegate classloader to new URLClassLoader which loads from the .jars found above.
+ URL[] urls = new URL[jarURLs.size()];
+ return jarURLs.toArray(urls);
+
+ }
+
+ /**
+ * Creates a new DirectoryClassLoader configured to load .jar files from
+ * the given directory.
+ *
+ * @param dir
+ * The directory from which .jar files should be read.
+ *
+ * @throws GuacamoleException
+ * If the given file is not a directory, or the contents of the given
+ * directory cannot be read.
+ */
+
+ private DirectoryClassLoader(File dir) throws GuacamoleException {
+ super(getJarURLs(dir), DirectoryClassLoader.class.getClassLoader());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/extension/Extension.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/extension/Extension.java b/guacamole/src/main/java/org/apache/guacamole/extension/Extension.java
new file mode 100644
index 0000000..7ac0563
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/extension/Extension.java
@@ -0,0 +1,515 @@
+/*
+ * 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.extension;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+import java.util.zip.ZipFile;
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.GuacamoleServerException;
+import org.apache.guacamole.net.auth.AuthenticationProvider;
+import org.apache.guacamole.resource.ClassPathResource;
+import org.apache.guacamole.resource.Resource;
+
+/**
+ * A Guacamole extension, which may provide custom authentication, static
+ * files, theming/branding, etc.
+ *
+ * @author Michael Jumper
+ */
+public class Extension {
+
+ /**
+ * The Jackson parser for parsing the language JSON files.
+ */
+ private static final ObjectMapper mapper = new ObjectMapper();
+
+ /**
+ * The name of the manifest file that describes the contents of a
+ * Guacamole extension.
+ */
+ private static final String MANIFEST_NAME = "guac-manifest.json";
+
+ /**
+ * The parsed manifest file of this extension, describing the location of
+ * resources within the extension.
+ */
+ private final ExtensionManifest manifest;
+
+ /**
+ * The classloader to use when reading resources from this extension,
+ * including classes and static files.
+ */
+ private final ClassLoader classLoader;
+
+ /**
+ * Map of all JavaScript resources defined within the extension, where each
+ * key is the path to that resource within the extension.
+ */
+ private final Map<String, Resource> javaScriptResources;
+
+ /**
+ * Map of all CSS resources defined within the extension, where each key is
+ * the path to that resource within the extension.
+ */
+ private final Map<String, Resource> cssResources;
+
+ /**
+ * Map of all HTML patch resources defined within the extension, where each
+ * key is the path to that resource within the extension.
+ */
+ private final Map<String, Resource> htmlResources;
+
+ /**
+ * Map of all translation resources defined within the extension, where
+ * each key is the path to that resource within the extension.
+ */
+ private final Map<String, Resource> translationResources;
+
+ /**
+ * Map of all resources defined within the extension which are not already
+ * associated as JavaScript, CSS, or translation resources, where each key
+ * is the path to that resource within the extension.
+ */
+ private final Map<String, Resource> staticResources;
+
+ /**
+ * The collection of all AuthenticationProvider classes defined within the
+ * extension.
+ */
+ private final Collection<Class<AuthenticationProvider>> authenticationProviderClasses;
+
+ /**
+ * The resource for the small favicon for the extension. If provided, this
+ * will replace the default Guacamole icon.
+ */
+ private final Resource smallIcon;
+
+ /**
+ * The resource foe the large favicon for the extension. If provided, this
+ * will replace the default Guacamole icon.
+ */
+ private final Resource largeIcon;
+
+ /**
+ * Returns a new map of all resources corresponding to the collection of
+ * paths provided. Each resource will be associated with the given
+ * mimetype, and stored in the map using its path as the key.
+ *
+ * @param mimetype
+ * The mimetype to associate with each resource.
+ *
+ * @param paths
+ * The paths corresponding to the resources desired.
+ *
+ * @return
+ * A new, unmodifiable map of resources corresponding to the
+ * collection of paths provided, where the key of each entry in the
+ * map is the path for the resource stored in that entry.
+ */
+ private Map<String, Resource> getClassPathResources(String mimetype, Collection<String> paths) {
+
+ // If no paths are provided, just return an empty map
+ if (paths == null)
+ return Collections.<String, Resource>emptyMap();
+
+ // Add classpath resource for each path provided
+ Map<String, Resource> resources = new HashMap<String, Resource>(paths.size());
+ for (String path : paths)
+ resources.put(path, new ClassPathResource(classLoader, mimetype, path));
+
+ // Callers should not rely on modifying the result
+ return Collections.unmodifiableMap(resources);
+
+ }
+
+ /**
+ * Returns a new map of all resources corresponding to the map of resource
+ * paths provided. Each resource will be associated with the mimetype
+ * stored in the given map using its path as the key.
+ *
+ * @param resourceTypes
+ * A map of all paths to their corresponding mimetypes.
+ *
+ * @return
+ * A new, unmodifiable map of resources corresponding to the
+ * collection of paths provided, where the key of each entry in the
+ * map is the path for the resource stored in that entry.
+ */
+ private Map<String, Resource> getClassPathResources(Map<String, String> resourceTypes) {
+
+ // If no paths are provided, just return an empty map
+ if (resourceTypes == null)
+ return Collections.<String, Resource>emptyMap();
+
+ // Add classpath resource for each path/mimetype pair provided
+ Map<String, Resource> resources = new HashMap<String, Resource>(resourceTypes.size());
+ for (Map.Entry<String, String> resource : resourceTypes.entrySet()) {
+
+ // Get path and mimetype from entry
+ String path = resource.getKey();
+ String mimetype = resource.getValue();
+
+ // Store as path/resource pair
+ resources.put(path, new ClassPathResource(classLoader, mimetype, path));
+
+ }
+
+ // Callers should not rely on modifying the result
+ return Collections.unmodifiableMap(resources);
+
+ }
+
+ /**
+ * Retrieve the AuthenticationProvider subclass having the given name. If
+ * the class having the given name does not exist or isn't actually a
+ * subclass of AuthenticationProvider, an exception will be thrown.
+ *
+ * @param name
+ * The name of the AuthenticationProvider class to retrieve.
+ *
+ * @return
+ * The subclass of AuthenticationProvider having the given name.
+ *
+ * @throws GuacamoleException
+ * If no such class exists, or if the class with the given name is not
+ * a subclass of AuthenticationProvider.
+ */
+ @SuppressWarnings("unchecked") // We check this ourselves with isAssignableFrom()
+ private Class<AuthenticationProvider> getAuthenticationProviderClass(String name)
+ throws GuacamoleException {
+
+ try {
+
+ // Get authentication provider class
+ Class<?> authenticationProviderClass = classLoader.loadClass(name);
+
+ // Verify the located class is actually a subclass of AuthenticationProvider
+ if (!AuthenticationProvider.class.isAssignableFrom(authenticationProviderClass))
+ throw new GuacamoleServerException("Authentication providers MUST extend the AuthenticationProvider class.");
+
+ // Return located class
+ return (Class<AuthenticationProvider>) authenticationProviderClass;
+
+ }
+ catch (ClassNotFoundException e) {
+ throw new GuacamoleException("Authentication provider class not found.", e);
+ }
+
+ }
+
+ /**
+ * Returns a new collection of all AuthenticationProvider subclasses having
+ * the given names. If any class does not exist or isn't actually a
+ * subclass of AuthenticationProvider, an exception will be thrown, and
+ * no further AuthenticationProvider classes will be loaded.
+ *
+ * @param names
+ * The names of the AuthenticationProvider classes to retrieve.
+ *
+ * @return
+ * A new collection of all AuthenticationProvider subclasses having the
+ * given names.
+ *
+ * @throws GuacamoleException
+ * If any given class does not exist, or if any given class is not a
+ * subclass of AuthenticationProvider.
+ */
+ private Collection<Class<AuthenticationProvider>> getAuthenticationProviderClasses(Collection<String> names)
+ throws GuacamoleException {
+
+ // If no classnames are provided, just return an empty list
+ if (names == null)
+ return Collections.<Class<AuthenticationProvider>>emptyList();
+
+ // Define all auth provider classes
+ Collection<Class<AuthenticationProvider>> classes = new ArrayList<Class<AuthenticationProvider>>(names.size());
+ for (String name : names)
+ classes.add(getAuthenticationProviderClass(name));
+
+ // Callers should not rely on modifying the result
+ return Collections.unmodifiableCollection(classes);
+
+ }
+
+ /**
+ * Loads the given file as an extension, which must be a .jar containing
+ * a guac-manifest.json file describing its contents.
+ *
+ * @param parent
+ * The classloader to use as the parent for the isolated classloader of
+ * this extension.
+ *
+ * @param file
+ * The file to load as an extension.
+ *
+ * @throws GuacamoleException
+ * If the provided file is not a .jar file, does not contain the
+ * guac-manifest.json, or if guac-manifest.json is invalid and cannot
+ * be parsed.
+ */
+ public Extension(final ClassLoader parent, final File file) throws GuacamoleException {
+
+ try {
+
+ // Open extension
+ ZipFile extension = new ZipFile(file);
+
+ try {
+
+ // Retrieve extension manifest
+ ZipEntry manifestEntry = extension.getEntry(MANIFEST_NAME);
+ if (manifestEntry == null)
+ throw new GuacamoleServerException("Extension " + file.getName() + " is missing " + MANIFEST_NAME);
+
+ // Parse manifest
+ manifest = mapper.readValue(extension.getInputStream(manifestEntry), ExtensionManifest.class);
+ if (manifest == null)
+ throw new GuacamoleServerException("Contents of " + MANIFEST_NAME + " must be a valid JSON object.");
+
+ }
+
+ // Always close zip file, if possible
+ finally {
+ extension.close();
+ }
+
+ try {
+
+ // Create isolated classloader for this extension
+ classLoader = AccessController.doPrivileged(new PrivilegedExceptionAction<ClassLoader>() {
+
+ @Override
+ public ClassLoader run() throws GuacamoleException {
+
+ try {
+
+ // Classloader must contain only the extension itself
+ return new URLClassLoader(new URL[]{file.toURI().toURL()}, parent);
+
+ }
+ catch (MalformedURLException e) {
+ throw new GuacamoleException(e);
+ }
+
+ }
+
+ });
+
+ }
+
+ // Rethrow any GuacamoleException
+ catch (PrivilegedActionException e) {
+ throw (GuacamoleException) e.getException();
+ }
+
+ }
+
+ // Abort load if not a valid zip file
+ catch (ZipException e) {
+ throw new GuacamoleServerException("Extension is not a valid zip file: " + file.getName(), e);
+ }
+
+ // Abort if manifest cannot be parsed (invalid JSON)
+ catch (JsonParseException e) {
+ throw new GuacamoleServerException(MANIFEST_NAME + " is not valid JSON: " + file.getName(), e);
+ }
+
+ // Abort if zip file cannot be read at all due to I/O errors
+ catch (IOException e) {
+ throw new GuacamoleServerException("Unable to read extension: " + file.getName(), e);
+ }
+
+ // Define static resources
+ cssResources = getClassPathResources("text/css", manifest.getCSSPaths());
+ javaScriptResources = getClassPathResources("text/javascript", manifest.getJavaScriptPaths());
+ htmlResources = getClassPathResources("text/html", manifest.getHTMLPaths());
+ translationResources = getClassPathResources("application/json", manifest.getTranslationPaths());
+ staticResources = getClassPathResources(manifest.getResourceTypes());
+
+ // Define authentication providers
+ authenticationProviderClasses = getAuthenticationProviderClasses(manifest.getAuthProviders());
+
+ // Get small icon resource if provided
+ if (manifest.getSmallIcon() != null)
+ smallIcon = new ClassPathResource(classLoader, "image/png", manifest.getSmallIcon());
+ else
+ smallIcon = null;
+
+ // Get large icon resource if provided
+ if (manifest.getLargeIcon() != null)
+ largeIcon = new ClassPathResource(classLoader, "image/png", manifest.getLargeIcon());
+ else
+ largeIcon = null;
+ }
+
+ /**
+ * Returns the version of the Guacamole web application for which this
+ * extension was built.
+ *
+ * @return
+ * The version of the Guacamole web application for which this
+ * extension was built.
+ */
+ public String getGuacamoleVersion() {
+ return manifest.getGuacamoleVersion();
+ }
+
+ /**
+ * Returns the name of this extension, as declared in the extension's
+ * manifest.
+ *
+ * @return
+ * The name of this extension.
+ */
+ public String getName() {
+ return manifest.getName();
+ }
+
+ /**
+ * Returns the namespace of this extension, as declared in the extension's
+ * manifest.
+ *
+ * @return
+ * The namespace of this extension.
+ */
+ public String getNamespace() {
+ return manifest.getNamespace();
+ }
+
+ /**
+ * Returns a map of all declared JavaScript resources associated with this
+ * extension, where the key of each entry in the map is the path to that
+ * resource within the extension .jar. JavaScript resources are declared
+ * within the extension manifest.
+ *
+ * @return
+ * All declared JavaScript resources associated with this extension.
+ */
+ public Map<String, Resource> getJavaScriptResources() {
+ return javaScriptResources;
+ }
+
+ /**
+ * Returns a map of all declared CSS resources associated with this
+ * extension, where the key of each entry in the map is the path to that
+ * resource within the extension .jar. CSS resources are declared within
+ * the extension manifest.
+ *
+ * @return
+ * All declared CSS resources associated with this extension.
+ */
+ public Map<String, Resource> getCSSResources() {
+ return cssResources;
+ }
+
+ /**
+ * Returns a map of all declared HTML patch resources associated with this
+ * extension, where the key of each entry in the map is the path to that
+ * resource within the extension .jar. HTML patch resources are declared
+ * within the extension manifest.
+ *
+ * @return
+ * All declared HTML patch resources associated with this extension.
+ */
+ public Map<String, Resource> getHTMLResources() {
+ return htmlResources;
+ }
+
+ /**
+ * Returns a map of all declared translation resources associated with this
+ * extension, where the key of each entry in the map is the path to that
+ * resource within the extension .jar. Translation resources are declared
+ * within the extension manifest.
+ *
+ * @return
+ * All declared translation resources associated with this extension.
+ */
+ public Map<String, Resource> getTranslationResources() {
+ return translationResources;
+ }
+
+ /**
+ * Returns a map of all declared resources associated with this extension,
+ * where these resources are not already associated as JavaScript, CSS, or
+ * translation resources. The key of each entry in the map is the path to
+ * that resource within the extension .jar. Static resources are declared
+ * within the extension manifest.
+ *
+ * @return
+ * All declared static resources associated with this extension.
+ */
+ public Map<String, Resource> getStaticResources() {
+ return staticResources;
+ }
+
+ /**
+ * Returns all declared authentication providers classes associated with
+ * this extension. Authentication providers are declared within the
+ * extension manifest.
+ *
+ * @return
+ * All declared authentication provider classes with this extension.
+ */
+ public Collection<Class<AuthenticationProvider>> getAuthenticationProviderClasses() {
+ return authenticationProviderClasses;
+ }
+
+ /**
+ * Returns the resource for the small favicon for the extension. If
+ * provided, this will replace the default Guacamole icon.
+ *
+ * @return
+ * The resource for the small favicon.
+ */
+ public Resource getSmallIcon() {
+ return smallIcon;
+ }
+
+ /**
+ * Returns the resource for the large favicon for the extension. If
+ * provided, this will replace the default Guacamole icon.
+ *
+ * @return
+ * The resource for the large favicon.
+ */
+ public Resource getLargeIcon() {
+ return largeIcon;
+ }
+
+}