Migration steps for enabling user profile by default

Closes #25528

Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>
This commit is contained in:
Pedro Igor 2023-12-15 20:31:35 -03:00
parent 32a70cbedd
commit 810ebf4efd
10 changed files with 129 additions and 1 deletions

View file

@ -0,0 +1,85 @@
/*
* Copyright 2023 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.migration.migrators;
import org.jboss.logging.Logger;
import org.keycloak.migration.ModelVersion;
import org.keycloak.models.KeycloakContext;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.userprofile.config.UPConfig;
import org.keycloak.representations.userprofile.config.UPConfig.UnmanagedAttributePolicy;
import org.keycloak.userprofile.UserProfileProvider;
public class MigrateTo24_0_0 implements Migration {
private static final Logger LOG = Logger.getLogger(MigrateTo24_0_0.class);
public static final ModelVersion VERSION = new ModelVersion("24.0.0");
private static final String REALM_USER_PROFILE_ENABLED = "userProfileEnabled";
@Override
public void migrate(KeycloakSession session) {
session.realms().getRealmsStream().forEach(realm -> migrateRealm(session, realm));
}
@Override
public void migrateImport(KeycloakSession session, RealmModel realm, RealmRepresentation rep, boolean skipUserDependent) {
migrateRealm(session, realm);
}
@Override
public ModelVersion getVersion() {
return VERSION;
}
private void migrateRealm(KeycloakSession session, RealmModel realm) {
KeycloakContext context = session.getContext();
try {
context.setRealm(realm);
updateUserProfileSettings(session);
} finally {
context.setRealm(null);
}
}
private void updateUserProfileSettings(KeycloakSession session) {
RealmModel realm = session.getContext().getRealm();
boolean isUserProfileEnabled = Boolean.parseBoolean(realm.getAttribute(REALM_USER_PROFILE_ENABLED));
if (isUserProfileEnabled) {
// existing realms with user profile enabled does not need any addition migration step
LOG.debugf("Skipping migration for realm %s. The declarative user profile is already enabled.", realm.getName());
return;
}
// user profile is enabled by default since this version
realm.setAttribute(REALM_USER_PROFILE_ENABLED, Boolean.TRUE.toString());
// for backward compatibility in terms of behavior, we enable unmanaged attributes for existing realms
// that don't have the declarative user profile enabled
UserProfileProvider provider = session.getProvider(UserProfileProvider.class);
UPConfig upConfig = provider.getConfiguration();
upConfig.setUnmanagedAttributePolicy(UnmanagedAttributePolicy.ENABLED);
provider.setConfiguration(upConfig);
LOG.debugf("Enabled the declarative user profile to realm %s with support for unmanaged attributes", realm.getName());
}
}

View file

@ -37,6 +37,7 @@ import org.keycloak.migration.migrators.MigrateTo1_9_2;
import org.keycloak.migration.migrators.MigrateTo21_0_0; import org.keycloak.migration.migrators.MigrateTo21_0_0;
import org.keycloak.migration.migrators.MigrateTo22_0_0; import org.keycloak.migration.migrators.MigrateTo22_0_0;
import org.keycloak.migration.migrators.MigrateTo23_0_0; import org.keycloak.migration.migrators.MigrateTo23_0_0;
import org.keycloak.migration.migrators.MigrateTo24_0_0;
import org.keycloak.migration.migrators.MigrateTo2_0_0; import org.keycloak.migration.migrators.MigrateTo2_0_0;
import org.keycloak.migration.migrators.MigrateTo2_1_0; import org.keycloak.migration.migrators.MigrateTo2_1_0;
import org.keycloak.migration.migrators.MigrateTo2_2_0; import org.keycloak.migration.migrators.MigrateTo2_2_0;
@ -112,7 +113,8 @@ public class LegacyMigrationManager implements MigrationManager {
new MigrateTo20_0_0(), new MigrateTo20_0_0(),
new MigrateTo21_0_0(), new MigrateTo21_0_0(),
new MigrateTo22_0_0(), new MigrateTo22_0_0(),
new MigrateTo23_0_0() new MigrateTo23_0_0(),
new MigrateTo24_0_0()
}; };
private final KeycloakSession session; private final KeycloakSession session;

View file

@ -63,6 +63,8 @@ import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.representations.idm.authorization.DecisionStrategy; import org.keycloak.representations.idm.authorization.DecisionStrategy;
import org.keycloak.representations.idm.authorization.ResourceRepresentation; import org.keycloak.representations.idm.authorization.ResourceRepresentation;
import org.keycloak.representations.idm.authorization.ResourceServerRepresentation; import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
import org.keycloak.representations.userprofile.config.UPConfig;
import org.keycloak.representations.userprofile.config.UPConfig.UnmanagedAttributePolicy;
import org.keycloak.storage.UserStorageProvider; import org.keycloak.storage.UserStorageProvider;
import org.keycloak.testsuite.AbstractKeycloakTest; import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.Assert; import org.keycloak.testsuite.Assert;
@ -110,6 +112,7 @@ import static org.keycloak.models.AccountRoles.VIEW_GROUPS;
import static org.keycloak.models.Constants.ACCOUNT_MANAGEMENT_CLIENT_ID; import static org.keycloak.models.Constants.ACCOUNT_MANAGEMENT_CLIENT_ID;
import static org.keycloak.testsuite.Assert.assertNames; import static org.keycloak.testsuite.Assert.assertNames;
import static org.keycloak.testsuite.auth.page.AuthRealm.MASTER; import static org.keycloak.testsuite.auth.page.AuthRealm.MASTER;
import static org.keycloak.userprofile.DeclarativeUserProfileProvider.REALM_USER_PROFILE_ENABLED;
import static org.keycloak.userprofile.DeclarativeUserProfileProvider.UP_COMPONENT_CONFIG_KEY; import static org.keycloak.userprofile.DeclarativeUserProfileProvider.UP_COMPONENT_CONFIG_KEY;
/** /**
@ -395,6 +398,15 @@ public abstract class AbstractMigrationTest extends AbstractKeycloakTest {
testRegistrationProfileFormActionRemoved(migrationRealm2); testRegistrationProfileFormActionRemoved(migrationRealm2);
} }
protected void testMigrationTo24_0_0(boolean testUserProfileMigration) {
if (testUserProfileMigration) {
testUserProfileEnabledByDefault(migrationRealm);
testUnmanagedAttributePolicySet(migrationRealm, UnmanagedAttributePolicy.ENABLED);
testUserProfileEnabledByDefault(migrationRealm2);
testUnmanagedAttributePolicySet(migrationRealm2, null);
}
}
protected void testDeleteAccount(RealmResource realm) { protected void testDeleteAccount(RealmResource realm) {
ClientRepresentation accountClient = realm.clients().findByClientId(ACCOUNT_MANAGEMENT_CLIENT_ID).get(0); ClientRepresentation accountClient = realm.clients().findByClientId(ACCOUNT_MANAGEMENT_CLIENT_ID).get(0);
ClientResource accountResource = realm.clients().get(accountClient.getId()); ClientResource accountResource = realm.clients().get(accountClient.getId());
@ -1079,6 +1091,10 @@ public abstract class AbstractMigrationTest extends AbstractKeycloakTest {
testMigrationTo23_0_0(testUserProfileMigration); testMigrationTo23_0_0(testUserProfileMigration);
} }
protected void testMigrationTo24_x(boolean testUserProfileMigration) {
testMigrationTo24_0_0(testUserProfileMigration);
}
protected void testMigrationTo7_x(boolean supportedAuthzServices) { protected void testMigrationTo7_x(boolean supportedAuthzServices) {
if (supportedAuthzServices) { if (supportedAuthzServices) {
testDecisionStrategySetOnResourceServer(); testDecisionStrategySetOnResourceServer();
@ -1183,4 +1199,16 @@ public abstract class AbstractMigrationTest extends AbstractKeycloakTest {
Map<String, String> realmAttributes = migrationRealm.toRepresentation().getAttributes(); Map<String, String> realmAttributes = migrationRealm.toRepresentation().getAttributes();
assertEquals("custom_value", realmAttributes.get("custom_attribute")); assertEquals("custom_value", realmAttributes.get("custom_attribute"));
} }
private void testUserProfileEnabledByDefault(RealmResource realm) {
RealmRepresentation rep = realm.toRepresentation();
Map<String, String> attributes = rep.getAttributes();
String userProfileEnabled = attributes.get(REALM_USER_PROFILE_ENABLED);
assertTrue(Boolean.parseBoolean(userProfileEnabled));
}
private void testUnmanagedAttributePolicySet(RealmResource realm, UnmanagedAttributePolicy policy) {
UPConfig upConfig = realm.users().userProfile().getConfiguration();
assertEquals(policy, upConfig.getUnmanagedAttributePolicy());
}
} }

View file

@ -17,8 +17,10 @@
package org.keycloak.testsuite.migration; package org.keycloak.testsuite.migration;
import org.junit.Test; import org.junit.Test;
import org.keycloak.common.Profile.Feature;
import org.keycloak.exportimport.util.ImportUtils; import org.keycloak.exportimport.util.ImportUtils;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
import org.keycloak.testsuite.utils.io.IOUtil; import org.keycloak.testsuite.utils.io.IOUtil;
import org.keycloak.util.JsonSerialization; import org.keycloak.util.JsonSerialization;
@ -29,6 +31,7 @@ import java.util.Map;
/** /**
* Tests that we can import json file from previous version. MigrationTest only tests DB. * Tests that we can import json file from previous version. MigrationTest only tests DB.
*/ */
@EnableFeature(Feature.DECLARATIVE_USER_PROFILE)
public class JsonFileImport1903MigrationTest extends AbstractJsonFileImportMigrationTest { public class JsonFileImport1903MigrationTest extends AbstractJsonFileImportMigrationTest {
@Override @Override
@ -52,6 +55,7 @@ public class JsonFileImport1903MigrationTest extends AbstractJsonFileImportMigra
testMigrationTo21_x(); testMigrationTo21_x();
testMigrationTo22_x(); testMigrationTo22_x();
testMigrationTo23_x(true); testMigrationTo23_x(true);
testMigrationTo24_x(true);
} }
} }

View file

@ -78,6 +78,7 @@ public class JsonFileImport198MigrationTest extends AbstractJsonFileImportMigrat
testMigrationTo21_x(); testMigrationTo21_x();
testMigrationTo22_x(); testMigrationTo22_x();
testMigrationTo23_x(false); testMigrationTo23_x(false);
testMigrationTo24_x(false);
} }
@Override @Override

View file

@ -72,6 +72,7 @@ public class JsonFileImport255MigrationTest extends AbstractJsonFileImportMigrat
testMigrationTo21_x(); testMigrationTo21_x();
testMigrationTo22_x(); testMigrationTo22_x();
testMigrationTo23_x(false); testMigrationTo23_x(false);
testMigrationTo24_x(false);
} }
} }

View file

@ -67,6 +67,7 @@ public class JsonFileImport343MigrationTest extends AbstractJsonFileImportMigrat
testMigrationTo21_x(); testMigrationTo21_x();
testMigrationTo22_x(); testMigrationTo22_x();
testMigrationTo23_x(false); testMigrationTo23_x(false);
testMigrationTo24_x(false);
} }
} }

View file

@ -61,6 +61,7 @@ public class JsonFileImport483MigrationTest extends AbstractJsonFileImportMigrat
testMigrationTo21_x(); testMigrationTo21_x();
testMigrationTo22_x(); testMigrationTo22_x();
testMigrationTo23_x(false); testMigrationTo23_x(false);
testMigrationTo24_x(false);
} }
} }

View file

@ -54,6 +54,7 @@ public class JsonFileImport903MigrationTest extends AbstractJsonFileImportMigrat
testMigrationTo21_x(); testMigrationTo21_x();
testMigrationTo22_x(); testMigrationTo22_x();
testMigrationTo23_x(false); testMigrationTo23_x(false);
testMigrationTo24_x(false);
} }
} }

View file

@ -19,7 +19,9 @@ package org.keycloak.testsuite.migration;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.keycloak.admin.client.resource.RealmResource; import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.common.Profile.Feature;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
import org.keycloak.testsuite.arquillian.migration.Migration; import org.keycloak.testsuite.arquillian.migration.Migration;
import jakarta.ws.rs.NotFoundException; import jakarta.ws.rs.NotFoundException;
@ -32,6 +34,7 @@ import static org.keycloak.testsuite.auth.page.AuthRealm.MASTER;
* *
* @author <a href="mailto:vramik@redhat.com">Vlastislav Ramik</a> * @author <a href="mailto:vramik@redhat.com">Vlastislav Ramik</a>
*/ */
@EnableFeature(Feature.DECLARATIVE_USER_PROFILE)
public class MigrationTest extends AbstractMigrationTest { public class MigrationTest extends AbstractMigrationTest {
@Override @Override
@ -69,5 +72,6 @@ public class MigrationTest extends AbstractMigrationTest {
testMigrationTo21_x(); testMigrationTo21_x();
testMigrationTo22_x(); testMigrationTo22_x();
testMigrationTo23_x(true); testMigrationTo23_x(true);
testMigrationTo24_x(true);
} }
} }