GUACAMOLE-300: Support posixGroup in LDAP Authentication and Group-based Session Admission

reset/rebase/squash a chaos of commits:
- implement user/group membership search using Apache Directory Ldap module instead of JLDAP
- Retrieve user's group membership if specified by username rather than DN
- New enum 'MemberAttributeType'
- New GuacamoleProperty 'MemberAttributeTypeProperty'
- New configuration property 'ldap-member-attribute-type'
    Specifies what the field specified by 'ldap-member-attribute' actually
    contains -- "dn" (default) or "uid" or ...
This commit is contained in:
Magnus Lewis-Smith
2019-10-23 10:48:22 +01:00
parent ff8fb55880
commit 450af91be9
5 changed files with 146 additions and 1 deletions

View File

@@ -373,4 +373,22 @@ public class ConfigurationService {
); );
} }
/**
* 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
);
}
} }

View File

@@ -255,4 +255,15 @@ public class LDAPGuacamoleProperties {
public String getName() { return "ldap-member-attribute"; } public String getName() { return "ldap-member-attribute"; }
}; };
/**
* Specify the type of data contained in 'ldap-member-attribute'
*/
public static final MemberAttributeTypeProperty LDAP_MEMBER_ATTRIBUTE_TYPE = new MemberAttributeTypeProperty() {
@Override
public String getName() { return "ldap-member-attribute-type"; }
};
} }

View File

@@ -0,0 +1,34 @@
/*
* 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;
/**
* All possible means of describing membership within LDAP group directory records.
*/
public enum MemberAttributeType {
/**
* group membership is specified by DN
*/
DN,
/**
* group membership is specified by usercode
*/
UID;
}

View File

@@ -0,0 +1,53 @@
/*
* 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 org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleServerException;
import org.apache.guacamole.properties.GuacamoleProperty;
/**
* A GuacamoleProperty whose value is a MemberAttributeType. The possible
* strings "dn" or "uid" are mapped to their values as a MemberAttributeType
* enum. Anything else results in a parse error.
*/
public abstract class MemberAttributeTypeProperty implements GuacamoleProperty<MemberAttributeType> {
@Override
public MemberAttributeType parseValue(String value) throws GuacamoleException {
// If no value provided, return null.
if (value == null)
return null;
// dn
if (value.equals("dn"))
return MemberAttributeType.DN;
// uid
if (value.equals("uid"))
return MemberAttributeType.UID;
// The provided value is not legal
throw new GuacamoleServerException("Member attribute type must be one of \"dn\" or \"uid\".");
}
}

View File

@@ -35,6 +35,7 @@ import org.apache.directory.api.ldap.model.filter.PresenceNode;
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.directory.ldap.client.api.LdapNetworkConnection;
import org.apache.guacamole.auth.ldap.conf.ConfigurationService; import org.apache.guacamole.auth.ldap.conf.ConfigurationService;
import org.apache.guacamole.auth.ldap.conf.MemberAttributeType;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.ldap.ObjectQueryService; import org.apache.guacamole.auth.ldap.ObjectQueryService;
import org.apache.guacamole.net.auth.UserGroup; import org.apache.guacamole.net.auth.UserGroup;
@@ -176,6 +177,34 @@ public class UserGroupService {
if (groupBaseDN == null) if (groupBaseDN == null)
return Collections.emptyList(); return Collections.emptyList();
// memberAttribute specified in properties could contain DN or username
MemberAttributeType memberAttributeType = confService.getMemberAttributeType();
String userIDorDN = userDN.toString();
if (memberAttributeType == MemberAttributeType.UID) {
// Retrieve user objects with userDN
List<Entry> userEntries = queryService.search(
ldapConnection,
userDN,
confService.getUserSearchFilter(),
0);
// ... there can surely only be one
if (userEntries.size() != 1) {
logger.warn("user DN \"{}\" does not return unique value and will be ignored",
userDN.toString());
} else {
// determine unique identifier for user
Entry userEntry = userEntries.get(0);
Collection<String> userAttributes = confService.getUsernameAttributes();
try {
userIDorDN = queryService.getIdentifier(userEntry, userAttributes);
}
catch (LdapInvalidAttributeValueException e) {
logger.error("User group missing identifier: {}", e.getMessage());
logger.debug("LDAP exception while getting group identifier.", e);
}
}
}
// 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(
@@ -183,7 +212,7 @@ public class UserGroupService {
groupBaseDN, groupBaseDN,
getGroupSearchFilter(), getGroupSearchFilter(),
Collections.singleton(confService.getMemberAttribute()), Collections.singleton(confService.getMemberAttribute()),
userDN.toString() userIDorDN
); );
} }