mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 05:07:41 +00:00
GUAC-586: Implement listing of visible users within LDAP (by completely rewriting the LDAP auth provider).
This commit is contained in:
@@ -102,6 +102,18 @@
|
|||||||
<version>4.3</version>
|
<version>4.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Guice -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.inject</groupId>
|
||||||
|
<artifactId>guice</artifactId>
|
||||||
|
<version>3.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.inject.extensions</groupId>
|
||||||
|
<artifactId>guice-multibindings</artifactId>
|
||||||
|
<version>3.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
@@ -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
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -23,25 +23,15 @@
|
|||||||
package net.sourceforge.guacamole.net.auth.ldap;
|
package net.sourceforge.guacamole.net.auth.ldap;
|
||||||
|
|
||||||
|
|
||||||
import com.novell.ldap.LDAPAttribute;
|
import org.glyptodon.guacamole.auth.ldap.AuthenticationProviderService;
|
||||||
import com.novell.ldap.LDAPConnection;
|
import org.glyptodon.guacamole.auth.ldap.LDAPAuthenticationProviderModule;
|
||||||
import com.novell.ldap.LDAPEntry;
|
import com.google.inject.Guice;
|
||||||
import com.novell.ldap.LDAPException;
|
import com.google.inject.Injector;
|
||||||
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.GuacamoleException;
|
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 org.glyptodon.guacamole.net.auth.Credentials;
|
||||||
import net.sourceforge.guacamole.net.auth.ldap.properties.LDAPGuacamoleProperties;
|
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||||
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;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows users to be authenticated against an LDAP server. Each user may have
|
* Allows users to be authenticated against an LDAP server. Each user may have
|
||||||
@@ -50,17 +40,13 @@ import org.slf4j.LoggerFactory;
|
|||||||
*
|
*
|
||||||
* @author Michael Jumper
|
* @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);
|
private final Injector injector;
|
||||||
|
|
||||||
/**
|
|
||||||
* Guacamole server environment.
|
|
||||||
*/
|
|
||||||
private final Environment environment;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new LDAPAuthenticationProvider that authenticates users
|
* Creates a new LDAPAuthenticationProvider that authenticates users
|
||||||
@@ -71,7 +57,12 @@ public class LDAPAuthenticationProvider extends SimpleAuthenticationProvider {
|
|||||||
* a property.
|
* a property.
|
||||||
*/
|
*/
|
||||||
public LDAPAuthenticationProvider() throws GuacamoleException {
|
public LDAPAuthenticationProvider() throws GuacamoleException {
|
||||||
environment = new LocalEnvironment();
|
|
||||||
|
// Set up Guice injector.
|
||||||
|
injector = Guice.createInjector(
|
||||||
|
new LDAPAuthenticationProviderModule(this)
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -79,219 +70,33 @@ public class LDAPAuthenticationProvider extends SimpleAuthenticationProvider {
|
|||||||
return "ldap";
|
return "ldap";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Courtesy of OWASP: https://www.owasp.org/index.php/Preventing_LDAP_Injection_in_Java
|
@Override
|
||||||
private static String escapeLDAPSearchFilter(String filter) {
|
public AuthenticatedUser authenticateUser(Credentials credentials) throws GuacamoleException {
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
for (int i = 0; i < filter.length(); i++) {
|
AuthenticationProviderService authProviderService = injector.getInstance(AuthenticationProviderService.class);
|
||||||
char curChar = filter.charAt(i);
|
return authProviderService.authenticateUser(credentials);
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
@Override
|
||||||
public Map<String, GuacamoleConfiguration> getAuthorizedConfigurations(Credentials credentials) throws GuacamoleException {
|
public AuthenticatedUser updateAuthenticatedUser(AuthenticatedUser authenticatedUser,
|
||||||
|
Credentials credentials) throws GuacamoleException {
|
||||||
// Require username
|
return authenticatedUser;
|
||||||
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
|
@Override
|
||||||
if (credentials.getPassword() == null
|
public UserContext getUserContext(AuthenticatedUser authenticatedUser)
|
||||||
|| credentials.getPassword().length() == 0) {
|
throws GuacamoleException {
|
||||||
logger.debug("Anonymous bind is not currently allowed by the LDAP authentication provider.");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Connect to LDAP server
|
AuthenticationProviderService authProviderService = injector.getInstance(AuthenticationProviderService.class);
|
||||||
LDAPConnection ldapConnection;
|
return authProviderService.getUserContext(authenticatedUser);
|
||||||
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<String, GuacamoleConfiguration> configs = new TreeMap<String, GuacamoleConfiguration>();
|
|
||||||
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);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
@Override
|
||||||
|
public UserContext updateUserContext(UserContext context,
|
||||||
}
|
AuthenticatedUser authenticatedUser) throws GuacamoleException {
|
||||||
|
return context;
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -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<AuthenticatedUser> authenticatedUserProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provider for UserContext objects.
|
||||||
|
*/
|
||||||
|
@Inject
|
||||||
|
private Provider<UserContext> 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -20,7 +20,7 @@
|
|||||||
* THE SOFTWARE.
|
* 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.IntegerGuacamoleProperty;
|
||||||
import org.glyptodon.guacamole.properties.StringGuacamoleProperty;
|
import org.glyptodon.guacamole.properties.StringGuacamoleProperty;
|
@@ -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<String, Connection> 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<String, Connection> connections = new HashMap<String, Connection>();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -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<User> userDirectory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Directory containing all Connection objects accessible to the user
|
||||||
|
* associated with this UserContext.
|
||||||
|
*/
|
||||||
|
private Directory<Connection> connectionDirectory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Directory containing all ConnectionGroup objects accessible to the user
|
||||||
|
* associated with this UserContext.
|
||||||
|
*/
|
||||||
|
private Directory<ConnectionGroup> 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<User>(
|
||||||
|
userService.getUsers(ldapConnection)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Query all accessible connections
|
||||||
|
connectionDirectory = new SimpleDirectory<Connection>(
|
||||||
|
connectionService.getConnections(ldapConnection)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Root group contains only connections
|
||||||
|
rootGroup = new SimpleConnectionGroup(
|
||||||
|
ROOT_CONNECTION_GROUP, ROOT_CONNECTION_GROUP,
|
||||||
|
connectionDirectory.getIdentifiers(),
|
||||||
|
Collections.<String>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<User> getUserDirectory() throws GuacamoleException {
|
||||||
|
return userDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Directory<Connection> getConnectionDirectory()
|
||||||
|
throws GuacamoleException {
|
||||||
|
return connectionDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Directory<ConnectionGroup> getConnectionGroupDirectory()
|
||||||
|
throws GuacamoleException {
|
||||||
|
return connectionGroupDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ConnectionGroup getRootConnectionGroup() throws GuacamoleException {
|
||||||
|
return rootGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Directory<ActiveConnection> getActiveConnectionDirectory()
|
||||||
|
throws GuacamoleException {
|
||||||
|
return new SimpleDirectory<ActiveConnection>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<Form> getUserAttributes() {
|
||||||
|
return Collections.<Form>emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<Form> getConnectionAttributes() {
|
||||||
|
return Collections.<Form>emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<Form> getConnectionGroupAttributes() {
|
||||||
|
return Collections.<Form>emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,129 @@
|
|||||||
|
/*
|
||||||
|
* 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.LDAPAttribute;
|
||||||
|
import com.novell.ldap.LDAPConnection;
|
||||||
|
import com.novell.ldap.LDAPEntry;
|
||||||
|
import com.novell.ldap.LDAPException;
|
||||||
|
import com.novell.ldap.LDAPSearchResults;
|
||||||
|
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.User;
|
||||||
|
import org.glyptodon.guacamole.net.auth.simple.SimpleUser;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service for queries the users visible to a particular Guacamole user
|
||||||
|
* according to an LDAP directory.
|
||||||
|
*
|
||||||
|
* @author Michael Jumper
|
||||||
|
*/
|
||||||
|
public class UserService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logger for this class.
|
||||||
|
*/
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(UserService.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 users 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 users accessible to the user currently bound under the given
|
||||||
|
* LDAP connection, as a map of connection identifier to corresponding
|
||||||
|
* user object.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If an error occurs preventing retrieval of users.
|
||||||
|
*/
|
||||||
|
public Map<String, User> getUsers(LDAPConnection ldapConnection)
|
||||||
|
throws GuacamoleException {
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
// Get username attribute
|
||||||
|
String usernameAttribute = confService.getUsernameAttribute();
|
||||||
|
|
||||||
|
// Find all Guacamole users underneath base DN
|
||||||
|
LDAPSearchResults results = ldapConnection.search(
|
||||||
|
confService.getUserBaseDN(),
|
||||||
|
LDAPConnection.SCOPE_ONE,
|
||||||
|
"(&(objectClass=*)(" + escapingService.escapeLDAPSearchFilter(usernameAttribute) + "=*))",
|
||||||
|
null,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
// Read all visible users
|
||||||
|
Map<String, User> users = new HashMap<String, User>();
|
||||||
|
while (results.hasMore()) {
|
||||||
|
|
||||||
|
LDAPEntry entry = results.next();
|
||||||
|
|
||||||
|
// Get common name (CN)
|
||||||
|
LDAPAttribute username = entry.getAttribute(usernameAttribute);
|
||||||
|
if (username == null) {
|
||||||
|
logger.warn("Queried user is missing the username attribute \"{}\".", usernameAttribute);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store connection using cn for both identifier and name
|
||||||
|
String identifier = username.getStringValue();
|
||||||
|
users.put(identifier, new SimpleUser(identifier));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return map of all connections
|
||||||
|
return users;
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (LDAPException e) {
|
||||||
|
throw new GuacamoleServerException("Error while querying users.", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -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
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -28,7 +28,6 @@ import java.util.HashSet;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.glyptodon.guacamole.GuacamoleException;
|
import org.glyptodon.guacamole.GuacamoleException;
|
||||||
import org.glyptodon.guacamole.GuacamoleSecurityException;
|
|
||||||
import org.glyptodon.guacamole.net.auth.AbstractUser;
|
import org.glyptodon.guacamole.net.auth.AbstractUser;
|
||||||
import org.glyptodon.guacamole.net.auth.permission.ObjectPermission;
|
import org.glyptodon.guacamole.net.auth.permission.ObjectPermission;
|
||||||
import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet;
|
import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet;
|
||||||
@@ -41,6 +40,12 @@ import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet;
|
|||||||
*/
|
*/
|
||||||
public class SimpleUser extends AbstractUser {
|
public class SimpleUser extends AbstractUser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All connection permissions granted to this user.
|
||||||
|
*/
|
||||||
|
private final Set<ObjectPermission> userPermissions =
|
||||||
|
new HashSet<ObjectPermission>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All connection permissions granted to this user.
|
* All connection permissions granted to this user.
|
||||||
*/
|
*/
|
||||||
@@ -59,6 +64,19 @@ public class SimpleUser extends AbstractUser {
|
|||||||
public SimpleUser() {
|
public SimpleUser() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new SimpleUser having the given username and no permissions.
|
||||||
|
*
|
||||||
|
* @param username
|
||||||
|
* The username to assign to this SimpleUser.
|
||||||
|
*/
|
||||||
|
public SimpleUser(String username) {
|
||||||
|
|
||||||
|
// Set username
|
||||||
|
setIdentifier(username);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a new READ permission to the given set of permissions for each of
|
* Adds a new READ permission to the given set of permissions for each of
|
||||||
* the given identifiers.
|
* the given identifiers.
|
||||||
@@ -89,6 +107,7 @@ public class SimpleUser extends AbstractUser {
|
|||||||
*
|
*
|
||||||
* @param username
|
* @param username
|
||||||
* The username to assign to this SimpleUser.
|
* The username to assign to this SimpleUser.
|
||||||
|
*
|
||||||
* @param connectionIdentifiers
|
* @param connectionIdentifiers
|
||||||
* The identifiers of all connections this user has READ access to.
|
* The identifiers of all connections this user has READ access to.
|
||||||
*
|
*
|
||||||
@@ -100,8 +119,7 @@ public class SimpleUser extends AbstractUser {
|
|||||||
Collection<String> connectionIdentifiers,
|
Collection<String> connectionIdentifiers,
|
||||||
Collection<String> connectionGroupIdentifiers) {
|
Collection<String> connectionGroupIdentifiers) {
|
||||||
|
|
||||||
// Set username
|
this(username);
|
||||||
setIdentifier(username);
|
|
||||||
|
|
||||||
// Add permissions
|
// Add permissions
|
||||||
addReadPermissions(connectionPermissions, connectionIdentifiers);
|
addReadPermissions(connectionPermissions, connectionIdentifiers);
|
||||||
@@ -109,6 +127,37 @@ public class SimpleUser extends AbstractUser {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new SimpleUser having the given username and READ access to
|
||||||
|
* the users, connections, and groups having the given identifiers.
|
||||||
|
*
|
||||||
|
* @param username
|
||||||
|
* The username to assign to this SimpleUser.
|
||||||
|
*
|
||||||
|
* @param userIdentifiers
|
||||||
|
* The identifiers of all users this user has READ access to.
|
||||||
|
*
|
||||||
|
* @param connectionIdentifiers
|
||||||
|
* The identifiers of all connections this user has READ access to.
|
||||||
|
*
|
||||||
|
* @param connectionGroupIdentifiers
|
||||||
|
* The identifiers of all connection groups this user has READ access
|
||||||
|
* to.
|
||||||
|
*/
|
||||||
|
public SimpleUser(String username,
|
||||||
|
Collection<String> userIdentifiers,
|
||||||
|
Collection<String> connectionIdentifiers,
|
||||||
|
Collection<String> connectionGroupIdentifiers) {
|
||||||
|
|
||||||
|
this(username);
|
||||||
|
|
||||||
|
// Add permissions
|
||||||
|
addReadPermissions(userPermissions, userIdentifiers);
|
||||||
|
addReadPermissions(connectionPermissions, connectionIdentifiers);
|
||||||
|
addReadPermissions(connectionGroupPermissions, connectionGroupIdentifiers);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, String> getAttributes() {
|
public Map<String, String> getAttributes() {
|
||||||
return Collections.<String, String>emptyMap();
|
return Collections.<String, String>emptyMap();
|
||||||
@@ -140,7 +189,7 @@ public class SimpleUser extends AbstractUser {
|
|||||||
@Override
|
@Override
|
||||||
public ObjectPermissionSet getUserPermissions()
|
public ObjectPermissionSet getUserPermissions()
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
return new SimpleObjectPermissionSet();
|
return new SimpleObjectPermissionSet(userPermissions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Reference in New Issue
Block a user