blob: 14cfd8e3a24aa8d8264dfbdf2241b645af48320f [file] [log] [blame]
/*
* 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.group;
import com.google.inject.Inject;
import com.novell.ldap.LDAPConnection;
import com.novell.ldap.LDAPEntry;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.guacamole.auth.ldap.ConfigurationService;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.ldap.ObjectQueryService;
import org.apache.guacamole.net.auth.UserGroup;
import org.apache.guacamole.net.auth.simple.SimpleUserGroup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Service for querying user group membership and retrieving user groups
* visible to a particular Guacamole user.
*/
public class UserGroupService {
/**
* Logger for this class.
*/
private final Logger logger = LoggerFactory.getLogger(UserGroupService.class);
/**
* Service for retrieving LDAP server configuration information.
*/
@Inject
private ConfigurationService confService;
/**
* Service for executing LDAP queries.
*/
@Inject
private ObjectQueryService queryService;
/**
* Returns the base search filter which should be used to retrieve user
* groups which do not represent Guacamole connections. As excluding the
* guacConfigGroup object class may not work as expected if it is not
* defined (may always return zero results), it should only be explicitly
* excluded if it is expected to have been defined.
*
* @return
* The base search filter which should be used to retrieve user groups.
*
* @throws GuacamoleException
* If guacamole.properties cannot be parsed.
*/
private String getGroupSearchFilter() throws GuacamoleException {
// Explicitly exclude guacConfigGroup object class only if it should
// be assumed to be defined (query may fail due to no such object
// class existing otherwise)
if (confService.getConfigurationBaseDN() != null)
return "(!(objectClass=guacConfigGroup))";
// Read any object as a group if LDAP is not being used for connection
// storage (guacConfigGroup)
return "(objectClass=*)";
}
/**
* Returns all Guacamole user groups accessible to the user currently bound
* under the given LDAP connection.
*
* @param ldapConnection
* The current connection to the LDAP server, associated with the
* current user.
*
* @return
* All user groups accessible to the user currently bound under the
* given LDAP connection, as a map of user group identifier to
* corresponding UserGroup object.
*
* @throws GuacamoleException
* If an error occurs preventing retrieval of user groups.
*/
public Map<String, UserGroup> getUserGroups(LDAPConnection ldapConnection)
throws GuacamoleException {
// Do not return any user groups if base DN is not specified
String groupBaseDN = confService.getGroupBaseDN();
if (groupBaseDN == null)
return Collections.emptyMap();
// Retrieve all visible user groups which are not guacConfigGroups
Collection<String> attributes = confService.getGroupNameAttributes();
List<LDAPEntry> results = queryService.search(
ldapConnection,
groupBaseDN,
getGroupSearchFilter(),
attributes,
null
);
// Convert retrieved user groups to map of identifier to Guacamole
// user group object
return queryService.asMap(results, entry -> {
// Translate entry into UserGroup object having proper identifier
String name = queryService.getIdentifier(entry, attributes);
if (name != null)
return new SimpleUserGroup(name);
// Ignore user groups which lack a name attribute
logger.debug("User group \"{}\" is missing a name attribute "
+ "and will be ignored.", entry.getDN());
return null;
});
}
/**
* Returns the LDAP entries representing all user groups that the given
* user is a member of. Only user groups which are readable by the current
* user will be retrieved.
*
* @param ldapConnection
* The current connection to the LDAP server, associated with the
* current user.
*
* @param userDN
* The DN of the user whose group membership should be retrieved.
*
* @return
* The LDAP entries representing all readable parent user groups of the
* user having the given DN.
*
* @throws GuacamoleException
* If an error occurs preventing retrieval of user groups.
*/
public List<LDAPEntry> getParentUserGroupEntries(LDAPConnection ldapConnection,
String userDN) throws GuacamoleException {
// Do not return any user groups if base DN is not specified
String groupBaseDN = confService.getGroupBaseDN();
if (groupBaseDN == null)
return Collections.emptyList();
// Get all groups the user is a member of starting at the groupBaseDN,
// excluding guacConfigGroups
return queryService.search(
ldapConnection,
groupBaseDN,
getGroupSearchFilter(),
Collections.singleton("member"),
userDN
);
}
/**
* Returns the identifiers of all user groups that the given user is a
* member of. Only identifiers of user groups which are readable by the
* current user will be retrieved.
*
* @param ldapConnection
* The current connection to the LDAP server, associated with the
* current user.
*
* @param userDN
* The DN of the user whose group membership should be retrieved.
*
* @return
* The identifiers of all readable parent user groups of the user
* having the given DN.
*
* @throws GuacamoleException
* If an error occurs preventing retrieval of user groups.
*/
public Set<String> getParentUserGroupIdentifiers(LDAPConnection ldapConnection,
String userDN) throws GuacamoleException {
Collection<String> attributes = confService.getGroupNameAttributes();
List<LDAPEntry> userGroups = getParentUserGroupEntries(ldapConnection, userDN);
Set<String> identifiers = new HashSet<>(userGroups.size());
userGroups.forEach(entry -> {
// Determine unique identifier for user group
String name = queryService.getIdentifier(entry, attributes);
if (name != null)
identifiers.add(name);
// Ignore user groups which lack a name attribute
else
logger.debug("User group \"{}\" is missing a name attribute "
+ "and will be ignored.", entry.getDN());
});
return identifiers;
}
}