diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/AuthenticationProviderService.java b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/AuthenticationProviderService.java index 856a536e0..42afdf510 100644 --- a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/AuthenticationProviderService.java +++ b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/AuthenticationProviderService.java @@ -168,6 +168,74 @@ public class AuthenticationProviderService { } + /** + * Returns a new ConnectedLDAPConfiguration that is connected to an LDAP + * server associated with the user having the given username and bound + * using the provided password. All LDAP servers associated with the given + * user are tried until the connection and authentication attempt succeeds. + * If no LDAP servers are available, or no LDAP servers are associated with + * the given user, null is returned. + * + * @param username + * The username or DN of the user to bind as. + * + * @param password + * The password of the user to bind as. + * + * @return + * A new ConnectedLDAPConfiguration which is bound to an LDAP server + * using the provided credentials, or null if no LDAP servers are + * available for the given user or connecting/authenticating has + * failed. + * + * @throws GuacamoleException + * If configuration information for the user's LDAP server(s) cannot + * be retrieved. + */ + private ConnectedLDAPConfiguration getLDAPConfiguration(String username, + String password) throws GuacamoleException { + + // Get relevant LDAP configurations for user + Collection configs = confService.getLDAPConfigurations(username); + if (configs.isEmpty()) { + logger.info("User \"{}\" does not map to any defined LDAP configurations.", username); + return null; + } + + // Try each possible LDAP configuration until the TCP connection and + // authentication are successful + for (LDAPConfiguration config : configs) { + + // Derive DN of user within this LDAP server + Dn bindDn = getUserBindDN(config, username); + if (bindDn == null || bindDn.isEmpty()) { + logger.info("Unable to determine DN of user \"{}\" using LDAP " + + "server \"{}\". Proceeding with next server...", + username, config.getServerHostname()); + continue; + } + + // Attempt bind (authentication) + LdapNetworkConnection ldapConnection = ldapService.bindAs(config, bindDn.getName(), password); + if (ldapConnection == null) { + logger.info("Unable to bind as user \"{}\" against LDAP " + + "server \"{}\". Proceeding with next server...", + username, config.getServerHostname()); + continue; + } + + // Connection and bind were successful + logger.info("User \"{}\" was successfully authenticated by LDAP server \"{}\".", username, config.getServerHostname()); + return new ConnectedLDAPConfiguration(config, bindDn, ldapConnection); + + } + + // No LDAP connection/authentication attempt succeeded + logger.info("User \"{}\" did not successfully authenticate against any LDAP server.", username); + return null; + + } + /** * Returns an AuthenticatedUser representing the user authenticated by the * given credentials. Also adds custom LDAP attributes to the @@ -200,46 +268,29 @@ public class AuthenticationProviderService { + " authentication provider.", CredentialsInfo.USERNAME_PASSWORD); } - // Get relevant LDAP configuration for user - LDAPConfiguration config = confService.getLDAPConfiguration(username); - if (config == null) { - throw new GuacamoleInvalidCredentialsException("User \"" + username + "\" " - + "does not map to any defined LDAP configuration.", CredentialsInfo.USERNAME_PASSWORD); - } - - Dn bindDn = getUserBindDN(config, username); - if (bindDn == null || bindDn.isEmpty()) { - throw new GuacamoleInvalidCredentialsException("Unable to determine" - + " DN of user " + username, CredentialsInfo.USERNAME_PASSWORD); - } - - // Attempt bind - LdapNetworkConnection ldapConnection = - ldapService.bindAs(config, bindDn.getName(), password); - if (ldapConnection == null) + ConnectedLDAPConfiguration config = getLDAPConfiguration(username, password); + if (config == null) throw new GuacamoleInvalidCredentialsException("Invalid login.", CredentialsInfo.USERNAME_PASSWORD); try { - + // Retrieve group membership of the user that just authenticated Set effectiveGroups = - userGroupService.getParentUserGroupIdentifiers(config, - ldapConnection, bindDn); + userGroupService.getParentUserGroupIdentifiers(config, config.getBindDN()); // Return AuthenticatedUser if bind succeeds LDAPAuthenticatedUser authenticatedUser = authenticatedUserProvider.get(); authenticatedUser.init(config, credentials, - getAttributeTokens(config, ldapConnection, bindDn), - effectiveGroups, bindDn); + getAttributeTokens(config), effectiveGroups); return authenticatedUser; } - // Always disconnect - finally { - ldapConnection.close(); + catch (GuacamoleException | RuntimeException | Error e) { + config.close(); + throw e; } } @@ -254,12 +305,6 @@ public class AuthenticationProviderService { * @param config * The configuration of the LDAP server being queried. * - * @param ldapConnection - * LDAP connection to use to read the attributes of the user. - * - * @param username - * The username of the user whose attributes are to be queried. - * * @return * A map of parameter tokens generated from attributes on the user * currently bound under the given LDAP connection, as a map of token @@ -269,8 +314,8 @@ public class AuthenticationProviderService { * @throws GuacamoleException * If an error occurs retrieving the user DN or the attributes. */ - private Map getAttributeTokens(LDAPConfiguration config, - LdapNetworkConnection ldapConnection, Dn userDn) throws GuacamoleException { + private Map getAttributeTokens(ConnectedLDAPConfiguration config) + throws GuacamoleException { // Get attributes from configuration information List attrList = config.getAttributes(); @@ -286,7 +331,7 @@ public class AuthenticationProviderService { try { // Get LDAP attributes by querying LDAP - Entry userEntry = ldapConnection.lookup(userDn, attrArray); + Entry userEntry = config.getLDAPConnection().lookup(config.getBindDN(), attrArray); if (userEntry == null) return Collections.emptyMap(); @@ -326,37 +371,26 @@ public class AuthenticationProviderService { public LDAPUserContext getUserContext(AuthenticatedUser authenticatedUser) throws GuacamoleException { - // Bind using credentials associated with AuthenticatedUser - Credentials credentials = authenticatedUser.getCredentials(); if (authenticatedUser instanceof LDAPAuthenticatedUser) { LDAPAuthenticatedUser ldapAuthenticatedUser = (LDAPAuthenticatedUser) authenticatedUser; - LDAPConfiguration config = ldapAuthenticatedUser.getLDAPConfiguration(); - Dn bindDn = ldapAuthenticatedUser.getBindDn(); - - LdapNetworkConnection ldapConnection = ldapService.bindAs(config, bindDn.getName(), credentials.getPassword()); - if (ldapConnection == null) { - logger.debug("LDAP bind succeeded for \"{}\" during " - + "authentication but failed during data retrieval.", - authenticatedUser.getIdentifier()); - throw new GuacamoleInvalidCredentialsException("Invalid login.", - CredentialsInfo.USERNAME_PASSWORD); - } + ConnectedLDAPConfiguration config = ldapAuthenticatedUser.getLDAPConfiguration(); try { // Build user context by querying LDAP LDAPUserContext userContext = userContextProvider.get(); - userContext.init(ldapAuthenticatedUser, ldapConnection); + userContext.init(ldapAuthenticatedUser); return userContext; } // Always disconnect finally { - ldapConnection.close(); + config.close(); } } + return null; } diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/ConnectedLDAPConfiguration.java b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/ConnectedLDAPConfiguration.java new file mode 100644 index 000000000..f4a875e6e --- /dev/null +++ b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/ConnectedLDAPConfiguration.java @@ -0,0 +1,210 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.guacamole.auth.ldap; + +import java.util.List; +import org.apache.directory.api.ldap.model.filter.ExprNode; +import org.apache.directory.api.ldap.model.message.AliasDerefMode; +import org.apache.directory.api.ldap.model.name.Dn; +import org.apache.directory.ldap.client.api.LdapNetworkConnection; +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.auth.ldap.conf.EncryptionMethod; +import org.apache.guacamole.auth.ldap.conf.LDAPConfiguration; +import org.apache.guacamole.auth.ldap.conf.MemberAttributeType; + +/** + * LDAPConfiguration implementation that is associated with an + * LdapNetworkConnection to the configured LDAP server. + */ +public class ConnectedLDAPConfiguration implements LDAPConfiguration, AutoCloseable { + + /** + * The wrapped LDAPConfiguration. + */ + private final LDAPConfiguration config; + + /** + * The connection to the LDAP server represented by this configuration. + */ + private final LdapNetworkConnection connection; + + /** + * The LDAP DN that was used to bind with the LDAP server to produce + * {@link #connection}. + */ + private final Dn bindDn; + + /** + * Creates a new ConnectedLDAPConfiguration that associates the given + * LdapNetworkConnection with the given LDAPConfiguration. All functions + * inherited from the LDAPConfiguration interface are delegated to the + * given LDAPConfiguration. It is the responsibility of the caller to + * ensure the provided LdapNetworkConnection is closed after it is no + * longer needed. + * + * @param config + * The LDAPConfiguration to wrap. + * + * @param bindDn + * The LDAP DN that was used to bind with the LDAP server to produce + * the given LdapNetworkConnection. + * + * @param connection + * The connection to the LDAP server represented by the given + * configuration. + */ + public ConnectedLDAPConfiguration(LDAPConfiguration config, Dn bindDn, LdapNetworkConnection connection) { + this.config = config; + this.bindDn = bindDn; + this.connection = connection; + } + + /** + * Returns the LdapNetworkConnection for the connection to the LDAP server + * represented by this configuration. The lifecycle of this connection is + * managed externally. The connection is not guaranteed to still be + * connected. + * + * @return + * The LdapNetworkConnection for the connection to the LDAP server + * represented by this configuration. + */ + public LdapNetworkConnection getLDAPConnection() { + return connection; + } + + /** + * Returns the LDAP DN that was used to bind with the LDAP server to + * produce the LdapNetworkConnection associated with this + * ConnectedLDAPConfiguration. + * + * @return + * The LDAP DN that was used to bind with the LDAP server. + */ + public Dn getBindDN() { + return bindDn; + } + + @Override + public void close() { + connection.close(); + } + + @Override + public String getServerHostname() throws GuacamoleException { + return config.getServerHostname(); + } + + @Override + public int getServerPort() throws GuacamoleException { + return config.getServerPort(); + } + + @Override + public List getUsernameAttributes() throws GuacamoleException { + return config.getUsernameAttributes(); + } + + @Override + public Dn getUserBaseDN() throws GuacamoleException { + return config.getUserBaseDN(); + } + + @Override + public Dn getConfigurationBaseDN() throws GuacamoleException { + return config.getConfigurationBaseDN(); + } + + @Override + public List getGroupNameAttributes() throws GuacamoleException { + return config.getGroupNameAttributes(); + } + + @Override + public Dn getGroupBaseDN() throws GuacamoleException { + return config.getGroupBaseDN(); + } + + @Override + public String getSearchBindDN() throws GuacamoleException { + return config.getSearchBindDN(); + } + + @Override + public String getSearchBindPassword() throws GuacamoleException { + return config.getSearchBindPassword(); + } + + @Override + public EncryptionMethod getEncryptionMethod() throws GuacamoleException { + return config.getEncryptionMethod(); + } + + @Override + public int getMaxResults() throws GuacamoleException { + return config.getMaxResults(); + } + + @Override + public AliasDerefMode getDereferenceAliases() throws GuacamoleException { + return config.getDereferenceAliases(); + } + + @Override + public boolean getFollowReferrals() throws GuacamoleException { + return config.getFollowReferrals(); + } + + @Override + public int getMaxReferralHops() throws GuacamoleException { + return config.getMaxReferralHops(); + } + + @Override + public ExprNode getUserSearchFilter() throws GuacamoleException { + return config.getUserSearchFilter(); + } + + @Override + public ExprNode getGroupSearchFilter() throws GuacamoleException { + return config.getGroupSearchFilter(); + } + + @Override + public int getOperationTimeout() throws GuacamoleException { + return config.getOperationTimeout(); + } + + @Override + public List getAttributes() throws GuacamoleException { + return config.getAttributes(); + } + + @Override + public String getMemberAttribute() throws GuacamoleException { + return config.getMemberAttribute(); + } + + @Override + public MemberAttributeType getMemberAttributeType() throws GuacamoleException { + return config.getMemberAttributeType(); + } + +} diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/ConfigurationService.java b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/ConfigurationService.java index 80d98cd22..d84ac47ea 100644 --- a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/ConfigurationService.java +++ b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/conf/ConfigurationService.java @@ -20,11 +20,13 @@ package org.apache.guacamole.auth.ldap.conf; import com.google.inject.Inject; +import java.util.Collection; +import java.util.Collections; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.environment.Environment; /** - * Service for retrieving configuration information regarding the LDAP server. + * Service for retrieving configuration information regarding LDAP servers. */ public class ConfigurationService { @@ -35,24 +37,25 @@ public class ConfigurationService { private Environment environment; /** - * Returns the configuration information for the LDAP server related to the - * user having the given username. If no such LDAP server is defined, null - * is returned. + * Returns the configuration information for the LDAP servers related to + * the user having the given username, if any. If multiple servers are + * returned, each should be tried in order until a successful LDAP + * connection is established. * * @param username * The username of the user whose corresponding LDAP server * configuration should be retrieved. * * @return - * The configuration of the LDAP server related to the user having the - * given username, or null if no such LDAP server is defined. + * The configurations of the LDAP servers related to the user having + * the given username. * * @throws GuacamoleException - * If the configuration information of the LDAP server related to the + * If the configuration information of the LDAP servers related to the * user having the given username cannot be retrieved due to an error. */ - public LDAPConfiguration getLDAPConfiguration(String username) throws GuacamoleException { - return new EnvironmentLDAPConfiguration(environment); + public Collection getLDAPConfigurations(String username) throws GuacamoleException { + return Collections.singletonList(new EnvironmentLDAPConfiguration(environment)); } } diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/connection/ConnectionService.java b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/connection/ConnectionService.java index bff49858c..9da1547ba 100644 --- a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/connection/ConnectionService.java +++ b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/connection/ConnectionService.java @@ -35,13 +35,11 @@ import org.apache.directory.api.ldap.model.filter.EqualityNode; import org.apache.directory.api.ldap.model.filter.ExprNode; import org.apache.directory.api.ldap.model.filter.OrNode; import org.apache.directory.api.ldap.model.name.Dn; -import org.apache.directory.ldap.client.api.LdapConnectionConfig; -import org.apache.directory.ldap.client.api.LdapNetworkConnection; import org.apache.guacamole.auth.ldap.LDAPAuthenticationProvider; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleServerException; +import org.apache.guacamole.auth.ldap.ConnectedLDAPConfiguration; import org.apache.guacamole.auth.ldap.ObjectQueryService; -import org.apache.guacamole.auth.ldap.conf.LDAPConfiguration; import org.apache.guacamole.auth.ldap.group.UserGroupService; import org.apache.guacamole.auth.ldap.user.LDAPAuthenticatedUser; import org.apache.guacamole.net.auth.Connection; @@ -117,17 +115,12 @@ public class ConnectionService { /** - * Returns all Guacamole connections accessible to the user currently bound - * under the given LDAP connection. + * Returns all Guacamole connections accessible to the given user. * * @param user * The AuthenticatedUser object associated with the user who is * currently authenticated with Guacamole. * - * @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 @@ -136,11 +129,11 @@ public class ConnectionService { * @throws GuacamoleException * If an error occurs preventing retrieval of connections. */ - public Map getConnections(LDAPAuthenticatedUser user, - LdapNetworkConnection ldapConnection) throws GuacamoleException { + public Map getConnections(LDAPAuthenticatedUser user) + throws GuacamoleException { + + ConnectedLDAPConfiguration ldapConfig = user.getLDAPConfiguration(); - LDAPConfiguration ldapConfig = user.getLDAPConfiguration(); - // Do not return any connections if base DN is not specified Dn configurationBaseDN = ldapConfig.getConfigurationBaseDN(); if (configurationBaseDN == null) @@ -148,24 +141,15 @@ public class ConnectionService { try { - // Pull the current user DN from the LDAP connection - LdapConnectionConfig ldapConnectionConfig = ldapConnection.getConfig(); - Dn userDN = new Dn(ldapConnectionConfig.getName()); - - // getConnections() will only be called after a connection has been - // authenticated (via non-anonymous bind), thus userDN cannot - // possibly be null - assert(userDN != null); - // Get the search filter for finding connections accessible by the // current user - ExprNode connectionSearchFilter = getConnectionSearchFilter(user, userDN, ldapConnection); + ExprNode connectionSearchFilter = getConnectionSearchFilter(user); // Find all Guacamole connections for the given user by // looking for direct membership in the guacConfigGroup // and possibly any groups the user is a member of that are // referred to in the seeAlso attribute of the guacConfigGroup. - List results = queryService.search(ldapConfig, ldapConnection, + List results = queryService.search(ldapConfig, ldapConfig.getLDAPConnection(), configurationBaseDN, connectionSearchFilter, 0, GUAC_CONFIG_LDAP_ATTRIBUTES); // Return a map of all readable connections @@ -271,19 +255,12 @@ public class ConnectionService { /** * Returns an LDAP search filter which queries all connections accessible - * by the user having the given DN. + * by the given user. * * @param user * The AuthenticatedUser object associated with the user who is * currently authenticated with Guacamole. * - * @param userDN - * DN of the user to search for associated guacConfigGroup connections. - * - * @param ldapConnection - * LDAP connection to use if additional information must be queried to - * produce the filter, such as groups driving RBAC. - * * @return * An LDAP search filter which queries all guacConfigGroup objects * accessible by the user having the given DN. @@ -294,11 +271,11 @@ public class ConnectionService { * @throws GuacamoleException * If an error occurs retrieving the group base DN. */ - private ExprNode getConnectionSearchFilter(LDAPAuthenticatedUser user, - Dn userDN, LdapNetworkConnection ldapConnection) + private ExprNode getConnectionSearchFilter(LDAPAuthenticatedUser user) throws LdapException, GuacamoleException { - LDAPConfiguration config = user.getLDAPConfiguration(); + ConnectedLDAPConfiguration config = user.getLDAPConfiguration(); + Dn userDN = config.getBindDN(); AndNode searchFilter = new AndNode(); @@ -312,7 +289,7 @@ public class ConnectionService { // Additionally filter by group membership if the current user is a // member of any user groups - List userGroups = userGroupService.getParentUserGroupEntries(config, ldapConnection, userDN); + List userGroups = userGroupService.getParentUserGroupEntries(config, userDN); if (!userGroups.isEmpty()) { userGroups.forEach(entry -> groupFilter.addNode(new EqualityNode(LDAP_ATTRIBUTE_NAME_GROUPS,entry.getDn().toString())) diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/group/UserGroupService.java b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/group/UserGroupService.java index a3dc9c1e8..b38fc9198 100644 --- a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/group/UserGroupService.java +++ b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/group/UserGroupService.java @@ -33,9 +33,9 @@ import org.apache.directory.api.ldap.model.filter.EqualityNode; import org.apache.directory.api.ldap.model.filter.ExprNode; import org.apache.directory.api.ldap.model.filter.NotNode; import org.apache.directory.api.ldap.model.name.Dn; -import org.apache.directory.ldap.client.api.LdapNetworkConnection; import org.apache.guacamole.auth.ldap.conf.MemberAttributeType; import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.auth.ldap.ConnectedLDAPConfiguration; import org.apache.guacamole.auth.ldap.ObjectQueryService; import org.apache.guacamole.auth.ldap.conf.LDAPConfiguration; import org.apache.guacamole.auth.ldap.user.LDAPAuthenticatedUser; @@ -98,17 +98,12 @@ public class UserGroupService { } /** - * Returns all Guacamole user groups accessible to the user currently bound - * under the given LDAP connection. + * Returns all Guacamole user groups accessible to the given user. * * @param user * The AuthenticatedUser object associated with the user who is * currently authenticated with Guacamole. * - * @param ldapConnection - * The current connection to the LDAP server, associated with the - * current user. - * * @return * All user groups accessible to the user currently bound under the * given LDAP connection, as a map of user group identifier to @@ -117,10 +112,10 @@ public class UserGroupService { * @throws GuacamoleException * If an error occurs preventing retrieval of user groups. */ - public Map getUserGroups(LDAPAuthenticatedUser user, - LdapNetworkConnection ldapConnection) throws GuacamoleException { + public Map getUserGroups(LDAPAuthenticatedUser user) + throws GuacamoleException { - LDAPConfiguration config = user.getLDAPConfiguration(); + ConnectedLDAPConfiguration config = user.getLDAPConfiguration(); // Do not return any user groups if base DN is not specified Dn groupBaseDN = config.getGroupBaseDN(); @@ -136,7 +131,7 @@ public class UserGroupService { Collection attributes = config.getGroupNameAttributes(); List results = queryService.search( config, - ldapConnection, + config.getLDAPConnection(), groupBaseDN, getGroupSearchFilter(config), attributes, @@ -175,10 +170,6 @@ public class UserGroupService { * @param config * The configuration of the LDAP server being queried. * - * @param ldapConnection - * The current connection to the LDAP server, associated with the - * current user. - * * @param userDN * The DN of the user whose group membership should be retrieved. * @@ -189,8 +180,7 @@ public class UserGroupService { * @throws GuacamoleException * If an error occurs preventing retrieval of user groups. */ - public List getParentUserGroupEntries(LDAPConfiguration config, - LdapNetworkConnection ldapConnection, Dn userDN) + public List getParentUserGroupEntries(ConnectedLDAPConfiguration config, Dn userDN) throws GuacamoleException { // Do not return any user groups if base DN is not specified @@ -206,7 +196,7 @@ public class UserGroupService { // Retrieve user objects with userDN List userEntries = queryService.search( config, - ldapConnection, + config.getLDAPConnection(), userDN, config.getUserSearchFilter(), 0, @@ -240,7 +230,7 @@ public class UserGroupService { // excluding guacConfigGroups return queryService.search( config, - ldapConnection, + config.getLDAPConnection(), groupBaseDN, getGroupSearchFilter(config), Collections.singleton(memberAttribute), @@ -258,10 +248,6 @@ public class UserGroupService { * @param config * The configuration of the LDAP server being queried. * - * @param ldapConnection - * The current connection to the LDAP server, associated with the - * current user. - * * @param userDN * The DN of the user whose group membership should be retrieved. * @@ -272,12 +258,11 @@ public class UserGroupService { * @throws GuacamoleException * If an error occurs preventing retrieval of user groups. */ - public Set getParentUserGroupIdentifiers(LDAPConfiguration config, - LdapNetworkConnection ldapConnection, Dn userDN) + public Set getParentUserGroupIdentifiers(ConnectedLDAPConfiguration config, Dn userDN) throws GuacamoleException { Collection attributes = config.getGroupNameAttributes(); - List userGroups = getParentUserGroupEntries(config, ldapConnection, userDN); + List userGroups = getParentUserGroupEntries(config, userDN); Set identifiers = new HashSet<>(userGroups.size()); userGroups.forEach(entry -> { diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/user/LDAPAuthenticatedUser.java b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/user/LDAPAuthenticatedUser.java index 97eab6cae..6889e61a7 100644 --- a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/user/LDAPAuthenticatedUser.java +++ b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/user/LDAPAuthenticatedUser.java @@ -24,7 +24,7 @@ import java.util.Collections; import java.util.Map; import java.util.Set; import org.apache.directory.api.ldap.model.name.Dn; -import org.apache.guacamole.auth.ldap.conf.LDAPConfiguration; +import org.apache.guacamole.auth.ldap.ConnectedLDAPConfiguration; import org.apache.guacamole.net.auth.AbstractAuthenticatedUser; import org.apache.guacamole.net.auth.AuthenticationProvider; import org.apache.guacamole.net.auth.Credentials; @@ -68,11 +68,11 @@ public class LDAPAuthenticatedUser extends AbstractAuthenticatedUser { * The configuration of the LDAP server that should be used for all queries * related to this AuthenticatedUser. */ - private LDAPConfiguration config; + private ConnectedLDAPConfiguration config; /** * Initializes this AuthenticatedUser with the given credentials, - * connection parameter tokens. and set of effective user groups. + * connection parameter tokens, and set of effective user groups. * * @param config * The configuration of the LDAP server that should be used for all @@ -88,17 +88,14 @@ public class LDAPAuthenticatedUser extends AbstractAuthenticatedUser { * @param effectiveGroups * The unique identifiers of all user groups which affect the * permissions available to this user. - * - * @param bindDn - * The LDAP DN used to bind this user. */ - public void init(LDAPConfiguration config, Credentials credentials, - Map tokens, Set effectiveGroups, Dn bindDn) { + public void init(ConnectedLDAPConfiguration config, Credentials credentials, + Map tokens, Set effectiveGroups) { this.config = config; this.credentials = credentials; this.tokens = Collections.unmodifiableMap(tokens); this.effectiveGroups = effectiveGroups; - this.bindDn = bindDn; + this.bindDn = config.getBindDN(); setIdentifier(credentials.getUsername()); } @@ -115,7 +112,7 @@ public class LDAPAuthenticatedUser extends AbstractAuthenticatedUser { public Map getTokens() { return tokens; } - + /** * Returns the LDAP DN used to bind this user. * @@ -134,7 +131,7 @@ public class LDAPAuthenticatedUser extends AbstractAuthenticatedUser { * The configuration of the LDAP server related to this * AuthenticatedUser. */ - public LDAPConfiguration getLDAPConfiguration() { + public ConnectedLDAPConfiguration getLDAPConfiguration() { return config; } @@ -153,4 +150,9 @@ public class LDAPAuthenticatedUser extends AbstractAuthenticatedUser { return effectiveGroups; } + @Override + public void invalidate() { + config.close(); + } + } diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/user/LDAPUserContext.java b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/user/LDAPUserContext.java index cb2afd516..79b1af718 100644 --- a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/user/LDAPUserContext.java +++ b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/user/LDAPUserContext.java @@ -21,7 +21,6 @@ package org.apache.guacamole.auth.ldap.user; import com.google.inject.Inject; import java.util.Collections; -import org.apache.directory.ldap.client.api.LdapNetworkConnection; import org.apache.guacamole.auth.ldap.connection.ConnectionService; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.auth.ldap.LDAPAuthenticationProvider; @@ -100,38 +99,32 @@ public class LDAPUserContext extends AbstractUserContext { private ConnectionGroup rootGroup; /** - * Initializes this UserContext using the provided AuthenticatedUser and - * LdapNetworkConnection. + * Initializes this UserContext using the provided AuthenticatedUser. * * @param user * The AuthenticatedUser representing the user that authenticated. This * user will always have been authenticated via LDAP, as LDAP data is * not provided to non-LDAP users. * - * @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(LDAPAuthenticatedUser user, LdapNetworkConnection ldapConnection) - throws GuacamoleException { + public void init(LDAPAuthenticatedUser user) throws GuacamoleException { // Query all accessible users userDirectory = new SimpleDirectory<>( - userService.getUsers(user, ldapConnection) + userService.getUsers(user) ); // Query all accessible user groups userGroupDirectory = new SimpleDirectory<>( - userGroupService.getUserGroups(user, ldapConnection) + userGroupService.getUserGroups(user) ); // Query all accessible connections connectionDirectory = new SimpleDirectory<>( - connectionService.getConnections(user, ldapConnection) + connectionService.getConnections(user) ); // Root group contains only connections diff --git a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/user/UserService.java b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/user/UserService.java index 69df58a79..fa9fe1522 100644 --- a/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/user/UserService.java +++ b/extensions/guacamole-auth-ldap/src/main/java/org/apache/guacamole/auth/ldap/user/UserService.java @@ -34,6 +34,7 @@ import org.apache.directory.api.ldap.model.name.Rdn; import org.apache.directory.ldap.client.api.LdapNetworkConnection; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleServerException; +import org.apache.guacamole.auth.ldap.ConnectedLDAPConfiguration; import org.apache.guacamole.auth.ldap.conf.LDAPGuacamoleProperties; import org.apache.guacamole.auth.ldap.ObjectQueryService; import org.apache.guacamole.auth.ldap.conf.LDAPConfiguration; @@ -60,17 +61,12 @@ public class UserService { private ObjectQueryService queryService; /** - * Returns all Guacamole users accessible to the user currently bound under - * the given LDAP connection. + * Returns all Guacamole users accessible to the given user. * * @param user * The AuthenticatedUser object associated with the user who is * currently authenticated with Guacamole. * - * @param ldapConnection - * The current connection to the LDAP server, associated with the - * current user. - * * @return * All users accessible to the user currently bound under the given * LDAP connection, as a map of connection identifier to corresponding @@ -79,21 +75,24 @@ public class UserService { * @throws GuacamoleException * If an error occurs preventing retrieval of users. */ - public Map getUsers(LDAPAuthenticatedUser user, - LdapNetworkConnection ldapConnection) throws GuacamoleException { + public Map getUsers(LDAPAuthenticatedUser user) + throws GuacamoleException { - LDAPConfiguration config = user.getLDAPConfiguration(); + ConnectedLDAPConfiguration config = user.getLDAPConfiguration(); // Retrieve all visible user objects Collection usernameAttrs = config.getUsernameAttributes(); Collection attributes = new HashSet<>(usernameAttrs); attributes.addAll(config.getAttributes()); - List results = queryService.search(config, ldapConnection, - config.getUserBaseDN(), - config.getUserSearchFilter(), - usernameAttrs, - null, - attributes); + List results = queryService.search( + config, + config.getLDAPConnection(), + config.getUserBaseDN(), + config.getUserSearchFilter(), + usernameAttrs, + null, + attributes + ); // Convert retrieved users to map of identifier to Guacamole user object return queryService.asMap(results, entry -> {