diff --git a/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/auth/Authorization.java b/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/auth/Authorization.java
new file mode 100644
index 000000000..c04a5d644
--- /dev/null
+++ b/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/auth/Authorization.java
@@ -0,0 +1,247 @@
+package net.sourceforge.guacamole.net.basic.auth;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Map;
+import java.util.TreeMap;
+import net.sourceforge.guacamole.protocol.GuacamoleConfiguration;
+
+/*
+ * Guacamole - Clientless Remote Desktop
+ * Copyright (C) 2010 Michael Jumper
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+/**
+ * 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 configs = new
+ TreeMap();
+
+ /**
+ * 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()));
+ return hashedPassword.equals(this.password.toUpperCase());
+ }
+ 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 getConfigurations() {
+ return configs;
+ }
+
+}
diff --git a/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/auth/UserMapping.java b/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/auth/UserMapping.java
new file mode 100644
index 000000000..fca8e2e8c
--- /dev/null
+++ b/guacamole/src/main/java/net/sourceforge/guacamole/net/basic/auth/UserMapping.java
@@ -0,0 +1,59 @@
+package net.sourceforge.guacamole.net.basic.auth;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/*
+ * Guacamole - Clientless Remote Desktop
+ * Copyright (C) 2010 Michael Jumper
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+
+/**
+ * Mapping of all usernames to corresponding authorizations.
+ *
+ * @author Mike Jumper
+ */
+public class UserMapping {
+
+ /**
+ * All authorizations, indexed by username.
+ */
+ private Map authorizations =
+ new HashMap();
+
+ /**
+ * 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);
+ }
+
+}