KEYCLOAK-2655 Support of lazy sync LDAP groups, which user is member of

This commit is contained in:
mposolda 2016-03-11 22:29:22 +01:00
parent 85ccd64e01
commit 1142ed5583
4 changed files with 81 additions and 12 deletions

View file

@ -288,29 +288,46 @@ public class GroupLDAPFederationMapper extends AbstractLDAPFederationMapper impl
} }
} }
// Override if better effectivity or different algorithm is needed
protected GroupModel findKcGroupByLDAPGroup(LDAPObject ldapGroup) { protected GroupModel findKcGroupByLDAPGroup(LDAPObject ldapGroup) {
String groupNameAttr = config.getGroupNameLdapAttribute(); String groupNameAttr = config.getGroupNameLdapAttribute();
String groupName = ldapGroup.getAttributeAsString(groupNameAttr); String groupName = ldapGroup.getAttributeAsString(groupNameAttr);
List<GroupModel> groups = realm.getGroups(); if (config.isPreserveGroupsInheritance()) {
for (GroupModel group : groups) { // Override if better effectivity or different algorithm is needed
if (group.getName().equals(groupName)) { List<GroupModel> groups = realm.getGroups();
return group; for (GroupModel group : groups) {
if (group.getName().equals(groupName)) {
return group;
}
} }
}
return null; return null;
} else {
// Without preserved inheritance, it's always top-level group
return KeycloakModelUtils.findGroupByPath(realm, "/" + groupName);
}
} }
protected GroupModel findKcGroupOrSyncFromLDAP(LDAPObject ldapGroup, UserModel user) { protected GroupModel findKcGroupOrSyncFromLDAP(LDAPObject ldapGroup, UserModel user) {
GroupModel kcGroup = findKcGroupByLDAPGroup(ldapGroup); GroupModel kcGroup = findKcGroupByLDAPGroup(ldapGroup);
if (kcGroup == null) { if (kcGroup == null) {
// Sync groups from LDAP
if (!syncFromLDAPPerformedInThisTransaction) { if (config.isPreserveGroupsInheritance()) {
syncDataFromFederationProviderToKeycloak();
kcGroup = findKcGroupByLDAPGroup(ldapGroup); // Better to sync all groups from LDAP with preserved inheritance
if (!syncFromLDAPPerformedInThisTransaction) {
syncDataFromFederationProviderToKeycloak();
kcGroup = findKcGroupByLDAPGroup(ldapGroup);
}
} else {
String groupNameAttr = config.getGroupNameLdapAttribute();
String groupName = ldapGroup.getAttributeAsString(groupNameAttr);
kcGroup = realm.createGroup(groupName);
updateAttributesOfKCGroup(kcGroup, ldapGroup);
realm.moveGroup(kcGroup, null);
} }
// Could theoretically happen on some LDAP servers if 'memberof' style is used and 'memberof' attribute of user references non-existing group // Could theoretically happen on some LDAP servers if 'memberof' style is used and 'memberof' attribute of user references non-existing group

View file

@ -61,6 +61,7 @@ public class LDAPGroupMapper2WaySyncTest {
Map<String,String> ldapConfig = ldapRule.getConfig(); Map<String,String> ldapConfig = ldapRule.getConfig();
ldapConfig.put(LDAPConstants.SYNC_REGISTRATIONS, "true"); ldapConfig.put(LDAPConstants.SYNC_REGISTRATIONS, "true");
ldapConfig.put(LDAPConstants.EDIT_MODE, UserFederationProvider.EditMode.WRITABLE.toString()); ldapConfig.put(LDAPConstants.EDIT_MODE, UserFederationProvider.EditMode.WRITABLE.toString());
ldapConfig.put(LDAPConstants.BATCH_SIZE_FOR_SYNC, "4"); // Issues with pagination on ApacheDS
ldapModel = appRealm.addUserFederationProvider(LDAPFederationProviderFactory.PROVIDER_NAME, ldapConfig, 0, "test-ldap", -1, -1, 0); ldapModel = appRealm.addUserFederationProvider(LDAPFederationProviderFactory.PROVIDER_NAME, ldapConfig, 0, "test-ldap", -1, -1, 0);
LDAPFederationProvider ldapFedProvider = FederationTestUtils.getLdapProvider(session, ldapModel); LDAPFederationProvider ldapFedProvider = FederationTestUtils.getLdapProvider(session, ldapModel);

View file

@ -19,6 +19,7 @@ package org.keycloak.testsuite.federation.ldap.base;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
@ -46,6 +47,7 @@ import org.keycloak.models.UserFederationMapperModel;
import org.keycloak.models.UserFederationProvider; import org.keycloak.models.UserFederationProvider;
import org.keycloak.models.UserFederationProviderModel; import org.keycloak.models.UserFederationProviderModel;
import org.keycloak.models.UserFederationSyncResult; import org.keycloak.models.UserFederationSyncResult;
import org.keycloak.models.UserModel;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.RealmManager;
import org.keycloak.testsuite.federation.ldap.FederationTestUtils; import org.keycloak.testsuite.federation.ldap.FederationTestUtils;
@ -258,4 +260,53 @@ public class LDAPGroupMapperSyncTest {
} }
} }
@Test
public void test04_syncNoPreserveGroupInheritanceWithLazySync() throws Exception {
KeycloakSession session = keycloakRule.startSession();
try {
RealmModel realm = session.realms().getRealmByName("test");
UserFederationMapperModel mapperModel = realm.getUserFederationMapperByName(ldapModel.getId(), "groupsMapper");
LDAPFederationProvider ldapProvider = FederationTestUtils.getLdapProvider(session, ldapModel);
GroupLDAPFederationMapper groupMapper = FederationTestUtils.getGroupMapper(mapperModel, ldapProvider, realm);
// Update group mapper to skip preserve inheritance
FederationTestUtils.updateGroupMapperConfigOptions(mapperModel, GroupMapperConfig.PRESERVE_GROUP_INHERITANCE, "false");
realm.updateUserFederationMapper(mapperModel);
// Add user to LDAP and put him as member of group11
FederationTestUtils.removeAllLDAPUsers(ldapProvider, realm);
LDAPObject johnLdap = FederationTestUtils.addLDAPUser(ldapProvider, realm, "johnkeycloak", "John", "Doe", "john@email.org", null, "1234");
FederationTestUtils.updateLDAPPassword(ldapProvider, johnLdap, "Password1");
groupMapper.addGroupMappingInLDAP("group11", johnLdap);
// Assert groups not yet imported to Keycloak DB
Assert.assertNull(KeycloakModelUtils.findGroupByPath(realm, "/group1"));
Assert.assertNull(KeycloakModelUtils.findGroupByPath(realm, "/group11"));
Assert.assertNull(KeycloakModelUtils.findGroupByPath(realm, "/group12"));
// Load user from LDAP to Keycloak DB
UserModel john = session.users().getUserByUsername("johnkeycloak", realm);
Set<GroupModel> johnGroups = john.getGroups();
// Assert just those groups, which john was memberOf exists because they were lazily created
GroupModel group1 = KeycloakModelUtils.findGroupByPath(realm, "/group1");
GroupModel group11 = KeycloakModelUtils.findGroupByPath(realm, "/group11");
GroupModel group12 = KeycloakModelUtils.findGroupByPath(realm, "/group12");
Assert.assertNull(group1);
Assert.assertNotNull(group11);
Assert.assertNull(group12);
Assert.assertEquals(1, johnGroups.size());
Assert.assertTrue(johnGroups.contains(group11));
// Delete group mapping
john.leaveGroup(group11);
} finally {
keycloakRule.stopSession(session, false);
}
}
} }