diff --git a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo12_0_0.java b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo12_0_0.java index d158e3d591..944b09adb0 100644 --- a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo12_0_0.java +++ b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo12_0_0.java @@ -1,9 +1,26 @@ +/* + * Copyright 2020 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 java.util.Objects; import org.keycloak.migration.ModelVersion; import org.keycloak.models.AccountRoles; +import org.keycloak.models.Constants; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RequiredActionProviderModel; @@ -26,14 +43,13 @@ public class MigrateTo12_0_0 implements Migration { @Override public void migrate(KeycloakSession session) { session.realms() - .getRealms() - .stream() - .map(realm -> realm.getClientByClientId("account")) + .getRealmsStream() + .map(realm -> realm.getClientByClientId(Constants.ACCOUNT_MANAGEMENT_CLIENT_ID)) .filter(client -> Objects.isNull(client.getRole(AccountRoles.DELETE_ACCOUNT))) .forEach(client -> client.addRole(AccountRoles.DELETE_ACCOUNT) .setDescription("${role_"+AccountRoles.DELETE_ACCOUNT+"}")); - session.realms().getRealms().stream().filter(realm -> Objects.isNull(realm.getRequiredActionProviderByAlias("delete_account"))).forEach(realm -> realm.addRequiredActionProvider(deleteAccount)); + session.realms().getRealmsStream().filter(realm -> Objects.isNull(realm.getRequiredActionProviderByAlias("delete_account"))).forEach(realm -> realm.addRequiredActionProvider(deleteAccount)); } @Override diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/DefaultRequiredActions.java b/server-spi-private/src/main/java/org/keycloak/models/utils/DefaultRequiredActions.java index 17cb81dd83..d5de86719a 100755 --- a/server-spi-private/src/main/java/org/keycloak/models/utils/DefaultRequiredActions.java +++ b/server-spi-private/src/main/java/org/keycloak/models/utils/DefaultRequiredActions.java @@ -84,7 +84,10 @@ public class DefaultRequiredActions { } addUpdateLocaleAction(realm); + addDeleteAccountAction(realm); + } + public static void addDeleteAccountAction(RealmModel realm) { if (realm.getRequiredActionProviderByAlias("delete_account") == null) { RequiredActionProviderModel deleteAccount = new RequiredActionProviderModel(); deleteAccount.setEnabled(false); diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java b/server-spi-private/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java index 3247ef4f02..4fdd72ebda 100755 --- a/server-spi-private/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java +++ b/server-spi-private/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java @@ -62,6 +62,7 @@ import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.keycloak.models.AccountRoles; /** * Set of helper methods, which are useful in various model implementations. @@ -350,6 +351,13 @@ public final class KeycloakModelUtils { return offlineRole; } + public static void setupDeleteAccount(ClientModel accountClient) { + RoleModel deleteOwnAccount = accountClient.getRole(AccountRoles.DELETE_ACCOUNT); + if (deleteOwnAccount == null) { + deleteOwnAccount = accountClient.addRole(AccountRoles.DELETE_ACCOUNT); + } + deleteOwnAccount.setDescription("${role_" + AccountRoles.DELETE_ACCOUNT + "}"); + } /** * Recursively find all AuthenticationExecutionModel from specified flow or all it's subflows diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java b/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java index 3d02852570..39bea9e8f9 100755 --- a/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java +++ b/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java @@ -294,6 +294,7 @@ public class RepresentationToModel { newRealm.addRequiredActionProvider(model); } + DefaultRequiredActions.addDeleteAccountAction(newRealm); } else { DefaultRequiredActions.addActions(newRealm); } diff --git a/services/src/main/java/org/keycloak/services/managers/RealmManager.java b/services/src/main/java/org/keycloak/services/managers/RealmManager.java index 4a5b52ab4c..34944f21de 100755 --- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java +++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java @@ -443,8 +443,7 @@ public class RealmManager { manageConsentRole.setDescription("${role_" + AccountRoles.MANAGE_CONSENT + "}"); manageConsentRole.addCompositeRole(viewConsentRole); - RoleModel deleteOwnAccount = accountClient.addRole(AccountRoles.DELETE_ACCOUNT); - deleteOwnAccount.setDescription("${role_"+AccountRoles.DELETE_ACCOUNT+"}"); + KeycloakModelUtils.setupDeleteAccount(accountClient); ClientModel accountConsoleClient = realm.getClientByClientId(Constants.ACCOUNT_CONSOLE_CLIENT_ID); if (accountConsoleClient == null) { @@ -550,6 +549,7 @@ public class RealmManager { setupOfflineTokens(realm, rep); } + if (rep.getClientScopes() == null) { createDefaultClientScopes(realm); } @@ -583,6 +583,10 @@ public class RealmManager { setupAuthenticationFlows(realm); setupRequiredActions(realm); + if (!hasRealmRole(rep, AccountRoles.DELETE_ACCOUNT)) { + KeycloakModelUtils.setupDeleteAccount(realm.getClientByClientId(Constants.ACCOUNT_MANAGEMENT_CLIENT_ID)); + } + // Refresh periodic sync tasks for configured storageProviders UserStorageSyncManager storageSync = new UserStorageSyncManager(); realm.getUserStorageProvidersStream() diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/AbstractMigrationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/AbstractMigrationTest.java index 969327bf31..8a5efddea0 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/AbstractMigrationTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/AbstractMigrationTest.java @@ -286,16 +286,16 @@ public abstract class AbstractMigrationTest extends AbstractKeycloakTest { } protected void testMigrationTo12_0_0() { - testAccountConsoleClientHasDeleteUserRole(masterRealm); - testAccountConsoleClientHasDeleteUserRole(migrationRealm); + testDeleteAccount(masterRealm); + testDeleteAccount(migrationRealm); } - private void testAccountConsoleClientHasDeleteUserRole(RealmResource realm) { + private void testDeleteAccount(RealmResource realm) { ClientRepresentation accountClient = realm.clients().findByClientId(ACCOUNT_MANAGEMENT_CLIENT_ID).get(0); - ClientResource accountResource = realm.clients().get(accountClient.getId()); - RoleRepresentation deleteUserRole = accountResource.roles().get(AccountRoles.DELETE_ACCOUNT).toRepresentation(); - assertNotNull(deleteUserRole); + + assertNotNull(accountResource.roles().get(AccountRoles.DELETE_ACCOUNT).toRepresentation()); + assertNotNull(realm.flows().getRequiredAction("delete_account")); } private void testAccountClient(RealmResource realm) { diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport198MigrationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport198MigrationTest.java index 5230407fce..3f4b39a38c 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport198MigrationTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport198MigrationTest.java @@ -70,6 +70,7 @@ public class JsonFileImport198MigrationTest extends AbstractJsonFileImportMigrat testMigrationTo7_x(false); testMigrationTo8_x(); testMigrationTo9_x(); + testMigrationTo12_x(); } @Override diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport255MigrationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport255MigrationTest.java index ed6e4343d6..2075b0eb9f 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport255MigrationTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport255MigrationTest.java @@ -64,6 +64,7 @@ public class JsonFileImport255MigrationTest extends AbstractJsonFileImportMigrat testMigrationTo7_x(true); testMigrationTo8_x(); testMigrationTo9_x(); + testMigrationTo12_x(); } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport343MigrationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport343MigrationTest.java index e7d2643033..5ea4c70f09 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport343MigrationTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport343MigrationTest.java @@ -63,6 +63,7 @@ public class JsonFileImport343MigrationTest extends AbstractJsonFileImportMigrat testMigrationTo7_x(true); testMigrationTo8_x(); testMigrationTo9_x(); + testMigrationTo12_x(); } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport483MigrationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport483MigrationTest.java index 42174b3182..9ab4ef34f8 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport483MigrationTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport483MigrationTest.java @@ -56,6 +56,7 @@ public class JsonFileImport483MigrationTest extends AbstractJsonFileImportMigrat testMigrationTo7_x(true); testMigrationTo8_x(); testMigrationTo9_x(); + testMigrationTo12_x(); } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport903MigrationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport903MigrationTest.java index c988a1e044..26b8fb7ab9 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport903MigrationTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport903MigrationTest.java @@ -51,7 +51,7 @@ public class JsonFileImport903MigrationTest extends AbstractJsonFileImportMigrat @Test public void migration9_0_3Test() throws Exception { checkRealmsImported(); -// testMigrationTo10_x(); + testMigrationTo12_x(); } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/MigrationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/MigrationTest.java index 799976d43b..9f2bcd6b4a 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/MigrationTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/MigrationTest.java @@ -57,17 +57,11 @@ public class MigrationTest extends AbstractMigrationTest { } } - @Test - @Migration(versionFrom = "12.") - public void migration12_xTest() { - testMigrationTo12_x(); - } - @Test @Migration(versionFrom = "9.") public void migration9_xTest() throws Exception { testMigratedData(false); -// testMigrationTo10_x(); + testMigrationTo12_x(); // Always test offline-token login during migration test testOfflineTokenLogin(); @@ -82,6 +76,7 @@ public class MigrationTest extends AbstractMigrationTest { testMigrationTo7_x(true); testMigrationTo8_x(); testMigrationTo9_x(); + testMigrationTo12_x(); // Always test offline-token login during migration test testOfflineTokenLogin(); @@ -97,6 +92,7 @@ public class MigrationTest extends AbstractMigrationTest { testMigrationTo7_x(true); testMigrationTo8_x(); testMigrationTo9_x(); + testMigrationTo12_x(); // Always test offline-token login during migration test testOfflineTokenLogin(); @@ -113,6 +109,7 @@ public class MigrationTest extends AbstractMigrationTest { testMigrationTo7_x(true); testMigrationTo8_x(); testMigrationTo9_x(); + testMigrationTo12_x(); // Always test offline-token login during migration test testOfflineTokenLogin(); @@ -130,6 +127,7 @@ public class MigrationTest extends AbstractMigrationTest { testMigrationTo7_x(false); testMigrationTo8_x(); testMigrationTo9_x(); + testMigrationTo12_x(); // Always test offline-token login during migration test testOfflineTokenLogin();