diff --git a/federation/ldap/src/main/java/org/keycloak/storage/ldap/LDAPStorageProvider.java b/federation/ldap/src/main/java/org/keycloak/storage/ldap/LDAPStorageProvider.java index d75812f506..e6f52d3b79 100755 --- a/federation/ldap/src/main/java/org/keycloak/storage/ldap/LDAPStorageProvider.java +++ b/federation/ldap/src/main/java/org/keycloak/storage/ldap/LDAPStorageProvider.java @@ -101,7 +101,6 @@ import org.keycloak.userprofile.UserProfileMetadata; import org.keycloak.userprofile.UserProfileUtil; import org.keycloak.utils.StreamsUtil; - /** * @author Marek Posolda * @author Bill Burke diff --git a/federation/ldap/src/main/java/org/keycloak/storage/ldap/LDAPStorageProviderFactory.java b/federation/ldap/src/main/java/org/keycloak/storage/ldap/LDAPStorageProviderFactory.java index e49be2eb80..1d7b32a29e 100755 --- a/federation/ldap/src/main/java/org/keycloak/storage/ldap/LDAPStorageProviderFactory.java +++ b/federation/ldap/src/main/java/org/keycloak/storage/ldap/LDAPStorageProviderFactory.java @@ -54,6 +54,7 @@ import org.keycloak.storage.ldap.mappers.FullNameLDAPStorageMapper; import org.keycloak.storage.ldap.mappers.FullNameLDAPStorageMapperFactory; import org.keycloak.storage.ldap.mappers.HardcodedLDAPAttributeMapper; import org.keycloak.storage.ldap.mappers.HardcodedLDAPAttributeMapperFactory; +import org.keycloak.storage.ldap.mappers.KerberosPrincipalAttributeMapperFactory; import org.keycloak.storage.ldap.mappers.LDAPConfigDecorator; import org.keycloak.storage.ldap.mappers.LDAPMappersComparator; import org.keycloak.storage.ldap.mappers.LDAPStorageMapper; @@ -451,6 +452,11 @@ public class LDAPStorageProviderFactory implements UserStorageProviderFactory { + LDAPTestContext ctx = LDAPTestContext.init(session); + RealmModel testRealm = ctx.getRealm(); + + ctx.getLdapModel().getConfig().putSingle(LDAPConstants.EDIT_MODE, UserStorageProvider.EditMode.WRITABLE.toString()); + UserStorageSyncManager usersSyncManager = new UserStorageSyncManager(); + + renameUserInLDAP(ctx, testRealm, "hnelson", "hnelson2", "hnelson2@keycloak.org", "hnelson2@KEYCLOAK.ORG", "secret2"); + + // Assert still old users in local provider + LDAPTestAsserts.assertUserImported(UserStoragePrivateUtil.userLocalStorage(session), testRealm, "hnelson", "Horatio", "Nelson", "hnelson@keycloak.org", null); + + // Trigger sync + KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory(); + SynchronizationResult syncResult = usersSyncManager.syncAllUsers(sessionFactory, testRealm.getId(), ctx.getLdapModel()); + Assert.assertEquals(0, syncResult.getFailed()); + }); + + testingClient.server().run(session -> { + LDAPTestContext ctx = LDAPTestContext.init(session); + RealmModel testRealm = ctx.getRealm(); + UserProvider userProvider = UserStoragePrivateUtil.userLocalStorage(session); + // Assert users updated in local provider + LDAPTestAsserts.assertUserImported(session.users(), testRealm, "hnelson2", "Horatio", "Nelson", "hnelson2@keycloak.org", null); + UserModel updatedLocalUser = userProvider.getUserByUsername(testRealm, "hnelson2"); + LDAPObject ldapUser = ctx.getLdapProvider().loadLDAPUserByUsername(testRealm, "hnelson2"); + Assert.assertNull(userProvider.getUserByUsername(testRealm, "hnelson")); + // Assert UUID didn't change + Assert.assertEquals(updatedLocalUser.getAttributeStream(LDAPConstants.LDAP_ID).findFirst().get(), ldapUser.getUuid()); + // Assert Kerberos principal was changed in Keycloak + Assert.assertEquals(updatedLocalUser.getAttributeStream(KERBEROS_PRINCIPAL).findFirst().get(), ldapUser.getAttributeAsString(ctx.getLdapProvider().getKerberosConfig().getKerberosPrincipalAttribute())); + }); + + // login not possible with old user + loginPage.open(); + loginPage.login("hnelson", "secret2"); + Assert.assertEquals("Invalid username or password.", loginPage.getInputError()); + + // login after update successful + assertSuccessfulSpnegoLogin("hnelson2", "hnelson2", "secret2"); + } finally { + // revert changes in LDAP + testingClient.server().run(session -> { + LDAPTestContext ctx = LDAPTestContext.init(session); + RealmModel testRealm = ctx.getRealm(); + + renameUserInLDAP(ctx, testRealm, "hnelson2", "hnelson", "hnelson@keycloak.org", "hnelson@KEYCLOAK.ORG", "secret"); + }); + } + } + + private static void renameUserInLDAP(LDAPTestContext ctx, RealmModel testRealm, String username, String newUsername, String newEmail, String newKr5Principal, String secret) { + // Update user in LDAP, change username, email, krb5Principal + LDAPObject ldapUser = ctx.getLdapProvider().loadLDAPUserByUsername(testRealm, username); + + if (ldapUser != null) { + ldapUser.removeReadOnlyAttributeName("uid"); + ldapUser.removeReadOnlyAttributeName("mail"); + ldapUser.removeReadOnlyAttributeName(ctx.getLdapProvider().getKerberosConfig().getKerberosPrincipalAttribute()); + String userNameLdapAttributeName = ctx.getLdapProvider().getLdapIdentityStore().getConfig().getUsernameLdapAttribute(); + ldapUser.setSingleAttribute(userNameLdapAttributeName, newUsername); + ldapUser.setSingleAttribute(LDAPConstants.EMAIL, newEmail); + ldapUser.setSingleAttribute(ctx.getLdapProvider().getKerberosConfig().getKerberosPrincipalAttribute(), newKr5Principal); + ctx.getLdapProvider().getLdapIdentityStore().update(ldapUser); + + // update also password in LDAP to force propagation into KDC + LDAPTestUtils.updateLDAPPassword(ctx.getLdapProvider(), ldapUser, secret); + } + } + @Test public void validatePasswordPolicyTest() throws Exception{ updateProviderEditMode(UserStorageProvider.EditMode.WRITABLE);