Add migration for the useTruststoreSpi config property in LDAP user storage provider

- legacy `ldapsOnly` value now migrated to `always`.

Closes #25912

Signed-off-by: Stefan Guilhen <sguilhen@redhat.com>
This commit is contained in:
Stefan Guilhen 2024-02-09 10:41:35 -03:00 committed by Alexander Schwartz
parent eac43822c3
commit 2161e72872
6 changed files with 81 additions and 6 deletions

View file

@ -65,8 +65,7 @@ public class LDAPConfig {
} }
public String getUseTruststoreSpi() { public String getUseTruststoreSpi() {
String value = config.getFirst(LDAPConstants.USE_TRUSTSTORE_SPI); return config.getFirst(LDAPConstants.USE_TRUSTSTORE_SPI);
return LDAPConstants.USE_TRUSTSTORE_LDAPS_ONLY.equals(value) ? LDAPConstants.USE_TRUSTSTORE_ALWAYS : value;
} }
public String getUsersDn() { public String getUsersDn() {

View file

@ -23,10 +23,12 @@ import org.jboss.logging.Logger;
import org.keycloak.migration.ModelVersion; import org.keycloak.migration.ModelVersion;
import org.keycloak.models.KeycloakContext; import org.keycloak.models.KeycloakContext;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.LDAPConstants;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.userprofile.config.UPConfig; import org.keycloak.representations.userprofile.config.UPConfig;
import org.keycloak.representations.userprofile.config.UPConfig.UnmanagedAttributePolicy; import org.keycloak.representations.userprofile.config.UPConfig.UnmanagedAttributePolicy;
import org.keycloak.storage.UserStorageProvider;
import org.keycloak.userprofile.UserProfileProvider; import org.keycloak.userprofile.UserProfileProvider;
public class MigrateTo24_0_0 implements Migration { public class MigrateTo24_0_0 implements Migration {
@ -55,6 +57,7 @@ public class MigrateTo24_0_0 implements Migration {
try { try {
context.setRealm(realm); context.setRealm(realm);
updateUserProfileSettings(session); updateUserProfileSettings(session);
updateLdapProviderConfig(session);
} finally { } finally {
context.setRealm(null); context.setRealm(null);
} }
@ -82,4 +85,15 @@ public class MigrateTo24_0_0 implements Migration {
LOG.debugf("Enabled the declarative user profile to realm %s with support for unmanaged attributes", realm.getName()); LOG.debugf("Enabled the declarative user profile to realm %s with support for unmanaged attributes", realm.getName());
} }
private void updateLdapProviderConfig(final KeycloakSession session) {
RealmModel realm = session.getContext().getRealm();
// ensure `ldapsOnly` value for `useTruststoreSpi` in LDAP providers is migrated to `always`.
realm.getComponentsStream(realm.getId(), UserStorageProvider.class.getName())
.filter(c -> LDAPConstants.USE_TRUSTSTORE_LDAPS_ONLY.equals(c.getConfig().getFirst(LDAPConstants.USE_TRUSTSTORE_SPI)))
.forEach(c -> {
c.getConfig().putSingle(LDAPConstants.USE_TRUSTSTORE_SPI, LDAPConstants.USE_TRUSTSTORE_ALWAYS);
realm.updateComponent(c);
});
}
} }

View file

@ -32,6 +32,7 @@ import org.keycloak.authentication.authenticators.browser.OTPFormAuthenticatorFa
import org.keycloak.authentication.authenticators.conditional.ConditionalUserConfiguredAuthenticatorFactory; import org.keycloak.authentication.authenticators.conditional.ConditionalUserConfiguredAuthenticatorFactory;
import org.keycloak.broker.provider.util.SimpleHttp; import org.keycloak.broker.provider.util.SimpleHttp;
import org.keycloak.common.constants.KerberosConstants; import org.keycloak.common.constants.KerberosConstants;
import org.keycloak.common.util.MultivaluedHashMap;
import org.keycloak.component.PrioritizedComponentModel; import org.keycloak.component.PrioritizedComponentModel;
import org.keycloak.keys.KeyProvider; import org.keycloak.keys.KeyProvider;
import org.keycloak.models.AccountRoles; import org.keycloak.models.AccountRoles;
@ -398,13 +399,16 @@ public abstract class AbstractMigrationTest extends AbstractKeycloakTest {
testRegistrationProfileFormActionRemoved(migrationRealm2); testRegistrationProfileFormActionRemoved(migrationRealm2);
} }
protected void testMigrationTo24_0_0(boolean testUserProfileMigration) { protected void testMigrationTo24_0_0(boolean testUserProfileMigration, boolean testLdapUseTruststoreSpiMigration) {
if (testUserProfileMigration) { if (testUserProfileMigration) {
testUserProfileEnabledByDefault(migrationRealm); testUserProfileEnabledByDefault(migrationRealm);
testUnmanagedAttributePolicySet(migrationRealm, UnmanagedAttributePolicy.ENABLED); testUnmanagedAttributePolicySet(migrationRealm, UnmanagedAttributePolicy.ENABLED);
testUserProfileEnabledByDefault(migrationRealm2); testUserProfileEnabledByDefault(migrationRealm2);
testUnmanagedAttributePolicySet(migrationRealm2, null); testUnmanagedAttributePolicySet(migrationRealm2, null);
} }
if (testLdapUseTruststoreSpiMigration) {
testLdapUseTruststoreSpiMigration(migrationRealm2);
}
} }
protected void testDeleteAccount(RealmResource realm) { protected void testDeleteAccount(RealmResource realm) {
@ -1092,7 +1096,11 @@ public abstract class AbstractMigrationTest extends AbstractKeycloakTest {
} }
protected void testMigrationTo24_x(boolean testUserProfileMigration) { protected void testMigrationTo24_x(boolean testUserProfileMigration) {
testMigrationTo24_0_0(testUserProfileMigration); testMigrationTo24_0_0(testUserProfileMigration, false);
}
protected void testMigrationTo24_x(boolean testUserProfileMigration, boolean testLdapUseTruststoreSpiMigration) {
testMigrationTo24_0_0(testUserProfileMigration, testLdapUseTruststoreSpiMigration);
} }
protected void testMigrationTo7_x(boolean supportedAuthzServices) { protected void testMigrationTo7_x(boolean supportedAuthzServices) {
@ -1211,4 +1219,22 @@ public abstract class AbstractMigrationTest extends AbstractKeycloakTest {
UPConfig upConfig = realm.users().userProfile().getConfiguration(); UPConfig upConfig = realm.users().userProfile().getConfiguration();
assertEquals(policy, upConfig.getUnmanagedAttributePolicy()); assertEquals(policy, upConfig.getUnmanagedAttributePolicy());
} }
/**
* Checks if the {@code useTruststoreSpi} flag in the LDAP federation provider present in realm {@code Migration2}
* was properly migrated from the old value {@code ldapsOnly} to {@code always}.
* </p>
* This provider was added to the file migration-realm-19.0.3.json as a disabled provider, so it doesn't get involved
* in actual user searches and is there just to test the migration of the {@code useTruststoreSpi} config attribute.
*
* @param realm the migrated realm resource.
*/
private void testLdapUseTruststoreSpiMigration(final RealmResource realm) {
RealmRepresentation rep = realm.toRepresentation();
List<ComponentRepresentation> componentsRep = realm.components().query(rep.getId(), UserStorageProvider.class.getName());
assertThat(componentsRep.size(), equalTo(1));
MultivaluedHashMap<String, String> config = componentsRep.get(0).getConfig();
assertNotNull(config);
assertThat(config.getFirst(LDAPConstants.USE_TRUSTSTORE_SPI), equalTo(LDAPConstants.USE_TRUSTSTORE_ALWAYS));
}
} }

View file

@ -67,7 +67,7 @@ public class JsonFileImport1903MigrationTest extends AbstractJsonFileImportMigra
testMigrationTo21_x(); testMigrationTo21_x();
testMigrationTo22_x(); testMigrationTo22_x();
testMigrationTo23_x(true); testMigrationTo23_x(true);
testMigrationTo24_x(true); testMigrationTo24_x(true, true);
} }
@Test @Test

View file

@ -69,6 +69,6 @@ public class MigrationTest extends AbstractMigrationTest {
testMigrationTo21_x(); testMigrationTo21_x();
testMigrationTo22_x(); testMigrationTo22_x();
testMigrationTo23_x(true); testMigrationTo23_x(true);
testMigrationTo24_x(true); testMigrationTo24_x(true, true);
} }
} }

View file

@ -2912,6 +2912,42 @@
"identityProviders" : [ ], "identityProviders" : [ ],
"identityProviderMappers" : [ ], "identityProviderMappers" : [ ],
"components" : { "components" : {
"org.keycloak.storage.UserStorageProvider": [
{
"id": "307bba27-f8da-4c4d-a1b9-3c1bf49f824e",
"name": "ldap",
"providerId": "ldap",
"subComponents": {},
"config": {
"pagination": [ "false" ],
"fullSyncPeriod": [ "-1" ],
"startTls": [ "false" ],
"usersDn": [ "ou=People,dc=keycloak,dc=org" ],
"connectionPooling": [ "false" ],
"cachePolicy": [ "DEFAULT" ],
"useKerberosForPasswordAuthentication": [ "false" ],
"importEnabled": [ "true" ],
"enabled": [ "false" ],
"bindCredential": [ "anything" ],
"changedSyncPeriod": [ "-1" ],
"bindDn": [ "uid=admin,ou=system" ],
"usernameLDAPAttribute": [ "uid" ],
"vendor": [ "other" ],
"uuidLDAPAttribute": [ "entryUUID" ],
"connectionUrl": [ "ldap://localhost:10389" ],
"allowKerberosAuthentication": [ "false" ],
"syncRegistrations": [ "true" ],
"authType": [ "simple" ],
"useTruststoreSpi": [ "ldapsOnly" ],
"usePasswordModifyExtendedOp": [ "false" ],
"trustEmail": [ "false" ],
"userObjectClasses": [ "inetOrgPerson, organizationalPerson" ],
"rdnLDAPAttribute": [ "uid" ],
"editMode": [ "WRITABLE" ],
"validatePasswordPolicy": [ "false" ]
}
}
],
"org.keycloak.userprofile.UserProfileProvider": [ "org.keycloak.userprofile.UserProfileProvider": [
{ {
"id": "88cef18c-bcd8-40d2-9e7d-d257298317f2", "id": "88cef18c-bcd8-40d2-9e7d-d257298317f2",