mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 05:07:41 +00:00
GUACAMOLE-957: Merge add support for querying multiple LDAP servers.
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
com.fasterxml.jackson.core:jackson-databind:jar:2.12.2
|
com.fasterxml.jackson.core:jackson-databind:jar:2.12.2
|
||||||
com.fasterxml.jackson.core:jackson-core:jar:2.12.2
|
com.fasterxml.jackson.core:jackson-core:jar:2.12.2
|
||||||
com.fasterxml.jackson.core:jackson-annotations:jar:2.12.2
|
com.fasterxml.jackson.core:jackson-annotations:jar:2.12.2
|
||||||
|
com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:jar:2.12.2
|
||||||
com.fasterxml.jackson.module:jackson-module-jaxb-annotations:jar:2.12.2
|
com.fasterxml.jackson.module:jackson-module-jaxb-annotations:jar:2.12.2
|
||||||
|
8
doc/licenses/snakeyaml-1.27/README
Normal file
8
doc/licenses/snakeyaml-1.27/README
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
SnakeYAML (https://bitbucket.org/asomov/snakeyaml/)
|
||||||
|
---------------------------------------------------
|
||||||
|
|
||||||
|
Version: 1.27
|
||||||
|
From: 'Andrey Somov' (https://bitbucket.org/asomov/)
|
||||||
|
License(s):
|
||||||
|
Apache v2.0
|
||||||
|
|
1
doc/licenses/snakeyaml-1.27/dep-coordinates.txt
Normal file
1
doc/licenses/snakeyaml-1.27/dep-coordinates.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
org.yaml:snakeyaml:jar:1.27
|
@@ -60,6 +60,16 @@
|
|||||||
<artifactId>guice</artifactId>
|
<artifactId>guice</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Jackson and YAML support -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
||||||
|
<artifactId>jackson-dataformat-yaml</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
package org.apache.guacamole.auth.ldap;
|
package org.apache.guacamole.auth.ldap;
|
||||||
|
|
||||||
|
import org.apache.guacamole.auth.ldap.user.UserLDAPConfiguration;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.Provider;
|
import com.google.inject.Provider;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -35,6 +36,7 @@ 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;
|
||||||
import org.apache.guacamole.auth.ldap.conf.ConfigurationService;
|
import org.apache.guacamole.auth.ldap.conf.ConfigurationService;
|
||||||
|
import org.apache.guacamole.auth.ldap.conf.LDAPConfiguration;
|
||||||
import org.apache.guacamole.auth.ldap.group.UserGroupService;
|
import org.apache.guacamole.auth.ldap.group.UserGroupService;
|
||||||
import org.apache.guacamole.auth.ldap.user.LDAPAuthenticatedUser;
|
import org.apache.guacamole.auth.ldap.user.LDAPAuthenticatedUser;
|
||||||
import org.apache.guacamole.auth.ldap.user.LDAPUserContext;
|
import org.apache.guacamole.auth.ldap.user.LDAPUserContext;
|
||||||
@@ -105,6 +107,9 @@ public class AuthenticationProviderService {
|
|||||||
* or queried from the LDAP server, depending on how LDAP authentication
|
* or queried from the LDAP server, depending on how LDAP authentication
|
||||||
* has been configured.
|
* has been configured.
|
||||||
*
|
*
|
||||||
|
* @param config
|
||||||
|
* The configuration of the LDAP server being queried.
|
||||||
|
*
|
||||||
* @param username
|
* @param username
|
||||||
* The username of the user whose corresponding DN should be returned.
|
* The username of the user whose corresponding DN should be returned.
|
||||||
*
|
*
|
||||||
@@ -115,18 +120,17 @@ public class AuthenticationProviderService {
|
|||||||
* If required properties are missing, and thus the user DN cannot be
|
* If required properties are missing, and thus the user DN cannot be
|
||||||
* determined.
|
* determined.
|
||||||
*/
|
*/
|
||||||
private Dn getUserBindDN(String username) throws GuacamoleException {
|
private Dn getUserBindDN(LDAPConfiguration config, String username)
|
||||||
|
throws GuacamoleException {
|
||||||
|
|
||||||
// If a search DN is provided, search the LDAP directory for the DN
|
// If a search DN is provided, search the LDAP directory for the DN
|
||||||
// corresponding to the given username
|
// corresponding to the given username
|
||||||
String searchBindLogon = confService.getSearchBindDN();
|
String searchBindLogon = config.getSearchBindDN();
|
||||||
if (searchBindLogon != null) {
|
if (searchBindLogon != null) {
|
||||||
|
|
||||||
// Create an LDAP connection using the search account
|
// Create an LDAP connection using the search account
|
||||||
LdapNetworkConnection searchConnection = ldapService.bindAs(
|
LdapNetworkConnection searchConnection = ldapService.bindAs(config,
|
||||||
searchBindLogon,
|
searchBindLogon, config.getSearchBindPassword());
|
||||||
confService.getSearchBindPassword()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Warn of failure to find
|
// Warn of failure to find
|
||||||
if (searchConnection == null) {
|
if (searchConnection == null) {
|
||||||
@@ -138,7 +142,7 @@ public class AuthenticationProviderService {
|
|||||||
try {
|
try {
|
||||||
|
|
||||||
// Retrieve all DNs associated with the given username
|
// Retrieve all DNs associated with the given username
|
||||||
List<Dn> userDNs = userService.getUserDNs(searchConnection, username);
|
List<Dn> userDNs = userService.getUserDNs(config, searchConnection, username);
|
||||||
if (userDNs.isEmpty())
|
if (userDNs.isEmpty())
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@@ -161,10 +165,89 @@ public class AuthenticationProviderService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, derive user DN from base DN
|
// Otherwise, derive user DN from base DN
|
||||||
return userService.deriveUserDN(username);
|
return userService.deriveUserDN(config, username);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new UserLDAPConfiguration that is connected to an LDAP server
|
||||||
|
* associated with the Guacamole 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. The Guacamole username will be
|
||||||
|
* internally translated to a fully-qualified LDAP DN according to the
|
||||||
|
* configuration of the LDAP server that is ultimately chosen.
|
||||||
|
*
|
||||||
|
* @param username
|
||||||
|
* The username of the Guacamole user to bind as.
|
||||||
|
*
|
||||||
|
* @param password
|
||||||
|
* The password of the user to bind as.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* A new UserLDAPConfiguration 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 UserLDAPConfiguration getLDAPConfiguration(String username,
|
||||||
|
String password) throws GuacamoleException {
|
||||||
|
|
||||||
|
// Get all LDAP server configurations
|
||||||
|
Collection<? extends LDAPConfiguration> configs = confService.getLDAPConfigurations();
|
||||||
|
if (configs.isEmpty()) {
|
||||||
|
logger.info("Skipping LDAP authentication as no LDAP servers are configured.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try each possible LDAP configuration until the TCP connection and
|
||||||
|
// authentication are successful
|
||||||
|
for (LDAPConfiguration config : configs) {
|
||||||
|
|
||||||
|
// Attempt connection only if username matches
|
||||||
|
String translatedUsername = config.appliesTo(username);
|
||||||
|
if (translatedUsername == null) {
|
||||||
|
logger.debug("LDAP server \"{}\" does not match username \"{}\".", config.getServerHostname(), username);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug("LDAP server \"{}\" matched username \"{}\" as \"{}\".",
|
||||||
|
config.getServerHostname(), username, translatedUsername);
|
||||||
|
|
||||||
|
// Derive DN of user within this LDAP server
|
||||||
|
Dn bindDn = getUserBindDN(config, translatedUsername);
|
||||||
|
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 UserLDAPConfiguration(config, translatedUsername, 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
|
* 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
|
||||||
@@ -196,39 +279,30 @@ public class AuthenticationProviderService {
|
|||||||
"Anonymous bind is not currently allowed by the LDAP"
|
"Anonymous bind is not currently allowed by the LDAP"
|
||||||
+ " authentication provider.", CredentialsInfo.USERNAME_PASSWORD);
|
+ " authentication provider.", CredentialsInfo.USERNAME_PASSWORD);
|
||||||
}
|
}
|
||||||
|
|
||||||
Dn bindDn = getUserBindDN(username);
|
UserLDAPConfiguration config = getLDAPConfiguration(username, password);
|
||||||
if (bindDn == null || bindDn.isEmpty()) {
|
if (config == null)
|
||||||
throw new GuacamoleInvalidCredentialsException("Unable to determine"
|
|
||||||
+ " DN of user " + username, CredentialsInfo.USERNAME_PASSWORD);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempt bind
|
|
||||||
LdapNetworkConnection ldapConnection =
|
|
||||||
ldapService.bindAs(bindDn.getName(), password);
|
|
||||||
if (ldapConnection == null)
|
|
||||||
throw new GuacamoleInvalidCredentialsException("Invalid login.",
|
throw new GuacamoleInvalidCredentialsException("Invalid login.",
|
||||||
CredentialsInfo.USERNAME_PASSWORD);
|
CredentialsInfo.USERNAME_PASSWORD);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// 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(config, config.getBindDN());
|
||||||
bindDn);
|
|
||||||
|
|
||||||
// Return AuthenticatedUser if bind succeeds
|
// Return AuthenticatedUser if bind succeeds
|
||||||
LDAPAuthenticatedUser authenticatedUser = authenticatedUserProvider.get();
|
LDAPAuthenticatedUser authenticatedUser = authenticatedUserProvider.get();
|
||||||
authenticatedUser.init(credentials, getAttributeTokens(ldapConnection,
|
authenticatedUser.init(config, credentials,
|
||||||
bindDn), effectiveGroups, bindDn);
|
getAttributeTokens(config), effectiveGroups);
|
||||||
|
|
||||||
return authenticatedUser;
|
return authenticatedUser;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always disconnect
|
catch (GuacamoleException | RuntimeException | Error e) {
|
||||||
finally {
|
config.close();
|
||||||
ldapConnection.close();
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -240,11 +314,8 @@ public class AuthenticationProviderService {
|
|||||||
* guacamole.properties. If no attributes are specified or none are
|
* guacamole.properties. If no attributes are specified or none are
|
||||||
* found on the LDAP user object, an empty map is returned.
|
* found on the LDAP user object, an empty map is returned.
|
||||||
*
|
*
|
||||||
* @param ldapConnection
|
* @param config
|
||||||
* LDAP connection to use to read the attributes of the user.
|
* The configuration of the LDAP server being queried.
|
||||||
*
|
|
||||||
* @param username
|
|
||||||
* The username of the user whose attributes are to be queried.
|
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* A map of parameter tokens generated from attributes on the user
|
* A map of parameter tokens generated from attributes on the user
|
||||||
@@ -255,11 +326,11 @@ public class AuthenticationProviderService {
|
|||||||
* @throws GuacamoleException
|
* @throws GuacamoleException
|
||||||
* 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(ConnectedLDAPConfiguration config)
|
||||||
Dn userDn) throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
// Get attributes from configuration information
|
// Get attributes from configuration information
|
||||||
List<String> attrList = confService.getAttributes();
|
List<String> attrList = config.getAttributes();
|
||||||
|
|
||||||
// If there are no attributes there is no reason to search LDAP
|
// If there are no attributes there is no reason to search LDAP
|
||||||
if (attrList.isEmpty())
|
if (attrList.isEmpty())
|
||||||
@@ -272,7 +343,7 @@ public class AuthenticationProviderService {
|
|||||||
try {
|
try {
|
||||||
|
|
||||||
// Get LDAP attributes by querying LDAP
|
// Get LDAP attributes by querying LDAP
|
||||||
Entry userEntry = ldapConnection.lookup(userDn, attrArray);
|
Entry userEntry = config.getLDAPConnection().lookup(config.getBindDN(), attrArray);
|
||||||
if (userEntry == null)
|
if (userEntry == null)
|
||||||
return Collections.<String, String>emptyMap();
|
return Collections.<String, String>emptyMap();
|
||||||
|
|
||||||
@@ -312,35 +383,26 @@ public class AuthenticationProviderService {
|
|||||||
public LDAPUserContext getUserContext(AuthenticatedUser authenticatedUser)
|
public LDAPUserContext getUserContext(AuthenticatedUser authenticatedUser)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
// Bind using credentials associated with AuthenticatedUser
|
|
||||||
Credentials credentials = authenticatedUser.getCredentials();
|
|
||||||
if (authenticatedUser instanceof LDAPAuthenticatedUser) {
|
if (authenticatedUser instanceof LDAPAuthenticatedUser) {
|
||||||
|
|
||||||
Dn bindDn = ((LDAPAuthenticatedUser) authenticatedUser).getBindDn();
|
LDAPAuthenticatedUser ldapAuthenticatedUser = (LDAPAuthenticatedUser) authenticatedUser;
|
||||||
LdapNetworkConnection ldapConnection =
|
ConnectedLDAPConfiguration config = ldapAuthenticatedUser.getLDAPConfiguration();
|
||||||
ldapService.bindAs(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);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// Build user context by querying LDAP
|
// Build user context by querying LDAP
|
||||||
LDAPUserContext userContext = userContextProvider.get();
|
LDAPUserContext userContext = userContextProvider.get();
|
||||||
userContext.init(authenticatedUser, ldapConnection);
|
userContext.init(ldapAuthenticatedUser);
|
||||||
return userContext;
|
return userContext;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always disconnect
|
// Always disconnect
|
||||||
finally {
|
finally {
|
||||||
ldapConnection.close();
|
config.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,220 @@
|
|||||||
|
/*
|
||||||
|
* 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 appliesTo(String username) throws GuacamoleException {
|
||||||
|
return config.appliesTo(username);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getServerHostname() throws GuacamoleException {
|
||||||
|
return config.getServerHostname();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getServerPort() throws GuacamoleException {
|
||||||
|
return config.getServerPort();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> 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<String> 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 int getNetworkTimeout() throws GuacamoleException {
|
||||||
|
return config.getNetworkTimeout();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getAttributes() throws GuacamoleException {
|
||||||
|
return config.getAttributes();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMemberAttribute() throws GuacamoleException {
|
||||||
|
return config.getMemberAttribute();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MemberAttributeType getMemberAttributeType() throws GuacamoleException {
|
||||||
|
return config.getMemberAttributeType();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
package org.apache.guacamole.auth.ldap;
|
package org.apache.guacamole.auth.ldap;
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
|
||||||
import org.apache.directory.api.ldap.model.exception.LdapAuthenticationException;
|
import org.apache.directory.api.ldap.model.exception.LdapAuthenticationException;
|
||||||
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.exception.LdapInvalidDnException;
|
||||||
@@ -34,8 +33,8 @@ 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;
|
||||||
import org.apache.guacamole.GuacamoleUnsupportedException;
|
import org.apache.guacamole.GuacamoleUnsupportedException;
|
||||||
import org.apache.guacamole.auth.ldap.conf.ConfigurationService;
|
|
||||||
import org.apache.guacamole.auth.ldap.conf.EncryptionMethod;
|
import org.apache.guacamole.auth.ldap.conf.EncryptionMethod;
|
||||||
|
import org.apache.guacamole.auth.ldap.conf.LDAPConfiguration;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -49,12 +48,6 @@ public class LDAPConnectionService {
|
|||||||
*/
|
*/
|
||||||
private static final Logger logger = LoggerFactory.getLogger(LDAPConnectionService.class);
|
private static final Logger logger = LoggerFactory.getLogger(LDAPConnectionService.class);
|
||||||
|
|
||||||
/**
|
|
||||||
* Service for retrieving LDAP server configuration information.
|
|
||||||
*/
|
|
||||||
@Inject
|
|
||||||
private ConfigurationService confService;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance of LdapNetworkConnection, configured as required
|
* Creates a new instance of LdapNetworkConnection, configured as required
|
||||||
* to use the given encryption method to communicate with the LDAP server
|
* to use the given encryption method to communicate with the LDAP server
|
||||||
@@ -74,6 +67,10 @@ public class LDAPConnectionService {
|
|||||||
* The encryption method that should be used to communicate with the
|
* The encryption method that should be used to communicate with the
|
||||||
* LDAP server.
|
* LDAP server.
|
||||||
*
|
*
|
||||||
|
* @param timeout
|
||||||
|
* The maximum number of milliseconds to wait for a response from the
|
||||||
|
* LDAP server.
|
||||||
|
*
|
||||||
* @return
|
* @return
|
||||||
* A new instance of LdapNetworkConnection which uses the given
|
* A new instance of LdapNetworkConnection which uses the given
|
||||||
* encryption method to communicate with the LDAP server at the given
|
* encryption method to communicate with the LDAP server at the given
|
||||||
@@ -84,11 +81,13 @@ public class LDAPConnectionService {
|
|||||||
* bug).
|
* bug).
|
||||||
*/
|
*/
|
||||||
private LdapNetworkConnection createLDAPConnection(String host, int port,
|
private LdapNetworkConnection createLDAPConnection(String host, int port,
|
||||||
EncryptionMethod encryptionMethod) throws GuacamoleException {
|
EncryptionMethod encryptionMethod, int timeout)
|
||||||
|
throws GuacamoleException {
|
||||||
|
|
||||||
LdapConnectionConfig config = new LdapConnectionConfig();
|
LdapConnectionConfig config = new LdapConnectionConfig();
|
||||||
config.setLdapHost(host);
|
config.setLdapHost(host);
|
||||||
config.setLdapPort(port);
|
config.setLdapPort(port);
|
||||||
|
config.setTimeout(timeout);
|
||||||
|
|
||||||
// Map encryption method to proper connection and socket factory
|
// Map encryption method to proper connection and socket factory
|
||||||
switch (encryptionMethod) {
|
switch (encryptionMethod) {
|
||||||
@@ -130,6 +129,9 @@ public class LDAPConnectionService {
|
|||||||
* requested, and will not be connected until it is used in an LDAP
|
* requested, and will not be connected until it is used in an LDAP
|
||||||
* operation (such as a bind).
|
* operation (such as a bind).
|
||||||
*
|
*
|
||||||
|
* @param config
|
||||||
|
* The configuration of the LDAP server being queried.
|
||||||
|
*
|
||||||
* @return
|
* @return
|
||||||
* A new LdapNetworkConnection instance which has already been
|
* A new LdapNetworkConnection instance which has already been
|
||||||
* configured to use the encryption method, hostname, and port
|
* configured to use the encryption method, hostname, and port
|
||||||
@@ -139,12 +141,13 @@ public class LDAPConnectionService {
|
|||||||
* If an error occurs while parsing guacamole.properties, or if the
|
* If an error occurs while parsing guacamole.properties, or if the
|
||||||
* requested encryption method is actually not implemented (a bug).
|
* requested encryption method is actually not implemented (a bug).
|
||||||
*/
|
*/
|
||||||
private LdapNetworkConnection createLDAPConnection()
|
private LdapNetworkConnection createLDAPConnection(LDAPConfiguration config)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
return createLDAPConnection(
|
return createLDAPConnection(
|
||||||
confService.getServerHostname(),
|
config.getServerHostname(),
|
||||||
confService.getServerPort(),
|
config.getServerPort(),
|
||||||
confService.getEncryptionMethod());
|
config.getEncryptionMethod(),
|
||||||
|
config.getNetworkTimeout());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -156,6 +159,9 @@ public class LDAPConnectionService {
|
|||||||
* requested, and will not be connected until it is used in an LDAP
|
* requested, and will not be connected until it is used in an LDAP
|
||||||
* operation (such as a bind).
|
* operation (such as a bind).
|
||||||
*
|
*
|
||||||
|
* @param config
|
||||||
|
* The configuration of the LDAP server being queried.
|
||||||
|
*
|
||||||
* @param url
|
* @param url
|
||||||
* The LDAP URL containing the details which should be used to connect
|
* The LDAP URL containing the details which should be used to connect
|
||||||
* to the LDAP server.
|
* to the LDAP server.
|
||||||
@@ -170,8 +176,8 @@ public class LDAPConnectionService {
|
|||||||
* method indicated by the URL is known but not actually implemented (a
|
* method indicated by the URL is known but not actually implemented (a
|
||||||
* bug).
|
* bug).
|
||||||
*/
|
*/
|
||||||
private LdapNetworkConnection createLDAPConnection(String url)
|
private LdapNetworkConnection createLDAPConnection(LDAPConfiguration config,
|
||||||
throws GuacamoleException {
|
String url) throws GuacamoleException {
|
||||||
|
|
||||||
// Parse provided LDAP URL
|
// Parse provided LDAP URL
|
||||||
LdapUrl ldapUrl;
|
LdapUrl ldapUrl;
|
||||||
@@ -197,7 +203,7 @@ public class LDAPConnectionService {
|
|||||||
|
|
||||||
// Use STARTTLS for otherwise unencrypted ldap:// URLs if the main
|
// Use STARTTLS for otherwise unencrypted ldap:// URLs if the main
|
||||||
// LDAP connection requires STARTTLS
|
// LDAP connection requires STARTTLS
|
||||||
else if (confService.getEncryptionMethod() == EncryptionMethod.STARTTLS) {
|
else if (config.getEncryptionMethod() == EncryptionMethod.STARTTLS) {
|
||||||
logger.debug("Using STARTTLS for LDAP URL \"{}\" as the main LDAP "
|
logger.debug("Using STARTTLS for LDAP URL \"{}\" as the main LDAP "
|
||||||
+ "connection described in guacamole.properties is "
|
+ "connection described in guacamole.properties is "
|
||||||
+ "configured to use STARTTLS.", url);
|
+ "configured to use STARTTLS.", url);
|
||||||
@@ -210,7 +216,8 @@ public class LDAPConnectionService {
|
|||||||
if (port < 1)
|
if (port < 1)
|
||||||
port = encryptionMethod.DEFAULT_PORT;
|
port = encryptionMethod.DEFAULT_PORT;
|
||||||
|
|
||||||
return createLDAPConnection(host, port, encryptionMethod);
|
return createLDAPConnection(host, port, encryptionMethod,
|
||||||
|
config.getNetworkTimeout());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,6 +336,9 @@ public class LDAPConnectionService {
|
|||||||
* hostname, port, and encryption method of the LDAP server are determined
|
* hostname, port, and encryption method of the LDAP server are determined
|
||||||
* from guacamole.properties.
|
* from guacamole.properties.
|
||||||
*
|
*
|
||||||
|
* @param config
|
||||||
|
* The configuration of the LDAP server being queried.
|
||||||
|
*
|
||||||
* @param bindUser
|
* @param bindUser
|
||||||
* The DN or UPN of the user to bind as, or null to bind anonymously.
|
* The DN or UPN of the user to bind as, or null to bind anonymously.
|
||||||
*
|
*
|
||||||
@@ -344,15 +354,18 @@ public class LDAPConnectionService {
|
|||||||
* If an error occurs while parsing guacamole.properties, or if the
|
* If an error occurs while parsing guacamole.properties, or if the
|
||||||
* configured encryption method is actually not implemented (a bug).
|
* configured encryption method is actually not implemented (a bug).
|
||||||
*/
|
*/
|
||||||
public LdapNetworkConnection bindAs(String bindUser, String password)
|
public LdapNetworkConnection bindAs(LDAPConfiguration config,
|
||||||
throws GuacamoleException {
|
String bindUser, String password) throws GuacamoleException {
|
||||||
return bindAs(createLDAPConnection(), bindUser, password);
|
return bindAs(createLDAPConnection(config), bindUser, password);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Binds to the LDAP server indicated by the given LDAP URL using the
|
* Binds to the LDAP server indicated by the given LDAP URL using the
|
||||||
* credentials that were used to bind an existing LdapNetworkConnection.
|
* credentials that were used to bind an existing LdapNetworkConnection.
|
||||||
*
|
*
|
||||||
|
* @param config
|
||||||
|
* The configuration of the LDAP server being queried.
|
||||||
|
*
|
||||||
* @param url
|
* @param url
|
||||||
* The LDAP URL containing the details which should be used to connect
|
* The LDAP URL containing the details which should be used to connect
|
||||||
* to the LDAP server.
|
* to the LDAP server.
|
||||||
@@ -370,16 +383,19 @@ public class LDAPConnectionService {
|
|||||||
* method indicated by the URL is known but not actually implemented (a
|
* method indicated by the URL is known but not actually implemented (a
|
||||||
* bug).
|
* bug).
|
||||||
*/
|
*/
|
||||||
public LdapNetworkConnection bindAs(String url,
|
public LdapNetworkConnection bindAs(LDAPConfiguration config, String url,
|
||||||
LdapNetworkConnection useCredentialsFrom)
|
LdapNetworkConnection useCredentialsFrom)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
return bindAs(createLDAPConnection(url), useCredentialsFrom);
|
return bindAs(createLDAPConnection(config, url), useCredentialsFrom);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a SearchRequest object using the given Base DN and filter
|
* Generate a SearchRequest object using the given Base DN and filter
|
||||||
* and retrieving other properties from the LDAP configuration service.
|
* and retrieving other properties from the LDAP configuration service.
|
||||||
*
|
*
|
||||||
|
* @param config
|
||||||
|
* The configuration of the LDAP server being queried.
|
||||||
|
*
|
||||||
* @param baseDn
|
* @param baseDn
|
||||||
* The LDAP Base DN at which to search the search.
|
* The LDAP Base DN at which to search the search.
|
||||||
*
|
*
|
||||||
@@ -392,19 +408,19 @@ public class LDAPConnectionService {
|
|||||||
* @throws GuacamoleException
|
* @throws GuacamoleException
|
||||||
* If an error occurs retrieving any of the configuration values.
|
* If an error occurs retrieving any of the configuration values.
|
||||||
*/
|
*/
|
||||||
public SearchRequest getSearchRequest(Dn baseDn, ExprNode filter)
|
public SearchRequest getSearchRequest(LDAPConfiguration config, Dn baseDn,
|
||||||
throws GuacamoleException {
|
ExprNode filter) throws GuacamoleException {
|
||||||
|
|
||||||
SearchRequest searchRequest = new SearchRequestImpl();
|
SearchRequest searchRequest = new SearchRequestImpl();
|
||||||
searchRequest.setBase(baseDn);
|
searchRequest.setBase(baseDn);
|
||||||
searchRequest.setDerefAliases(confService.getDereferenceAliases());
|
searchRequest.setDerefAliases(config.getDereferenceAliases());
|
||||||
searchRequest.setScope(SearchScope.SUBTREE);
|
searchRequest.setScope(SearchScope.SUBTREE);
|
||||||
searchRequest.setFilter(filter);
|
searchRequest.setFilter(filter);
|
||||||
searchRequest.setSizeLimit(confService.getMaxResults());
|
searchRequest.setSizeLimit(config.getMaxResults());
|
||||||
searchRequest.setTimeLimit(confService.getOperationTimeout());
|
searchRequest.setTimeLimit(config.getOperationTimeout());
|
||||||
searchRequest.setTypesOnly(false);
|
searchRequest.setTypesOnly(false);
|
||||||
|
|
||||||
if (confService.getFollowReferrals())
|
if (config.getFollowReferrals())
|
||||||
searchRequest.followReferrals();
|
searchRequest.followReferrals();
|
||||||
|
|
||||||
return searchRequest;
|
return searchRequest;
|
||||||
|
@@ -44,7 +44,7 @@ import org.apache.directory.api.ldap.model.name.Dn;
|
|||||||
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;
|
||||||
import org.apache.guacamole.auth.ldap.conf.ConfigurationService;
|
import org.apache.guacamole.auth.ldap.conf.LDAPConfiguration;
|
||||||
import org.apache.guacamole.auth.ldap.conf.LDAPGuacamoleProperties;
|
import org.apache.guacamole.auth.ldap.conf.LDAPGuacamoleProperties;
|
||||||
import org.apache.guacamole.net.auth.Identifiable;
|
import org.apache.guacamole.net.auth.Identifiable;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -70,12 +70,6 @@ public class ObjectQueryService {
|
|||||||
@Inject
|
@Inject
|
||||||
private LDAPConnectionService ldapService;
|
private LDAPConnectionService ldapService;
|
||||||
|
|
||||||
/**
|
|
||||||
* Service for retrieving LDAP server configuration information.
|
|
||||||
*/
|
|
||||||
@Inject
|
|
||||||
private ConfigurationService confService;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the identifier of the object represented by the given LDAP
|
* Returns the identifier of the object represented by the given LDAP
|
||||||
* entry. Multiple attributes may be declared as containing the identifier
|
* entry. Multiple attributes may be declared as containing the identifier
|
||||||
@@ -184,6 +178,9 @@ public class ObjectQueryService {
|
|||||||
* list of all results. Only objects beneath the given base DN are
|
* list of all results. Only objects beneath the given base DN are
|
||||||
* included in the search.
|
* included in the search.
|
||||||
*
|
*
|
||||||
|
* @param config
|
||||||
|
* The configuration of the LDAP server being queried.
|
||||||
|
*
|
||||||
* @param ldapConnection
|
* @param ldapConnection
|
||||||
* The current connection to the LDAP server, associated with the
|
* The current connection to the LDAP server, associated with the
|
||||||
* current user.
|
* current user.
|
||||||
@@ -212,12 +209,13 @@ public class ObjectQueryService {
|
|||||||
* information required to execute the query cannot be read from
|
* information required to execute the query cannot be read from
|
||||||
* guacamole.properties.
|
* guacamole.properties.
|
||||||
*/
|
*/
|
||||||
public List<Entry> search(LdapNetworkConnection ldapConnection,
|
public List<Entry> search(LDAPConfiguration config,
|
||||||
Dn baseDN, ExprNode query, int searchHop,
|
LdapNetworkConnection ldapConnection, Dn baseDN, ExprNode query,
|
||||||
Collection<String> attributes) throws GuacamoleException {
|
int searchHop, Collection<String> attributes)
|
||||||
|
throws GuacamoleException {
|
||||||
|
|
||||||
// Refuse to follow referrals if limit has been reached
|
// Refuse to follow referrals if limit has been reached
|
||||||
int maxHops = confService.getMaxReferralHops();
|
int maxHops = config.getMaxReferralHops();
|
||||||
if (searchHop >= maxHops) {
|
if (searchHop >= maxHops) {
|
||||||
logger.debug("Refusing to follow further referrals as the maximum "
|
logger.debug("Refusing to follow further referrals as the maximum "
|
||||||
+ "number of referral hops ({}) has been reached. LDAP "
|
+ "number of referral hops ({}) has been reached. LDAP "
|
||||||
@@ -230,8 +228,7 @@ public class ObjectQueryService {
|
|||||||
logger.debug("Searching \"{}\" for objects matching \"{}\".", baseDN, query);
|
logger.debug("Searching \"{}\" for objects matching \"{}\".", baseDN, query);
|
||||||
|
|
||||||
// Search within subtree of given base DN
|
// Search within subtree of given base DN
|
||||||
SearchRequest request = ldapService.getSearchRequest(baseDN, query);
|
SearchRequest request = ldapService.getSearchRequest(config, baseDN, query);
|
||||||
|
|
||||||
if (attributes != null)
|
if (attributes != null)
|
||||||
request.addAttributes(attributes.toArray(new String[0]));
|
request.addAttributes(attributes.toArray(new String[0]));
|
||||||
|
|
||||||
@@ -257,10 +254,10 @@ public class ObjectQueryService {
|
|||||||
|
|
||||||
// Connect to referred LDAP server to retrieve further results, ensuring the network
|
// Connect to referred LDAP server to retrieve further results, ensuring the network
|
||||||
// connection is always closed when it will no longer be used
|
// connection is always closed when it will no longer be used
|
||||||
try (LdapNetworkConnection referralConnection = ldapService.bindAs(url, ldapConnection)) {
|
try (LdapNetworkConnection referralConnection = ldapService.bindAs(config, url, ldapConnection)) {
|
||||||
if (referralConnection != null) {
|
if (referralConnection != null) {
|
||||||
logger.debug("Following referral to \"{}\"...", url);
|
logger.debug("Following referral to \"{}\"...", url);
|
||||||
entries.addAll(search(referralConnection, baseDN, query, searchHop + 1, attributes));
|
entries.addAll(search(config, referralConnection, baseDN, query, searchHop + 1, attributes));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
logger.debug("Could not bind with LDAP "
|
logger.debug("Could not bind with LDAP "
|
||||||
@@ -304,6 +301,9 @@ public class ObjectQueryService {
|
|||||||
* given connection, returning a list of all results. Only objects beneath
|
* given connection, returning a list of all results. Only objects beneath
|
||||||
* the given base DN are included in the search.
|
* the given base DN are included in the search.
|
||||||
*
|
*
|
||||||
|
* @param config
|
||||||
|
* The configuration of the LDAP server being queried.
|
||||||
|
*
|
||||||
* @param ldapConnection
|
* @param ldapConnection
|
||||||
* The current connection to the LDAP server, associated with the
|
* The current connection to the LDAP server, associated with the
|
||||||
* current user.
|
* current user.
|
||||||
@@ -339,12 +339,12 @@ public class ObjectQueryService {
|
|||||||
* information required to execute the query cannot be read from
|
* information required to execute the query cannot be read from
|
||||||
* guacamole.properties.
|
* guacamole.properties.
|
||||||
*/
|
*/
|
||||||
public List<Entry> search(LdapNetworkConnection ldapConnection, Dn baseDN,
|
public List<Entry> search(LDAPConfiguration config,
|
||||||
ExprNode filter, Collection<String> filterAttributes, String filterValue,
|
LdapNetworkConnection ldapConnection, Dn baseDN, ExprNode filter,
|
||||||
Collection<String> attributes)
|
Collection<String> filterAttributes, String filterValue,
|
||||||
throws GuacamoleException {
|
Collection<String> attributes) throws GuacamoleException {
|
||||||
ExprNode query = generateQuery(filter, filterAttributes, filterValue);
|
ExprNode query = generateQuery(filter, filterAttributes, filterValue);
|
||||||
return search(ldapConnection, baseDN, query, 0, attributes);
|
return search(config, ldapConnection, baseDN, query, 0, attributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* 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.conf;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonParseException;
|
||||||
|
import com.fasterxml.jackson.core.JsonParser;
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.core.JsonToken;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||||
|
import com.fasterxml.jackson.databind.deser.std.StdScalarDeserializer;
|
||||||
|
import com.fasterxml.jackson.databind.type.LogicalType;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.regex.PatternSyntaxException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom JSON (or YAML) deserializer for Jackson that deserializes string
|
||||||
|
* values as Patterns with the case insensitive flag set by default. Jackson
|
||||||
|
* will actually handle deserialization of Patterns automatically, but does not
|
||||||
|
* provide for setting the default flags.
|
||||||
|
*/
|
||||||
|
public class CaseInsensitivePatternDeserializer extends StdScalarDeserializer<Pattern> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unique version identifier of this {@link Serializable} class.
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new CaseInsensitivePatternDeserializer which deserializes
|
||||||
|
* string values to Pattern objects with the case insensitive flag set.
|
||||||
|
*/
|
||||||
|
public CaseInsensitivePatternDeserializer() {
|
||||||
|
super(Pattern.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LogicalType logicalType() {
|
||||||
|
return LogicalType.Textual;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCachable() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Pattern deserialize(JsonParser parser, DeserializationContext context)
|
||||||
|
throws IOException, JsonProcessingException {
|
||||||
|
|
||||||
|
if (!parser.hasToken(JsonToken.VALUE_STRING))
|
||||||
|
throw new JsonParseException(parser, "Regular expressions may only be represented as strings.");
|
||||||
|
|
||||||
|
try {
|
||||||
|
return Pattern.compile(parser.getText(), Pattern.CASE_INSENSITIVE);
|
||||||
|
}
|
||||||
|
catch (PatternSyntaxException e) {
|
||||||
|
throw new JsonParseException(parser, "Invalid regular expression.", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -19,21 +19,57 @@
|
|||||||
|
|
||||||
package org.apache.guacamole.auth.ldap.conf;
|
package org.apache.guacamole.auth.ldap.conf;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||||
|
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Singleton;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
import org.apache.directory.api.ldap.model.filter.ExprNode;
|
import java.util.regex.Pattern;
|
||||||
import org.apache.directory.api.ldap.model.filter.PresenceNode;
|
|
||||||
import org.apache.directory.api.ldap.model.message.AliasDerefMode;
|
|
||||||
import org.apache.directory.api.ldap.model.name.Dn;
|
|
||||||
import org.apache.guacamole.GuacamoleException;
|
import org.apache.guacamole.GuacamoleException;
|
||||||
import org.apache.guacamole.environment.Environment;
|
import org.apache.guacamole.environment.Environment;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service for retrieving configuration information regarding the LDAP server.
|
* Service for retrieving configuration information regarding LDAP servers.
|
||||||
*/
|
*/
|
||||||
|
@Singleton
|
||||||
public class ConfigurationService {
|
public class ConfigurationService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logger for this class.
|
||||||
|
*/
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(ConfigurationService.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ObjectMapper for deserializing YAML.
|
||||||
|
*/
|
||||||
|
private final ObjectMapper mapper = new ObjectMapper(new YAMLFactory())
|
||||||
|
.registerModule(new SimpleModule().addDeserializer(Pattern.class, new CaseInsensitivePatternDeserializer()));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the file within GUACAMOLE_HOME that defines each available
|
||||||
|
* LDAP server (if not using guacamole.properties).
|
||||||
|
*/
|
||||||
|
private static final String LDAP_SERVERS_YML = "ldap-servers.yml";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The timestamp that the {@link #LDAP_SERVERS_YML} was last modified when
|
||||||
|
* it was read, as would be returned by {@link File#lastModified()}.
|
||||||
|
*/
|
||||||
|
private final AtomicLong lastModified = new AtomicLong(0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cached copy of the configuration read from {@link #LDAP_SERVERS_YML}.
|
||||||
|
*/
|
||||||
|
private Collection<JacksonLDAPConfiguration> cachedConfigurations = Collections.emptyList();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Guacamole server environment.
|
* The Guacamole server environment.
|
||||||
*/
|
*/
|
||||||
@@ -41,375 +77,56 @@ public class ConfigurationService {
|
|||||||
private Environment environment;
|
private Environment environment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the hostname of the LDAP server as configured with
|
* Returns the configuration information for all configured LDAP servers.
|
||||||
* guacamole.properties. By default, this will be "localhost".
|
* If multiple servers are returned, each should be tried in order until a
|
||||||
|
* successful LDAP connection is established.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* The hostname of the LDAP server, as configured with
|
* The configurations of all LDAP servers.
|
||||||
* guacamole.properties.
|
|
||||||
*
|
*
|
||||||
* @throws GuacamoleException
|
* @throws GuacamoleException
|
||||||
* If guacamole.properties cannot be parsed.
|
* If the configuration information of the LDAP servers cannot be
|
||||||
|
* retrieved due to an error.
|
||||||
*/
|
*/
|
||||||
public String getServerHostname() throws GuacamoleException {
|
public Collection<? extends LDAPConfiguration> getLDAPConfigurations() throws GuacamoleException {
|
||||||
return environment.getProperty(
|
|
||||||
LDAPGuacamoleProperties.LDAP_HOSTNAME,
|
|
||||||
"localhost"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
// Read configuration from YAML, if available
|
||||||
* Returns the port of the LDAP server configured with
|
File ldapServers = new File(environment.getGuacamoleHome(), LDAP_SERVERS_YML);
|
||||||
* guacamole.properties. The default value depends on which encryption
|
if (ldapServers.exists()) {
|
||||||
* method is being used. For unencrypted LDAP and STARTTLS, this will be
|
|
||||||
* 389. For LDAPS (LDAP over SSL) this will be 636.
|
|
||||||
*
|
|
||||||
* @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,
|
|
||||||
getEncryptionMethod().DEFAULT_PORT
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
long oldLastModified = lastModified.get();
|
||||||
* Returns all username attributes which should be used to query and bind
|
long currentLastModified = ldapServers.lastModified();
|
||||||
* users using the LDAP directory. By default, this will be "uid" - a
|
|
||||||
* common attribute used for this purpose.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The username attributes which should be used to query and bind users
|
|
||||||
* using the LDAP directory.
|
|
||||||
*
|
|
||||||
* @throws GuacamoleException
|
|
||||||
* If guacamole.properties cannot be parsed.
|
|
||||||
*/
|
|
||||||
public List<String> getUsernameAttributes() throws GuacamoleException {
|
|
||||||
return environment.getProperty(
|
|
||||||
LDAPGuacamoleProperties.LDAP_USERNAME_ATTRIBUTE,
|
|
||||||
Collections.singletonList("uid")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
// Update cached copy of YAML if things have changed, ensuring only
|
||||||
* Returns the base DN under which all Guacamole users will be stored
|
// one concurrent request updates the cache at any given time
|
||||||
* within the LDAP directory.
|
if (currentLastModified > oldLastModified && lastModified.compareAndSet(oldLastModified, currentLastModified)) {
|
||||||
*
|
try {
|
||||||
* @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 Dn getUserBaseDN() throws GuacamoleException {
|
|
||||||
return environment.getRequiredProperty(
|
|
||||||
LDAPGuacamoleProperties.LDAP_USER_BASE_DN
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
logger.debug("Reading updated LDAP configuration from \"{}\"...", ldapServers);
|
||||||
* Returns the base DN under which all Guacamole configurations
|
Collection<JacksonLDAPConfiguration> configs = mapper.readValue(ldapServers, new TypeReference<Collection<JacksonLDAPConfiguration>>() {});
|
||||||
* (connections) will be stored within the LDAP directory. If Guacamole
|
|
||||||
* configurations will not be stored within LDAP, null is returned.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The base DN under which all Guacamole configurations will be stored
|
|
||||||
* within the LDAP directory, or null if no Guacamole configurations
|
|
||||||
* will be stored within the LDAP directory.
|
|
||||||
*
|
|
||||||
* @throws GuacamoleException
|
|
||||||
* If guacamole.properties cannot be parsed.
|
|
||||||
*/
|
|
||||||
public Dn getConfigurationBaseDN() throws GuacamoleException {
|
|
||||||
return environment.getProperty(
|
|
||||||
LDAPGuacamoleProperties.LDAP_CONFIG_BASE_DN
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
logger.debug("Reading LDAP configuration defaults from guacamole.properties...");
|
||||||
* Returns all attributes which should be used to determine the unique
|
LDAPConfiguration defaultConfig = new EnvironmentLDAPConfiguration(environment);
|
||||||
* identifier of each user group. By default, this will be "cn".
|
configs.forEach((config) -> config.setDefaults(defaultConfig));
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The attributes which should be used to determine the unique
|
|
||||||
* identifier of each group.
|
|
||||||
*
|
|
||||||
* @throws GuacamoleException
|
|
||||||
* If guacamole.properties cannot be parsed.
|
|
||||||
*/
|
|
||||||
public List<String> getGroupNameAttributes() throws GuacamoleException {
|
|
||||||
return environment.getProperty(
|
|
||||||
LDAPGuacamoleProperties.LDAP_GROUP_NAME_ATTRIBUTE,
|
|
||||||
Collections.singletonList("cn")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
cachedConfigurations = configs;
|
||||||
* Returns the base DN under which all Guacamole role based access control
|
|
||||||
* (RBAC) groups will be stored within the LDAP directory. If RBAC will not
|
|
||||||
* be used, null is returned.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The base DN under which all Guacamole RBAC groups will be stored
|
|
||||||
* within the LDAP directory, or null if RBAC will not be used.
|
|
||||||
*
|
|
||||||
* @throws GuacamoleException
|
|
||||||
* If guacamole.properties cannot be parsed.
|
|
||||||
*/
|
|
||||||
public Dn getGroupBaseDN() throws GuacamoleException {
|
|
||||||
return environment.getProperty(
|
|
||||||
LDAPGuacamoleProperties.LDAP_GROUP_BASE_DN
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
}
|
||||||
* Returns the login that should be used when searching for the DNs of users
|
catch (IOException e) {
|
||||||
* attempting to authenticate. If no such search should be performed, null
|
logger.error("\"{}\" could not be read/parsed: {}", ldapServers, e.getMessage());
|
||||||
* is returned.
|
}
|
||||||
*
|
}
|
||||||
* @return
|
else
|
||||||
* The DN that should be used when searching for the DNs of users
|
logger.debug("Using cached LDAP configuration from \"{}\".", ldapServers);
|
||||||
* attempting to authenticate, or null if no such search should be
|
|
||||||
* performed.
|
|
||||||
*
|
|
||||||
* @throws GuacamoleException
|
|
||||||
* If guacamole.properties cannot be parsed.
|
|
||||||
*/
|
|
||||||
public String getSearchBindDN() throws GuacamoleException {
|
|
||||||
return environment.getProperty(
|
|
||||||
LDAPGuacamoleProperties.LDAP_SEARCH_BIND_DN
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
return cachedConfigurations;
|
||||||
* Returns the password that should be used when binding to the LDAP server
|
|
||||||
* using the DN returned by getSearchBindDN(). If no password should be
|
|
||||||
* used, null is returned.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The password that should be used when binding to the LDAP server
|
|
||||||
* using the DN returned by getSearchBindDN(), or null if no password
|
|
||||||
* should be used.
|
|
||||||
*
|
|
||||||
* @throws GuacamoleException
|
|
||||||
* If guacamole.properties cannot be parsed.
|
|
||||||
*/
|
|
||||||
public String getSearchBindPassword() throws GuacamoleException {
|
|
||||||
return environment.getProperty(
|
|
||||||
LDAPGuacamoleProperties.LDAP_SEARCH_BIND_PASSWORD
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
}
|
||||||
* Returns the encryption method that should be used when connecting to the
|
|
||||||
* LDAP server. By default, no encryption is used.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The encryption method that should be used when connecting to the
|
|
||||||
* LDAP server.
|
|
||||||
*
|
|
||||||
* @throws GuacamoleException
|
|
||||||
* If guacamole.properties cannot be parsed.
|
|
||||||
*/
|
|
||||||
public EncryptionMethod getEncryptionMethod() throws GuacamoleException {
|
|
||||||
return environment.getProperty(
|
|
||||||
LDAPGuacamoleProperties.LDAP_ENCRYPTION_METHOD,
|
|
||||||
EncryptionMethod.NONE
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
// Use guacamole.properties if not using YAML
|
||||||
* Returns maximum number of results a LDAP query can return,
|
logger.debug("Reading LDAP configuration from guacamole.properties...");
|
||||||
* as configured with guacamole.properties.
|
return Collections.singletonList(new EnvironmentLDAPConfiguration(environment));
|
||||||
* By default, this will be 1000.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The maximum number of results a LDAP query can return,
|
|
||||||
* as configured with guacamole.properties.
|
|
||||||
*
|
|
||||||
* @throws GuacamoleException
|
|
||||||
* If guacamole.properties cannot be parsed.
|
|
||||||
*/
|
|
||||||
public int getMaxResults() throws GuacamoleException {
|
|
||||||
return environment.getProperty(
|
|
||||||
LDAPGuacamoleProperties.LDAP_MAX_SEARCH_RESULTS,
|
|
||||||
1000
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether or not LDAP aliases will be dereferenced,
|
|
||||||
* as configured with guacamole.properties. The default
|
|
||||||
* behavior if not explicitly defined is to never
|
|
||||||
* dereference them.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The behavior for handling dereferencing of aliases
|
|
||||||
* as configured in guacamole.properties.
|
|
||||||
*
|
|
||||||
* @throws GuacamoleException
|
|
||||||
* If guacamole.properties cannot be parsed.
|
|
||||||
*/
|
|
||||||
public AliasDerefMode getDereferenceAliases() throws GuacamoleException {
|
|
||||||
return environment.getProperty(
|
|
||||||
LDAPGuacamoleProperties.LDAP_DEREFERENCE_ALIASES,
|
|
||||||
AliasDerefMode.NEVER_DEREF_ALIASES
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the boolean value for whether the connection should
|
|
||||||
* follow referrals or not. By default, it will not.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The boolean value of whether to follow referrals
|
|
||||||
* as configured in guacamole.properties.
|
|
||||||
*
|
|
||||||
* @throws GuacamoleException
|
|
||||||
* If guacamole.properties cannot be parsed.
|
|
||||||
*/
|
|
||||||
public boolean getFollowReferrals() throws GuacamoleException {
|
|
||||||
return environment.getProperty(
|
|
||||||
LDAPGuacamoleProperties.LDAP_FOLLOW_REFERRALS,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the maximum number of referral hops to follow. By default
|
|
||||||
* a maximum of 5 hops is allowed.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The maximum number of referral hops to follow
|
|
||||||
* as configured in guacamole.properties.
|
|
||||||
*
|
|
||||||
* @throws GuacamoleException
|
|
||||||
* If guacamole.properties cannot be parsed.
|
|
||||||
*/
|
|
||||||
public int getMaxReferralHops() throws GuacamoleException {
|
|
||||||
return environment.getProperty(
|
|
||||||
LDAPGuacamoleProperties.LDAP_MAX_REFERRAL_HOPS,
|
|
||||||
5
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the search filter that should be used when querying the
|
|
||||||
* LDAP server for Guacamole users. If no filter is specified,
|
|
||||||
* a default of "(objectClass=user)" is returned.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The search filter that should be used when querying the
|
|
||||||
* LDAP server for users that are valid in Guacamole, or
|
|
||||||
* "(objectClass=user)" if not specified.
|
|
||||||
*
|
|
||||||
* @throws GuacamoleException
|
|
||||||
* If guacamole.properties cannot be parsed.
|
|
||||||
*/
|
|
||||||
public ExprNode getUserSearchFilter() throws GuacamoleException {
|
|
||||||
return environment.getProperty(
|
|
||||||
LDAPGuacamoleProperties.LDAP_USER_SEARCH_FILTER,
|
|
||||||
new PresenceNode("objectClass")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the search filter that should be used when querying the
|
|
||||||
* LDAP server for Guacamole groups. If no filter is specified,
|
|
||||||
* a default of "(objectClass=*)" is used.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The search filter that should be used when querying the
|
|
||||||
* LDAP server for groups that are valid in Guacamole, or
|
|
||||||
* "(objectClass=*)" if not specified.
|
|
||||||
*
|
|
||||||
* @throws GuacamoleException
|
|
||||||
* If guacamole.properties cannot be parsed.
|
|
||||||
*/
|
|
||||||
public ExprNode getGroupSearchFilter() throws GuacamoleException {
|
|
||||||
return environment.getProperty(
|
|
||||||
LDAPGuacamoleProperties.LDAP_GROUP_SEARCH_FILTER,
|
|
||||||
new PresenceNode("objectClass")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the maximum number of seconds to wait for LDAP operations.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The maximum number of seconds to wait for LDAP operations
|
|
||||||
* as configured in guacamole.properties.
|
|
||||||
*
|
|
||||||
* @throws GuacamoleException
|
|
||||||
* If guacamole.properties cannot be parsed.
|
|
||||||
*/
|
|
||||||
public int getOperationTimeout() throws GuacamoleException {
|
|
||||||
return environment.getProperty(
|
|
||||||
LDAPGuacamoleProperties.LDAP_OPERATION_TIMEOUT,
|
|
||||||
30
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns names for custom LDAP user attributes. By default no
|
|
||||||
* attributes will be returned.
|
|
||||||
*
|
|
||||||
* @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,
|
|
||||||
Collections.<String>emptyList()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the name of the LDAP attribute used to enumerate
|
|
||||||
* members in a group, or "member" by default.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The name of the LDAP attribute to use to enumerate
|
|
||||||
* members in a group.
|
|
||||||
*
|
|
||||||
* @throws GuacamoleException
|
|
||||||
* If guacamole.properties connect be parsed.
|
|
||||||
*/
|
|
||||||
public String getMemberAttribute() throws GuacamoleException {
|
|
||||||
return environment.getProperty(
|
|
||||||
LDAPGuacamoleProperties.LDAP_MEMBER_ATTRIBUTE,
|
|
||||||
"member"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether the LDAP attribute used to enumerate members in a group
|
|
||||||
* specifies UID or DN.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The type of data contained in the LDAP attribute used to enumerate
|
|
||||||
* members in a group, as configured in guacamole.properties
|
|
||||||
*
|
|
||||||
* @throws GuacamoleException
|
|
||||||
* If guacamole.properties cannot be parsed.
|
|
||||||
*/
|
|
||||||
public MemberAttributeType getMemberAttributeType()
|
|
||||||
throws GuacamoleException {
|
|
||||||
return environment.getProperty(
|
|
||||||
LDAPGuacamoleProperties.LDAP_MEMBER_ATTRIBUTE_TYPE,
|
|
||||||
MemberAttributeType.DN
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,149 @@
|
|||||||
|
/*
|
||||||
|
* 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.conf;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import org.apache.directory.api.ldap.model.filter.ExprNode;
|
||||||
|
import org.apache.directory.api.ldap.model.filter.PresenceNode;
|
||||||
|
import org.apache.directory.api.ldap.model.message.AliasDerefMode;
|
||||||
|
import org.apache.directory.api.ldap.model.name.Dn;
|
||||||
|
import org.apache.guacamole.GuacamoleException;
|
||||||
|
import org.apache.guacamole.GuacamoleServerException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LDAPConfiguration implementation that returns the default values for all
|
||||||
|
* configuration parameters. For any configuration parameters that are
|
||||||
|
* required (such as {@link #getUserBaseDN()}), an exception is thrown.
|
||||||
|
*/
|
||||||
|
public class DefaultLDAPConfiguration implements LDAPConfiguration {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String appliesTo(String username) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getServerHostname() {
|
||||||
|
return "localhost";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getServerPort() {
|
||||||
|
return getEncryptionMethod().DEFAULT_PORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getUsernameAttributes() {
|
||||||
|
return Collections.singletonList("uid");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dn getUserBaseDN() throws GuacamoleException {
|
||||||
|
throw new GuacamoleServerException("All LDAP servers must have a defined user base DN.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dn getConfigurationBaseDN() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getGroupNameAttributes() {
|
||||||
|
return Collections.singletonList("cn");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dn getGroupBaseDN() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSearchBindDN() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSearchBindPassword() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EncryptionMethod getEncryptionMethod() {
|
||||||
|
return EncryptionMethod.NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxResults() {
|
||||||
|
return 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AliasDerefMode getDereferenceAliases() {
|
||||||
|
return AliasDerefMode.NEVER_DEREF_ALIASES;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getFollowReferrals() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxReferralHops() {
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ExprNode getUserSearchFilter() {
|
||||||
|
return new PresenceNode("objectClass");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ExprNode getGroupSearchFilter() {
|
||||||
|
return new PresenceNode("objectClass");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOperationTimeout() {
|
||||||
|
return 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNetworkTimeout() {
|
||||||
|
return 30000;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getAttributes() {
|
||||||
|
return Collections.<String>emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMemberAttribute() {
|
||||||
|
return "member";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MemberAttributeType getMemberAttributeType()
|
||||||
|
throws GuacamoleException {
|
||||||
|
return MemberAttributeType.DN;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,229 @@
|
|||||||
|
/*
|
||||||
|
* 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.conf;
|
||||||
|
|
||||||
|
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.guacamole.GuacamoleException;
|
||||||
|
import org.apache.guacamole.environment.Environment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LDAPConfiguration implementation that reads its configuration details from
|
||||||
|
* guacamole.properties.
|
||||||
|
*/
|
||||||
|
public class EnvironmentLDAPConfiguration implements LDAPConfiguration {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Guacamole server environment.
|
||||||
|
*/
|
||||||
|
private final Environment environment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default configuration options for all parameters.
|
||||||
|
*/
|
||||||
|
private static final LDAPConfiguration DEFAULT = new DefaultLDAPConfiguration();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new EnvironmentLDAPConfiguration that reads its configuration
|
||||||
|
* details from guacamole.properties, as exposed by the given Environment.
|
||||||
|
*
|
||||||
|
* @param environment
|
||||||
|
* The Guacamole server environment.
|
||||||
|
*/
|
||||||
|
public EnvironmentLDAPConfiguration(Environment environment) {
|
||||||
|
this.environment = environment;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String appliesTo(String username) throws GuacamoleException {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getServerHostname() throws GuacamoleException {
|
||||||
|
return environment.getProperty(
|
||||||
|
LDAPGuacamoleProperties.LDAP_HOSTNAME,
|
||||||
|
DEFAULT.getServerHostname()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getServerPort() throws GuacamoleException {
|
||||||
|
return environment.getProperty(
|
||||||
|
LDAPGuacamoleProperties.LDAP_PORT,
|
||||||
|
getEncryptionMethod().DEFAULT_PORT
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getUsernameAttributes() throws GuacamoleException {
|
||||||
|
return environment.getProperty(
|
||||||
|
LDAPGuacamoleProperties.LDAP_USERNAME_ATTRIBUTE,
|
||||||
|
DEFAULT.getUsernameAttributes()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dn getUserBaseDN() throws GuacamoleException {
|
||||||
|
return environment.getRequiredProperty(
|
||||||
|
LDAPGuacamoleProperties.LDAP_USER_BASE_DN
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dn getConfigurationBaseDN() throws GuacamoleException {
|
||||||
|
return environment.getProperty(
|
||||||
|
LDAPGuacamoleProperties.LDAP_CONFIG_BASE_DN,
|
||||||
|
DEFAULT.getConfigurationBaseDN()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getGroupNameAttributes() throws GuacamoleException {
|
||||||
|
return environment.getProperty(
|
||||||
|
LDAPGuacamoleProperties.LDAP_GROUP_NAME_ATTRIBUTE,
|
||||||
|
DEFAULT.getGroupNameAttributes()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dn getGroupBaseDN() throws GuacamoleException {
|
||||||
|
return environment.getProperty(
|
||||||
|
LDAPGuacamoleProperties.LDAP_GROUP_BASE_DN,
|
||||||
|
DEFAULT.getGroupBaseDN()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSearchBindDN() throws GuacamoleException {
|
||||||
|
return environment.getProperty(
|
||||||
|
LDAPGuacamoleProperties.LDAP_SEARCH_BIND_DN,
|
||||||
|
DEFAULT.getSearchBindDN()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSearchBindPassword() throws GuacamoleException {
|
||||||
|
return environment.getProperty(
|
||||||
|
LDAPGuacamoleProperties.LDAP_SEARCH_BIND_PASSWORD,
|
||||||
|
DEFAULT.getSearchBindPassword()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EncryptionMethod getEncryptionMethod() throws GuacamoleException {
|
||||||
|
return environment.getProperty(
|
||||||
|
LDAPGuacamoleProperties.LDAP_ENCRYPTION_METHOD,
|
||||||
|
DEFAULT.getEncryptionMethod()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxResults() throws GuacamoleException {
|
||||||
|
return environment.getProperty(
|
||||||
|
LDAPGuacamoleProperties.LDAP_MAX_SEARCH_RESULTS,
|
||||||
|
DEFAULT.getMaxResults()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AliasDerefMode getDereferenceAliases() throws GuacamoleException {
|
||||||
|
return environment.getProperty(
|
||||||
|
LDAPGuacamoleProperties.LDAP_DEREFERENCE_ALIASES,
|
||||||
|
DEFAULT.getDereferenceAliases()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getFollowReferrals() throws GuacamoleException {
|
||||||
|
return environment.getProperty(
|
||||||
|
LDAPGuacamoleProperties.LDAP_FOLLOW_REFERRALS,
|
||||||
|
DEFAULT.getFollowReferrals()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxReferralHops() throws GuacamoleException {
|
||||||
|
return environment.getProperty(
|
||||||
|
LDAPGuacamoleProperties.LDAP_MAX_REFERRAL_HOPS,
|
||||||
|
DEFAULT.getMaxReferralHops()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ExprNode getUserSearchFilter() throws GuacamoleException {
|
||||||
|
return environment.getProperty(
|
||||||
|
LDAPGuacamoleProperties.LDAP_USER_SEARCH_FILTER,
|
||||||
|
DEFAULT.getUserSearchFilter()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ExprNode getGroupSearchFilter() throws GuacamoleException {
|
||||||
|
return environment.getProperty(
|
||||||
|
LDAPGuacamoleProperties.LDAP_GROUP_SEARCH_FILTER,
|
||||||
|
DEFAULT.getGroupSearchFilter()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOperationTimeout() throws GuacamoleException {
|
||||||
|
return environment.getProperty(
|
||||||
|
LDAPGuacamoleProperties.LDAP_OPERATION_TIMEOUT,
|
||||||
|
DEFAULT.getOperationTimeout()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNetworkTimeout() throws GuacamoleException {
|
||||||
|
return environment.getProperty(
|
||||||
|
LDAPGuacamoleProperties.LDAP_NETWORK_TIMEOUT,
|
||||||
|
DEFAULT.getNetworkTimeout()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getAttributes() throws GuacamoleException {
|
||||||
|
return environment.getProperty(
|
||||||
|
LDAPGuacamoleProperties.LDAP_USER_ATTRIBUTES,
|
||||||
|
DEFAULT.getAttributes()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMemberAttribute() throws GuacamoleException {
|
||||||
|
return environment.getProperty(
|
||||||
|
LDAPGuacamoleProperties.LDAP_MEMBER_ATTRIBUTE,
|
||||||
|
DEFAULT.getMemberAttribute()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MemberAttributeType getMemberAttributeType()
|
||||||
|
throws GuacamoleException {
|
||||||
|
return environment.getProperty(
|
||||||
|
LDAPGuacamoleProperties.LDAP_MEMBER_ATTRIBUTE_TYPE,
|
||||||
|
DEFAULT.getMemberAttributeType()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,428 @@
|
|||||||
|
/*
|
||||||
|
* 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.conf;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import static com.fasterxml.jackson.annotation.JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
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.guacamole.GuacamoleException;
|
||||||
|
import org.apache.guacamole.properties.GuacamoleProperty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LDAPConfiguration implementation that is annotated for deserialization by
|
||||||
|
* Jackson.
|
||||||
|
*/
|
||||||
|
public class JacksonLDAPConfiguration implements LDAPConfiguration {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The regular expressions that match all users that should be routed to
|
||||||
|
* the LDAP server represented by this configuration.
|
||||||
|
*/
|
||||||
|
@JsonProperty("match-usernames")
|
||||||
|
@JsonFormat(with = ACCEPT_SINGLE_VALUE_AS_ARRAY)
|
||||||
|
private List<Pattern> matchUsernames;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The raw YAML value of {@link LDAPGuacamoleProperties#LDAP_HOSTNAME}. If
|
||||||
|
* not set within the YAML, this will be null.
|
||||||
|
*/
|
||||||
|
@JsonProperty("hostname")
|
||||||
|
private String hostname;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The raw YAML value of {@link LDAPGuacamoleProperties#LDAP_PORT}. If not
|
||||||
|
* set within the YAML, this will be null.
|
||||||
|
*/
|
||||||
|
@JsonProperty("port")
|
||||||
|
private Integer port;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The raw YAML value of {@link LDAPGuacamoleProperties#LDAP_USERNAME_ATTRIBUTES}.
|
||||||
|
* If not set within the YAML, this will be null.
|
||||||
|
*/
|
||||||
|
@JsonProperty("username-attribute")
|
||||||
|
@JsonFormat(with = ACCEPT_SINGLE_VALUE_AS_ARRAY)
|
||||||
|
private List<String> usernameAttributes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The raw YAML value of {@link LDAPGuacamoleProperties#LDAP_USER_BASE_DN}.
|
||||||
|
* If not set within the YAML, this will be null.
|
||||||
|
*/
|
||||||
|
@JsonProperty("user-base-dn")
|
||||||
|
private String userBaseDn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The raw YAML value of {@link LDAPGuacamoleProperties#LDAP_CONFIG_BASE_DN}.
|
||||||
|
* If not set within the YAML, this will be null.
|
||||||
|
*/
|
||||||
|
@JsonProperty("config-base-dn")
|
||||||
|
private String configBaseDn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The raw YAML value of {@link LDAPGuacamoleProperties#LDAP_GROUP_BASE_DN}.
|
||||||
|
* If not set within the YAML, this will be null.
|
||||||
|
*/
|
||||||
|
@JsonProperty("group-base-dn")
|
||||||
|
private String groupBaseDn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The raw YAML value of {@link LDAPGuacamoleProperties#LDAP_GROUP_NAME_ATTRIBUTES}.
|
||||||
|
* If not set within the YAML, this will be null.
|
||||||
|
*/
|
||||||
|
@JsonProperty("group-name-attribute")
|
||||||
|
@JsonFormat(with = ACCEPT_SINGLE_VALUE_AS_ARRAY)
|
||||||
|
private List<String> groupNameAttributes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The raw YAML value of {@link LDAPGuacamoleProperties#LDAP_SEARCH_BIND_DN}.
|
||||||
|
* If not set within the YAML, this will be null.
|
||||||
|
*/
|
||||||
|
@JsonProperty("search-bind-dn")
|
||||||
|
private String searchBindDn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The raw YAML value of {@link LDAPGuacamoleProperties#LDAP_SEARCH_BIND_PASSWORD}.
|
||||||
|
* If not set within the YAML, this will be null.
|
||||||
|
*/
|
||||||
|
@JsonProperty("search-bind-password")
|
||||||
|
private String searchBindPassword;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The raw YAML value of {@link LDAPGuacamoleProperties#LDAP_ENCRYPTION_METHOD}.
|
||||||
|
* If not set within the YAML, this will be null.
|
||||||
|
*/
|
||||||
|
@JsonProperty("encryption-method")
|
||||||
|
private String encryptionMethod;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The raw YAML value of {@link LDAPGuacamoleProperties#LDAP_MAX_SEARCH_RESULTS}.
|
||||||
|
* If not set within the YAML, this will be null.
|
||||||
|
*/
|
||||||
|
@JsonProperty("max-search-results")
|
||||||
|
private Integer maxSearchResults;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The raw YAML value of {@link LDAPGuacamoleProperties#LDAP_DEREFERENCE_ALIASES}.
|
||||||
|
* If not set within the YAML, this will be null.
|
||||||
|
*/
|
||||||
|
@JsonProperty("dereference-aliases")
|
||||||
|
private String dereferenceAliases;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The raw YAML value of {@link LDAPGuacamoleProperties#LDAP_FOLLOW_REFERRALS}.
|
||||||
|
* If not set within the YAML, this will be null.
|
||||||
|
*/
|
||||||
|
@JsonProperty("follow-referrals")
|
||||||
|
private Boolean followReferrals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The raw YAML value of {@link LDAPGuacamoleProperties#LDAP_MAX_REFERRAL_HOPS}.
|
||||||
|
* If not set within the YAML, this will be null.
|
||||||
|
*/
|
||||||
|
@JsonProperty("max-referral-hops")
|
||||||
|
private Integer maxReferralHops;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The raw YAML value of {@link LDAPGuacamoleProperties#LDAP_USER_SEARCH_FILTER}.
|
||||||
|
* If not set within the YAML, this will be null.
|
||||||
|
*/
|
||||||
|
@JsonProperty("user-search-filter")
|
||||||
|
private String userSearchFilter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The raw YAML value of {@link LDAPGuacamoleProperties#LDAP_GROUP_SEARCH_FILTER}.
|
||||||
|
* If not set within the YAML, this will be null.
|
||||||
|
*/
|
||||||
|
@JsonProperty("group-search-filter")
|
||||||
|
private String groupSearchFilter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The raw YAML value of {@link LDAPGuacamoleProperties#LDAP_OPERATION_TIMEOUT}.
|
||||||
|
* If not set within the YAML, this will be null.
|
||||||
|
*/
|
||||||
|
@JsonProperty("operation-timeout")
|
||||||
|
private Integer operationTimeout;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The raw YAML value of {@link LDAPGuacamoleProperties#LDAP_NETWORK_TIMEOUT}.
|
||||||
|
* If not set within the YAML, this will be null.
|
||||||
|
*/
|
||||||
|
@JsonProperty("network-timeout")
|
||||||
|
private Integer networkTimeout;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The raw YAML value of {@link LDAPGuacamoleProperties#LDAP_USER_ATTRIBUTES}.
|
||||||
|
* If not set within the YAML, this will be null.
|
||||||
|
*/
|
||||||
|
@JsonProperty("user-attributes")
|
||||||
|
@JsonFormat(with = ACCEPT_SINGLE_VALUE_AS_ARRAY)
|
||||||
|
private List<String> userAttributes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The raw YAML value of {@link LDAPGuacamoleProperties#LDAP_MEMBER_ATTRIBUTE}.
|
||||||
|
* If not set within the YAML, this will be null.
|
||||||
|
*/
|
||||||
|
@JsonProperty("member-attribute")
|
||||||
|
private String memberAttribute;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The raw YAML value of {@link LDAPGuacamoleProperties#LDAP_MEMBER_ATTRIBUTE_TYPE}.
|
||||||
|
* If not set within the YAML, this will be null.
|
||||||
|
*/
|
||||||
|
@JsonProperty("member-attribute-type")
|
||||||
|
private String memberAttributeType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default configuration options for all parameters.
|
||||||
|
*/
|
||||||
|
private LDAPConfiguration defaultConfig = new DefaultLDAPConfiguration();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supplier of default values for LDAP configurations. Unlike
|
||||||
|
* {@link java.util.function.Supplier}, the {@link #get()} function of
|
||||||
|
* DefaultSupplier may throw a {@link GuacamoleException}.
|
||||||
|
*
|
||||||
|
* @param <T>
|
||||||
|
* The type of value returned by this DefaultSupplier.
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
private interface DefaultSupplier<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value supplied by this DefaultSupplier. The value
|
||||||
|
* returned is not cached and may be non-deterministic.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The value supplied by this DefaultSupplier.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If an error occurs while producing/retrieving the value.
|
||||||
|
*/
|
||||||
|
T get() throws GuacamoleException;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the given value, if non-null. If null, the given default value
|
||||||
|
* is returned.
|
||||||
|
*
|
||||||
|
* @param <T>
|
||||||
|
* The type of value accepted and returned.
|
||||||
|
*
|
||||||
|
* @param value
|
||||||
|
* The possibly null value to return if non-null.
|
||||||
|
*
|
||||||
|
* @param defaultValue
|
||||||
|
* A function which supplies the value to return if the provided value
|
||||||
|
* is null.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The provided value, if non-null, otherwise the provided default
|
||||||
|
* value.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If an error occurs while producing/retrieving the default value.
|
||||||
|
*/
|
||||||
|
private <T> T withDefault(T value, DefaultSupplier<T> defaultValue)
|
||||||
|
throws GuacamoleException {
|
||||||
|
return value != null ? value : defaultValue.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses and returns the given value, if non-null. If null, the given
|
||||||
|
* default value is returned.
|
||||||
|
*
|
||||||
|
* @param <T>
|
||||||
|
* The type of value accepted and returned.
|
||||||
|
*
|
||||||
|
* @param property
|
||||||
|
* The GuacamoleProperty implementation to use to parse the provided
|
||||||
|
* String value.
|
||||||
|
*
|
||||||
|
* @param value
|
||||||
|
* The possibly null value to return if non-null.
|
||||||
|
*
|
||||||
|
* @param defaultValue
|
||||||
|
* A function which supplies the value to return if the provided value
|
||||||
|
* is null.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The provided value, if non-null, otherwise the provided default
|
||||||
|
* value.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If an error occurs while producing/retrieving the default value.
|
||||||
|
*/
|
||||||
|
private <T> T withDefault(GuacamoleProperty<T> property, String value,
|
||||||
|
DefaultSupplier<T> defaultValue)
|
||||||
|
throws GuacamoleException {
|
||||||
|
return withDefault(property.parseValue(value), defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the LDAPConfiguration that should be used for the default values of
|
||||||
|
* any configuration options omitted from the YAML. If not set, an instance
|
||||||
|
* of {@link DefaultLDAPConfiguration} will be used.
|
||||||
|
*
|
||||||
|
* @param defaultConfig
|
||||||
|
* The LDAPConfiguration to use for the default values of any omitted
|
||||||
|
* configuration options.
|
||||||
|
*/
|
||||||
|
public void setDefaults(LDAPConfiguration defaultConfig) {
|
||||||
|
this.defaultConfig = defaultConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String appliesTo(String username) throws GuacamoleException {
|
||||||
|
|
||||||
|
// Match any user by default
|
||||||
|
if (matchUsernames == null || matchUsernames.isEmpty())
|
||||||
|
return username;
|
||||||
|
|
||||||
|
for (Pattern pattern : matchUsernames) {
|
||||||
|
Matcher matcher = pattern.matcher(username);
|
||||||
|
if (matcher.matches())
|
||||||
|
return matcher.groupCount() >= 1 ? matcher.group(1) : username;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getServerHostname() throws GuacamoleException {
|
||||||
|
return withDefault(hostname, defaultConfig::getServerHostname);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getServerPort() throws GuacamoleException {
|
||||||
|
return withDefault(port, () -> getEncryptionMethod().DEFAULT_PORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getUsernameAttributes() throws GuacamoleException {
|
||||||
|
return withDefault(usernameAttributes, defaultConfig::getUsernameAttributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dn getUserBaseDN() throws GuacamoleException {
|
||||||
|
return withDefault(LDAPGuacamoleProperties.LDAP_USER_BASE_DN,
|
||||||
|
userBaseDn, defaultConfig::getUserBaseDN);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dn getConfigurationBaseDN() throws GuacamoleException {
|
||||||
|
return withDefault(LDAPGuacamoleProperties.LDAP_CONFIG_BASE_DN,
|
||||||
|
configBaseDn, defaultConfig::getConfigurationBaseDN);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getGroupNameAttributes() throws GuacamoleException {
|
||||||
|
return withDefault(groupNameAttributes, defaultConfig::getGroupNameAttributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dn getGroupBaseDN() throws GuacamoleException {
|
||||||
|
return withDefault(LDAPGuacamoleProperties.LDAP_GROUP_BASE_DN,
|
||||||
|
groupBaseDn, defaultConfig::getGroupBaseDN);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSearchBindDN() throws GuacamoleException {
|
||||||
|
return withDefault(searchBindDn, defaultConfig::getSearchBindDN);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSearchBindPassword() throws GuacamoleException {
|
||||||
|
return withDefault(searchBindPassword, defaultConfig::getSearchBindDN);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EncryptionMethod getEncryptionMethod() throws GuacamoleException {
|
||||||
|
return withDefault(LDAPGuacamoleProperties.LDAP_ENCRYPTION_METHOD,
|
||||||
|
encryptionMethod, defaultConfig::getEncryptionMethod);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxResults() throws GuacamoleException {
|
||||||
|
return withDefault(maxSearchResults, defaultConfig::getMaxResults);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AliasDerefMode getDereferenceAliases() throws GuacamoleException {
|
||||||
|
return withDefault(LDAPGuacamoleProperties.LDAP_DEREFERENCE_ALIASES,
|
||||||
|
dereferenceAliases, defaultConfig::getDereferenceAliases);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getFollowReferrals() throws GuacamoleException {
|
||||||
|
return withDefault(followReferrals, defaultConfig::getFollowReferrals);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxReferralHops() throws GuacamoleException {
|
||||||
|
return withDefault(maxReferralHops, defaultConfig::getMaxReferralHops);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ExprNode getUserSearchFilter() throws GuacamoleException {
|
||||||
|
return withDefault(LDAPGuacamoleProperties.LDAP_USER_SEARCH_FILTER,
|
||||||
|
userSearchFilter, defaultConfig::getUserSearchFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ExprNode getGroupSearchFilter() throws GuacamoleException {
|
||||||
|
return withDefault(LDAPGuacamoleProperties.LDAP_GROUP_SEARCH_FILTER,
|
||||||
|
groupSearchFilter, defaultConfig::getGroupSearchFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOperationTimeout() throws GuacamoleException {
|
||||||
|
return withDefault(operationTimeout, defaultConfig::getOperationTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNetworkTimeout() throws GuacamoleException {
|
||||||
|
return withDefault(networkTimeout, defaultConfig::getNetworkTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getAttributes() throws GuacamoleException {
|
||||||
|
return withDefault(userAttributes, defaultConfig::getAttributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMemberAttribute() throws GuacamoleException {
|
||||||
|
return withDefault(memberAttribute, defaultConfig::getMemberAttribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MemberAttributeType getMemberAttributeType() throws GuacamoleException {
|
||||||
|
return withDefault(LDAPGuacamoleProperties.LDAP_MEMBER_ATTRIBUTE_TYPE,
|
||||||
|
memberAttributeType, defaultConfig::getMemberAttributeType);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,323 @@
|
|||||||
|
/*
|
||||||
|
* 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.conf;
|
||||||
|
|
||||||
|
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.guacamole.GuacamoleException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration information defining how a particular LDAP server should be
|
||||||
|
* queried.
|
||||||
|
*/
|
||||||
|
public interface LDAPConfiguration {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests whether this LDAPConfiguration applies to the user having the
|
||||||
|
* given username. If the configuration applies, the username that should
|
||||||
|
* be used to derive the user's DN is returned.
|
||||||
|
*
|
||||||
|
* @param username
|
||||||
|
* The username to test.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The username that should be used to derive this user's DN, or null
|
||||||
|
* if the configuration does not apply.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If an error prevents testing against this configuration.
|
||||||
|
*/
|
||||||
|
String appliesTo(String username) throws GuacamoleException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the hostname or IP address of the LDAP server.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The hostname or IP address of the LDAP server.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If the hostname or IP address of the LDAP server cannot be
|
||||||
|
* retrieved.
|
||||||
|
*/
|
||||||
|
String getServerHostname() throws GuacamoleException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the port of the LDAP server. The default value depends on which
|
||||||
|
* encryption method is being used. For unencrypted LDAP and STARTTLS, this
|
||||||
|
* will be 389. For LDAPS (LDAP over SSL) this will be 636.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The port of the LDAP server.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If the port of the LDAP server cannot be retrieved.
|
||||||
|
*/
|
||||||
|
int getServerPort() throws GuacamoleException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all username attributes which should be used to query and bind
|
||||||
|
* users using the LDAP directory.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The username attributes which should be used to query and bind users
|
||||||
|
* using the LDAP directory.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If the username attributes cannot be retrieved.
|
||||||
|
*/
|
||||||
|
List<String> getUsernameAttributes() throws GuacamoleException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 the user base DN cannot be retrieved.
|
||||||
|
*/
|
||||||
|
Dn getUserBaseDN() throws GuacamoleException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the base DN under which all Guacamole configurations
|
||||||
|
* (connections) will be stored within the LDAP directory. If Guacamole
|
||||||
|
* configurations will not be stored within LDAP, null is returned.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The base DN under which all Guacamole configurations will be stored
|
||||||
|
* within the LDAP directory, or null if no Guacamole configurations
|
||||||
|
* will be stored within the LDAP directory.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If the configuration base DN cannot be retrieved.
|
||||||
|
*/
|
||||||
|
Dn getConfigurationBaseDN() throws GuacamoleException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all attributes which should be used to determine the unique
|
||||||
|
* identifier of each user group.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The attributes which should be used to determine the unique
|
||||||
|
* identifier of each group.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If the group name attributes cannot be retrieved.
|
||||||
|
*/
|
||||||
|
List<String> getGroupNameAttributes() throws GuacamoleException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the base DN under which all Guacamole role based access control
|
||||||
|
* (RBAC) groups will be stored within the LDAP directory. If RBAC will not
|
||||||
|
* be used, null is returned.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The base DN under which all Guacamole RBAC groups will be stored
|
||||||
|
* within the LDAP directory, or null if RBAC will not be used.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If the group base DN cannot be retrieved.
|
||||||
|
*/
|
||||||
|
Dn getGroupBaseDN() throws GuacamoleException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the login that should be used when searching for the DNs of users
|
||||||
|
* attempting to authenticate. If no such search should be performed, null
|
||||||
|
* is returned.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The DN that should be used when searching for the DNs of users
|
||||||
|
* attempting to authenticate, or null if no such search should be
|
||||||
|
* performed.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If the search bind DN cannot be retrieved.
|
||||||
|
*/
|
||||||
|
String getSearchBindDN() throws GuacamoleException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the password that should be used when binding to the LDAP server
|
||||||
|
* using the DN returned by getSearchBindDN(). If no password should be
|
||||||
|
* used, null is returned.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The password that should be used when binding to the LDAP server
|
||||||
|
* using the DN returned by getSearchBindDN(), or null if no password
|
||||||
|
* should be used.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If the search bind password cannot be retrieved.
|
||||||
|
*/
|
||||||
|
String getSearchBindPassword() throws GuacamoleException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the encryption method that should be used when connecting to the
|
||||||
|
* LDAP server.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The encryption method that should be used when connecting to the
|
||||||
|
* LDAP server.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If the encryption method cannot be retrieved.
|
||||||
|
*/
|
||||||
|
EncryptionMethod getEncryptionMethod() throws GuacamoleException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns maximum number of results a LDAP query can return.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The maximum number of results a LDAP query can return.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If the maximum number of results cannot be retrieved.
|
||||||
|
*/
|
||||||
|
int getMaxResults() throws GuacamoleException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether or not LDAP aliases will be dereferenced.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The LDAP alias dereferencing mode.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If the LDAP alias dereferencing mode cannot be retrieved.
|
||||||
|
*/
|
||||||
|
AliasDerefMode getDereferenceAliases() throws GuacamoleException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether referrals should be automatically followed.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Whether referrals should be followed.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If the configuration information determining whether LDAP referrals
|
||||||
|
* should be followed cannot be retrieved.
|
||||||
|
*/
|
||||||
|
boolean getFollowReferrals() throws GuacamoleException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the maximum number of referral hops to follow.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The maximum number of referral hops to follow.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If the maximum number of referral hops cannot be retrieved.
|
||||||
|
*/
|
||||||
|
int getMaxReferralHops() throws GuacamoleException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the search filter that should be used when querying the
|
||||||
|
* LDAP server for Guacamole users.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The search filter that should be used when querying the
|
||||||
|
* LDAP server for users that are valid in Guacamole.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If the user search filter cannot be retrieved.
|
||||||
|
*/
|
||||||
|
ExprNode getUserSearchFilter() throws GuacamoleException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the search filter that should be used when querying the
|
||||||
|
* LDAP server for Guacamole groups.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The search filter that should be used when querying the
|
||||||
|
* LDAP server for groups that are valid in Guacamole.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If the group search filter cannot be retrieved.
|
||||||
|
*/
|
||||||
|
ExprNode getGroupSearchFilter() throws GuacamoleException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the maximum number of milliseconds to wait for a response when
|
||||||
|
* communicating with the LDAP server.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The maximum number of milliseconds to wait for responses from the
|
||||||
|
* LDAP server.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If the LDAP network timeout cannot be retrieved.
|
||||||
|
*/
|
||||||
|
int getNetworkTimeout() throws GuacamoleException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the maximum number of seconds to wait for LDAP operations.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The maximum number of seconds to wait for LDAP operations.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If the LDAP operation timeout cannot be retrieved.
|
||||||
|
*/
|
||||||
|
int getOperationTimeout() throws GuacamoleException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns names of any LDAP user attributes that should be made available
|
||||||
|
* as parameter tokens.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* A list of all LDAP user attributes that should be made available as
|
||||||
|
* parameter tokens.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If the names of the LDAP user attributes to be exposed as parameter
|
||||||
|
* tokens cannot be retrieved.
|
||||||
|
*/
|
||||||
|
List<String> getAttributes() throws GuacamoleException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the LDAP attribute used to enumerate members in a
|
||||||
|
* group.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The name of the LDAP attribute to use to enumerate
|
||||||
|
* members in a group.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If the group member attribute cannot be retrieved.
|
||||||
|
*/
|
||||||
|
String getMemberAttribute() throws GuacamoleException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the LDAP attribute used to enumerate members in a group
|
||||||
|
* specifies a UID or DN.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The type of data contained in the LDAP attribute used to enumerate
|
||||||
|
* members in a group.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If the type of attribute used to enumerate group members cannot be
|
||||||
|
* retrieved.
|
||||||
|
*/
|
||||||
|
MemberAttributeType getMemberAttributeType() throws GuacamoleException;
|
||||||
|
|
||||||
|
}
|
@@ -254,6 +254,17 @@ public class LDAPGuacamoleProperties {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of milliseconds to wait for responses from the LDAP server.
|
||||||
|
*/
|
||||||
|
public static final IntegerGuacamoleProperty LDAP_NETWORK_TIMEOUT =
|
||||||
|
new IntegerGuacamoleProperty() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() { return "ldap-network-timeout"; }
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom attribute or attributes to query from Guacamole user's record in
|
* Custom attribute or attributes to query from Guacamole user's record in
|
||||||
* the LDAP directory.
|
* the LDAP directory.
|
||||||
|
@@ -35,16 +35,13 @@ 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.ExprNode;
|
||||||
import org.apache.directory.api.ldap.model.filter.OrNode;
|
import org.apache.directory.api.ldap.model.filter.OrNode;
|
||||||
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.guacamole.auth.ldap.LDAPAuthenticationProvider;
|
import org.apache.guacamole.auth.ldap.LDAPAuthenticationProvider;
|
||||||
import org.apache.guacamole.auth.ldap.conf.ConfigurationService;
|
|
||||||
import org.apache.guacamole.GuacamoleException;
|
import org.apache.guacamole.GuacamoleException;
|
||||||
import org.apache.guacamole.GuacamoleServerException;
|
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.ObjectQueryService;
|
||||||
import org.apache.guacamole.auth.ldap.group.UserGroupService;
|
import org.apache.guacamole.auth.ldap.group.UserGroupService;
|
||||||
import org.apache.guacamole.auth.ldap.user.LDAPAuthenticatedUser;
|
import org.apache.guacamole.auth.ldap.user.LDAPAuthenticatedUser;
|
||||||
import org.apache.guacamole.net.auth.AuthenticatedUser;
|
|
||||||
import org.apache.guacamole.net.auth.Connection;
|
import org.apache.guacamole.net.auth.Connection;
|
||||||
import org.apache.guacamole.net.auth.TokenInjectingConnection;
|
import org.apache.guacamole.net.auth.TokenInjectingConnection;
|
||||||
import org.apache.guacamole.net.auth.simple.SimpleConnection;
|
import org.apache.guacamole.net.auth.simple.SimpleConnection;
|
||||||
@@ -63,12 +60,6 @@ public class ConnectionService {
|
|||||||
*/
|
*/
|
||||||
private static final Logger logger = LoggerFactory.getLogger(ConnectionService.class);
|
private static final Logger logger = LoggerFactory.getLogger(ConnectionService.class);
|
||||||
|
|
||||||
/**
|
|
||||||
* Service for retrieving LDAP server configuration information.
|
|
||||||
*/
|
|
||||||
@Inject
|
|
||||||
private ConfigurationService confService;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service for executing LDAP queries.
|
* Service for executing LDAP queries.
|
||||||
*/
|
*/
|
||||||
@@ -124,17 +115,12 @@ public class ConnectionService {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all Guacamole connections accessible to the user currently bound
|
* Returns all Guacamole connections accessible to the given user.
|
||||||
* under the given LDAP connection.
|
|
||||||
*
|
*
|
||||||
* @param user
|
* @param user
|
||||||
* The AuthenticatedUser object associated with the user who is
|
* The AuthenticatedUser object associated with the user who is
|
||||||
* currently authenticated with Guacamole.
|
* currently authenticated with Guacamole.
|
||||||
*
|
*
|
||||||
* @param ldapConnection
|
|
||||||
* The current connection to the LDAP server, associated with the
|
|
||||||
* current user.
|
|
||||||
*
|
|
||||||
* @return
|
* @return
|
||||||
* All connections accessible to the user currently bound under the
|
* All connections accessible to the user currently bound under the
|
||||||
* given LDAP connection, as a map of connection identifier to
|
* given LDAP connection, as a map of connection identifier to
|
||||||
@@ -143,34 +129,27 @@ public class ConnectionService {
|
|||||||
* @throws GuacamoleException
|
* @throws GuacamoleException
|
||||||
* If an error occurs preventing retrieval of connections.
|
* If an error occurs preventing retrieval of connections.
|
||||||
*/
|
*/
|
||||||
public Map<String, Connection> getConnections(AuthenticatedUser user,
|
public Map<String, Connection> getConnections(LDAPAuthenticatedUser user)
|
||||||
LdapNetworkConnection ldapConnection) throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
|
ConnectedLDAPConfiguration ldapConfig = user.getLDAPConfiguration();
|
||||||
|
|
||||||
// Do not return any connections if base DN is not specified
|
// Do not return any connections if base DN is not specified
|
||||||
Dn configurationBaseDN = confService.getConfigurationBaseDN();
|
Dn configurationBaseDN = ldapConfig.getConfigurationBaseDN();
|
||||||
if (configurationBaseDN == null)
|
if (configurationBaseDN == null)
|
||||||
return Collections.<String, Connection>emptyMap();
|
return Collections.<String, Connection>emptyMap();
|
||||||
|
|
||||||
try {
|
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
|
// Get the search filter for finding connections accessible by the
|
||||||
// current user
|
// current user
|
||||||
ExprNode connectionSearchFilter = getConnectionSearchFilter(userDN, ldapConnection);
|
ExprNode connectionSearchFilter = getConnectionSearchFilter(user);
|
||||||
|
|
||||||
// Find all Guacamole connections for the given user by
|
// Find all Guacamole connections for the given user by
|
||||||
// looking for direct membership in the guacConfigGroup
|
// looking for direct membership in the guacConfigGroup
|
||||||
// and possibly any groups the user is a member of that are
|
// and possibly any groups the user is a member of that are
|
||||||
// referred to in the seeAlso attribute of the guacConfigGroup.
|
// referred to in the seeAlso attribute of the guacConfigGroup.
|
||||||
List<Entry> results = queryService.search(ldapConnection,
|
List<Entry> results = queryService.search(ldapConfig, ldapConfig.getLDAPConnection(),
|
||||||
configurationBaseDN, connectionSearchFilter, 0, GUAC_CONFIG_LDAP_ATTRIBUTES);
|
configurationBaseDN, connectionSearchFilter, 0, GUAC_CONFIG_LDAP_ATTRIBUTES);
|
||||||
|
|
||||||
// Return a map of all readable connections
|
// Return a map of all readable connections
|
||||||
@@ -261,8 +240,7 @@ public class ConnectionService {
|
|||||||
// Inject LDAP-specific tokens only if LDAP handled user
|
// Inject LDAP-specific tokens only if LDAP handled user
|
||||||
// authentication
|
// authentication
|
||||||
if (user instanceof LDAPAuthenticatedUser)
|
if (user instanceof LDAPAuthenticatedUser)
|
||||||
connection = new TokenInjectingConnection(connection,
|
connection = new TokenInjectingConnection(connection, user.getTokens());
|
||||||
((LDAPAuthenticatedUser) user).getTokens());
|
|
||||||
|
|
||||||
return connection;
|
return connection;
|
||||||
|
|
||||||
@@ -277,14 +255,11 @@ public class ConnectionService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an LDAP search filter which queries all connections accessible
|
* Returns an LDAP search filter which queries all connections accessible
|
||||||
* by the user having the given DN.
|
* by the given user.
|
||||||
*
|
*
|
||||||
* @param userDN
|
* @param user
|
||||||
* DN of the user to search for associated guacConfigGroup connections.
|
* The AuthenticatedUser object associated with the user who is
|
||||||
*
|
* currently authenticated with Guacamole.
|
||||||
* @param ldapConnection
|
|
||||||
* LDAP connection to use if additional information must be queried to
|
|
||||||
* produce the filter, such as groups driving RBAC.
|
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* An LDAP search filter which queries all guacConfigGroup objects
|
* An LDAP search filter which queries all guacConfigGroup objects
|
||||||
@@ -296,10 +271,12 @@ public class ConnectionService {
|
|||||||
* @throws GuacamoleException
|
* @throws GuacamoleException
|
||||||
* If an error occurs retrieving the group base DN.
|
* If an error occurs retrieving the group base DN.
|
||||||
*/
|
*/
|
||||||
private ExprNode getConnectionSearchFilter(Dn userDN,
|
private ExprNode getConnectionSearchFilter(LDAPAuthenticatedUser user)
|
||||||
LdapNetworkConnection ldapConnection)
|
|
||||||
throws LdapException, GuacamoleException {
|
throws LdapException, GuacamoleException {
|
||||||
|
|
||||||
|
ConnectedLDAPConfiguration config = user.getLDAPConfiguration();
|
||||||
|
Dn userDN = config.getBindDN();
|
||||||
|
|
||||||
AndNode searchFilter = new AndNode();
|
AndNode searchFilter = new AndNode();
|
||||||
|
|
||||||
// Add the prefix to the search filter, prefix filter searches for guacConfigGroups with the userDN as the member attribute value
|
// Add the prefix to the search filter, prefix filter searches for guacConfigGroups with the userDN as the member attribute value
|
||||||
@@ -307,12 +284,12 @@ public class ConnectionService {
|
|||||||
|
|
||||||
// Apply group filters
|
// Apply group filters
|
||||||
OrNode groupFilter = new OrNode();
|
OrNode groupFilter = new OrNode();
|
||||||
groupFilter.addNode(new EqualityNode(confService.getMemberAttribute(),
|
groupFilter.addNode(new EqualityNode(config.getMemberAttribute(),
|
||||||
userDN.toString()));
|
userDN.toString()));
|
||||||
|
|
||||||
// Additionally filter by group membership if the current user is a
|
// Additionally filter by group membership if the current user is a
|
||||||
// member of any user groups
|
// member of any user groups
|
||||||
List<Entry> userGroups = userGroupService.getParentUserGroupEntries(ldapConnection, userDN);
|
List<Entry> userGroups = userGroupService.getParentUserGroupEntries(config, userDN);
|
||||||
if (!userGroups.isEmpty()) {
|
if (!userGroups.isEmpty()) {
|
||||||
userGroups.forEach(entry ->
|
userGroups.forEach(entry ->
|
||||||
groupFilter.addNode(new EqualityNode(LDAP_ATTRIBUTE_NAME_GROUPS,entry.getDn().toString()))
|
groupFilter.addNode(new EqualityNode(LDAP_ATTRIBUTE_NAME_GROUPS,entry.getDn().toString()))
|
||||||
|
@@ -33,11 +33,12 @@ 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.ExprNode;
|
||||||
import org.apache.directory.api.ldap.model.filter.NotNode;
|
import org.apache.directory.api.ldap.model.filter.NotNode;
|
||||||
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.LdapNetworkConnection;
|
|
||||||
import org.apache.guacamole.auth.ldap.conf.ConfigurationService;
|
|
||||||
import org.apache.guacamole.auth.ldap.conf.MemberAttributeType;
|
import org.apache.guacamole.auth.ldap.conf.MemberAttributeType;
|
||||||
import org.apache.guacamole.GuacamoleException;
|
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.ObjectQueryService;
|
||||||
|
import org.apache.guacamole.auth.ldap.conf.LDAPConfiguration;
|
||||||
|
import org.apache.guacamole.auth.ldap.user.LDAPAuthenticatedUser;
|
||||||
import org.apache.guacamole.net.auth.UserGroup;
|
import org.apache.guacamole.net.auth.UserGroup;
|
||||||
import org.apache.guacamole.net.auth.simple.SimpleUserGroup;
|
import org.apache.guacamole.net.auth.simple.SimpleUserGroup;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -54,12 +55,6 @@ public class UserGroupService {
|
|||||||
*/
|
*/
|
||||||
private static final Logger logger = LoggerFactory.getLogger(UserGroupService.class);
|
private static final Logger logger = LoggerFactory.getLogger(UserGroupService.class);
|
||||||
|
|
||||||
/**
|
|
||||||
* Service for retrieving LDAP server configuration information.
|
|
||||||
*/
|
|
||||||
@Inject
|
|
||||||
private ConfigurationService confService;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service for executing LDAP queries.
|
* Service for executing LDAP queries.
|
||||||
*/
|
*/
|
||||||
@@ -73,22 +68,25 @@ public class UserGroupService {
|
|||||||
* defined (may always return zero results), it should only be explicitly
|
* defined (may always return zero results), it should only be explicitly
|
||||||
* excluded if it is expected to have been defined.
|
* excluded if it is expected to have been defined.
|
||||||
*
|
*
|
||||||
|
* @param config
|
||||||
|
* The configuration of the LDAP server being queried.
|
||||||
|
*
|
||||||
* @return
|
* @return
|
||||||
* The base search filter which should be used to retrieve user groups.
|
* The base search filter which should be used to retrieve user groups.
|
||||||
*
|
*
|
||||||
* @throws GuacamoleException
|
* @throws GuacamoleException
|
||||||
* If guacamole.properties cannot be parsed.
|
* If guacamole.properties cannot be parsed.
|
||||||
*/
|
*/
|
||||||
private ExprNode getGroupSearchFilter() throws GuacamoleException {
|
private ExprNode getGroupSearchFilter(LDAPConfiguration config) throws GuacamoleException {
|
||||||
|
|
||||||
// Use filter defined by "ldap-group-search-filter" as basis for all
|
// Use filter defined by "ldap-group-search-filter" as basis for all
|
||||||
// retrieval of user groups
|
// retrieval of user groups
|
||||||
ExprNode groupFilter = confService.getGroupSearchFilter();
|
ExprNode groupFilter = config.getGroupSearchFilter();
|
||||||
|
|
||||||
// Explicitly exclude guacConfigGroup object class only if it should
|
// Explicitly exclude guacConfigGroup object class only if it should
|
||||||
// be assumed to be defined (query may fail due to no such object
|
// be assumed to be defined (query may fail due to no such object
|
||||||
// class existing otherwise)
|
// class existing otherwise)
|
||||||
if (confService.getConfigurationBaseDN() != null) {
|
if (config.getConfigurationBaseDN() != null) {
|
||||||
groupFilter = new AndNode(
|
groupFilter = new AndNode(
|
||||||
groupFilter,
|
groupFilter,
|
||||||
new NotNode(new EqualityNode<String>("objectClass", "guacConfigGroup"))
|
new NotNode(new EqualityNode<String>("objectClass", "guacConfigGroup"))
|
||||||
@@ -100,12 +98,11 @@ public class UserGroupService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all Guacamole user groups accessible to the user currently bound
|
* Returns all Guacamole user groups accessible to the given user.
|
||||||
* under the given LDAP connection.
|
|
||||||
*
|
*
|
||||||
* @param ldapConnection
|
* @param user
|
||||||
* The current connection to the LDAP server, associated with the
|
* The AuthenticatedUser object associated with the user who is
|
||||||
* current user.
|
* currently authenticated with Guacamole.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* All user groups accessible to the user currently bound under the
|
* All user groups accessible to the user currently bound under the
|
||||||
@@ -115,25 +112,28 @@ public class UserGroupService {
|
|||||||
* @throws GuacamoleException
|
* @throws GuacamoleException
|
||||||
* If an error occurs preventing retrieval of user groups.
|
* If an error occurs preventing retrieval of user groups.
|
||||||
*/
|
*/
|
||||||
public Map<String, UserGroup> getUserGroups(LdapNetworkConnection ldapConnection)
|
public Map<String, UserGroup> getUserGroups(LDAPAuthenticatedUser user)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
|
ConnectedLDAPConfiguration config = user.getLDAPConfiguration();
|
||||||
|
|
||||||
// Do not return any user groups if base DN is not specified
|
// Do not return any user groups if base DN is not specified
|
||||||
Dn groupBaseDN = confService.getGroupBaseDN();
|
Dn groupBaseDN = config.getGroupBaseDN();
|
||||||
if (groupBaseDN == null)
|
if (groupBaseDN == null)
|
||||||
return Collections.emptyMap();
|
return Collections.emptyMap();
|
||||||
|
|
||||||
// Gather all attributes relevant for a group
|
// Gather all attributes relevant for a group
|
||||||
String memberAttribute = confService.getMemberAttribute();
|
String memberAttribute = config.getMemberAttribute();
|
||||||
Collection<String> groupAttributes = new HashSet<>(confService.getGroupNameAttributes());
|
Collection<String> groupAttributes = new HashSet<>(config.getGroupNameAttributes());
|
||||||
groupAttributes.add(memberAttribute);
|
groupAttributes.add(memberAttribute);
|
||||||
|
|
||||||
// Retrieve all visible user groups which are not guacConfigGroups
|
// Retrieve all visible user groups which are not guacConfigGroups
|
||||||
Collection<String> attributes = confService.getGroupNameAttributes();
|
Collection<String> attributes = config.getGroupNameAttributes();
|
||||||
List<Entry> results = queryService.search(
|
List<Entry> results = queryService.search(
|
||||||
ldapConnection,
|
config,
|
||||||
|
config.getLDAPConnection(),
|
||||||
groupBaseDN,
|
groupBaseDN,
|
||||||
getGroupSearchFilter(),
|
getGroupSearchFilter(config),
|
||||||
attributes,
|
attributes,
|
||||||
null,
|
null,
|
||||||
groupAttributes
|
groupAttributes
|
||||||
@@ -167,9 +167,8 @@ public class UserGroupService {
|
|||||||
* user is a member of. Only user groups which are readable by the current
|
* user is a member of. Only user groups which are readable by the current
|
||||||
* user will be retrieved.
|
* user will be retrieved.
|
||||||
*
|
*
|
||||||
* @param ldapConnection
|
* @param config
|
||||||
* The current connection to the LDAP server, associated with the
|
* The configuration of the LDAP server being queried.
|
||||||
* current user.
|
|
||||||
*
|
*
|
||||||
* @param userDN
|
* @param userDN
|
||||||
* The DN of the user whose group membership should be retrieved.
|
* The DN of the user whose group membership should be retrieved.
|
||||||
@@ -181,24 +180,25 @@ public class UserGroupService {
|
|||||||
* @throws GuacamoleException
|
* @throws GuacamoleException
|
||||||
* If an error occurs preventing retrieval of user groups.
|
* If an error occurs preventing retrieval of user groups.
|
||||||
*/
|
*/
|
||||||
public List<Entry> getParentUserGroupEntries(LdapNetworkConnection ldapConnection,
|
public List<Entry> getParentUserGroupEntries(ConnectedLDAPConfiguration config, Dn userDN)
|
||||||
Dn userDN) throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
// Do not return any user groups if base DN is not specified
|
// Do not return any user groups if base DN is not specified
|
||||||
Dn groupBaseDN = confService.getGroupBaseDN();
|
Dn groupBaseDN = config.getGroupBaseDN();
|
||||||
if (groupBaseDN == null)
|
if (groupBaseDN == null)
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
|
|
||||||
// memberAttribute specified in properties could contain DN or username
|
// memberAttribute specified in properties could contain DN or username
|
||||||
MemberAttributeType memberAttributeType = confService.getMemberAttributeType();
|
MemberAttributeType memberAttributeType = config.getMemberAttributeType();
|
||||||
String userIDorDN = userDN.toString();
|
String userIDorDN = userDN.toString();
|
||||||
Collection<String> userAttributes = confService.getUsernameAttributes();
|
Collection<String> userAttributes = config.getUsernameAttributes();
|
||||||
if (memberAttributeType == MemberAttributeType.UID) {
|
if (memberAttributeType == MemberAttributeType.UID) {
|
||||||
// Retrieve user objects with userDN
|
// Retrieve user objects with userDN
|
||||||
List<Entry> userEntries = queryService.search(
|
List<Entry> userEntries = queryService.search(
|
||||||
ldapConnection,
|
config,
|
||||||
|
config.getLDAPConnection(),
|
||||||
userDN,
|
userDN,
|
||||||
confService.getUserSearchFilter(),
|
config.getUserSearchFilter(),
|
||||||
0,
|
0,
|
||||||
userAttributes);
|
userAttributes);
|
||||||
// ... there can surely only be one
|
// ... there can surely only be one
|
||||||
@@ -222,16 +222,17 @@ public class UserGroupService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Gather all attributes relevant for a group
|
// Gather all attributes relevant for a group
|
||||||
String memberAttribute = confService.getMemberAttribute();
|
String memberAttribute = config.getMemberAttribute();
|
||||||
Collection<String> groupAttributes = new HashSet<>(confService.getGroupNameAttributes());
|
Collection<String> groupAttributes = new HashSet<>(config.getGroupNameAttributes());
|
||||||
groupAttributes.add(memberAttribute);
|
groupAttributes.add(memberAttribute);
|
||||||
|
|
||||||
// Get all groups the user is a member of starting at the groupBaseDN,
|
// Get all groups the user is a member of starting at the groupBaseDN,
|
||||||
// excluding guacConfigGroups
|
// excluding guacConfigGroups
|
||||||
return queryService.search(
|
return queryService.search(
|
||||||
ldapConnection,
|
config,
|
||||||
|
config.getLDAPConnection(),
|
||||||
groupBaseDN,
|
groupBaseDN,
|
||||||
getGroupSearchFilter(),
|
getGroupSearchFilter(config),
|
||||||
Collections.singleton(memberAttribute),
|
Collections.singleton(memberAttribute),
|
||||||
userIDorDN,
|
userIDorDN,
|
||||||
groupAttributes
|
groupAttributes
|
||||||
@@ -244,9 +245,8 @@ public class UserGroupService {
|
|||||||
* member of. Only identifiers of user groups which are readable by the
|
* member of. Only identifiers of user groups which are readable by the
|
||||||
* current user will be retrieved.
|
* current user will be retrieved.
|
||||||
*
|
*
|
||||||
* @param ldapConnection
|
* @param config
|
||||||
* The current connection to the LDAP server, associated with the
|
* The configuration of the LDAP server being queried.
|
||||||
* current user.
|
|
||||||
*
|
*
|
||||||
* @param userDN
|
* @param userDN
|
||||||
* The DN of the user whose group membership should be retrieved.
|
* The DN of the user whose group membership should be retrieved.
|
||||||
@@ -258,11 +258,11 @@ public class UserGroupService {
|
|||||||
* @throws GuacamoleException
|
* @throws GuacamoleException
|
||||||
* If an error occurs preventing retrieval of user groups.
|
* If an error occurs preventing retrieval of user groups.
|
||||||
*/
|
*/
|
||||||
public Set<String> getParentUserGroupIdentifiers(LdapNetworkConnection ldapConnection,
|
public Set<String> getParentUserGroupIdentifiers(ConnectedLDAPConfiguration config, Dn userDN)
|
||||||
Dn userDN) throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
Collection<String> attributes = confService.getGroupNameAttributes();
|
Collection<String> attributes = config.getGroupNameAttributes();
|
||||||
List<Entry> userGroups = getParentUserGroupEntries(ldapConnection, userDN);
|
List<Entry> userGroups = getParentUserGroupEntries(config, userDN);
|
||||||
|
|
||||||
Set<String> identifiers = new HashSet<>(userGroups.size());
|
Set<String> identifiers = new HashSet<>(userGroups.size());
|
||||||
userGroups.forEach(entry -> {
|
userGroups.forEach(entry -> {
|
||||||
|
@@ -24,6 +24,7 @@ import java.util.Collections;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.apache.directory.api.ldap.model.name.Dn;
|
import org.apache.directory.api.ldap.model.name.Dn;
|
||||||
|
import org.apache.guacamole.auth.ldap.ConnectedLDAPConfiguration;
|
||||||
import org.apache.guacamole.net.auth.AbstractAuthenticatedUser;
|
import org.apache.guacamole.net.auth.AbstractAuthenticatedUser;
|
||||||
import org.apache.guacamole.net.auth.AuthenticationProvider;
|
import org.apache.guacamole.net.auth.AuthenticationProvider;
|
||||||
import org.apache.guacamole.net.auth.Credentials;
|
import org.apache.guacamole.net.auth.Credentials;
|
||||||
@@ -63,9 +64,19 @@ public class LDAPAuthenticatedUser extends AbstractAuthenticatedUser {
|
|||||||
*/
|
*/
|
||||||
private Dn bindDn;
|
private Dn bindDn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The configuration of the LDAP server that should be used for all queries
|
||||||
|
* related to this AuthenticatedUser.
|
||||||
|
*/
|
||||||
|
private ConnectedLDAPConfiguration config;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes this AuthenticatedUser with the given credentials,
|
* 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
|
||||||
|
* queries related to this AuthenticatedUser.
|
||||||
*
|
*
|
||||||
* @param credentials
|
* @param credentials
|
||||||
* The credentials provided when this user was authenticated.
|
* The credentials provided when this user was authenticated.
|
||||||
@@ -77,17 +88,15 @@ 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(UserLDAPConfiguration config, Credentials credentials,
|
||||||
Set<String> effectiveGroups, Dn bindDn) {
|
Map<String, String> tokens, Set<String> effectiveGroups) {
|
||||||
|
this.config = config;
|
||||||
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;
|
this.bindDn = config.getBindDN();
|
||||||
setIdentifier(credentials.getUsername());
|
setIdentifier(config.getGuacamoleUsername());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -103,7 +112,7 @@ 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.
|
* Returns the LDAP DN used to bind this user.
|
||||||
*
|
*
|
||||||
@@ -114,6 +123,18 @@ public class LDAPAuthenticatedUser extends AbstractAuthenticatedUser {
|
|||||||
return bindDn;
|
return bindDn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the configuration of the LDAP server that should be used for all
|
||||||
|
* queries related to this AuthenticatedUser.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The configuration of the LDAP server related to this
|
||||||
|
* AuthenticatedUser.
|
||||||
|
*/
|
||||||
|
public ConnectedLDAPConfiguration getLDAPConfiguration() {
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AuthenticationProvider getAuthenticationProvider() {
|
public AuthenticationProvider getAuthenticationProvider() {
|
||||||
return authProvider;
|
return authProvider;
|
||||||
@@ -129,4 +150,9 @@ public class LDAPAuthenticatedUser extends AbstractAuthenticatedUser {
|
|||||||
return effectiveGroups;
|
return effectiveGroups;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invalidate() {
|
||||||
|
config.close();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -21,13 +21,11 @@ package org.apache.guacamole.auth.ldap.user;
|
|||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import org.apache.directory.ldap.client.api.LdapNetworkConnection;
|
|
||||||
import org.apache.guacamole.auth.ldap.connection.ConnectionService;
|
import org.apache.guacamole.auth.ldap.connection.ConnectionService;
|
||||||
import org.apache.guacamole.GuacamoleException;
|
import org.apache.guacamole.GuacamoleException;
|
||||||
import org.apache.guacamole.auth.ldap.LDAPAuthenticationProvider;
|
import org.apache.guacamole.auth.ldap.LDAPAuthenticationProvider;
|
||||||
import org.apache.guacamole.auth.ldap.group.UserGroupService;
|
import org.apache.guacamole.auth.ldap.group.UserGroupService;
|
||||||
import org.apache.guacamole.net.auth.AbstractUserContext;
|
import org.apache.guacamole.net.auth.AbstractUserContext;
|
||||||
import org.apache.guacamole.net.auth.AuthenticatedUser;
|
|
||||||
import org.apache.guacamole.net.auth.AuthenticationProvider;
|
import org.apache.guacamole.net.auth.AuthenticationProvider;
|
||||||
import org.apache.guacamole.net.auth.Connection;
|
import org.apache.guacamole.net.auth.Connection;
|
||||||
import org.apache.guacamole.net.auth.ConnectionGroup;
|
import org.apache.guacamole.net.auth.ConnectionGroup;
|
||||||
@@ -101,38 +99,32 @@ public class LDAPUserContext extends AbstractUserContext {
|
|||||||
private ConnectionGroup rootGroup;
|
private ConnectionGroup rootGroup;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes this UserContext using the provided AuthenticatedUser and
|
* Initializes this UserContext using the provided AuthenticatedUser.
|
||||||
* LdapNetworkConnection.
|
|
||||||
*
|
*
|
||||||
* @param user
|
* @param user
|
||||||
* The AuthenticatedUser representing the user that authenticated. This
|
* The AuthenticatedUser representing the user that authenticated. This
|
||||||
* user may have been authenticated by a different authentication
|
* user will always have been authenticated via LDAP, as LDAP data is
|
||||||
* provider (not LDAP).
|
* 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
|
* @throws GuacamoleException
|
||||||
* If associated data stored within the LDAP directory cannot be
|
* If associated data stored within the LDAP directory cannot be
|
||||||
* queried due to an error.
|
* queried due to an error.
|
||||||
*/
|
*/
|
||||||
public void init(AuthenticatedUser user, LdapNetworkConnection ldapConnection)
|
public void init(LDAPAuthenticatedUser user) throws GuacamoleException {
|
||||||
throws GuacamoleException {
|
|
||||||
|
|
||||||
// Query all accessible users
|
// Query all accessible users
|
||||||
userDirectory = new SimpleDirectory<>(
|
userDirectory = new SimpleDirectory<>(
|
||||||
userService.getUsers(ldapConnection)
|
userService.getUsers(user)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Query all accessible user groups
|
// Query all accessible user groups
|
||||||
userGroupDirectory = new SimpleDirectory<>(
|
userGroupDirectory = new SimpleDirectory<>(
|
||||||
userGroupService.getUserGroups(ldapConnection)
|
userGroupService.getUserGroups(user)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Query all accessible connections
|
// Query all accessible connections
|
||||||
connectionDirectory = new SimpleDirectory<>(
|
connectionDirectory = new SimpleDirectory<>(
|
||||||
connectionService.getConnections(user, ldapConnection)
|
connectionService.getConnections(user)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Root group contains only connections
|
// Root group contains only connections
|
||||||
|
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* 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.user;
|
||||||
|
|
||||||
|
import org.apache.directory.api.ldap.model.name.Dn;
|
||||||
|
import org.apache.directory.ldap.client.api.LdapNetworkConnection;
|
||||||
|
import org.apache.guacamole.auth.ldap.ConnectedLDAPConfiguration;
|
||||||
|
import org.apache.guacamole.auth.ldap.conf.LDAPConfiguration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LDAPConfiguration implementation that represents the configuration and
|
||||||
|
* network connection of an LDAP that has been bound on behalf of a Guacamole
|
||||||
|
* user.
|
||||||
|
*/
|
||||||
|
public class UserLDAPConfiguration extends ConnectedLDAPConfiguration {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The username of the associated Guacamole user.
|
||||||
|
*/
|
||||||
|
private final String username;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new UserLDAPConfiguration that associates the given
|
||||||
|
* LDAPConfiguration of an LDAP server with the active network connection to
|
||||||
|
* that server, as well as the username of the Guacamole user on behalf of
|
||||||
|
* whom that connection was established. 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 username
|
||||||
|
* The username of the associated Guacamole user.
|
||||||
|
*
|
||||||
|
* @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 UserLDAPConfiguration(LDAPConfiguration config,
|
||||||
|
String username, Dn bindDn, LdapNetworkConnection connection) {
|
||||||
|
super(config, bindDn, connection);
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the username of the Guacamole user on behalf of whom the
|
||||||
|
* associated LDAP network connection was established.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The username of the associated Guacamole user.
|
||||||
|
*/
|
||||||
|
public String getGuacamoleUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -32,11 +32,12 @@ import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueEx
|
|||||||
import org.apache.directory.api.ldap.model.name.Dn;
|
import org.apache.directory.api.ldap.model.name.Dn;
|
||||||
import org.apache.directory.api.ldap.model.name.Rdn;
|
import org.apache.directory.api.ldap.model.name.Rdn;
|
||||||
import org.apache.directory.ldap.client.api.LdapNetworkConnection;
|
import org.apache.directory.ldap.client.api.LdapNetworkConnection;
|
||||||
import org.apache.guacamole.auth.ldap.conf.ConfigurationService;
|
|
||||||
import org.apache.guacamole.GuacamoleException;
|
import org.apache.guacamole.GuacamoleException;
|
||||||
import org.apache.guacamole.GuacamoleServerException;
|
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.conf.LDAPGuacamoleProperties;
|
||||||
import org.apache.guacamole.auth.ldap.ObjectQueryService;
|
import org.apache.guacamole.auth.ldap.ObjectQueryService;
|
||||||
|
import org.apache.guacamole.auth.ldap.conf.LDAPConfiguration;
|
||||||
import org.apache.guacamole.net.auth.User;
|
import org.apache.guacamole.net.auth.User;
|
||||||
import org.apache.guacamole.net.auth.simple.SimpleUser;
|
import org.apache.guacamole.net.auth.simple.SimpleUser;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -53,12 +54,6 @@ public class UserService {
|
|||||||
*/
|
*/
|
||||||
private static final Logger logger = LoggerFactory.getLogger(UserService.class);
|
private static final Logger logger = LoggerFactory.getLogger(UserService.class);
|
||||||
|
|
||||||
/**
|
|
||||||
* Service for retrieving LDAP server configuration information.
|
|
||||||
*/
|
|
||||||
@Inject
|
|
||||||
private ConfigurationService confService;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service for executing LDAP queries.
|
* Service for executing LDAP queries.
|
||||||
*/
|
*/
|
||||||
@@ -66,12 +61,11 @@ public class UserService {
|
|||||||
private ObjectQueryService queryService;
|
private ObjectQueryService queryService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all Guacamole users accessible to the user currently bound under
|
* Returns all Guacamole users accessible to the given user.
|
||||||
* the given LDAP connection.
|
|
||||||
*
|
*
|
||||||
* @param ldapConnection
|
* @param user
|
||||||
* The current connection to the LDAP server, associated with the
|
* The AuthenticatedUser object associated with the user who is
|
||||||
* current user.
|
* currently authenticated with Guacamole.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* All users accessible to the user currently bound under the given
|
* All users accessible to the user currently bound under the given
|
||||||
@@ -81,19 +75,24 @@ public class UserService {
|
|||||||
* @throws GuacamoleException
|
* @throws GuacamoleException
|
||||||
* If an error occurs preventing retrieval of users.
|
* If an error occurs preventing retrieval of users.
|
||||||
*/
|
*/
|
||||||
public Map<String, User> getUsers(LdapNetworkConnection ldapConnection)
|
public Map<String, User> getUsers(LDAPAuthenticatedUser user)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
|
ConnectedLDAPConfiguration config = user.getLDAPConfiguration();
|
||||||
|
|
||||||
// Retrieve all visible user objects
|
// Retrieve all visible user objects
|
||||||
Collection<String> usernameAttrs = confService.getUsernameAttributes();
|
Collection<String> usernameAttrs = config.getUsernameAttributes();
|
||||||
Collection<String> attributes = new HashSet<>(usernameAttrs);
|
Collection<String> attributes = new HashSet<>(usernameAttrs);
|
||||||
attributes.addAll(confService.getAttributes());
|
attributes.addAll(config.getAttributes());
|
||||||
List<Entry> results = queryService.search(ldapConnection,
|
List<Entry> results = queryService.search(
|
||||||
confService.getUserBaseDN(),
|
config,
|
||||||
confService.getUserSearchFilter(),
|
config.getLDAPConnection(),
|
||||||
usernameAttrs,
|
config.getUserBaseDN(),
|
||||||
null,
|
config.getUserSearchFilter(),
|
||||||
attributes);
|
usernameAttrs,
|
||||||
|
null,
|
||||||
|
attributes
|
||||||
|
);
|
||||||
|
|
||||||
// Convert retrieved users to map of identifier to Guacamole user object
|
// Convert retrieved users to map of identifier to Guacamole user object
|
||||||
return queryService.asMap(results, entry -> {
|
return queryService.asMap(results, entry -> {
|
||||||
@@ -124,6 +123,9 @@ public class UserService {
|
|||||||
* is not enforced across the username attribute, it is possible that this
|
* is not enforced across the username attribute, it is possible that this
|
||||||
* will return multiple DNs.
|
* will return multiple DNs.
|
||||||
*
|
*
|
||||||
|
* @param config
|
||||||
|
* The configuration of the LDAP server being queried.
|
||||||
|
*
|
||||||
* @param ldapConnection
|
* @param ldapConnection
|
||||||
* The connection to the LDAP server to use when querying user DNs.
|
* The connection to the LDAP server to use when querying user DNs.
|
||||||
*
|
*
|
||||||
@@ -139,14 +141,14 @@ public class UserService {
|
|||||||
* If an error occurs while querying the user DNs, or if the username
|
* If an error occurs while querying the user DNs, or if the username
|
||||||
* attribute property cannot be parsed within guacamole.properties.
|
* attribute property cannot be parsed within guacamole.properties.
|
||||||
*/
|
*/
|
||||||
public List<Dn> getUserDNs(LdapNetworkConnection ldapConnection,
|
public List<Dn> getUserDNs(LDAPConfiguration config, LdapNetworkConnection ldapConnection,
|
||||||
String username) throws GuacamoleException {
|
String username) throws GuacamoleException {
|
||||||
|
|
||||||
// Retrieve user objects having a matching username
|
// Retrieve user objects having a matching username
|
||||||
List<Entry> results = queryService.search(ldapConnection,
|
List<Entry> results = queryService.search(config, ldapConnection,
|
||||||
confService.getUserBaseDN(),
|
config.getUserBaseDN(),
|
||||||
confService.getUserSearchFilter(),
|
config.getUserSearchFilter(),
|
||||||
confService.getUsernameAttributes(),
|
config.getUsernameAttributes(),
|
||||||
username,
|
username,
|
||||||
Collections.singletonList("dn"));
|
Collections.singletonList("dn"));
|
||||||
|
|
||||||
@@ -164,6 +166,9 @@ public class UserService {
|
|||||||
* or queried from the LDAP server, depending on how LDAP authentication
|
* or queried from the LDAP server, depending on how LDAP authentication
|
||||||
* has been configured.
|
* has been configured.
|
||||||
*
|
*
|
||||||
|
* @param config
|
||||||
|
* The configuration of the LDAP server being queried.
|
||||||
|
*
|
||||||
* @param username
|
* @param username
|
||||||
* The username of the user whose corresponding DN should be returned.
|
* The username of the user whose corresponding DN should be returned.
|
||||||
*
|
*
|
||||||
@@ -174,11 +179,11 @@ public class UserService {
|
|||||||
* If required properties are missing, and thus the user DN cannot be
|
* If required properties are missing, and thus the user DN cannot be
|
||||||
* determined.
|
* determined.
|
||||||
*/
|
*/
|
||||||
public Dn deriveUserDN(String username)
|
public Dn deriveUserDN(LDAPConfiguration config, String username)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
// Pull username attributes from properties
|
// Pull username attributes from properties
|
||||||
List<String> usernameAttributes = confService.getUsernameAttributes();
|
List<String> usernameAttributes = config.getUsernameAttributes();
|
||||||
|
|
||||||
// We need exactly one base DN to derive the user DN
|
// We need exactly one base DN to derive the user DN
|
||||||
if (usernameAttributes.size() != 1) {
|
if (usernameAttributes.size() != 1) {
|
||||||
@@ -193,7 +198,7 @@ public class UserService {
|
|||||||
// Derive user DN from base DN
|
// Derive user DN from base DN
|
||||||
try {
|
try {
|
||||||
return new Dn(new Rdn(usernameAttributes.get(0), username),
|
return new Dn(new Rdn(usernameAttributes.get(0), username),
|
||||||
confService.getUserBaseDN());
|
config.getUserBaseDN());
|
||||||
}
|
}
|
||||||
catch (LdapInvalidAttributeValueException | LdapInvalidDnException e) {
|
catch (LdapInvalidAttributeValueException | LdapInvalidDnException e) {
|
||||||
throw new GuacamoleServerException("Error trying to derive user DN.", e);
|
throw new GuacamoleServerException("Error trying to derive user DN.", e);
|
||||||
|
5
pom.xml
5
pom.xml
@@ -377,6 +377,11 @@
|
|||||||
<artifactId>jackson-databind</artifactId>
|
<artifactId>jackson-databind</artifactId>
|
||||||
<version>${jackson.version}</version>
|
<version>${jackson.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
||||||
|
<artifactId>jackson-dataformat-yaml</artifactId>
|
||||||
|
<version>${jackson.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.fasterxml.jackson.module</groupId>
|
<groupId>com.fasterxml.jackson.module</groupId>
|
||||||
<artifactId>jackson-module-jaxb-annotations</artifactId>
|
<artifactId>jackson-module-jaxb-annotations</artifactId>
|
||||||
|
Reference in New Issue
Block a user