/* * Copyright 2016 Red Hat, Inc. and/or its affiliates * and other contributors as indicated by the @author tags. * * Licensed 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.keycloak.testsuite.federation.ldap.base; import org.junit.Assert; import org.junit.ClassRule; import org.junit.FixMethodOrder; import org.junit.Rule; import org.junit.Test; import org.junit.runners.MethodSorters; import org.keycloak.federation.ldap.LDAPFederationProvider; import org.keycloak.federation.ldap.LDAPFederationProviderFactory; import org.keycloak.federation.ldap.mappers.membership.LDAPGroupMapperMode; import org.keycloak.federation.ldap.mappers.membership.group.GroupLDAPFederationMapperFactory; import org.keycloak.federation.ldap.mappers.membership.group.GroupMapperConfig; import org.keycloak.models.GroupModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.LDAPConstants; import org.keycloak.models.RealmModel; import org.keycloak.models.UserFederationMapperModel; import org.keycloak.models.UserFederationProvider; import org.keycloak.models.UserFederationProviderModel; import org.keycloak.models.UserFederationSyncResult; import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.services.managers.RealmManager; import org.keycloak.testsuite.federation.ldap.FederationTestUtils; import org.keycloak.testsuite.rule.KeycloakRule; import org.keycloak.testsuite.rule.LDAPRule; import java.util.Map; /** * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> */ @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class LDAPGroupMapper2WaySyncTest { @ClassRule public static LDAPRule ldapRule = new LDAPRule(); private static UserFederationProviderModel ldapModel = null; private static String descriptionAttrName = null; @Rule public KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() { @Override public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) { Map<String,String> ldapConfig = ldapRule.getConfig(); ldapConfig.put(LDAPConstants.SYNC_REGISTRATIONS, "true"); 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); LDAPFederationProvider ldapFedProvider = FederationTestUtils.getLdapProvider(session, ldapModel); descriptionAttrName = ldapFedProvider.getLdapIdentityStore().getConfig().isActiveDirectory() ? "displayName" : "description"; // Add group mapper FederationTestUtils.addOrUpdateGroupMapper(appRealm, ldapModel, LDAPGroupMapperMode.LDAP_ONLY, descriptionAttrName); // Remove all LDAP groups FederationTestUtils.removeAllLDAPGroups(session, appRealm, ldapModel, "groupsMapper"); // Add some groups for testing into Keycloak removeAllModelGroups(appRealm); GroupModel group1 = appRealm.createGroup("group1"); appRealm.moveGroup(group1, null); group1.setSingleAttribute(descriptionAttrName, "group1 - description1"); GroupModel group11 = appRealm.createGroup("group11"); appRealm.moveGroup(group11, group1); GroupModel group12 = appRealm.createGroup("group12"); appRealm.moveGroup(group12, group1); group12.setSingleAttribute(descriptionAttrName, "group12 - description12"); GroupModel group2 = appRealm.createGroup("group2"); appRealm.moveGroup(group2, null); } }); @Test public void test01_syncNoPreserveGroupInheritance() 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); // Update group mapper to skip preserve inheritance and check it will pass now FederationTestUtils.updateGroupMapperConfigOptions(mapperModel, GroupMapperConfig.PRESERVE_GROUP_INHERITANCE, "false"); realm.updateUserFederationMapper(mapperModel); // Sync from Keycloak into LDAP UserFederationSyncResult syncResult = new GroupLDAPFederationMapperFactory().create(session).syncDataFromKeycloakToFederationProvider(mapperModel, ldapProvider, session, realm); FederationTestUtils.assertSyncEquals(syncResult, 4, 0, 0, 0); } finally { keycloakRule.stopSession(session, true); } session = keycloakRule.startSession(); try { RealmModel realm = session.realms().getRealmByName("test"); // Delete all KC groups now removeAllModelGroups(realm); Assert.assertNull(KeycloakModelUtils.findGroupByPath(realm, "/group1")); Assert.assertNull(KeycloakModelUtils.findGroupByPath(realm, "/group11")); Assert.assertNull(KeycloakModelUtils.findGroupByPath(realm, "/group2")); } finally { keycloakRule.stopSession(session, true); } session = keycloakRule.startSession(); try { RealmModel realm = session.realms().getRealmByName("test"); UserFederationMapperModel mapperModel = realm.getUserFederationMapperByName(ldapModel.getId(), "groupsMapper"); LDAPFederationProvider ldapProvider = FederationTestUtils.getLdapProvider(session, ldapModel); // Sync from LDAP back into Keycloak UserFederationSyncResult syncResult = new GroupLDAPFederationMapperFactory().create(session).syncDataFromFederationProviderToKeycloak(mapperModel, ldapProvider, session, realm); FederationTestUtils.assertSyncEquals(syncResult, 4, 0, 0, 0); // Assert groups are imported to keycloak. All are at top level GroupModel kcGroup1 = KeycloakModelUtils.findGroupByPath(realm, "/group1"); GroupModel kcGroup11 = KeycloakModelUtils.findGroupByPath(realm, "/group11"); GroupModel kcGroup12 = KeycloakModelUtils.findGroupByPath(realm, "/group12"); GroupModel kcGroup2 = KeycloakModelUtils.findGroupByPath(realm, "/group2"); Assert.assertEquals(0, kcGroup1.getSubGroups().size()); Assert.assertEquals("group1 - description1", kcGroup1.getFirstAttribute(descriptionAttrName)); Assert.assertNull(kcGroup11.getFirstAttribute(descriptionAttrName)); Assert.assertEquals("group12 - description12", kcGroup12.getFirstAttribute(descriptionAttrName)); Assert.assertNull(kcGroup2.getFirstAttribute(descriptionAttrName)); // test drop non-existing works testDropNonExisting(session, realm, mapperModel, ldapProvider); } finally { keycloakRule.stopSession(session, true); } } @Test public void test02_syncWithGroupInheritance() 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); // Update group mapper to skip preserve inheritance and check it will pass now FederationTestUtils.updateGroupMapperConfigOptions(mapperModel, GroupMapperConfig.PRESERVE_GROUP_INHERITANCE, "true"); realm.updateUserFederationMapper(mapperModel); // Sync from Keycloak into LDAP UserFederationSyncResult syncResult = new GroupLDAPFederationMapperFactory().create(session).syncDataFromKeycloakToFederationProvider(mapperModel, ldapProvider, session, realm); FederationTestUtils.assertSyncEquals(syncResult, 4, 0, 0, 0); } finally { keycloakRule.stopSession(session, true); } session = keycloakRule.startSession(); try { RealmModel realm = session.realms().getRealmByName("test"); // Delete all KC groups now removeAllModelGroups(realm); Assert.assertNull(KeycloakModelUtils.findGroupByPath(realm, "/group1")); Assert.assertNull(KeycloakModelUtils.findGroupByPath(realm, "/group11")); Assert.assertNull(KeycloakModelUtils.findGroupByPath(realm, "/group2")); } finally { keycloakRule.stopSession(session, true); } session = keycloakRule.startSession(); try { RealmModel realm = session.realms().getRealmByName("test"); UserFederationMapperModel mapperModel = realm.getUserFederationMapperByName(ldapModel.getId(), "groupsMapper"); LDAPFederationProvider ldapProvider = FederationTestUtils.getLdapProvider(session, ldapModel); // Sync from LDAP back into Keycloak UserFederationSyncResult syncResult = new GroupLDAPFederationMapperFactory().create(session).syncDataFromFederationProviderToKeycloak(mapperModel, ldapProvider, session, realm); FederationTestUtils.assertSyncEquals(syncResult, 4, 0, 0, 0); // Assert groups are imported to keycloak. All are at top level GroupModel kcGroup1 = KeycloakModelUtils.findGroupByPath(realm, "/group1"); GroupModel kcGroup11 = KeycloakModelUtils.findGroupByPath(realm, "/group1/group11"); GroupModel kcGroup12 = KeycloakModelUtils.findGroupByPath(realm, "/group1/group12"); GroupModel kcGroup2 = KeycloakModelUtils.findGroupByPath(realm, "/group2"); Assert.assertEquals(2, kcGroup1.getSubGroups().size()); Assert.assertEquals("group1 - description1", kcGroup1.getFirstAttribute(descriptionAttrName)); Assert.assertNull(kcGroup11.getFirstAttribute(descriptionAttrName)); Assert.assertEquals("group12 - description12", kcGroup12.getFirstAttribute(descriptionAttrName)); Assert.assertNull(kcGroup2.getFirstAttribute(descriptionAttrName)); // test drop non-existing works testDropNonExisting(session, realm, mapperModel, ldapProvider); } finally { keycloakRule.stopSession(session, true); } } private static void removeAllModelGroups(RealmModel appRealm) { for (GroupModel group : appRealm.getTopLevelGroups()) { appRealm.removeGroup(group); } } private void testDropNonExisting(KeycloakSession session, RealmModel realm, UserFederationMapperModel mapperModel, LDAPFederationProvider ldapProvider) { // Put some group directly to LDAP FederationTestUtils.createLDAPGroup(session, realm, ldapModel, "group3"); // Sync and assert our group is still in LDAP UserFederationSyncResult syncResult = new GroupLDAPFederationMapperFactory().create(session).syncDataFromKeycloakToFederationProvider(mapperModel, ldapProvider, session, realm); FederationTestUtils.assertSyncEquals(syncResult, 0, 4, 0, 0); Assert.assertNotNull(FederationTestUtils.getGroupMapper(mapperModel, ldapProvider, realm).loadLDAPGroupByName("group3")); // Change config to drop non-existing groups FederationTestUtils.updateGroupMapperConfigOptions(mapperModel, GroupMapperConfig.DROP_NON_EXISTING_GROUPS_DURING_SYNC, "true"); realm.updateUserFederationMapper(mapperModel); // Sync and assert group removed from LDAP syncResult = new GroupLDAPFederationMapperFactory().create(session).syncDataFromKeycloakToFederationProvider(mapperModel, ldapProvider, session, realm); FederationTestUtils.assertSyncEquals(syncResult, 0, 4, 1, 0); Assert.assertNull(FederationTestUtils.getGroupMapper(mapperModel, ldapProvider, realm).loadLDAPGroupByName("group3")); } }