[Keycloak CI] - User Federation Tests - fixing AD tests

Closes #33231

Signed-off-by: Martin Kanis <mkanis@redhat.com>
This commit is contained in:
Martin Kanis 2024-10-02 15:40:28 +02:00 committed by Pedro Igor
parent b26febc32a
commit 51fd133f05
5 changed files with 101 additions and 9 deletions

View file

@ -79,6 +79,10 @@ public class LDAPConfig {
return usersDn; return usersDn;
} }
public String getBaseDn() {
return config.getFirst(LDAPConstants.BASE_DN);
}
public Collection<String> getUserObjectClasses() { public Collection<String> getUserObjectClasses() {
String objClassesCfg = config.getFirst(LDAPConstants.USER_OBJECT_CLASSES); String objClassesCfg = config.getFirst(LDAPConstants.USER_OBJECT_CLASSES);
String objClassesStr = (objClassesCfg != null && objClassesCfg.length() > 0) ? objClassesCfg.trim() : "inetOrgPerson,organizationalPerson"; String objClassesStr = (objClassesCfg != null && objClassesCfg.length() > 0) ? objClassesCfg.trim() : "inetOrgPerson,organizationalPerson";

View file

@ -21,6 +21,7 @@ import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.component.ComponentModel; import org.keycloak.component.ComponentModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.LDAPConstants; import org.keycloak.models.LDAPConstants;
import org.keycloak.models.ModelException;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.UserCredentialModel; import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
@ -176,6 +177,27 @@ public class LDAPTestUtils {
return ldapObject; return ldapObject;
} }
public static LDAPObject addLdapOUinBaseDn(LDAPStorageProvider ldapProvider, String name) {
LDAPObject ldapObject = new LDAPObject();
ldapObject.setRdnAttributeName("ou");
ldapObject.setObjectClasses(Collections.singletonList("organizationalUnit"));
ldapObject.setSingleAttribute("ou", name);
LDAPDn dn = LDAPDn.fromString(ldapProvider.getLdapIdentityStore().getConfig().getBaseDn());
dn.addFirst("ou", name);
ldapObject.setDn(dn);
// remove OU before adding it in case it already exists
try {
ldapProvider.getLdapIdentityStore().remove(ldapObject);
} catch (ModelException e) {
// OK
}
ldapProvider.getLdapIdentityStore().add(ldapObject);
return ldapObject;
}
public static void updateLDAPPassword(LDAPStorageProvider ldapProvider, LDAPObject ldapUser, String password) { public static void updateLDAPPassword(LDAPStorageProvider ldapProvider, LDAPObject ldapUser, String password) {
ldapProvider.getLdapIdentityStore().updatePassword(ldapUser, password, null); ldapProvider.getLdapIdentityStore().updatePassword(ldapUser, password, null);

View file

@ -28,8 +28,7 @@ import org.junit.Test;
import org.junit.runners.MethodSorters; import org.junit.runners.MethodSorters;
import org.keycloak.OAuth2Constants; import org.keycloak.OAuth2Constants;
import org.keycloak.admin.client.resource.UserResource; import org.keycloak.admin.client.resource.UserResource;
import org.keycloak.events.Details; import org.keycloak.component.ComponentModel;
import org.keycloak.events.Errors;
import org.keycloak.models.AuthenticationExecutionModel; import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.models.LDAPConstants; import org.keycloak.models.LDAPConstants;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
@ -42,7 +41,9 @@ import org.keycloak.storage.StorageId;
import org.keycloak.storage.UserStorageProvider; import org.keycloak.storage.UserStorageProvider;
import org.keycloak.storage.ldap.LDAPStorageProvider; import org.keycloak.storage.ldap.LDAPStorageProvider;
import org.keycloak.storage.ldap.idm.model.LDAPObject; import org.keycloak.storage.ldap.idm.model.LDAPObject;
import org.keycloak.testsuite.AssertEvents; import org.keycloak.storage.ldap.mappers.LDAPStorageMapper;
import org.keycloak.storage.ldap.mappers.msad.MSADUserAccountControlStorageMapper;
import org.keycloak.storage.ldap.mappers.msad.MSADUserAccountControlStorageMapperFactory;
import org.keycloak.testsuite.admin.ApiUtil; import org.keycloak.testsuite.admin.ApiUtil;
import org.keycloak.testsuite.pages.AppPage; import org.keycloak.testsuite.pages.AppPage;
import org.keycloak.testsuite.pages.LoginConfigTotpPage; import org.keycloak.testsuite.pages.LoginConfigTotpPage;
@ -99,6 +100,16 @@ public class LDAPReadOnlyTest extends AbstractLDAPTest {
LDAPStorageProvider ldapFedProvider = LDAPTestUtils.getLdapProvider(session, ctx.getLdapModel()); LDAPStorageProvider ldapFedProvider = LDAPTestUtils.getLdapProvider(session, ctx.getLdapModel());
ldapFedProvider.getModel().put(LDAPConstants.EDIT_MODE, UserStorageProvider.EditMode.READ_ONLY.toString()); ldapFedProvider.getModel().put(LDAPConstants.EDIT_MODE, UserStorageProvider.EditMode.READ_ONLY.toString());
// change MSAD mapper config "ALWAYS_READ_ENABLED_VALUE_FROM_LDAP" to false as edit mode is read only so setEnable(false) is not propagated to LDAP
ComponentModel msadMapperComponent = appRealm.getComponentsStream(ctx.getLdapModel().getId(), LDAPStorageMapper.class.getName())
.filter(c -> MSADUserAccountControlStorageMapperFactory.PROVIDER_ID.equals(c.getProviderId()))
.findFirst().orElse(null);
if (msadMapperComponent != null) {
msadMapperComponent.getConfig().putSingle(MSADUserAccountControlStorageMapper.ALWAYS_READ_ENABLED_VALUE_FROM_LDAP, "false");
appRealm.updateComponent(msadMapperComponent);
}
appRealm.updateComponent(ldapFedProvider.getModel()); appRealm.updateComponent(ldapFedProvider.getModel());
}); });
} }

View file

@ -43,6 +43,7 @@ import org.keycloak.models.UserProvider;
import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.storage.DatastoreProvider; import org.keycloak.storage.DatastoreProvider;
import org.keycloak.storage.datastore.DefaultDatastoreProvider; import org.keycloak.storage.datastore.DefaultDatastoreProvider;
import org.keycloak.storage.ldap.idm.model.LDAPObject;
import org.keycloak.testsuite.admin.ApiUtil; import org.keycloak.testsuite.admin.ApiUtil;
import org.keycloak.testsuite.util.LDAPRule; import org.keycloak.testsuite.util.LDAPRule;
import org.keycloak.testsuite.util.LDAPTestUtils; import org.keycloak.testsuite.util.LDAPTestUtils;
@ -67,15 +68,20 @@ public class LDAPSearchForUsersPaginationTest extends AbstractLDAPTest {
RealmModel appRealm = ctx.getRealm(); RealmModel appRealm = ctx.getRealm();
LDAPTestUtils.addUserAttributeMapper(appRealm, ctx.getLdapModel(), "streetMapper", LDAPConstants.STREET, LDAPConstants.STREET); LDAPTestUtils.addUserAttributeMapper(appRealm, ctx.getLdapModel(), "streetMapper", LDAPConstants.STREET, LDAPConstants.STREET);
// Delete all local users and add some new for testing
session.users().searchForUserStream(appRealm, new HashMap<>()).collect(Collectors.toList()).forEach(u -> session.users().removeUser(appRealm, u));
// Delete all LDAP users and add some new for testing // Delete all LDAP users and add some new for testing
LDAPTestUtils.removeAllLDAPUsers(ctx.getLdapProvider(), appRealm); LDAPTestUtils.removeAllLDAPUsers(ctx.getLdapProvider(), appRealm);
LDAPTestUtils.addLDAPUser(ctx.getLdapProvider(), appRealm, "john", "Some", "Some", "john14@email.org", "Acacia Avenue", "1234"); // Delete all local users and add some new for testing
LDAPTestUtils.addLDAPUser(ctx.getLdapProvider(), appRealm, "john00", "john", "Doe", "john0@email.org", "Acacia Avenue", "1234"); session.users().searchForUserStream(appRealm, new HashMap<>()).collect(Collectors.toList()).forEach(u -> session.users().removeUser(appRealm, u));
LDAPTestUtils.addLDAPUser(ctx.getLdapProvider(), appRealm, "john01", "john", "Doe", "john1@email.org", "Acacia Avenue", "1234");
LDAPObject ldapUser = LDAPTestUtils.addLDAPUser(ctx.getLdapProvider(), appRealm, "john", "Some", "Some", "john14@email.org", "Acacia Avenue", "1234");
// somehow, for MSAD it is only possible to create an enabled user by updating the password and setting USER_ACCOUNT_CONTROL attribute to 512
LDAPTestUtils.updateLDAPPassword(ctx.getLdapProvider(), ldapUser, "password");
ldapUser = LDAPTestUtils.addLDAPUser(ctx.getLdapProvider(), appRealm, "john00", "john", "Doe", "john0@email.org", "Acacia Avenue", "1234");
LDAPTestUtils.updateLDAPPassword(ctx.getLdapProvider(), ldapUser, "password");
ldapUser = LDAPTestUtils.addLDAPUser(ctx.getLdapProvider(), appRealm, "john01", "john", "Doe", "john1@email.org", "Acacia Avenue", "1234");
LDAPTestUtils.updateLDAPPassword(ctx.getLdapProvider(), ldapUser, "password");
LDAPTestUtils.addLDAPUser(ctx.getLdapProvider(), appRealm, "john02", "john", "Doe", "john2@email.org", null, "1234"); LDAPTestUtils.addLDAPUser(ctx.getLdapProvider(), appRealm, "john02", "john", "Doe", "john2@email.org", null, "1234");
LDAPTestUtils.addLDAPUser(ctx.getLdapProvider(), appRealm, "john03", "john", "Doe", "john3@email.org", null, "1234"); LDAPTestUtils.addLDAPUser(ctx.getLdapProvider(), appRealm, "john03", "john", "Doe", "john3@email.org", null, "1234");
LDAPTestUtils.addLDAPUser(ctx.getLdapProvider(), appRealm, "john04", "john", "Doe", "john4@email.org", null, "1234"); LDAPTestUtils.addLDAPUser(ctx.getLdapProvider(), appRealm, "john04", "john", "Doe", "john4@email.org", null, "1234");

View file

@ -25,6 +25,7 @@ import java.util.Set;
import org.jboss.arquillian.graphene.page.Page; import org.jboss.arquillian.graphene.page.Page;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Assume;
import org.junit.ClassRule; import org.junit.ClassRule;
import org.junit.FixMethodOrder; import org.junit.FixMethodOrder;
import org.junit.Test; import org.junit.Test;
@ -267,6 +268,12 @@ public class LDAPUserProfileTest extends AbstractLDAPTest {
ldapCompModel.put(PrioritizedComponentModel.PRIORITY, "100"); ldapCompModel.put(PrioritizedComponentModel.PRIORITY, "100");
testRealm.addComponentModel(ldapModel); testRealm.addComponentModel(ldapModel);
LDAPStorageProvider ldapProvider = LDAPTestUtils.getLdapProvider(session, ldapModel); LDAPStorageProvider ldapProvider = LDAPTestUtils.getLdapProvider(session, ldapModel);
// if AD, create new OU in a base DN because users.ldif is ignored for AD
if (LDAPConstants.VENDOR_ACTIVE_DIRECTORY.equals(ldapModel.getConfig().getFirst(LDAPConstants.VENDOR))) {
LDAPTestUtils.addLdapOUinBaseDn(ldapProvider, "OtherPeople2");
LDAPTestUtils.removeAllLDAPUsers(ldapProvider, testRealm);
}
LDAPObject john = LDAPTestUtils.addLDAPUser(ldapProvider, testRealm, "anotherjohn", "AnotherJohn", "AnotherDoe", "anotherjohn@email.org", null, "1234"); LDAPObject john = LDAPTestUtils.addLDAPUser(ldapProvider, testRealm, "anotherjohn", "AnotherJohn", "AnotherDoe", "anotherjohn@email.org", null, "1234");
LDAPTestUtils.updateLDAPPassword(ldapProvider, john, "Password1"); LDAPTestUtils.updateLDAPPassword(ldapProvider, john, "Password1");
}); });
@ -304,6 +311,11 @@ public class LDAPUserProfileTest extends AbstractLDAPTest {
@Test @Test
public void testUsernameRespectFormatFromExternalStore() { public void testUsernameRespectFormatFromExternalStore() {
Assume.assumeFalse("Skip for AD", testingClient.server().fetch(session -> {
LDAPTestContext ctx = LDAPTestContext.init(session);
return LDAPConstants.VENDOR_ACTIVE_DIRECTORY.equals(ctx.getLdapModel().getConfig().getFirst(LDAPConstants.VENDOR));
}, Boolean.class));
String upperCaseUsername = "JOHNKEYCLOAK3"; String upperCaseUsername = "JOHNKEYCLOAK3";
testingClient.server().run(session -> { testingClient.server().run(session -> {
LDAPTestContext ctx = LDAPTestContext.init(session, "test-ldap"); LDAPTestContext ctx = LDAPTestContext.init(session, "test-ldap");
@ -347,6 +359,43 @@ public class LDAPUserProfileTest extends AbstractLDAPTest {
appPage.assertCurrent(); appPage.assertCurrent();
} }
@Test
public void testUsernameRespectFormatFromExternalStoreAD() {
Assume.assumeTrue("Only run for AD", testingClient.server().fetch(session -> {
LDAPTestContext ctx = LDAPTestContext.init(session);
return LDAPConstants.VENDOR_ACTIVE_DIRECTORY.equals(ctx.getLdapModel().getConfig().getFirst(LDAPConstants.VENDOR));
}, Boolean.class));
String upperCaseUsername = "JOHNKEYCLOAK3";
testingClient.server().run(session -> {
LDAPTestContext ctx = LDAPTestContext.init(session, "test-ldap");
RealmModel appRealm = ctx.getRealm();
ComponentModel ldapComponentMapper = LDAPTestUtils.addUserAttributeMapper(appRealm, ctx.getLdapModel(), "username-cn-mapper", "username", LDAPConstants.CN);
ldapComponentMapper.put(UserAttributeLDAPStorageMapper.ALWAYS_READ_VALUE_FROM_LDAP, true);
appRealm.updateComponent(ldapComponentMapper);
LDAPObject john3 = LDAPTestUtils.addLDAPUser(ctx.getLdapProvider(), appRealm, upperCaseUsername, "John", "Doe", "john3@email.org", "12345");
LDAPTestUtils.updateLDAPPassword(ctx.getLdapProvider(), john3, "Password1");
});
UserResource johnResource = ApiUtil.findUserByUsernameId(testRealm(), upperCaseUsername);
UserRepresentation john = johnResource.toRepresentation(true);
Assert.assertEquals(upperCaseUsername, john.getUsername());
johnResource = ApiUtil.findUserByUsernameId(testRealm(), upperCaseUsername.toLowerCase());
john = johnResource.toRepresentation(true);
Assert.assertEquals(upperCaseUsername, john.getUsername());
loginPage.open();
loginPage.login(upperCaseUsername, "Password1");
appPage.assertCurrent();
testRealm().users().get(john.getId()).logout();
loginPage.open();
loginPage.login(upperCaseUsername.toLowerCase(), "Password1");
appPage.assertCurrent();
}
private void setLDAPReadOnly() { private void setLDAPReadOnly() {
testingClient.server().run(session -> { testingClient.server().run(session -> {
LDAPTestContext ctx = LDAPTestContext.init(session, "test-ldap"); LDAPTestContext ctx = LDAPTestContext.init(session, "test-ldap");