GUACAMOLE-524: Merge allow user attributes to be used as tokens.

This commit is contained in:
Nick Couchman
2018-06-21 11:14:06 -04:00
10 changed files with 181 additions and 14 deletions

View File

@@ -79,6 +79,7 @@ public class ModeledAuthenticatedUser extends RemoteAuthenticatedUser {
super(authenticatedUser.getAuthenticationProvider(), authenticatedUser.getCredentials());
this.modelAuthenticationProvider = modelAuthenticationProvider;
this.user = user;
super.setAttributes(authenticatedUser.getAttributes());
}
/**
@@ -93,7 +94,7 @@ public class ModeledAuthenticatedUser extends RemoteAuthenticatedUser {
* A ModeledUser object which is backed by the data associated with
* this user in the database.
*
* @param credentials
* @param credentials
* The credentials given by the user when they authenticated.
*/
public ModeledAuthenticatedUser(AuthenticationProvider authenticationProvider,
@@ -107,7 +108,7 @@ public class ModeledAuthenticatedUser extends RemoteAuthenticatedUser {
* Returns a ModeledUser object which is backed by the data associated with
* this user within the database.
*
* @return
* @return
* A ModeledUser object which is backed by the data associated with
* this user in the database.
*/

View File

@@ -19,6 +19,8 @@
package org.apache.guacamole.auth.jdbc.user;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
@@ -67,6 +69,21 @@ public abstract class RemoteAuthenticatedUser implements AuthenticatedUser {
*/
private static final Pattern X_FORWARDED_FOR = Pattern.compile("^" + IP_ADDRESS_REGEX + "(, " + IP_ADDRESS_REGEX + ")*$");
/**
* Arbitrary attributes associated with this RemoteAuthenticatedUser object.
*/
private Map<String, String> attributes = new HashMap<String, String>();
@Override
public Map<String, String> getAttributes() {
return attributes;
}
@Override
public void setAttributes(Map<String, String> attributes) {
this.attributes = attributes;
}
/**
* Derives the remote host of the authenticating user from the given
* credentials object. The remote host is derived from X-Forwarded-For
@@ -98,7 +115,7 @@ public abstract class RemoteAuthenticatedUser implements AuthenticatedUser {
return request.getRemoteAddr();
}
/**
* Creates a new RemoteAuthenticatedUser, deriving the associated remote
* host from the given credentials.
@@ -106,7 +123,7 @@ public abstract class RemoteAuthenticatedUser implements AuthenticatedUser {
* @param authenticationProvider
* The AuthenticationProvider that has authenticated the given user.
*
* @param credentials
* @param credentials
* The credentials given by the user when they authenticated.
*/
public RemoteAuthenticatedUser(AuthenticationProvider authenticationProvider,

View File

@@ -21,11 +21,18 @@ package org.apache.guacamole.auth.ldap;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.novell.ldap.LDAPAttribute;
import com.novell.ldap.LDAPAttributeSet;
import com.novell.ldap.LDAPConnection;
import com.novell.ldap.LDAPEntry;
import com.novell.ldap.LDAPException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.guacamole.auth.ldap.user.AuthenticatedUser;
import org.apache.guacamole.auth.ldap.user.UserContext;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleServerException;
import org.apache.guacamole.auth.ldap.user.UserService;
import org.apache.guacamole.net.auth.Credentials;
import org.apache.guacamole.net.auth.credentials.CredentialsInfo;
@@ -189,7 +196,8 @@ public class AuthenticationProviderService {
/**
* Returns an AuthenticatedUser representing the user authenticated by the
* given credentials.
* given credentials. Also adds custom LDAP attributes to the
* AuthenticatedUser.
*
* @param credentials
* The credentials to use for authentication.
@@ -221,14 +229,16 @@ public class AuthenticationProviderService {
throw new GuacamoleInvalidCredentialsException("Permission denied.", CredentialsInfo.USERNAME_PASSWORD);
try {
// Return AuthenticatedUser if bind succeeds
AuthenticatedUser authenticatedUser = authenticatedUserProvider.get();
authenticatedUser.init(credentials);
// Set attributes
authenticatedUser.setAttributes(getLDAPAttributes(ldapConnection, credentials.getUsername()));
return authenticatedUser;
}
// Always disconnect
finally {
ldapService.disconnect(ldapConnection);
@@ -236,6 +246,58 @@ public class AuthenticationProviderService {
}
/**
* Returns all custom LDAP attributes on the user currently bound under
* the given LDAP connection. The custom attributes are specified in
* guacamole.properties.
*
* @param ldapConnection
* LDAP connection to find the custom LDAP attributes.
*
* @param username
* The username of the user whose attributes are queried.
*
* @return
* All attributes on the user currently bound under the
* given LDAP connection, as a map of attribute name to
* corresponding attribute value.
*
* @throws GuacamoleException
* If an error occurs retrieving the user DN or the attributes.
*/
private Map<String, String> getLDAPAttributes(LDAPConnection ldapConnection,
String username) throws GuacamoleException {
// Get attributes from configuration information
List<String> attrList = confService.getAttributes();
// If there are no attributes there is no reason to search LDAP
if (attrList == null || attrList.isEmpty())
return null;
// Build LDAP query parameters
String[] attrArray = attrList.toArray(new String[attrList.size()]);
String userDN = getUserBindDN(username);
Map<String, String> attrMap = new HashMap<String, String>();
try {
// Get LDAP attributes by querying LDAP
LDAPEntry userEntry = ldapConnection.read(userDN, attrArray);
LDAPAttributeSet attrSet = userEntry.getAttributeSet();
// Add each attribute into Map
for (Object attrObj : attrSet) {
LDAPAttribute attr = (LDAPAttribute)attrObj;
attrMap.put(attr.getName(), attr.getStringValue());
}
}
catch (LDAPException e) {
throw new GuacamoleServerException("Error while querying for User Attributes.", e);
}
return attrMap;
}
/**
* Returns a UserContext object initialized with data accessible to the
* given AuthenticatedUser.

View File

@@ -227,7 +227,7 @@ public class ConfigurationService {
private int getMaxResults() throws GuacamoleException {
return environment.getProperty(
LDAPGuacamoleProperties.LDAP_MAX_SEARCH_RESULTS,
1000
1000
);
}
@@ -344,4 +344,19 @@ public class ConfigurationService {
);
}
/**
* Returns names for custom LDAP user attributes.
*
* @return
* Custom LDAP user attributes as configured in guacamole.properties.
*
* @throws GuacamoleException
* If guacamole.properties cannot be parsed.
*/
public List<String> getAttributes() throws GuacamoleException {
return environment.getProperty(
LDAPGuacamoleProperties.LDAP_USER_ATTRIBUTES
);
}
}

View File

@@ -205,4 +205,14 @@ public class LDAPGuacamoleProperties {
};
/**
* Custom attribute or attributes to query from Guacamole user's record in
* the LDAP directory.
*/
public static final StringListProperty LDAP_USER_ATTRIBUTES = new StringListProperty() {
@Override
public String getName() { return "ldap-user-attributes"; }
};
}

View File

@@ -20,6 +20,8 @@
package org.apache.guacamole.auth.ldap.user;
import com.google.inject.Inject;
import java.util.HashMap;
import java.util.Map;
import org.apache.guacamole.net.auth.AbstractAuthenticatedUser;
import org.apache.guacamole.net.auth.AuthenticationProvider;
import org.apache.guacamole.net.auth.Credentials;
@@ -42,6 +44,11 @@ public class AuthenticatedUser extends AbstractAuthenticatedUser {
*/
private Credentials credentials;
/**
* Arbitrary attributes associated with this AuthenticatedUser object.
*/
private Map<String, String> attributes = new HashMap<String, String>();
/**
* Initializes this AuthenticatedUser using the given credentials.
*
@@ -53,6 +60,16 @@ public class AuthenticatedUser extends AbstractAuthenticatedUser {
setIdentifier(credentials.getUsername());
}
@Override
public Map<String, String> getAttributes() {
return attributes;
}
@Override
public void setAttributes(Map<String, String> attributes) {
this.attributes = attributes;
}
@Override
public AuthenticationProvider getAuthenticationProvider() {
return authProvider;