Migrating Realm JSON with declarative user profile fails when scope selectors present on any attributes

closes #26266

Signed-off-by: mposolda <mposolda@gmail.com>
This commit is contained in:
mposolda 2024-01-30 18:32:19 +01:00 committed by Marek Posolda
parent 64b5f42c4a
commit cdc5d8fff8
3 changed files with 73 additions and 14 deletions

View file

@ -44,26 +44,24 @@ public class MigrateTo23_0_0 implements Migration {
@Override
public void migrate(KeycloakSession session) {
session.realms().getRealmsStream().forEach(realm -> {
KeycloakContext context = session.getContext();
try {
context.setRealm(realm);
migrateRealm(realm);
} finally {
context.setRealm(null);
}
});
session.realms().getRealmsStream().forEach(realm -> migrateRealm(session, realm));
}
@Override
public void migrateImport(KeycloakSession session, RealmModel realm, RealmRepresentation rep, boolean skipUserDependent) {
migrateRealm(realm);
migrateRealm(session, realm);
}
private void migrateRealm(RealmModel realm) {
updateUserProfileConfig(realm);
removeRegistrationProfileFormExecution(realm);
private void migrateRealm(KeycloakSession session, RealmModel realm) {
KeycloakContext context = session.getContext();
try {
context.setRealm(realm);
updateUserProfileConfig(realm);
removeRegistrationProfileFormExecution(realm);
} finally {
context.setRealm(null);
}
}
private void updateUserProfileConfig(RealmModel realm) {

View file

@ -17,14 +17,26 @@
package org.keycloak.testsuite.migration;
import org.junit.Test;
import org.keycloak.OAuth2Constants;
import org.keycloak.exportimport.util.ImportUtils;
import org.keycloak.representations.idm.ComponentRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.userprofile.config.UPAttribute;
import org.keycloak.representations.userprofile.config.UPConfig;
import org.keycloak.testsuite.utils.io.IOUtil;
import org.keycloak.userprofile.config.UPConfigUtils;
import org.keycloak.util.JsonSerialization;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertEquals;
import static org.keycloak.userprofile.DeclarativeUserProfileProvider.UP_COMPONENT_CONFIG_KEY;
/**
* Tests that we can import json file from previous version. MigrationTest only tests DB.
@ -37,6 +49,9 @@ public class JsonFileImport1903MigrationTest extends AbstractJsonFileImportMigra
try {
reps = ImportUtils.getRealmsFromStream(JsonSerialization.mapper, IOUtil.class.getResourceAsStream("/migration-test/migration-realm-19.0.3.json"));
masterRep = reps.remove("master");
RealmRepresentation upRealm = JsonSerialization.readValue(IOUtil.class.getResourceAsStream("/migration-test/migration-realm-19.0.3-user-profile.json"), RealmRepresentation.class);
reps.put(upRealm.getRealm(), upRealm);
} catch (IOException e) {
throw new RuntimeException(e);
}
@ -55,4 +70,24 @@ public class JsonFileImport1903MigrationTest extends AbstractJsonFileImportMigra
testMigrationTo24_x(true);
}
@Test
public void testUserProfileMigration() throws Exception {
List<ComponentRepresentation> userProfileComponents = adminClient.realm("migration-user-profile")
.components()
.query(null, "org.keycloak.userprofile.UserProfileProvider");
assertThat(userProfileComponents, hasSize(1));
ComponentRepresentation component = userProfileComponents.get(0);
// Test "street" attribute being presented with the expected scope selectors
UPConfig upConfig = UPConfigUtils.parseConfig(component.getConfig().getFirst(UP_COMPONENT_CONFIG_KEY));
UPAttribute streetAttr = upConfig.getAttribute("street");
assertThat(streetAttr, notNullValue());
assertThat(streetAttr.getSelector(), notNullValue());
assertEquals(Set.of(OAuth2Constants.SCOPE_ADDRESS), streetAttr.getSelector().getScopes());
assertThat(streetAttr.getSelector(), notNullValue());
assertEquals(Set.of(OAuth2Constants.SCOPE_PHONE), streetAttr.getRequired().getScopes());
}
}

View file

@ -0,0 +1,26 @@
{
"id": "migration-user-profile",
"realm": "migration-user-profile",
"enabled": true,
"attributes" : {
"userProfileEnabled" : "true"
},
"components" : {
"org.keycloak.userprofile.UserProfileProvider": [
{
"id": "98cef18c-bcd8-40d2-9e7d-d257298317f2",
"providerId": "declarative-user-profile",
"subComponents": {},
"config": {
"config-piece-0": [
"{\"attributes\":[{\"name\":\"username\",\"displayName\":\"${username}\",\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"validations\":{\"length\":{\"min\":3,\"max\":255},\"username-prohibited-characters\":{},\"up-username-not-idn-homograph\":{}}},{\"name\":\"email\",\"displayName\":\"${email}\",\"permissions\":{\"edit\":[\"admin\",\"user\"],\"view\":[\"admin\",\"user\"]},\"validations\":{\"email\":{},\"length\":{\"max\":255},\"pattern\":{\"pattern\":\"[a-zA-Z0-9!#$%&'*+/=?^_`{|}~.-]+@example.nl\",\"error-message\":\"Invalid domain selected\"}},\"annotations\":{\"\":\"\"},\"required\":{\"roles\":[\"user\"]},\"group\":null},{\"name\":\"firstName\",\"displayName\":\"${firstName}\",\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}}},{\"name\":\"lastName\",\"displayName\":\"${lastName}\",\"required\":{\"roles\":[\"user\"]},\"permissions\":{\"view\":[\"admin\",\"user\"],\"edit\":[\"admin\",\"user\"]},\"validations\":{\"length\":{\"max\":255},\"person-name-prohibited-characters\":{}}},{\"name\":\"street\",\"displayName\":\"Street\",\"required\":{\"scopes\":[\"phone\"],\"roles\":[\"admin\",\"user\"]},\"validations\":{},\"selector\":{\"scopes\":[\"address\"]},\"permissions\":{\"view\":[\"user\"],\"edit\":[\"user\",\"admin\"]},\"annotations\":{\"foo\":\"bar\"}}]}"
],
"config-pieces-count": [
"1"
]
}
}
]
},
"keycloakVersion" : "19.0.3"
}