Fixes in LDAP tests when using AD

Closing https://github.com/keycloak/keycloak/issues/24357
This commit is contained in:
rmartinc 2023-10-27 16:23:47 +02:00 committed by Alexander Schwartz
parent 8ff76694a2
commit 1b630326b2
4 changed files with 80 additions and 24 deletions

View file

@ -17,6 +17,7 @@
package org.keycloak.testsuite.util;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.LDAPConstants;
@ -89,6 +90,12 @@ public class LDAPTestUtils {
public static LDAPObject addLDAPUser(LDAPStorageProvider ldapProvider, RealmModel realm, final String username,
final String firstName, final String lastName, final String email, final String street, final String... postalCode) {
return addLDAPUser(ldapProvider, realm, username, firstName, lastName, email, street, new MultivaluedHashMap<>(), postalCode);
}
public static LDAPObject addLDAPUser(LDAPStorageProvider ldapProvider, RealmModel realm, final String username,
final String firstName, final String lastName, final String email, final String street,
final MultivaluedHashMap<String, String> otherAttrs, final String... postalCode) {
UserModel helperUser = new UserModelDelegate(null) {
@Override
@ -121,6 +128,8 @@ public class LDAPTestUtils {
return email;
} else if (UserModel.USERNAME.equals(name)) {
return username;
} else if (otherAttrs.containsKey(name)) {
return otherAttrs.getFirst(name);
}
return super.getFirstAttribute(name);
}
@ -139,6 +148,8 @@ public class LDAPTestUtils {
return Stream.of(postalCode);
} else if ("street".equals(name) && street != null) {
return Stream.of(street);
} else if (otherAttrs.containsKey(name)) {
return otherAttrs.getList(name).stream();
} else {
return Stream.empty();
}
@ -187,6 +198,10 @@ public class LDAPTestUtils {
addUserAttributeMapper(realm, providerModel, "zipCodeMapper", "postal_code", LDAPConstants.POSTAL_CODE);
}
public static void addPostalAddressLDAPMapper(RealmModel realm, ComponentModel providerModel) {
addUserAttributeMapper(realm, providerModel, "postalAddressMapper", "postalAddress", "postalAddress");
}
public static ComponentModel addUserAttributeMapper(RealmModel realm, ComponentModel providerModel, String mapperName, String userModelAttributeName, String ldapAttributeName) {
ComponentModel mapperModel = KeycloakModelUtils.createComponentModel(mapperName, providerModel.getId(), UserAttributeLDAPStorageMapperFactory.PROVIDER_ID, LDAPStorageMapper.class.getName(),
UserAttributeLDAPStorageMapper.USER_MODEL_ATTRIBUTE, userModelAttributeName,

View file

@ -19,6 +19,7 @@ package org.keycloak.testsuite.federation.ldap;
import org.jboss.logging.Logger;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.FixMethodOrder;
@ -94,12 +95,6 @@ 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, 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);
});
}
@ -115,8 +110,7 @@ public class LDAPGroupMapperSyncTest extends AbstractLDAPTest {
});
}
@Test
public void test01_syncNoPreserveGroupInheritance() throws Exception {
private void testSyncNoPreserveGroupInheritance() throws Exception {
testingClient.server().run(session -> {
LDAPTestContext ctx = LDAPTestContext.init(session);
RealmModel realm = ctx.getRealm();
@ -195,9 +189,36 @@ public class LDAPGroupMapperSyncTest extends AbstractLDAPTest {
});
}
@Test
public void test01_syncNoPreserveGroupInheritance() throws Exception {
testSyncNoPreserveGroupInheritance();
}
@Test
public void test02_syncWithGroupInheritance() throws Exception {
public void test02_syncNoPreserveGroupInheritanceWithOneGroupMissing() throws Exception {
Assume.assumeFalse("AD does not allow missing DN in group members",
LDAPConstants.VENDOR_ACTIVE_DIRECTORY.equals(ldapRule.getConfig().get(LDAPConstants.VENDOR)));
testingClient.server().run(session -> {
// create a non-existent group first in group1
LDAPTestContext ctx = LDAPTestContext.init(session);
RealmModel realm = ctx.getRealm();
ComponentModel mapperModel = LDAPTestUtils.getSubcomponentByName(realm, ctx.getLdapModel(), "groupsMapper");
LDAPStorageProvider ldapProvider = LDAPTestUtils.getLdapProvider(session, ctx.getLdapModel());
GroupLDAPStorageMapper groupMapper = LDAPTestUtils.getGroupMapper(mapperModel, ldapProvider, realm);
LDAPObject group1 = groupMapper.loadLDAPGroupByName("group1");
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);
});
testSyncNoPreserveGroupInheritance();
}
@Test
public void test03_syncWithGroupInheritance() throws Exception {
testingClient.server().run(session -> {
LDAPTestContext ctx = LDAPTestContext.init(session);
RealmModel realm = ctx.getRealm();
@ -253,7 +274,7 @@ public class LDAPGroupMapperSyncTest extends AbstractLDAPTest {
@Test
public void test03_syncWithDropNonExistingGroups() throws Exception {
public void test04_syncWithDropNonExistingGroups() throws Exception {
testingClient.server().run(session -> {
LDAPTestContext ctx = LDAPTestContext.init(session);
RealmModel realm = ctx.getRealm();
@ -309,7 +330,7 @@ public class LDAPGroupMapperSyncTest extends AbstractLDAPTest {
@Test
public void test04_syncNoPreserveGroupInheritanceWithLazySync() throws Exception {
public void test05_syncNoPreserveGroupInheritanceWithLazySync() throws Exception {
// Update group mapper to skip preserve inheritance
testingClient.server().run(session -> {
LDAPTestContext ctx = LDAPTestContext.init(session);
@ -374,7 +395,7 @@ public class LDAPGroupMapperSyncTest extends AbstractLDAPTest {
@Test
public void test05SyncRestAPI() {
public void test06SyncRestAPI() {
ComponentRepresentation groupMapperRep = findMapperRepByName("groupsMapper");
try {
@ -389,7 +410,7 @@ public class LDAPGroupMapperSyncTest extends AbstractLDAPTest {
// KEYCLOAK-8253 - Test if synchronization of large number of LDAP groups takes linear time
@Ignore("This test is not suitable for regular CI testing due to higher time / performance demand")
@Test
public void test06_ldapGroupsSyncHasLinearTimeComplexity() throws Exception {
public void test07_ldapGroupsSyncHasLinearTimeComplexity() throws Exception {
// Count of LDAP groups to test the duration of the sync operation. Defaults to 30k unless overridden via system property
final int GROUPS_COUNT = (System.getProperties().containsKey(TEST_LDAP_GROUPS_SYNC_LINEAR_TIME_GROUPS_COUNT)) ?
Integer.valueOf(System.getProperty(TEST_LDAP_GROUPS_SYNC_LINEAR_TIME_GROUPS_COUNT)) : 30000;

View file

@ -22,6 +22,7 @@ import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.ClassRule;
import org.junit.Test;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.component.ComponentModel;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
@ -37,6 +38,7 @@ import org.keycloak.testsuite.util.LDAPTestUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import static org.hamcrest.Matchers.contains;
@ -65,6 +67,7 @@ public class LDAPProvidersFullNameMapperTest extends AbstractLDAPTest {
RealmModel appRealm = ctx.getRealm();
LDAPTestUtils.addZipCodeLDAPMapper(appRealm, ctx.getLdapModel());
LDAPTestUtils.addPostalAddressLDAPMapper(appRealm, ctx.getLdapModel());
LDAPTestUtils.removeAllLDAPUsers(ctx.getLdapProvider(), appRealm);
appRealm.getClientByClientId("test-app").setDirectAccessGrantsEnabled(true);
@ -96,10 +99,12 @@ public class LDAPProvidersFullNameMapperTest extends AbstractLDAPTest {
ComponentModel ldapModel = LDAPTestUtils.getLdapProviderModel(appRealm);
LDAPStorageProvider ldapFedProvider = LDAPTestUtils.getLdapProvider(session, ldapModel);
LDAPTestUtils.addLDAPUser(ldapFedProvider, appRealm, "fullname", "James", "Dee", "fullname@email.org", null, "4578", "9876");
MultivaluedHashMap<String, String> otherAttrs = new MultivaluedHashMap<>();
otherAttrs.put("postalAddress", List.of("123456", "654321"));
LDAPTestUtils.addLDAPUser(ldapFedProvider, appRealm, "fullname", "James", "Dee", "fullname@email.org", null, otherAttrs, "4578");
// Assert user is successfully imported in Keycloak DB now with correct firstName and lastName
LDAPTestAsserts.assertUserImported(session.users(), appRealm, "fullname", "James", "Dee", "fullname@email.org", "4578", "9876");
LDAPTestAsserts.assertUserImported(session.users(), appRealm, "fullname", "James", "Dee", "fullname@email.org", "4578", otherAttrs);
});
// Assert user will be changed in LDAP too
@ -110,7 +115,7 @@ public class LDAPProvidersFullNameMapperTest extends AbstractLDAPTest {
UserModel fullnameUser = session.users().getUserByUsername(appRealm, "fullname");
fullnameUser.setFirstName("James2");
fullnameUser.setLastName("Dee2");
fullnameUser.setAttribute("postal_code", Arrays.asList("1234", "2345", "3456"));
fullnameUser.setAttribute("postalAddress", Arrays.asList("1234", "2345", "3456"));
});
// Assert changed user available in Keycloak
@ -119,7 +124,9 @@ public class LDAPProvidersFullNameMapperTest extends AbstractLDAPTest {
RealmModel appRealm = ctx.getRealm();
// Assert user is successfully imported in Keycloak DB now with correct firstName and lastName
LDAPTestAsserts.assertUserImported(session.users(), appRealm, "fullname", "James2", "Dee2", "fullname@email.org", "1234", "2345", "3456");
MultivaluedHashMap<String, String> otherAttrs = new MultivaluedHashMap<>();
otherAttrs.put("postalAddress", List.of("1234", "2345", "3456"));
LDAPTestAsserts.assertUserImported(session.users(), appRealm, "fullname", "James2", "Dee2", "fullname@email.org", "4578", otherAttrs);
// Remove "fullnameUser" to assert he is removed from LDAP.
UserModel fullnameUser = session.users().getUserByUsername(appRealm, "fullname");

View file

@ -17,11 +17,10 @@
package org.keycloak.testsuite.federation.ldap;
import java.util.Arrays;
import java.util.Collections;
import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
import org.junit.Assert;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserProvider;
@ -35,20 +34,34 @@ import org.keycloak.storage.user.SynchronizationResult;
*/
public class LDAPTestAsserts {
public static UserModel assertUserImported(UserProvider userProvider, RealmModel realm, String username, String expectedFirstName, String expectedLastName, String expectedEmail, String... expectedPostalCode) {
public static UserModel assertUserImported(UserProvider userProvider, RealmModel realm, String username,
String expectedFirstName, String expectedLastName, String expectedEmail, String expectedPostalCode) {
return assertUserImported(userProvider, realm, username, expectedFirstName,
expectedLastName, expectedEmail, expectedPostalCode, new MultivaluedHashMap<>());
}
public static UserModel assertUserImported(UserProvider userProvider, RealmModel realm, String username, String expectedFirstName,
String expectedLastName, String expectedEmail, String expectedPostalCode, MultivaluedHashMap<String, String> otherAttrs) {
UserModel user = userProvider.getUserByUsername(realm, username);
assertLoaded(user, username, expectedFirstName, expectedLastName, expectedEmail, expectedPostalCode);
assertLoaded(user, username, expectedFirstName, expectedLastName, expectedEmail, expectedPostalCode, otherAttrs);
return user;
}
public static void assertLoaded(UserModel user, String username, String expectedFirstName,
String expectedLastName, String expectedEmail, String expectedPostalCode) {
assertLoaded(user, username, expectedFirstName, expectedLastName, expectedEmail, expectedPostalCode, new MultivaluedHashMap<>());
}
public static void assertLoaded(UserModel user, String username, String expectedFirstName, String expectedLastName, String expectedEmail, String... expectedPostalCode) {
public static void assertLoaded(UserModel user, String username, String expectedFirstName, String expectedLastName,
String expectedEmail, String expectedPostalCode, MultivaluedHashMap<String, String> otherAttrs) {
Assert.assertNotNull(user);
Assert.assertEquals(expectedFirstName, user.getFirstName());
Assert.assertEquals(expectedLastName, user.getLastName());
Assert.assertEquals(expectedEmail, user.getEmail());
MatcherAssert.assertThat(expectedPostalCode == null? Collections.emptyList() : Arrays.asList(expectedPostalCode),
Matchers.containsInAnyOrder(user.getAttributeStream("postal_code").toArray(String[]::new)));
Assert.assertEquals(expectedPostalCode, user.getFirstAttribute("postal_code"));
for (String name : otherAttrs.keySet()) {
MatcherAssert.assertThat(otherAttrs.getList(name), Matchers.containsInAnyOrder(user.getAttributeStream(name).toArray(String[]::new)));
}
}