KEYCLOAK-16502 Migration of DELETE_ACCOUNT role

This commit is contained in:
vramik 2020-12-01 01:07:45 +01:00 committed by Hynek Mlnařík
parent 6a6dba5d6e
commit cd9e01af90
12 changed files with 54 additions and 20 deletions

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -294,6 +294,7 @@ public class RepresentationToModel {
newRealm.addRequiredActionProvider(model);
}
DefaultRequiredActions.addDeleteAccountAction(newRealm);
} else {
DefaultRequiredActions.addActions(newRealm);
}

View file

@ -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()

View file

@ -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) {

View file

@ -70,6 +70,7 @@ public class JsonFileImport198MigrationTest extends AbstractJsonFileImportMigrat
testMigrationTo7_x(false);
testMigrationTo8_x();
testMigrationTo9_x();
testMigrationTo12_x();
}
@Override

View file

@ -64,6 +64,7 @@ public class JsonFileImport255MigrationTest extends AbstractJsonFileImportMigrat
testMigrationTo7_x(true);
testMigrationTo8_x();
testMigrationTo9_x();
testMigrationTo12_x();
}
}

View file

@ -63,6 +63,7 @@ public class JsonFileImport343MigrationTest extends AbstractJsonFileImportMigrat
testMigrationTo7_x(true);
testMigrationTo8_x();
testMigrationTo9_x();
testMigrationTo12_x();
}
}

View file

@ -56,6 +56,7 @@ public class JsonFileImport483MigrationTest extends AbstractJsonFileImportMigrat
testMigrationTo7_x(true);
testMigrationTo8_x();
testMigrationTo9_x();
testMigrationTo12_x();
}
}

View file

@ -51,7 +51,7 @@ public class JsonFileImport903MigrationTest extends AbstractJsonFileImportMigrat
@Test
public void migration9_0_3Test() throws Exception {
checkRealmsImported();
// testMigrationTo10_x();
testMigrationTo12_x();
}
}

View file

@ -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();