diff --git a/extensions/guacamole-auth-ldap/pom.xml b/extensions/guacamole-auth-ldap/pom.xml
index f12905ec1..d5175be8e 100644
--- a/extensions/guacamole-auth-ldap/pom.xml
+++ b/extensions/guacamole-auth-ldap/pom.xml
@@ -102,6 +102,18 @@
4.3
+
+
+ com.google.inject
+ guice
+ 3.0
+
+
+ com.google.inject.extensions
+ guice-multibindings
+ 3.0
+
+
diff --git a/extensions/guacamole-auth-ldap/src/main/java/net/sourceforge/guacamole/net/auth/ldap/LDAPAuthenticationProvider.java b/extensions/guacamole-auth-ldap/src/main/java/net/sourceforge/guacamole/net/auth/ldap/LDAPAuthenticationProvider.java
index 9a25b94a2..945bcd9bd 100644
--- a/extensions/guacamole-auth-ldap/src/main/java/net/sourceforge/guacamole/net/auth/ldap/LDAPAuthenticationProvider.java
+++ b/extensions/guacamole-auth-ldap/src/main/java/net/sourceforge/guacamole/net/auth/ldap/LDAPAuthenticationProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Glyptodon LLC
+ * 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
@@ -23,25 +23,15 @@
package net.sourceforge.guacamole.net.auth.ldap;
-import com.novell.ldap.LDAPAttribute;
-import com.novell.ldap.LDAPConnection;
-import com.novell.ldap.LDAPEntry;
-import com.novell.ldap.LDAPException;
-import com.novell.ldap.LDAPSearchResults;
-import java.io.UnsupportedEncodingException;
-import java.util.Enumeration;
-import java.util.Map;
-import java.util.TreeMap;
+import org.glyptodon.guacamole.auth.ldap.AuthenticationProviderService;
+import org.glyptodon.guacamole.auth.ldap.LDAPAuthenticationProviderModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
import org.glyptodon.guacamole.GuacamoleException;
+import org.glyptodon.guacamole.net.auth.AuthenticatedUser;
+import org.glyptodon.guacamole.net.auth.AuthenticationProvider;
import org.glyptodon.guacamole.net.auth.Credentials;
-import net.sourceforge.guacamole.net.auth.ldap.properties.LDAPGuacamoleProperties;
-import org.glyptodon.guacamole.GuacamoleServerException;
-import org.glyptodon.guacamole.environment.Environment;
-import org.glyptodon.guacamole.environment.LocalEnvironment;
-import org.glyptodon.guacamole.net.auth.simple.SimpleAuthenticationProvider;
-import org.glyptodon.guacamole.protocol.GuacamoleConfiguration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.glyptodon.guacamole.net.auth.UserContext;
/**
* Allows users to be authenticated against an LDAP server. Each user may have
@@ -50,17 +40,13 @@ import org.slf4j.LoggerFactory;
*
* @author Michael Jumper
*/
-public class LDAPAuthenticationProvider extends SimpleAuthenticationProvider {
+public class LDAPAuthenticationProvider implements AuthenticationProvider {
/**
- * Logger for this class.
+ * Injector which will manage the object graph of this authentication
+ * provider.
*/
- private Logger logger = LoggerFactory.getLogger(LDAPAuthenticationProvider.class);
-
- /**
- * Guacamole server environment.
- */
- private final Environment environment;
+ private final Injector injector;
/**
* Creates a new LDAPAuthenticationProvider that authenticates users
@@ -71,7 +57,12 @@ public class LDAPAuthenticationProvider extends SimpleAuthenticationProvider {
* a property.
*/
public LDAPAuthenticationProvider() throws GuacamoleException {
- environment = new LocalEnvironment();
+
+ // Set up Guice injector.
+ injector = Guice.createInjector(
+ new LDAPAuthenticationProviderModule(this)
+ );
+
}
@Override
@@ -79,219 +70,33 @@ public class LDAPAuthenticationProvider extends SimpleAuthenticationProvider {
return "ldap";
}
- // Courtesy of OWASP: https://www.owasp.org/index.php/Preventing_LDAP_Injection_in_Java
- private static String escapeLDAPSearchFilter(String filter) {
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < filter.length(); i++) {
- char curChar = filter.charAt(i);
- switch (curChar) {
- case '\\':
- sb.append("\\5c");
- break;
- case '*':
- sb.append("\\2a");
- break;
- case '(':
- sb.append("\\28");
- break;
- case ')':
- sb.append("\\29");
- break;
- case '\u0000':
- sb.append("\\00");
- break;
- default:
- sb.append(curChar);
- }
- }
- return sb.toString();
+ @Override
+ public AuthenticatedUser authenticateUser(Credentials credentials) throws GuacamoleException {
+
+ AuthenticationProviderService authProviderService = injector.getInstance(AuthenticationProviderService.class);
+ return authProviderService.authenticateUser(credentials);
+
}
- // Courtesy of OWASP: https://www.owasp.org/index.php/Preventing_LDAP_Injection_in_Java
- private static String escapeDN(String name) {
- StringBuilder sb = new StringBuilder();
- if ((name.length() > 0) && ((name.charAt(0) == ' ') || (name.charAt(0) == '#'))) {
- sb.append('\\'); // add the leading backslash if needed
- }
- for (int i = 0; i < name.length(); i++) {
- char curChar = name.charAt(i);
- switch (curChar) {
- case '\\':
- sb.append("\\\\");
- break;
- case ',':
- sb.append("\\,");
- break;
- case '+':
- sb.append("\\+");
- break;
- case '"':
- sb.append("\\\"");
- break;
- case '<':
- sb.append("\\<");
- break;
- case '>':
- sb.append("\\>");
- break;
- case ';':
- sb.append("\\;");
- break;
- default:
- sb.append(curChar);
- }
- }
- if ((name.length() > 1) && (name.charAt(name.length() - 1) == ' ')) {
- sb.insert(sb.length() - 1, '\\'); // add the trailing backslash if needed
- }
- return sb.toString();
- }
+ @Override
+ public AuthenticatedUser updateAuthenticatedUser(AuthenticatedUser authenticatedUser,
+ Credentials credentials) throws GuacamoleException {
+ return authenticatedUser;
+ }
@Override
- public Map getAuthorizedConfigurations(Credentials credentials) throws GuacamoleException {
+ public UserContext getUserContext(AuthenticatedUser authenticatedUser)
+ throws GuacamoleException {
- // Require username
- if (credentials.getUsername() == null) {
- logger.debug("Anonymous bind is not currently allowed by the LDAP authentication provider.");
- return null;
- }
+ AuthenticationProviderService authProviderService = injector.getInstance(AuthenticationProviderService.class);
+ return authProviderService.getUserContext(authenticatedUser);
- // Require password, and do not allow anonymous binding
- if (credentials.getPassword() == null
- || credentials.getPassword().length() == 0) {
- logger.debug("Anonymous bind is not currently allowed by the LDAP authentication provider.");
- return null;
- }
-
- // Connect to LDAP server
- LDAPConnection ldapConnection;
- try {
-
- ldapConnection = new LDAPConnection();
- ldapConnection.connect(
- environment.getRequiredProperty(LDAPGuacamoleProperties.LDAP_HOSTNAME),
- environment.getRequiredProperty(LDAPGuacamoleProperties.LDAP_PORT)
- );
-
- }
- catch (LDAPException e) {
- throw new GuacamoleServerException("Unable to connect to LDAP server.", e);
- }
-
- // Get username attribute
- String username_attribute = environment.getRequiredProperty(
- LDAPGuacamoleProperties.LDAP_USERNAME_ATTRIBUTE
- );
-
- // Get user base DN
- String user_base_dn = environment.getRequiredProperty(
- LDAPGuacamoleProperties.LDAP_USER_BASE_DN
- );
-
- // Construct user DN
- String user_dn =
- escapeDN(username_attribute) + "=" + escapeDN(credentials.getUsername())
- + "," + user_base_dn;
-
- try {
-
- // Bind as user
- try {
- ldapConnection.bind(
- LDAPConnection.LDAP_V3,
- user_dn,
- credentials.getPassword().getBytes("UTF-8")
- );
- }
- catch (UnsupportedEncodingException e) {
- throw new GuacamoleException(e);
- }
-
- }
- catch (LDAPException e) {
- logger.debug("LDAP bind failed.", e);
- return null;
- }
-
- // Get config base DN
- String config_base_dn = environment.getRequiredProperty(
- LDAPGuacamoleProperties.LDAP_CONFIG_BASE_DN
- );
-
- // Pull all connections
- try {
-
- // Find all guac configs for this user
- LDAPSearchResults results = ldapConnection.search(
- config_base_dn,
- LDAPConnection.SCOPE_SUB,
- "(&(objectClass=guacConfigGroup)(member=" + escapeLDAPSearchFilter(user_dn) + "))",
- null,
- false
- );
-
- // Add all configs
- Map configs = new TreeMap();
- while (results.hasMore()) {
-
- LDAPEntry entry = results.next();
-
- // New empty configuration
- GuacamoleConfiguration config = new GuacamoleConfiguration();
-
- // Get CN
- LDAPAttribute cn = entry.getAttribute("cn");
- if (cn == null)
- throw new GuacamoleException("guacConfigGroup without cn");
-
- // Get protocol
- LDAPAttribute protocol = entry.getAttribute("guacConfigProtocol");
- if (protocol == null)
- throw new GuacamoleException("guacConfigGroup without guacConfigProtocol");
-
- // Set protocol
- config.setProtocol(protocol.getStringValue());
-
- // Get parameters, if any
- LDAPAttribute parameterAttribute = entry.getAttribute("guacConfigParameter");
- if (parameterAttribute != null) {
-
- // For each parameter
- Enumeration> parameters = parameterAttribute.getStringValues();
- while (parameters.hasMoreElements()) {
-
- String parameter = (String) parameters.nextElement();
-
- // Parse parameter
- int equals = parameter.indexOf('=');
- if (equals != -1) {
-
- // Parse name
- String name = parameter.substring(0, equals);
- String value = parameter.substring(equals+1);
-
- config.setParameter(name, value);
-
- }
-
- }
-
- }
-
- // Store config by CN
- configs.put(cn.getStringValue(), config);
-
- }
-
- // Disconnect
- ldapConnection.disconnect();
- return configs;
-
- }
- catch (LDAPException e) {
- throw new GuacamoleServerException("Error while querying for connections.", e);
- }
+ }
+ @Override
+ public UserContext updateUserContext(UserContext context,
+ AuthenticatedUser authenticatedUser) throws GuacamoleException {
+ return context;
}
}
diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/AuthenticationProviderService.java b/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/AuthenticationProviderService.java
new file mode 100644
index 000000000..8702c7ea8
--- /dev/null
+++ b/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/AuthenticationProviderService.java
@@ -0,0 +1,245 @@
+/*
+ * 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.glyptodon.guacamole.auth.ldap;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import com.novell.ldap.LDAPConnection;
+import com.novell.ldap.LDAPException;
+import java.io.UnsupportedEncodingException;
+import org.glyptodon.guacamole.auth.ldap.user.AuthenticatedUser;
+import org.glyptodon.guacamole.auth.ldap.user.UserContext;
+import org.glyptodon.guacamole.GuacamoleException;
+import org.glyptodon.guacamole.net.auth.Credentials;
+import org.glyptodon.guacamole.net.auth.credentials.CredentialsInfo;
+import org.glyptodon.guacamole.net.auth.credentials.GuacamoleInsufficientCredentialsException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Service providing convenience functions for the LDAP AuthenticationProvider
+ * implementation.
+ *
+ * @author Michael Jumper
+ */
+public class AuthenticationProviderService {
+
+ /**
+ * Logger for this class.
+ */
+ private final Logger logger = LoggerFactory.getLogger(AuthenticationProviderService.class);
+
+ /**
+ * Service for escaping parts of LDAP queries.
+ */
+ @Inject
+ private EscapingService escapingService;
+
+ /**
+ * Service for retrieving LDAP server configuration information.
+ */
+ @Inject
+ private ConfigurationService confService;
+
+ /**
+ * Provider for AuthenticatedUser objects.
+ */
+ @Inject
+ private Provider authenticatedUserProvider;
+
+ /**
+ * Provider for UserContext objects.
+ */
+ @Inject
+ private Provider userContextProvider;
+
+ /**
+ * Binds to the LDAP server using the provided Guacamole credentials. The
+ * DN of the user is derived using the LDAP configuration properties
+ * provided in guacamole.properties, as is the server hostname and port
+ * information.
+ *
+ * @param credentials
+ * The credentials to use to bind to the LDAP server.
+ *
+ * @return
+ * A bound LDAP connection, or null if the connection could not be
+ * bound.
+ *
+ * @throws GuacamoleException
+ * If an error occurs while binding to the LDAP server.
+ */
+ private LDAPConnection bindAs(Credentials credentials)
+ throws GuacamoleException {
+
+ LDAPConnection ldapConnection;
+
+ // Require username
+ if (credentials.getUsername() == null) {
+ logger.debug("Anonymous bind is not currently allowed by the LDAP authentication provider.");
+ return null;
+ }
+
+ // Require password, and do not allow anonymous binding
+ if (credentials.getPassword() == null
+ || credentials.getPassword().length() == 0) {
+ logger.debug("Anonymous bind is not currently allowed by the LDAP authentication provider.");
+ return null;
+ }
+
+ // Connect to LDAP server
+ try {
+ ldapConnection = new LDAPConnection();
+ ldapConnection.connect(
+ confService.getServerHostname(),
+ confService.getServerPort()
+ );
+ }
+ catch (LDAPException e) {
+ logger.error("Unable to connect to LDAP server: {}", e.getMessage());
+ logger.debug("Failed to connect to LDAP server.", e);
+ return null;
+ }
+
+ // Bind using provided credentials
+ try {
+
+ // Construct user DN
+ String userDN =
+ escapingService.escapeDN(confService.getUsernameAttribute())
+ + "=" + escapingService.escapeDN(credentials.getUsername())
+ + "," + confService.getUserBaseDN();
+
+ // Bind as user
+ try {
+ ldapConnection.bind(LDAPConnection.LDAP_V3, userDN,
+ credentials.getPassword().getBytes("UTF-8"));
+ }
+ catch (UnsupportedEncodingException e) {
+ logger.error("Unexpected lack of support for UTF-8: {}", e.getMessage());
+ logger.debug("Support for UTF-8 (as required by Java spec) not found.", e);
+ return null;
+ }
+
+ // Disconnect if an error occurs during bind
+ catch (LDAPException e) {
+ ldapConnection.disconnect();
+ throw e;
+ }
+
+ }
+ catch (LDAPException e) {
+ logger.debug("LDAP bind failed.", e);
+ return null;
+ }
+
+ return ldapConnection;
+
+ }
+
+ public AuthenticatedUser authenticateUser(Credentials credentials)
+ throws GuacamoleException {
+
+ // Attempt bind
+ LDAPConnection ldapConnection = bindAs(credentials);
+ if (ldapConnection == null)
+ throw new GuacamoleInsufficientCredentialsException("Permission denied.", CredentialsInfo.USERNAME_PASSWORD);
+
+ try {
+
+ // Return AuthenticatedUser if bind succeeds
+ AuthenticatedUser authenticatedUser = authenticatedUserProvider.get();
+ authenticatedUser.init(credentials);
+ return authenticatedUser;
+
+ }
+
+ // Always disconnect
+ finally {
+
+ // Attempt disconnect
+ try {
+ ldapConnection.disconnect();
+ }
+
+ // Warn if disconnect unexpectedly fails
+ catch (LDAPException e) {
+ logger.warn("Unable to disconnect from LDAP server: {}", e.getMessage());
+ logger.debug("LDAP disconnect failed.", e);
+ }
+
+ }
+
+ }
+
+ /**
+ * Returns a UserContext object initialized with data accessible to the
+ * given AuthenticatedUser.
+ *
+ * @param authenticatedUser
+ * The AuthenticatedUser to retrieve data for.
+ *
+ * @return
+ * A UserContext object initialized with data accessible to the given
+ * AuthenticatedUser.
+ *
+ * @throws GuacamoleException
+ * If the UserContext cannot be created due to an error.
+ */
+ public UserContext getUserContext(org.glyptodon.guacamole.net.auth.AuthenticatedUser authenticatedUser)
+ throws GuacamoleException {
+
+ // Bind using credentials associated with AuthenticatedUser
+ Credentials credentials = authenticatedUser.getCredentials();
+ LDAPConnection ldapConnection = bindAs(credentials);
+ if (ldapConnection == null)
+ return null;
+
+ try {
+
+ // Build user context by querying LDAP
+ UserContext userContext = userContextProvider.get();
+ userContext.init(authenticatedUser, ldapConnection);
+ return userContext;
+
+ }
+
+ // Always disconnect
+ finally {
+
+ // Attempt disconnect
+ try {
+ ldapConnection.disconnect();
+ }
+
+ // Warn if disconnect unexpectedly fails
+ catch (LDAPException e) {
+ logger.warn("Unable to disconnect from LDAP server: {}", e.getMessage());
+ logger.debug("LDAP disconnect failed.", e);
+ }
+
+ }
+
+ }
+
+}
diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/ConfigurationService.java b/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/ConfigurationService.java
new file mode 100644
index 000000000..692300499
--- /dev/null
+++ b/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/ConfigurationService.java
@@ -0,0 +1,134 @@
+/*
+ * 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.glyptodon.guacamole.auth.ldap;
+
+import com.google.inject.Inject;
+import org.glyptodon.guacamole.GuacamoleException;
+import org.glyptodon.guacamole.environment.Environment;
+
+/**
+ * Service for retrieving configuration information regarding the LDAP server.
+ *
+ * @author Michael Jumper
+ */
+public class ConfigurationService {
+
+ /**
+ * The Guacamole server environment.
+ */
+ @Inject
+ private Environment environment;
+
+ /**
+ * Returns the hostname of the LDAP server as configured with
+ * guacamole.properties. By default, this will be "localhost".
+ *
+ * @return
+ * The hostname of the LDAP server, as configured with
+ * guacamole.properties.
+ *
+ * @throws GuacamoleException
+ * If guacamole.properties cannot be parsed.
+ */
+ public String getServerHostname() throws GuacamoleException {
+ return environment.getProperty(
+ LDAPGuacamoleProperties.LDAP_HOSTNAME,
+ "localhost"
+ );
+ }
+
+ /**
+ * Returns the port of the LDAP server configured with
+ * guacamole.properties. By default, this will be 389 - the standard LDAP
+ * port.
+ *
+ * @return
+ * The port of the LDAP server, as configured with
+ * guacamole.properties.
+ *
+ * @throws GuacamoleException
+ * If guacamole.properties cannot be parsed.
+ */
+ public int getServerPort() throws GuacamoleException {
+ return environment.getProperty(
+ LDAPGuacamoleProperties.LDAP_PORT,
+ 389
+ );
+ }
+
+ /**
+ * Returns the username attribute which should be used to query and bind
+ * users using the LDAP directory. By default, this will be "uid" - a
+ * common attribute used for this purpose.
+ *
+ * @return
+ * The username attribute which should be used to query and bind users
+ * using the LDAP directory.
+ *
+ * @throws GuacamoleException
+ * If guacamole.properties cannot be parsed.
+ */
+ public String getUsernameAttribute() throws GuacamoleException {
+ return environment.getProperty(
+ LDAPGuacamoleProperties.LDAP_USERNAME_ATTRIBUTE,
+ "uid"
+ );
+ }
+
+ /**
+ * Returns the base DN under which all Guacamole users will be stored
+ * within the LDAP directory.
+ *
+ * @return
+ * The base DN under which all Guacamole users will be stored within
+ * the LDAP directory.
+ *
+ * @throws GuacamoleException
+ * If guacamole.properties cannot be parsed, or if the user base DN
+ * property is not specified.
+ */
+ public String getUserBaseDN() throws GuacamoleException {
+ return environment.getRequiredProperty(
+ LDAPGuacamoleProperties.LDAP_USER_BASE_DN
+ );
+ }
+
+ /**
+ * Returns the base DN under which all Guacamole configurations
+ * (connections) will be stored within the LDAP directory.
+ *
+ * @return
+ * The base DN under which all Guacamole configurations will be stored
+ * within the LDAP directory.
+ *
+ * @throws GuacamoleException
+ * If guacamole.properties cannot be parsed, or if the configuration
+ * base DN property is not specified.
+ */
+ public String getConfigurationBaseDN() throws GuacamoleException {
+ return environment.getRequiredProperty(
+ LDAPGuacamoleProperties.LDAP_CONFIG_BASE_DN
+ );
+ }
+
+}
diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/EscapingService.java b/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/EscapingService.java
new file mode 100644
index 000000000..925ba24cf
--- /dev/null
+++ b/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/EscapingService.java
@@ -0,0 +1,125 @@
+/*
+ * 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.glyptodon.guacamole.auth.ldap;
+
+/**
+ * Service for escaping LDAP filters, distinguished names (DN's), etc.
+ *
+ * @author Michael Jumper
+ */
+public class EscapingService {
+
+ /**
+ * Escapes the given string for use within an LDAP search filter. This
+ * implementation is provided courtesy of OWASP:
+ *
+ * https://www.owasp.org/index.php/Preventing_LDAP_Injection_in_Java
+ *
+ * @param filter
+ * The string to escape such that it has no special meaning within an
+ * LDAP search filter.
+ *
+ * @return
+ * The escaped string, safe for use within an LDAP search filter.
+ */
+ public String escapeLDAPSearchFilter(String filter) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < filter.length(); i++) {
+ char curChar = filter.charAt(i);
+ switch (curChar) {
+ case '\\':
+ sb.append("\\5c");
+ break;
+ case '*':
+ sb.append("\\2a");
+ break;
+ case '(':
+ sb.append("\\28");
+ break;
+ case ')':
+ sb.append("\\29");
+ break;
+ case '\u0000':
+ sb.append("\\00");
+ break;
+ default:
+ sb.append(curChar);
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Escapes the given string such that it is safe for use within an LDAP
+ * distinguished name (DN). This implementation is provided courtesy of
+ * OWASP:
+ *
+ * https://www.owasp.org/index.php/Preventing_LDAP_Injection_in_Java
+ *
+ * @param name
+ * The string to escape such that it has no special meaning within an
+ * LDAP DN.
+ *
+ * @return
+ * The escaped string, safe for use within an LDAP DN.
+ */
+ public String escapeDN(String name) {
+ StringBuilder sb = new StringBuilder();
+ if ((name.length() > 0) && ((name.charAt(0) == ' ') || (name.charAt(0) == '#'))) {
+ sb.append('\\'); // add the leading backslash if needed
+ }
+ for (int i = 0; i < name.length(); i++) {
+ char curChar = name.charAt(i);
+ switch (curChar) {
+ case '\\':
+ sb.append("\\\\");
+ break;
+ case ',':
+ sb.append("\\,");
+ break;
+ case '+':
+ sb.append("\\+");
+ break;
+ case '"':
+ sb.append("\\\"");
+ break;
+ case '<':
+ sb.append("\\<");
+ break;
+ case '>':
+ sb.append("\\>");
+ break;
+ case ';':
+ sb.append("\\;");
+ break;
+ default:
+ sb.append(curChar);
+ }
+ }
+ if ((name.length() > 1) && (name.charAt(name.length() - 1) == ' ')) {
+ sb.insert(sb.length() - 1, '\\'); // add the trailing backslash if needed
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/LDAPAuthenticationProviderModule.java b/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/LDAPAuthenticationProviderModule.java
new file mode 100644
index 000000000..4dbc1eddc
--- /dev/null
+++ b/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/LDAPAuthenticationProviderModule.java
@@ -0,0 +1,88 @@
+/*
+ * 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.glyptodon.guacamole.auth.ldap;
+
+import com.google.inject.AbstractModule;
+import org.glyptodon.guacamole.auth.ldap.connection.ConnectionService;
+import org.glyptodon.guacamole.auth.ldap.user.UserService;
+import org.glyptodon.guacamole.GuacamoleException;
+import org.glyptodon.guacamole.environment.Environment;
+import org.glyptodon.guacamole.environment.LocalEnvironment;
+import org.glyptodon.guacamole.net.auth.AuthenticationProvider;
+
+/**
+ * Guice module which configures LDAP-specific injections.
+ *
+ * @author Michael Jumper
+ */
+public class LDAPAuthenticationProviderModule extends AbstractModule {
+
+ /**
+ * Guacamole server environment.
+ */
+ private final Environment environment;
+
+ /**
+ * A reference to the LDAPAuthenticationProvider on behalf of which this
+ * module has configured injection.
+ */
+ private final AuthenticationProvider authProvider;
+
+ /**
+ * Creates a new LDAP authentication provider module which configures
+ * injection for the LDAPAuthenticationProvider.
+ *
+ * @param authProvider
+ * The AuthenticationProvider for which injection is being configured.
+ *
+ * @throws GuacamoleException
+ * If an error occurs while retrieving the Guacamole server
+ * environment.
+ */
+ public LDAPAuthenticationProviderModule(AuthenticationProvider authProvider)
+ throws GuacamoleException {
+
+ // Get local environment
+ this.environment = new LocalEnvironment();
+
+ // Store associated auth provider
+ this.authProvider = authProvider;
+
+ }
+
+ @Override
+ protected void configure() {
+
+ // Bind core implementations of guacamole-ext classes
+ bind(AuthenticationProvider.class).toInstance(authProvider);
+ bind(Environment.class).toInstance(environment);
+
+ // Bind LDAP-specific services
+ bind(ConfigurationService.class);
+ bind(ConnectionService.class);
+ bind(EscapingService.class);
+ bind(UserService.class);
+
+ }
+
+}
diff --git a/extensions/guacamole-auth-ldap/src/main/java/net/sourceforge/guacamole/net/auth/ldap/properties/LDAPGuacamoleProperties.java b/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/LDAPGuacamoleProperties.java
similarity index 98%
rename from extensions/guacamole-auth-ldap/src/main/java/net/sourceforge/guacamole/net/auth/ldap/properties/LDAPGuacamoleProperties.java
rename to extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/LDAPGuacamoleProperties.java
index e97c01a1e..8fabf816e 100644
--- a/extensions/guacamole-auth-ldap/src/main/java/net/sourceforge/guacamole/net/auth/ldap/properties/LDAPGuacamoleProperties.java
+++ b/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/LDAPGuacamoleProperties.java
@@ -20,7 +20,7 @@
* THE SOFTWARE.
*/
-package net.sourceforge.guacamole.net.auth.ldap.properties;
+package org.glyptodon.guacamole.auth.ldap;
import org.glyptodon.guacamole.properties.IntegerGuacamoleProperty;
import org.glyptodon.guacamole.properties.StringGuacamoleProperty;
diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/connection/ConnectionService.java b/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/connection/ConnectionService.java
new file mode 100644
index 000000000..71a5afc52
--- /dev/null
+++ b/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/connection/ConnectionService.java
@@ -0,0 +1,170 @@
+/*
+ * 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.glyptodon.guacamole.auth.ldap.connection;
+
+import com.google.inject.Inject;
+import com.novell.ldap.LDAPAttribute;
+import com.novell.ldap.LDAPConnection;
+import com.novell.ldap.LDAPEntry;
+import com.novell.ldap.LDAPException;
+import com.novell.ldap.LDAPSearchResults;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import org.glyptodon.guacamole.auth.ldap.ConfigurationService;
+import org.glyptodon.guacamole.auth.ldap.EscapingService;
+import org.glyptodon.guacamole.GuacamoleException;
+import org.glyptodon.guacamole.GuacamoleServerException;
+import org.glyptodon.guacamole.net.auth.Connection;
+import org.glyptodon.guacamole.net.auth.simple.SimpleConnection;
+import org.glyptodon.guacamole.protocol.GuacamoleConfiguration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Service for querying the connections available to a particular Guacamole
+ * user according to an LDAP directory.
+ *
+ * @author Michael Jumper
+ */
+public class ConnectionService {
+
+ /**
+ * Logger for this class.
+ */
+ private final Logger logger = LoggerFactory.getLogger(ConnectionService.class);
+
+ /**
+ * Service for escaping parts of LDAP queries.
+ */
+ @Inject
+ private EscapingService escapingService;
+
+ /**
+ * Service for retrieving LDAP server configuration information.
+ */
+ @Inject
+ private ConfigurationService confService;
+
+ /**
+ * Returns all Guacamole connections accessible to the user currently bound
+ * under the given LDAP connection.
+ *
+ * @param ldapConnection
+ * The current connection to the LDAP server, associated with the
+ * current user.
+ *
+ * @return
+ * All connections accessible to the user currently bound under the
+ * given LDAP connection, as a map of connection identifier to
+ * corresponding connection object.
+ *
+ * @throws GuacamoleException
+ * If an error occurs preventing retrieval of connections.
+ */
+ public Map getConnections(LDAPConnection ldapConnection)
+ throws GuacamoleException {
+
+ try {
+
+ // Pull the current user DN from the LDAP connection
+ String userDN = ldapConnection.getAuthenticationDN();
+
+ // Find all Guacamole connections for the given user
+ LDAPSearchResults results = ldapConnection.search(
+ confService.getConfigurationBaseDN(),
+ LDAPConnection.SCOPE_SUB,
+ "(&(objectClass=guacConfigGroup)(member=" + escapingService.escapeLDAPSearchFilter(userDN) + "))",
+ null,
+ false
+ );
+
+ // Produce connections for each readable configuration
+ Map connections = new HashMap();
+ while (results.hasMore()) {
+
+ LDAPEntry entry = results.next();
+
+ // Get common name (CN)
+ LDAPAttribute cn = entry.getAttribute("cn");
+ if (cn == null) {
+ logger.warn("guacConfigGroup is missing a cn.");
+ continue;
+ }
+
+ // Get associated protocol
+ LDAPAttribute protocol = entry.getAttribute("guacConfigProtocol");
+ if (protocol == null) {
+ logger.warn("guacConfigGroup \"{}\" is missing the "
+ + "required \"guacConfigProtocol\" attribute.",
+ cn.getStringValue());
+ continue;
+ }
+
+ // Set protocol
+ GuacamoleConfiguration config = new GuacamoleConfiguration();
+ config.setProtocol(protocol.getStringValue());
+
+ // Get parameters, if any
+ LDAPAttribute parameterAttribute = entry.getAttribute("guacConfigParameter");
+ if (parameterAttribute != null) {
+
+ // For each parameter
+ Enumeration> parameters = parameterAttribute.getStringValues();
+ while (parameters.hasMoreElements()) {
+
+ String parameter = (String) parameters.nextElement();
+
+ // Parse parameter
+ int equals = parameter.indexOf('=');
+ if (equals != -1) {
+
+ // Parse name
+ String name = parameter.substring(0, equals);
+ String value = parameter.substring(equals+1);
+
+ config.setParameter(name, value);
+
+ }
+
+ }
+
+ }
+
+ // Store connection using cn for both identifier and name
+ String name = cn.getStringValue();
+ connections.put(name, new SimpleConnection(name, name, config));
+
+ }
+
+ // Return map of all connections
+ return connections;
+
+ }
+ catch (LDAPException e) {
+ throw new GuacamoleServerException("Error while querying for connections.", e);
+ }
+
+ }
+
+}
diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/user/AuthenticatedUser.java b/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/user/AuthenticatedUser.java
new file mode 100644
index 000000000..e594193ec
--- /dev/null
+++ b/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/user/AuthenticatedUser.java
@@ -0,0 +1,71 @@
+/*
+ * 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.glyptodon.guacamole.auth.ldap.user;
+
+import com.google.inject.Inject;
+import org.glyptodon.guacamole.net.auth.AbstractAuthenticatedUser;
+import org.glyptodon.guacamole.net.auth.AuthenticationProvider;
+import org.glyptodon.guacamole.net.auth.Credentials;
+
+/**
+ * An LDAP-specific implementation of AuthenticatedUser, associating a
+ * particular set of credentials with the LDAP authentication provider.
+ *
+ * @author Michael Jumper
+ */
+public class AuthenticatedUser extends AbstractAuthenticatedUser {
+
+ /**
+ * Reference to the authentication provider associated with this
+ * authenticated user.
+ */
+ @Inject
+ private AuthenticationProvider authProvider;
+
+ /**
+ * The credentials provided when this user was authenticated.
+ */
+ private Credentials credentials;
+
+ /**
+ * Initializes this AuthenticatedUser using the given credentials.
+ *
+ * @param credentials
+ * The credentials provided when this user was authenticated.
+ */
+ public void init(Credentials credentials) {
+ this.credentials = credentials;
+ setIdentifier(credentials.getUsername());
+ }
+
+ @Override
+ public AuthenticationProvider getAuthenticationProvider() {
+ return authProvider;
+ }
+
+ @Override
+ public Credentials getCredentials() {
+ return credentials;
+ }
+
+}
diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/user/UserContext.java b/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/user/UserContext.java
new file mode 100644
index 000000000..930e8b42d
--- /dev/null
+++ b/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/user/UserContext.java
@@ -0,0 +1,215 @@
+/*
+ * 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.glyptodon.guacamole.auth.ldap.user;
+
+import com.google.inject.Inject;
+import com.novell.ldap.LDAPConnection;
+import java.util.Collection;
+import java.util.Collections;
+import org.glyptodon.guacamole.auth.ldap.connection.ConnectionService;
+import org.glyptodon.guacamole.GuacamoleException;
+import org.glyptodon.guacamole.form.Form;
+import org.glyptodon.guacamole.net.auth.ActiveConnection;
+import org.glyptodon.guacamole.net.auth.AuthenticatedUser;
+import org.glyptodon.guacamole.net.auth.AuthenticationProvider;
+import org.glyptodon.guacamole.net.auth.Connection;
+import org.glyptodon.guacamole.net.auth.ConnectionGroup;
+import org.glyptodon.guacamole.net.auth.Directory;
+import org.glyptodon.guacamole.net.auth.User;
+import org.glyptodon.guacamole.net.auth.simple.SimpleConnectionGroup;
+import org.glyptodon.guacamole.net.auth.simple.SimpleConnectionGroupDirectory;
+import org.glyptodon.guacamole.net.auth.simple.SimpleDirectory;
+import org.glyptodon.guacamole.net.auth.simple.SimpleUser;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * An LDAP-specific implementation of UserContext which queries all Guacamole
+ * connections and users from the LDAP directory.
+ *
+ * @author Michael Jumper
+ */
+public class UserContext implements org.glyptodon.guacamole.net.auth.UserContext {
+
+ /**
+ * Logger for this class.
+ */
+ private final Logger logger = LoggerFactory.getLogger(UserContext.class);
+
+ /**
+ * The identifier reserved for the root connection group.
+ */
+ private static final String ROOT_CONNECTION_GROUP = "ROOT";
+
+ /**
+ * Service for retrieving Guacamole connections from the LDAP server.
+ */
+ @Inject
+ private ConnectionService connectionService;
+
+ /**
+ * Service for retrieving Guacamole users from the LDAP server.
+ */
+ @Inject
+ private UserService userService;
+
+ /**
+ * Reference to the AuthenticationProvider associated with this
+ * UserContext.
+ */
+ @Inject
+ private AuthenticationProvider authProvider;
+
+ /**
+ * Reference to a User object representing the user whose access level
+ * dictates the users and connections visible through this UserContext.
+ */
+ private User self;
+
+ /**
+ * Directory containing all User objects accessible to the user associated
+ * with this UserContext.
+ */
+ private Directory userDirectory;
+
+ /**
+ * Directory containing all Connection objects accessible to the user
+ * associated with this UserContext.
+ */
+ private Directory connectionDirectory;
+
+ /**
+ * Directory containing all ConnectionGroup objects accessible to the user
+ * associated with this UserContext.
+ */
+ private Directory connectionGroupDirectory;
+
+ /**
+ * Reference to the root connection group.
+ */
+ private ConnectionGroup rootGroup;
+
+ /**
+ * Initializes this UserContext using the provided AuthenticatedUser and
+ * LDAPConnection.
+ *
+ * @param user
+ * The AuthenticatedUser representing the user that authenticated. This
+ * user may have been authenticated by a different authentication
+ * provider (not LDAP).
+ *
+ * @param ldapConnection
+ * The connection to the LDAP server to use when querying accessible
+ * Guacamole users and connections.
+ *
+ * @throws GuacamoleException
+ * If associated data stored within the LDAP directory cannot be
+ * queried due to an error.
+ */
+ public void init(AuthenticatedUser user, LDAPConnection ldapConnection)
+ throws GuacamoleException {
+
+ // Query all accessible users
+ userDirectory = new SimpleDirectory(
+ userService.getUsers(ldapConnection)
+ );
+
+ // Query all accessible connections
+ connectionDirectory = new SimpleDirectory(
+ connectionService.getConnections(ldapConnection)
+ );
+
+ // Root group contains only connections
+ rootGroup = new SimpleConnectionGroup(
+ ROOT_CONNECTION_GROUP, ROOT_CONNECTION_GROUP,
+ connectionDirectory.getIdentifiers(),
+ Collections.emptyList()
+ );
+
+ // Expose only the root group in the connection group directory
+ connectionGroupDirectory = new SimpleConnectionGroupDirectory(Collections.singleton(rootGroup));
+
+ // Init self with basic permissions
+ self = new SimpleUser(
+ user.getIdentifier(),
+ userDirectory.getIdentifiers(),
+ connectionDirectory.getIdentifiers(),
+ connectionGroupDirectory.getIdentifiers()
+ );
+
+ }
+
+ @Override
+ public User self() {
+ return self;
+ }
+
+ @Override
+ public AuthenticationProvider getAuthenticationProvider() {
+ return authProvider;
+ }
+
+ @Override
+ public Directory getUserDirectory() throws GuacamoleException {
+ return userDirectory;
+ }
+
+ @Override
+ public Directory getConnectionDirectory()
+ throws GuacamoleException {
+ return connectionDirectory;
+ }
+
+ @Override
+ public Directory getConnectionGroupDirectory()
+ throws GuacamoleException {
+ return connectionGroupDirectory;
+ }
+
+ @Override
+ public ConnectionGroup getRootConnectionGroup() throws GuacamoleException {
+ return rootGroup;
+ }
+
+ @Override
+ public Directory getActiveConnectionDirectory()
+ throws GuacamoleException {
+ return new SimpleDirectory();
+ }
+
+ @Override
+ public Collection