Check RDN attribute for DN membership

Closes https://github.com/keycloak/keycloak/issues/20718
This commit is contained in:
rmartinc 2023-07-18 08:52:45 +02:00 committed by Alexander Schwartz
parent 3cbd4eb10a
commit 7336ff07ac
2 changed files with 13 additions and 9 deletions

View file

@ -50,18 +50,20 @@ public enum MembershipType {
@Override @Override
public Set<LDAPDn> getLDAPSubgroups(CommonLDAPGroupMapper groupMapper, LDAPObject ldapGroup) { public Set<LDAPDn> getLDAPSubgroups(CommonLDAPGroupMapper groupMapper, LDAPObject ldapGroup) {
CommonLDAPGroupMapperConfig config = groupMapper.getConfig(); CommonLDAPGroupMapperConfig config = groupMapper.getConfig();
return getLDAPMembersWithParent(groupMapper.getLdapProvider(), ldapGroup, config.getMembershipLdapAttribute(), LDAPDn.fromString(config.getLDAPGroupsDn())); return getLDAPMembersWithParent(groupMapper.getLdapProvider(), ldapGroup, config.getMembershipLdapAttribute(),
LDAPDn.fromString(config.getLDAPGroupsDn()), config.getLDAPGroupNameLdapAttribute());
} }
// Get just those members of specified group, which are descendants of "requiredParentDn" // Get just those members of specified group, which are descendants of "requiredParentDn"
protected Set<LDAPDn> getLDAPMembersWithParent(LDAPStorageProvider ldapProvider, LDAPObject ldapGroup, String membershipLdapAttribute, LDAPDn requiredParentDn) { protected Set<LDAPDn> getLDAPMembersWithParent(LDAPStorageProvider ldapProvider, LDAPObject ldapGroup,
String membershipLdapAttribute, LDAPDn requiredParentDn, String rdnAttr) {
Set<String> allMemberships = LDAPUtils.getExistingMemberships(ldapProvider, membershipLdapAttribute, ldapGroup); Set<String> allMemberships = LDAPUtils.getExistingMemberships(ldapProvider, membershipLdapAttribute, ldapGroup);
// Filter and keep just descendants of requiredParentDn // Filter and keep just descendants of requiredParentDn
Set<LDAPDn> result = new HashSet<>(); Set<LDAPDn> result = new HashSet<>();
for (String membership : allMemberships) { for (String membership : allMemberships) {
LDAPDn childDn = LDAPDn.fromString(membership); LDAPDn childDn = LDAPDn.fromString(membership);
if (childDn.isDescendantOf(requiredParentDn)) { if (childDn.getFirstRdn().getAttrValue(rdnAttr) != null && childDn.isDescendantOf(requiredParentDn)) {
result.add(childDn); result.add(childDn);
} }
} }
@ -73,8 +75,9 @@ public enum MembershipType {
LDAPStorageProvider ldapProvider = groupMapper.getLdapProvider(); LDAPStorageProvider ldapProvider = groupMapper.getLdapProvider();
CommonLDAPGroupMapperConfig config = groupMapper.getConfig(); CommonLDAPGroupMapperConfig config = groupMapper.getConfig();
LDAPConfig ldapConfig = ldapProvider.getLdapIdentityStore().getConfig();
LDAPDn usersDn = LDAPDn.fromString(ldapProvider.getLdapIdentityStore().getConfig().getUsersDn()); LDAPDn usersDn = LDAPDn.fromString(ldapProvider.getLdapIdentityStore().getConfig().getUsersDn());
Set<LDAPDn> userDns = getLDAPMembersWithParent(ldapProvider, ldapGroup, config.getMembershipLdapAttribute(), usersDn); Set<LDAPDn> userDns = getLDAPMembersWithParent(ldapProvider, ldapGroup, config.getMembershipLdapAttribute(), usersDn, ldapConfig.getRdnLdapAttribute());
if (userDns == null) { if (userDns == null) {
return Collections.emptyList(); return Collections.emptyList();
@ -90,14 +93,9 @@ public enum MembershipType {
// If usernameAttrName is same like DN, we can just retrieve usernames from DNs // If usernameAttrName is same like DN, we can just retrieve usernames from DNs
List<String> usernames = new LinkedList<>(); List<String> usernames = new LinkedList<>();
LDAPConfig ldapConfig = ldapProvider.getLdapIdentityStore().getConfig();
if (ldapConfig.getUsernameLdapAttribute().equals(ldapConfig.getRdnLdapAttribute())) { if (ldapConfig.getUsernameLdapAttribute().equals(ldapConfig.getRdnLdapAttribute())) {
for (LDAPDn userDn : dns) { for (LDAPDn userDn : dns) {
String username = userDn.getFirstRdn().getAttrValue(ldapConfig.getRdnLdapAttribute()); String username = userDn.getFirstRdn().getAttrValue(ldapConfig.getRdnLdapAttribute());
if (username == null) {
throw new ModelException("User returned from LDAP has null username! Check configuration of your LDAP mappings. Mapped username LDAP attribute: " +
ldapConfig.getRdnLdapAttribute() + ", user DN: " + userDn + ", attributes from LDAP: " + userDn.getFirstRdn().getAllKeys());
}
usernames.add(username); usernames.add(username);
} }
} else { } else {

View file

@ -36,6 +36,7 @@ import org.keycloak.representations.idm.ComponentRepresentation;
import org.keycloak.representations.idm.SynchronizationResultRepresentation; import org.keycloak.representations.idm.SynchronizationResultRepresentation;
import org.keycloak.storage.ldap.LDAPStorageProvider; import org.keycloak.storage.ldap.LDAPStorageProvider;
import org.keycloak.storage.ldap.LDAPUtils; import org.keycloak.storage.ldap.LDAPUtils;
import org.keycloak.storage.ldap.idm.model.LDAPDn;
import org.keycloak.storage.ldap.idm.model.LDAPObject; import org.keycloak.storage.ldap.idm.model.LDAPObject;
import org.keycloak.storage.ldap.mappers.membership.LDAPGroupMapperMode; import org.keycloak.storage.ldap.mappers.membership.LDAPGroupMapperMode;
import org.keycloak.storage.ldap.mappers.membership.MembershipType; import org.keycloak.storage.ldap.mappers.membership.MembershipType;
@ -94,6 +95,11 @@ public class LDAPGroupMapperSyncTest extends AbstractLDAPTest {
LDAPUtils.addMember(ctx.getLdapProvider(), MembershipType.DN, LDAPConstants.MEMBER, "not-used", group1, group11); LDAPUtils.addMember(ctx.getLdapProvider(), MembershipType.DN, LDAPConstants.MEMBER, "not-used", group1, group11);
LDAPUtils.addMember(ctx.getLdapProvider(), MembershipType.DN, LDAPConstants.MEMBER, "not-used", group1, group12); LDAPUtils.addMember(ctx.getLdapProvider(), MembershipType.DN, LDAPConstants.MEMBER, "not-used", group1, group12);
LDAPObject nonExistentChild = new LDAPObject();
LDAPDn nonExistentChildDn = group1.getDn().getParentDn();
nonExistentChildDn.addFirst(LDAPConstants.UID, "non-existent-child");
nonExistentChild.setDn(nonExistentChildDn);
LDAPUtils.addMember(ctx.getLdapProvider(), MembershipType.DN, LDAPConstants.MEMBER, "not-used", group1, nonExistentChild);
}); });
} }