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 index 541906986..d10095bd2 100644 --- 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 @@ -25,8 +25,6 @@ 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 java.util.List; import org.glyptodon.guacamole.auth.ldap.user.AuthenticatedUser; import org.glyptodon.guacamole.auth.ldap.user.UserContext; @@ -51,6 +49,12 @@ public class AuthenticationProviderService { */ private final Logger logger = LoggerFactory.getLogger(AuthenticationProviderService.class); + /** + * Service for creating and managing connections to LDAP servers. + */ + @Inject + private LDAPConnectionService ldapService; + /** * Service for retrieving LDAP server configuration information. */ @@ -75,28 +79,6 @@ public class AuthenticationProviderService { @Inject private Provider userContextProvider; - /** - * Disconnects the given LDAP connection, logging any failure to do so - * appropriately. - * - * @param ldapConnection - * The LDAP connection to disconnect. - */ - private void disconnect(LDAPConnection ldapConnection) { - - // 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); - } - - } - /** * Determines the DN which corresponds to the user having the given * username. The DN will either be derived directly from the user base DN, @@ -122,7 +104,7 @@ public class AuthenticationProviderService { if (searchBindDN != null) { // Create an LDAP connection using the search account - LDAPConnection searchConnection = bindAs( + LDAPConnection searchConnection = ldapService.bindAs( searchBindDN, confService.getSearchBindPassword() ); @@ -147,7 +129,7 @@ public class AuthenticationProviderService { // Always disconnect finally { - disconnect(searchConnection); + ldapService.disconnect(searchConnection); } } @@ -157,78 +139,6 @@ public class AuthenticationProviderService { } - /** - * Binds to the LDAP server using the provided user DN and password. - * - * @param userDN - * The DN of the user to bind as, or null to bind anonymously. - * - * @param password - * The password to use when binding as the specified user, or null to - * attempt to bind without a password. - * - * @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(String userDN, String password) - throws GuacamoleException { - - LDAPConnection ldapConnection; - - // 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 { - - byte[] passwordBytes; - try { - - // Convert password into corresponding byte array - if (password != null) - passwordBytes = password.getBytes("UTF-8"); - else - passwordBytes = null; - - } - 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); - disconnect(ldapConnection); - return null; - } - - // Bind as user - ldapConnection.bind(LDAPConnection.LDAP_V3, userDN, passwordBytes); - - } - - // Disconnect if an error occurs during bind - catch (LDAPException e) { - logger.debug("LDAP bind failed.", e); - disconnect(ldapConnection); - return null; - } - - return ldapConnection; - - } - /** * Binds to the LDAP server using the provided Guacamole credentials. The * DN of the user is derived using the LDAP configuration properties @@ -272,7 +182,7 @@ public class AuthenticationProviderService { } // Bind using user's DN - return bindAs(userDN, password); + return ldapService.bindAs(userDN, password); } @@ -320,7 +230,7 @@ public class AuthenticationProviderService { // Always disconnect finally { - disconnect(ldapConnection); + ldapService.disconnect(ldapConnection); } } @@ -359,7 +269,7 @@ public class AuthenticationProviderService { // Always disconnect finally { - disconnect(ldapConnection); + ldapService.disconnect(ldapConnection); } } 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 index 4dbc1eddc..c0133baea 100644 --- 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 @@ -81,6 +81,7 @@ public class LDAPAuthenticationProviderModule extends AbstractModule { bind(ConfigurationService.class); bind(ConnectionService.class); bind(EscapingService.class); + bind(LDAPConnectionService.class); bind(UserService.class); } diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/LDAPConnectionService.java b/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/LDAPConnectionService.java new file mode 100644 index 000000000..cc0140a86 --- /dev/null +++ b/extensions/guacamole-auth-ldap/src/main/java/org/glyptodon/guacamole/auth/ldap/LDAPConnectionService.java @@ -0,0 +1,145 @@ +/* + * 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.novell.ldap.LDAPConnection; +import com.novell.ldap.LDAPException; +import java.io.UnsupportedEncodingException; +import org.glyptodon.guacamole.GuacamoleException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Service for creating and managing connections to LDAP servers. + * + * @author Michael Jumper + */ +public class LDAPConnectionService { + + /** + * Logger for this class. + */ + private final Logger logger = LoggerFactory.getLogger(LDAPConnectionService.class); + + /** + * Service for retrieving LDAP server configuration information. + */ + @Inject + private ConfigurationService confService; + + /** + * Binds to the LDAP server using the provided user DN and password. + * + * @param userDN + * The DN of the user to bind as, or null to bind anonymously. + * + * @param password + * The password to use when binding as the specified user, or null to + * attempt to bind without a password. + * + * @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. + */ + public LDAPConnection bindAs(String userDN, String password) + throws GuacamoleException { + + LDAPConnection ldapConnection; + + // 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 { + + byte[] passwordBytes; + try { + + // Convert password into corresponding byte array + if (password != null) + passwordBytes = password.getBytes("UTF-8"); + else + passwordBytes = null; + + } + 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); + disconnect(ldapConnection); + return null; + } + + // Bind as user + ldapConnection.bind(LDAPConnection.LDAP_V3, userDN, passwordBytes); + + } + + // Disconnect if an error occurs during bind + catch (LDAPException e) { + logger.debug("LDAP bind failed.", e); + disconnect(ldapConnection); + return null; + } + + return ldapConnection; + + } + + /** + * Disconnects the given LDAP connection, logging any failure to do so + * appropriately. + * + * @param ldapConnection + * The LDAP connection to disconnect. + */ + public void disconnect(LDAPConnection ldapConnection) { + + // 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); + } + + } + +}