GUACAMOLE-234: Add storage for the LDAP Bind DN to LDAPAuthenticateduser.

This commit is contained in:
Nick Couchman
2018-12-14 20:41:29 -05:00
committed by Virtually Nick
parent d0b1d7639e
commit 7a17b7f935
2 changed files with 57 additions and 78 deletions

View File

@@ -30,9 +30,7 @@ import java.util.Set;
import org.apache.directory.api.ldap.model.entry.Attribute; import org.apache.directory.api.ldap.model.entry.Attribute;
import org.apache.directory.api.ldap.model.entry.Entry; import org.apache.directory.api.ldap.model.entry.Entry;
import org.apache.directory.api.ldap.model.exception.LdapException; import org.apache.directory.api.ldap.model.exception.LdapException;
import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
import org.apache.directory.api.ldap.model.name.Dn; 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.directory.ldap.client.api.LdapNetworkConnection;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleServerException; import org.apache.guacamole.GuacamoleServerException;
@@ -44,6 +42,8 @@ import org.apache.guacamole.auth.ldap.user.UserService;
import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.AuthenticatedUser;
import org.apache.guacamole.net.auth.Credentials; import org.apache.guacamole.net.auth.Credentials;
import org.apache.guacamole.token.TokenName; import org.apache.guacamole.token.TokenName;
import org.apache.guacamole.net.auth.credentials.CredentialsInfo;
import org.apache.guacamole.net.auth.credentials.GuacamoleInvalidCredentialsException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -164,53 +164,6 @@ public class AuthenticationProviderService {
} }
/**
* 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 LdapNetworkConnection bindAs(Credentials credentials)
throws GuacamoleException {
// Get username and password from credentials
String username = credentials.getUsername();
String password = credentials.getPassword();
// Require username
if (username == null || username.isEmpty()) {
logger.debug("Anonymous bind is not currently allowed by the LDAP authentication provider.");
return null;
}
// Require password, and do not allow anonymous binding
if (password == null || password.isEmpty()) {
logger.debug("Anonymous bind is not currently allowed by the LDAP authentication provider.");
return null;
}
// Determine user DN
Dn userDN = getUserBindDN(username);
if (userDN == null) {
logger.debug("Unable to determine DN for user \"{}\".", username);
return null;
}
// Bind using user's DN
return ldapService.bindAs(userDN, password);
}
/** /**
* Returns an AuthenticatedUser representing the user authenticated by the * Returns an AuthenticatedUser representing the user authenticated by the
* given credentials. Also adds custom LDAP attributes to the * given credentials. Also adds custom LDAP attributes to the
@@ -229,33 +182,40 @@ public class AuthenticationProviderService {
*/ */
public LDAPAuthenticatedUser authenticateUser(Credentials credentials) public LDAPAuthenticatedUser authenticateUser(Credentials credentials)
throws GuacamoleException { throws GuacamoleException {
// Attempt bind
LdapNetworkConnection ldapConnection = bindAs(credentials);
LdapConnectionConfig ldapConnectionConfig = ldapConnection.getConfig();
try { String username = credentials.getUsername();
String password = credentials.getPassword();
Dn authDn = new Dn(ldapConnectionConfig.getName());
// Username and password are required
if (username == null
|| username.isEmpty()
|| password == null
|| password.isEmpty()) {
throw new GuacamoleInvalidCredentialsException(
"Anonymous bind is not currently allowed by the LDAP"
+ " authentication provider.", CredentialsInfo.USERNAME_PASSWORD);
}
Dn bindDn = getUserBindDN(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(bindDn, password);
// Retrieve group membership of the user that just authenticated // Retrieve group membership of the user that just authenticated
Set<String> effectiveGroups = Set<String> effectiveGroups =
userGroupService.getParentUserGroupIdentifiers(ldapConnection, userGroupService.getParentUserGroupIdentifiers(ldapConnection,
authDn); bindDn);
// Return AuthenticatedUser if bind succeeds // Return AuthenticatedUser if bind succeeds
LDAPAuthenticatedUser authenticatedUser = authenticatedUserProvider.get(); LDAPAuthenticatedUser authenticatedUser = authenticatedUserProvider.get();
authenticatedUser.init(credentials, getAttributeTokens(ldapConnection, credentials.getUsername()), effectiveGroups); authenticatedUser.init(credentials, getAttributeTokens(ldapConnection,
return authenticatedUser; bindDn), effectiveGroups, bindDn);
} return authenticatedUser;
catch (LdapInvalidDnException e) {
throw new GuacamoleServerException("Invalid DN trying to bind to server.", e);
}
// Always disconnect
finally {
ldapService.disconnect(ldapConnection);
}
} }
@@ -282,7 +242,7 @@ public class AuthenticationProviderService {
* If an error occurs retrieving the user DN or the attributes. * If an error occurs retrieving the user DN or the attributes.
*/ */
private Map<String, String> getAttributeTokens(LdapNetworkConnection ldapConnection, private Map<String, String> getAttributeTokens(LdapNetworkConnection ldapConnection,
String username) throws GuacamoleException { Dn userDn) throws GuacamoleException {
// Get attributes from configuration information // Get attributes from configuration information
List<String> attrList = confService.getAttributes(); List<String> attrList = confService.getAttributes();
@@ -293,13 +253,12 @@ public class AuthenticationProviderService {
// Build LDAP query parameters // Build LDAP query parameters
String[] attrArray = attrList.toArray(new String[attrList.size()]); String[] attrArray = attrList.toArray(new String[attrList.size()]);
Dn userDN = getUserBindDN(username);
Map<String, String> tokens = new HashMap<>(); Map<String, String> tokens = new HashMap<>();
try { try {
// Get LDAP attributes by querying LDAP // Get LDAP attributes by querying LDAP
Entry userEntry = ldapConnection.lookup(userDN, attrArray); Entry userEntry = ldapConnection.lookup(userDn, attrArray);
if (userEntry == null) if (userEntry == null)
return Collections.<String, String>emptyMap(); return Collections.<String, String>emptyMap();
@@ -341,7 +300,8 @@ public class AuthenticationProviderService {
// Bind using credentials associated with AuthenticatedUser // Bind using credentials associated with AuthenticatedUser
Credentials credentials = authenticatedUser.getCredentials(); Credentials credentials = authenticatedUser.getCredentials();
LdapNetworkConnection ldapConnection = bindAs(credentials); Dn bindDn = ((LDAPAuthenticatedUser) authenticatedUser).getBindDn();
LdapNetworkConnection ldapConnection = ldapService.bindAs(bindDn, credentials.getPassword());
try { try {

View File

@@ -57,6 +57,11 @@ public class LDAPAuthenticatedUser extends AbstractAuthenticatedUser {
* available to this user. * available to this user.
*/ */
private Set<String> effectiveGroups; private Set<String> effectiveGroups;
/**
* The LDAP DN used to bind this user.
*/
private Dn bindDn;
/** /**
* Initializes this AuthenticatedUser with the given credentials, * Initializes this AuthenticatedUser with the given credentials,
@@ -72,12 +77,16 @@ public class LDAPAuthenticatedUser extends AbstractAuthenticatedUser {
* @param effectiveGroups * @param effectiveGroups
* The unique identifiers of all user groups which affect the * The unique identifiers of all user groups which affect the
* permissions available to this user. * permissions available to this user.
*
* @param bindDn
* The LDAP DN used to bind this user.
*/ */
public void init(Credentials credentials, Map<String, String> tokens, public void init(Credentials credentials, Map<String, String> tokens,
Set<String> effectiveGroups) { Set<String> effectiveGroups, Dn bindDn) {
this.credentials = credentials; this.credentials = credentials;
this.tokens = Collections.unmodifiableMap(tokens); this.tokens = Collections.unmodifiableMap(tokens);
this.effectiveGroups = effectiveGroups; this.effectiveGroups = effectiveGroups;
this.bindDn = bindDn;
setIdentifier(credentials.getUsername()); setIdentifier(credentials.getUsername());
} }
@@ -94,6 +103,16 @@ public class LDAPAuthenticatedUser extends AbstractAuthenticatedUser {
public Map<String, String> getTokens() { public Map<String, String> getTokens() {
return tokens; return tokens;
} }
/**
* Returns the LDAP DN used to bind this user.
*
* @return
* The LDAP DN used to bind this user.
*/
public Dn getBindDn() {
return bindDn;
}
@Override @Override
public AuthenticationProvider getAuthenticationProvider() { public AuthenticationProvider getAuthenticationProvider() {