KEYCLOAK-2655 Support of lazy sync LDAP groups, which user is member of
This commit is contained in:
parent
85ccd64e01
commit
1142ed5583
4 changed files with 81 additions and 12 deletions
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue