From 8993ca08ad8af5a0e76df2c1610d5e8bbcff0ec7 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Tue, 21 Nov 2017 17:46:48 -0500 Subject: [PATCH] KEYCLOAK-4715 --- .../keycloak/models/jpa/JpaRealmProvider.java | 9 +- .../migration/MigrationModelManager.java | 46 ++ .../migration/migrators/MigrateTo1_2_0.java | 11 +- .../migration/migrators/MigrateTo1_3_0.java | 6 + .../migration/migrators/MigrateTo1_4_0.java | 27 +- .../migration/migrators/MigrateTo1_5_0.java | 56 ++- .../migration/migrators/MigrateTo1_6_0.java | 87 ++-- .../migration/migrators/MigrateTo1_7_0.java | 39 +- .../migration/migrators/MigrateTo1_8_0.java | 30 +- .../migration/migrators/MigrateTo1_9_2.java | 20 +- .../migration/migrators/MigrateTo2_0_0.java | 7 + .../migration/migrators/MigrateTo2_1_0.java | 10 +- .../migration/migrators/MigrateTo2_2_0.java | 7 + .../migration/migrators/MigrateTo2_3_0.java | 24 +- .../migration/migrators/MigrateTo2_5_0.java | 6 + .../migration/migrators/MigrateTo3_0_0.java | 40 +- .../migration/migrators/MigrateTo3_1_0.java | 27 +- .../migration/migrators/MigrateTo3_2_0.java | 63 ++- .../migration/migrators/MigrateTo3_4_0.java | 31 +- .../migration/migrators/MigrateTo3_4_1.java | 22 +- .../migration/migrators/Migration.java | 18 + .../models/utils/DefaultKeyProviders.java | 64 ++- .../services/managers/RealmManager.java | 5 + .../AbstractJsonFileImportMigrationTest.java | 65 +++ .../migration/AbstractMigrationTest.java | 422 ++++++++++++++++++ .../JsonFileImport198MigrationTest.java | 74 +++ .../JsonFileImport255MigrationTest.java | 58 +++ .../testsuite/migration/MigrationTest.java | 366 +-------------- 28 files changed, 1092 insertions(+), 548 deletions(-) create mode 100644 testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/AbstractJsonFileImportMigrationTest.java create mode 100644 testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/AbstractMigrationTest.java create mode 100644 testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport198MigrationTest.java create mode 100644 testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport255MigrationTest.java diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java index c70f755d9b..6f23dc58f4 100755 --- a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java +++ b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java @@ -26,6 +26,7 @@ import org.keycloak.models.ClientModel; import org.keycloak.models.ClientTemplateModel; import org.keycloak.models.GroupModel; import org.keycloak.models.KeycloakSession; +import org.keycloak.models.ModelDuplicateException; import org.keycloak.models.RealmModel; import org.keycloak.models.RealmProvider; import org.keycloak.models.RoleContainerModel; @@ -183,11 +184,14 @@ public class JpaRealmProvider implements RealmProvider { @Override public RoleModel addRealmRole(RealmModel realm, String name) { - return addRealmRole(realm, KeycloakModelUtils.generateId(), name); + return addRealmRole(realm, KeycloakModelUtils.generateId(), name); } @Override public RoleModel addRealmRole(RealmModel realm, String id, String name) { + if (getRealmRole(realm, name) != null) { + throw new ModelDuplicateException(); + } RoleEntity entity = new RoleEntity(); entity.setId(id); entity.setName(name); @@ -217,6 +221,9 @@ public class JpaRealmProvider implements RealmProvider { } @Override public RoleModel addClientRole(RealmModel realm, ClientModel client, String id, String name) { + if (getClientRole(realm, client, name) != null) { + throw new ModelDuplicateException(); + } ClientEntity clientEntity = em.getReference(ClientEntity.class, client.getId()); RoleEntity roleEntity = new RoleEntity(); roleEntity.setId(id); diff --git a/server-spi-private/src/main/java/org/keycloak/migration/MigrationModelManager.java b/server-spi-private/src/main/java/org/keycloak/migration/MigrationModelManager.java index c286aa068a..db980c40e1 100755 --- a/server-spi-private/src/main/java/org/keycloak/migration/MigrationModelManager.java +++ b/server-spi-private/src/main/java/org/keycloak/migration/MigrationModelManager.java @@ -39,6 +39,8 @@ import org.keycloak.migration.migrators.MigrateTo3_4_0; import org.keycloak.migration.migrators.MigrateTo3_4_1; import org.keycloak.migration.migrators.Migration; import org.keycloak.models.KeycloakSession; +import org.keycloak.models.RealmModel; +import org.keycloak.representations.idm.RealmRepresentation; /** * @author Bill Burke @@ -91,4 +93,48 @@ public class MigrationModelManager { model.setStoredVersion(latest.toString()); } + + public static final ModelVersion RHSSO_VERSION_7_0_KEYCLOAK_VERSION = new ModelVersion("1.9.8"); + public static final ModelVersion RHSSO_VERSION_7_1_KEYCLOAK_VERSION = new ModelVersion("2.5.0"); + public static final ModelVersion RHSSO_VERSION_7_2_KEYCLOAK_VERSION = new ModelVersion("3.4.2"); + + + public static void migrateImport(KeycloakSession session, RealmModel realm, RealmRepresentation rep, boolean skipUserDependent) { + ModelVersion latest = migrations[migrations.length-1].getVersion(); + ModelVersion stored = migrations[0].getVersion(); + if (rep.getKeycloakVersion() != null) { + stored = new ModelVersion(rep.getKeycloakVersion()); + // hack for importing RH-SSO json export + // NOTE!!!!! We need to do something once we reach community version 7. If community version is 7 or higher, look for the GA qualifier to identify it as RH SSO + if (latest.getMajor() < 7 || (stored.getMajor() == 7 && stored.getQualifier().equals("GA"))) { + if (stored.getMajor() == 7) { + if (stored.getMinor() == 0) { + stored = RHSSO_VERSION_7_0_KEYCLOAK_VERSION; + } else if (stored.getMinor() == 1) { + stored = RHSSO_VERSION_7_1_KEYCLOAK_VERSION; + } else if (stored.getMinor() == 2) { + stored = RHSSO_VERSION_7_2_KEYCLOAK_VERSION; + } + } + } + // strip out qualifier + stored = new ModelVersion(stored.major, stored.minor, stored.micro); + if (latest.equals(stored) || latest.lessThan(stored)) { + return; + } + } + + for (Migration m : migrations) { + if (stored == null || stored.lessThan(m.getVersion())) { + if (stored != null) { + logger.debugf("Migrating older json representation to %s", m.getVersion()); + } + try { + m.migrateImport(session, realm, rep, skipUserDependent); + } catch (Exception e) { + logger.error("Failed to migrate json representation for version: " + m.getVersion(), e); + } + } + } + } } diff --git a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_2_0.java b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_2_0.java index 5cd00378b9..1dffc27fc2 100755 --- a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_2_0.java +++ b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_2_0.java @@ -24,6 +24,7 @@ import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; import org.keycloak.models.RoleModel; import org.keycloak.models.utils.KeycloakModelUtils; +import org.keycloak.representations.idm.RealmRepresentation; import java.util.List; @@ -48,7 +49,9 @@ public class MigrateTo1_2_0 implements Migration { client.setFullScopeAllowed(false); for (String role : Constants.BROKER_SERVICE_ROLES) { - RoleModel roleModel = client.addRole(role); + RoleModel roleModel = client.getRole(role); + if (roleModel != null) continue; + roleModel = client.addRole(role); roleModel.setDescription("${role_" + role.toLowerCase().replaceAll("_", "-") + "}"); roleModel.setScopeParamRequired(false); } @@ -73,4 +76,10 @@ public class MigrateTo1_2_0 implements Migration { } } + + @Override + public void migrateImport(KeycloakSession session, RealmModel realm, RealmRepresentation rep, boolean skipUserDependent) { + setupBrokerService(realm); + setupClientNames(realm); + } } diff --git a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_3_0.java b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_3_0.java index cda91a44be..ea98f5822b 100755 --- a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_3_0.java +++ b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_3_0.java @@ -25,6 +25,7 @@ import org.keycloak.models.KeycloakSession; import org.keycloak.models.LDAPConstants; import org.keycloak.models.RealmModel; import org.keycloak.provider.ProviderFactory; +import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.storage.UserStorageProvider; import org.keycloak.storage.UserStorageProviderModel; @@ -52,6 +53,11 @@ public class MigrateTo1_3_0 implements Migration { } + @Override + public void migrateImport(KeycloakSession session, RealmModel realm, RealmRepresentation rep, boolean skipUserDependent) { + migrateLDAPProviders(session, realm); + } + private void migrateLDAPProviders(KeycloakSession session, RealmModel realm) { List federationProviders = realm.getUserStorageProviders(); for (UserStorageProviderModel fedProvider : federationProviders) { diff --git a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_4_0.java b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_4_0.java index 160906c8d6..792a151680 100755 --- a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_4_0.java +++ b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_4_0.java @@ -28,6 +28,7 @@ import org.keycloak.models.cache.UserCache; import org.keycloak.models.utils.DefaultAuthenticationFlows; import org.keycloak.models.utils.DefaultRequiredActions; import org.keycloak.models.utils.KeycloakModelUtils; +import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.storage.UserStorageProviderModel; import java.util.Arrays; @@ -46,18 +47,28 @@ public class MigrateTo1_4_0 implements Migration { public void migrate(KeycloakSession session) { List realms = session.realms().getRealms(); for (RealmModel realm : realms) { - if (realm.getAuthenticationFlows().size() == 0) { - DefaultAuthenticationFlows.migrateFlows(realm); - DefaultRequiredActions.addActions(realm); - } - ImpersonationConstants.setupImpersonationService(session, realm); - - migrateLDAPMappers(session, realm); - migrateUsers(session, realm); + migrateRealm(session, realm); } } + protected void migrateRealm(KeycloakSession session, RealmModel realm) { + if (realm.getAuthenticationFlows().size() == 0) { + DefaultAuthenticationFlows.migrateFlows(realm); + DefaultRequiredActions.addActions(realm); + } + ImpersonationConstants.setupImpersonationService(session, realm); + + migrateLDAPMappers(session, realm); + migrateUsers(session, realm); + } + + @Override + public void migrateImport(KeycloakSession session, RealmModel realm, RealmRepresentation rep, boolean skipUserDependent) { + migrateRealm(session, realm); + + } + private void migrateLDAPMappers(KeycloakSession session, RealmModel realm) { List mandatoryInLdap = Arrays.asList("username", "username-cn", "first name", "last name"); for (UserStorageProviderModel providerModel : realm.getUserStorageProviders()) { diff --git a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_5_0.java b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_5_0.java index 6969d5c30c..ec019f216d 100755 --- a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_5_0.java +++ b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_5_0.java @@ -25,6 +25,7 @@ import org.keycloak.models.OTPPolicy; import org.keycloak.models.RealmModel; import org.keycloak.models.utils.DefaultAuthenticationFlows; import org.keycloak.models.utils.KeycloakModelUtils; +import org.keycloak.representations.idm.RealmRepresentation; import java.util.List; @@ -42,30 +43,39 @@ public class MigrateTo1_5_0 implements Migration { public void migrate(KeycloakSession session) { List realms = session.realms().getRealms(); for (RealmModel realm : realms) { - DefaultAuthenticationFlows.migrateFlows(realm); // add reset credentials flo - realm.setOTPPolicy(OTPPolicy.DEFAULT_POLICY); - realm.setBrowserFlow(realm.getFlowByAlias(DefaultAuthenticationFlows.BROWSER_FLOW)); - realm.setRegistrationFlow(realm.getFlowByAlias(DefaultAuthenticationFlows.REGISTRATION_FLOW)); - realm.setDirectGrantFlow(realm.getFlowByAlias(DefaultAuthenticationFlows.DIRECT_GRANT_FLOW)); - - AuthenticationFlowModel resetFlow = realm.getFlowByAlias(DefaultAuthenticationFlows.RESET_CREDENTIALS_FLOW); - if (resetFlow == null) { - DefaultAuthenticationFlows.resetCredentialsFlow(realm); - } else { - realm.setResetCredentialsFlow(resetFlow); - } - - AuthenticationFlowModel clientAuthFlow = realm.getFlowByAlias(DefaultAuthenticationFlows.CLIENT_AUTHENTICATION_FLOW); - if (clientAuthFlow == null) { - DefaultAuthenticationFlows.clientAuthFlow(realm); - } else { - realm.setClientAuthenticationFlow(clientAuthFlow); - } - - for (ClientModel client : realm.getClients()) { - client.setClientAuthenticatorType(KeycloakModelUtils.getDefaultClientAuthenticatorType()); - } + migrateRealm(realm); } } + + @Override + public void migrateImport(KeycloakSession session, RealmModel realm, RealmRepresentation rep, boolean skipUserDependent) { + migrateRealm(realm); + } + + protected void migrateRealm(RealmModel realm) { + DefaultAuthenticationFlows.migrateFlows(realm); // add reset credentials flo + realm.setOTPPolicy(OTPPolicy.DEFAULT_POLICY); + realm.setBrowserFlow(realm.getFlowByAlias(DefaultAuthenticationFlows.BROWSER_FLOW)); + realm.setRegistrationFlow(realm.getFlowByAlias(DefaultAuthenticationFlows.REGISTRATION_FLOW)); + realm.setDirectGrantFlow(realm.getFlowByAlias(DefaultAuthenticationFlows.DIRECT_GRANT_FLOW)); + + AuthenticationFlowModel resetFlow = realm.getFlowByAlias(DefaultAuthenticationFlows.RESET_CREDENTIALS_FLOW); + if (resetFlow == null) { + DefaultAuthenticationFlows.resetCredentialsFlow(realm); + } else { + realm.setResetCredentialsFlow(resetFlow); + } + + AuthenticationFlowModel clientAuthFlow = realm.getFlowByAlias(DefaultAuthenticationFlows.CLIENT_AUTHENTICATION_FLOW); + if (clientAuthFlow == null) { + DefaultAuthenticationFlows.clientAuthFlow(realm); + } else { + realm.setClientAuthenticationFlow(clientAuthFlow); + } + + for (ClientModel client : realm.getClients()) { + client.setClientAuthenticatorType(KeycloakModelUtils.getDefaultClientAuthenticatorType()); + } + } } diff --git a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_6_0.java b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_6_0.java index aab2d527e2..d044d9295b 100644 --- a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_6_0.java +++ b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_6_0.java @@ -27,6 +27,7 @@ import org.keycloak.models.ProtocolMapperModel; import org.keycloak.models.RealmModel; import org.keycloak.models.RoleModel; import org.keycloak.models.utils.KeycloakModelUtils; +import org.keycloak.representations.idm.RealmRepresentation; import java.util.List; @@ -58,48 +59,70 @@ public class MigrateTo1_6_0 implements Migration { List realms = session.realms().getRealms(); for (RealmModel realm : realms) { - realm.setOfflineSessionIdleTimeout(Constants.DEFAULT_OFFLINE_SESSION_IDLE_TIMEOUT); + migrateRealm(session, localeMapper, realm); + } + } - if (realm.getRole(Constants.OFFLINE_ACCESS_ROLE) == null) { - for (RoleModel realmRole : realm.getRoles()) { - realmRole.setScopeParamRequired(false); + @Override + public void migrateImport(KeycloakSession session, RealmModel realm, RealmRepresentation rep, boolean skipUserDependent) { + MigrationProvider provider = session.getProvider(MigrationProvider.class); + List builtinMappers = provider.getBuiltinMappers("openid-connect"); + ProtocolMapperModel localeMapper = null; + for (ProtocolMapperModel m : builtinMappers) { + if (m.getName().equals("locale")) { + localeMapper = m; + } + } + if (localeMapper == null) { + throw new RuntimeException("Can't find default locale mapper"); + } + migrateRealm(session, localeMapper, realm); + + + } + + protected void migrateRealm(KeycloakSession session, ProtocolMapperModel localeMapper, RealmModel realm) { + realm.setOfflineSessionIdleTimeout(Constants.DEFAULT_OFFLINE_SESSION_IDLE_TIMEOUT); + + if (realm.getRole(Constants.OFFLINE_ACCESS_ROLE) == null) { + for (RoleModel realmRole : realm.getRoles()) { + realmRole.setScopeParamRequired(false); + } + for (ClientModel client : realm.getClients()) { + for (RoleModel clientRole : client.getRoles()) { + clientRole.setScopeParamRequired(false); } - for (ClientModel client : realm.getClients()) { - for (RoleModel clientRole : client.getRoles()) { - clientRole.setScopeParamRequired(false); - } - } - - KeycloakModelUtils.setupOfflineTokens(realm); - RoleModel role = realm.getRole(Constants.OFFLINE_ACCESS_ROLE); - - // Bulk grant of offline_access role to all users - session.users().grantToAllUsers(realm, role); } - ClientModel adminConsoleClient = realm.getClientByClientId(Constants.ADMIN_CONSOLE_CLIENT_ID); - if ((adminConsoleClient != null) && !localeMapperAdded(adminConsoleClient)) { - adminConsoleClient.addProtocolMapper(localeMapper); - } + KeycloakModelUtils.setupOfflineTokens(realm); + RoleModel role = realm.getRole(Constants.OFFLINE_ACCESS_ROLE); - ClientModel client = realm.getMasterAdminClient(); + // Bulk grant of offline_access role to all users + session.users().grantToAllUsers(realm, role); + } + + ClientModel adminConsoleClient = realm.getClientByClientId(Constants.ADMIN_CONSOLE_CLIENT_ID); + if ((adminConsoleClient != null) && !localeMapperAdded(adminConsoleClient)) { + adminConsoleClient.addProtocolMapper(localeMapper); + } + + ClientModel client = realm.getMasterAdminClient(); + if (client.getRole(AdminRoles.CREATE_CLIENT) == null) { + RoleModel role = client.addRole(AdminRoles.CREATE_CLIENT); + role.setDescription("${role_" + AdminRoles.CREATE_CLIENT + "}"); + role.setScopeParamRequired(false); + + client.getRealm().getRole(AdminRoles.ADMIN).addCompositeRole(role); + } + + if (!realm.getName().equals(Config.getAdminRealm())) { + client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID); if (client.getRole(AdminRoles.CREATE_CLIENT) == null) { RoleModel role = client.addRole(AdminRoles.CREATE_CLIENT); role.setDescription("${role_" + AdminRoles.CREATE_CLIENT + "}"); role.setScopeParamRequired(false); - client.getRealm().getRole(AdminRoles.ADMIN).addCompositeRole(role); - } - - if (!realm.getName().equals(Config.getAdminRealm())) { - client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID); - if (client.getRole(AdminRoles.CREATE_CLIENT) == null) { - RoleModel role = client.addRole(AdminRoles.CREATE_CLIENT); - role.setDescription("${role_" + AdminRoles.CREATE_CLIENT + "}"); - role.setScopeParamRequired(false); - - client.getRole(AdminRoles.REALM_ADMIN).addCompositeRole(role); - } + client.getRole(AdminRoles.REALM_ADMIN).addCompositeRole(role); } } } diff --git a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_7_0.java b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_7_0.java index 55e09586ab..adb6801f24 100644 --- a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_7_0.java +++ b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_7_0.java @@ -25,6 +25,7 @@ import org.keycloak.models.IdentityProviderModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; import org.keycloak.models.utils.DefaultAuthenticationFlows; +import org.keycloak.representations.idm.RealmRepresentation; import java.util.List; @@ -42,23 +43,33 @@ public class MigrateTo1_7_0 implements Migration { public void migrate(KeycloakSession session) { List realms = session.realms().getRealms(); for (RealmModel realm : realms) { - // Set default accessToken timeout for implicit flow - realm.setAccessTokenLifespanForImplicitFlow(Constants.DEFAULT_ACCESS_TOKEN_LIFESPAN_FOR_IMPLICIT_FLOW_TIMEOUT); + migrateRealm(session, realm); - // Add 'admin-cli' builtin client - MigrationProvider migrationProvider = session.getProvider(MigrationProvider.class); - migrationProvider.setupAdminCli(realm); + } + } - // add firstBrokerLogin flow and set it to all identityProviders - DefaultAuthenticationFlows.migrateFlows(realm); - AuthenticationFlowModel firstBrokerLoginFlow = realm.getFlowByAlias(DefaultAuthenticationFlows.FIRST_BROKER_LOGIN_FLOW); + @Override + public void migrateImport(KeycloakSession session, RealmModel realm, RealmRepresentation rep, boolean skipUserDependent) { + migrateRealm(session, realm); + } - List identityProviders = realm.getIdentityProviders(); - for (IdentityProviderModel identityProvider : identityProviders) { - if (identityProvider.getFirstBrokerLoginFlowId() == null) { - identityProvider.setFirstBrokerLoginFlowId(firstBrokerLoginFlow.getId()); - realm.updateIdentityProvider(identityProvider); - } + protected void migrateRealm(KeycloakSession session, RealmModel realm) { + // Set default accessToken timeout for implicit flow + realm.setAccessTokenLifespanForImplicitFlow(Constants.DEFAULT_ACCESS_TOKEN_LIFESPAN_FOR_IMPLICIT_FLOW_TIMEOUT); + + // Add 'admin-cli' builtin client + MigrationProvider migrationProvider = session.getProvider(MigrationProvider.class); + migrationProvider.setupAdminCli(realm); + + // add firstBrokerLogin flow and set it to all identityProviders + DefaultAuthenticationFlows.migrateFlows(realm); + AuthenticationFlowModel firstBrokerLoginFlow = realm.getFlowByAlias(DefaultAuthenticationFlows.FIRST_BROKER_LOGIN_FLOW); + + List identityProviders = realm.getIdentityProviders(); + for (IdentityProviderModel identityProvider : identityProviders) { + if (identityProvider.getFirstBrokerLoginFlowId() == null) { + identityProvider.setFirstBrokerLoginFlowId(firstBrokerLoginFlow.getId()); + realm.updateIdentityProvider(identityProvider); } } } diff --git a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_8_0.java b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_8_0.java index 3c5d4d9fd2..d291e1648e 100644 --- a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_8_0.java +++ b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_8_0.java @@ -24,6 +24,7 @@ import org.keycloak.models.KeycloakSession; import org.keycloak.models.LDAPConstants; import org.keycloak.models.RealmModel; import org.keycloak.models.utils.KeycloakModelUtils; +import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.storage.UserStorageProviderModel; import java.util.List; @@ -45,21 +46,30 @@ public class MigrateTo1_8_0 implements Migration { List realms = session.realms().getRealms(); for (RealmModel realm : realms) { - List federationProviders = realm.getUserStorageProviders(); - for (UserStorageProviderModel fedProvider : federationProviders) { + migrateRealm(realm); - if (fedProvider.getProviderId().equals(LDAPConstants.LDAP_PROVIDER)) { + } + } - if (isActiveDirectory(fedProvider)) { - // Create mapper for MSAD account controls - if (getMapperByName(realm, fedProvider, "MSAD account controls") == null) { - ComponentModel mapperModel = KeycloakModelUtils.createComponentModel("MSAD account controls", fedProvider.getId(), LDAPConstants.MSAD_USER_ACCOUNT_CONTROL_MAPPER, "org.keycloak.storage.ldap.mappers.LDAPStorageMapper"); - realm.addComponentModel(mapperModel); - } + @Override + public void migrateImport(KeycloakSession session, RealmModel realm, RealmRepresentation rep, boolean skipUserDependent) { + migrateRealm(realm); + } + + protected void migrateRealm(RealmModel realm) { + List federationProviders = realm.getUserStorageProviders(); + for (UserStorageProviderModel fedProvider : federationProviders) { + + if (fedProvider.getProviderId().equals(LDAPConstants.LDAP_PROVIDER)) { + + if (isActiveDirectory(fedProvider)) { + // Create mapper for MSAD account controls + if (getMapperByName(realm, fedProvider, "MSAD account controls") == null) { + ComponentModel mapperModel = KeycloakModelUtils.createComponentModel("MSAD account controls", fedProvider.getId(), LDAPConstants.MSAD_USER_ACCOUNT_CONTROL_MAPPER, "org.keycloak.storage.ldap.mappers.LDAPStorageMapper"); + realm.addComponentModel(mapperModel); } } } - } } diff --git a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_9_2.java b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_9_2.java index 3a41058c81..171d9ef0e5 100644 --- a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_9_2.java +++ b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo1_9_2.java @@ -20,6 +20,7 @@ package org.keycloak.migration.migrators; import org.keycloak.migration.ModelVersion; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; +import org.keycloak.representations.idm.RealmRepresentation; import java.util.Collections; import java.util.HashMap; @@ -35,13 +36,22 @@ public class MigrateTo1_9_2 implements Migration { public void migrate(KeycloakSession session) { for (RealmModel realm : session.realms().getRealms()) { - if (realm.getBrowserSecurityHeaders() != null) { + migrateRealm(realm); + } + } - Map browserSecurityHeaders = new HashMap<>(realm.getBrowserSecurityHeaders()); - browserSecurityHeaders.put("xContentTypeOptions", "nosniff"); + @Override + public void migrateImport(KeycloakSession session, RealmModel realm, RealmRepresentation rep, boolean skipUserDependent) { + migrateRealm(realm); + } - realm.setBrowserSecurityHeaders(Collections.unmodifiableMap(browserSecurityHeaders)); - } + protected void migrateRealm(RealmModel realm) { + if (realm.getBrowserSecurityHeaders() != null) { + + Map browserSecurityHeaders = new HashMap<>(realm.getBrowserSecurityHeaders()); + browserSecurityHeaders.put("xContentTypeOptions", "nosniff"); + + realm.setBrowserSecurityHeaders(Collections.unmodifiableMap(browserSecurityHeaders)); } } diff --git a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_0_0.java b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_0_0.java index d36a8583c7..788e373a7c 100644 --- a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_0_0.java +++ b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_0_0.java @@ -22,6 +22,7 @@ import org.keycloak.models.AdminRoles; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; import org.keycloak.models.utils.KeycloakModelUtils; +import org.keycloak.representations.idm.RealmRepresentation; public class MigrateTo2_0_0 implements Migration { @@ -37,6 +38,12 @@ public class MigrateTo2_0_0 implements Migration { } } + @Override + public void migrateImport(KeycloakSession session, RealmModel realm, RealmRepresentation rep, boolean skipUserDependent) { + migrateAuthorizationServices(realm); + + } + private void migrateAuthorizationServices(RealmModel realm) { KeycloakModelUtils.setupAuthorizationServices(realm); diff --git a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_1_0.java b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_1_0.java index 9ff2a52cd7..2bb7f88360 100644 --- a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_1_0.java +++ b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_1_0.java @@ -26,6 +26,7 @@ import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; import org.keycloak.models.RequiredActionProviderModel; import org.keycloak.models.UserModel; +import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.util.JsonSerialization; import java.util.HashMap; @@ -51,7 +52,14 @@ public class MigrateTo2_1_0 implements Migration { migrateRolePolicies(realm, session); } } - + + @Override + public void migrateImport(KeycloakSession session, RealmModel realm, RealmRepresentation rep, boolean skipUserDependent) { + migrateDefaultRequiredAction(realm); + migrateRolePolicies(realm, session); + + } + // KEYCLOAK-3244: Required Action "Configure Totp" should be "Configure OTP" private void migrateDefaultRequiredAction(RealmModel realm) { RequiredActionProviderModel otpAction = realm.getRequiredActionProviderByAlias(UserModel.RequiredAction.CONFIGURE_TOTP.name()); diff --git a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_2_0.java b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_2_0.java index 411bf243dd..19ab4c4a1c 100644 --- a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_2_0.java +++ b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_2_0.java @@ -23,6 +23,7 @@ import org.keycloak.models.IdentityProviderModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; import org.keycloak.models.utils.DefaultAuthenticationFlows; +import org.keycloak.representations.idm.RealmRepresentation; public class MigrateTo2_2_0 implements Migration { public static final ModelVersion VERSION = new ModelVersion("2.2.0"); @@ -39,6 +40,12 @@ public class MigrateTo2_2_0 implements Migration { } } + @Override + public void migrateImport(KeycloakSession session, RealmModel realm, RealmRepresentation rep, boolean skipUserDependent) { + addIdentityProviderAuthenticator(realm); + + } + private void addIdentityProviderAuthenticator(RealmModel realm) { String defaultProvider = null; for (IdentityProviderModel provider : realm.getIdentityProviders()) { diff --git a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_3_0.java b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_3_0.java index 56aee36229..8568776e1f 100644 --- a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_3_0.java +++ b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_3_0.java @@ -23,6 +23,7 @@ import org.keycloak.models.ClientModel; import org.keycloak.models.ClientTemplateModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; +import org.keycloak.representations.idm.RealmRepresentation; /** * @author Marek Posolda @@ -34,16 +35,25 @@ public class MigrateTo2_3_0 implements Migration { @Override public void migrate(KeycloakSession session) { for (RealmModel realm : session.realms().getRealms()) { - for (ClientModel client : realm.getClients()) { - MigrationUtils.updateProtocolMappers(client); - } - - for (ClientTemplateModel clientTemplate : realm.getClientTemplates()) { - MigrationUtils.updateProtocolMappers(clientTemplate); - } + migrateRealm(realm); } } + protected void migrateRealm(RealmModel realm) { + for (ClientModel client : realm.getClients()) { + MigrationUtils.updateProtocolMappers(client); + } + + for (ClientTemplateModel clientTemplate : realm.getClientTemplates()) { + MigrationUtils.updateProtocolMappers(clientTemplate); + } + } + + @Override + public void migrateImport(KeycloakSession session, RealmModel realm, RealmRepresentation rep, boolean skipUserDependent) { + migrateRealm(realm); + } + @Override public ModelVersion getVersion() { return VERSION; diff --git a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_5_0.java b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_5_0.java index ee9a04175d..95623c0952 100644 --- a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_5_0.java +++ b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo2_5_0.java @@ -24,6 +24,7 @@ import org.keycloak.models.ClientTemplateModel; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; import org.keycloak.models.utils.DefaultKeyProviders; +import org.keycloak.representations.idm.RealmRepresentation; /** * @author Marek Posolda @@ -39,6 +40,11 @@ public class MigrateTo2_5_0 implements Migration { ); } + @Override + public void migrateImport(KeycloakSession session, RealmModel realm, RealmRepresentation rep, boolean skipUserDependent) { + DefaultKeyProviders.createSecretProvider(realm); + } + @Override public ModelVersion getVersion() { return VERSION; diff --git a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo3_0_0.java b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo3_0_0.java index 4daf7551aa..1999dd415c 100644 --- a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo3_0_0.java +++ b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo3_0_0.java @@ -24,6 +24,7 @@ import org.keycloak.models.Constants; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; import org.keycloak.models.RoleModel; +import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.oidc.OIDCClientRepresentation; import java.util.Objects; @@ -44,26 +45,35 @@ public class MigrateTo3_0_0 implements Migration { public void migrate(KeycloakSession session) { for (RealmModel realm : session.realms().getRealms()) { - realm.getClients().stream() - .filter(clientModel -> defaultClients.contains(clientModel.getId())) - .filter(clientModel -> Objects.isNull(clientModel.getProtocol())) - .forEach(clientModel -> clientModel.setProtocol("openid-connect")); - - ClientModel client = realm.getClientByClientId(ACCOUNT_MANAGEMENT_CLIENT_ID); - if (client == null) continue; - RoleModel linkRole = client.getRole(MANAGE_ACCOUNT_LINKS); - if (linkRole == null) { - client.addRole(MANAGE_ACCOUNT_LINKS); - } - RoleModel manageAccount = client.getRole(MANAGE_ACCOUNT); - if (manageAccount == null) continue; - RoleModel manageAccountLinks = client.getRole(MANAGE_ACCOUNT_LINKS); - manageAccount.addCompositeRole(manageAccountLinks); + migrateRealm(realm); } } + @Override + public void migrateImport(KeycloakSession session, RealmModel realm, RealmRepresentation rep, boolean skipUserDependent) { + migrateRealm(realm); + } + + protected void migrateRealm(RealmModel realm) { + realm.getClients().stream() + .filter(clientModel -> defaultClients.contains(clientModel.getId())) + .filter(clientModel -> Objects.isNull(clientModel.getProtocol())) + .forEach(clientModel -> clientModel.setProtocol("openid-connect")); + + ClientModel client = realm.getClientByClientId(ACCOUNT_MANAGEMENT_CLIENT_ID); + if (client == null) return; + RoleModel linkRole = client.getRole(MANAGE_ACCOUNT_LINKS); + if (linkRole == null) { + client.addRole(MANAGE_ACCOUNT_LINKS); + } + RoleModel manageAccount = client.getRole(MANAGE_ACCOUNT); + if (manageAccount == null) return; + RoleModel manageAccountLinks = client.getRole(MANAGE_ACCOUNT_LINKS); + manageAccount.addCompositeRole(manageAccountLinks); + } + @Override public ModelVersion getVersion() { return VERSION; diff --git a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo3_1_0.java b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo3_1_0.java index b405d42f65..4f66fc07df 100644 --- a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo3_1_0.java +++ b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo3_1_0.java @@ -21,6 +21,7 @@ package org.keycloak.migration.migrators; import org.keycloak.migration.ModelVersion; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; +import org.keycloak.representations.idm.RealmRepresentation; import java.util.Collections; import java.util.HashMap; @@ -36,17 +37,27 @@ public class MigrateTo3_1_0 implements Migration { @Override public void migrate(KeycloakSession session) { for (RealmModel realm : session.realms().getRealms()) { - if (realm.getBrowserSecurityHeaders() != null) { - - Map browserSecurityHeaders = new HashMap<>(realm.getBrowserSecurityHeaders()); - browserSecurityHeaders.put("xRobotsTag", "none"); - browserSecurityHeaders.put("xXSSProtection", "1; mode=block"); - - realm.setBrowserSecurityHeaders(Collections.unmodifiableMap(browserSecurityHeaders)); - } + migrateRealm(realm); } } + protected void migrateRealm(RealmModel realm) { + if (realm.getBrowserSecurityHeaders() != null) { + + Map browserSecurityHeaders = new HashMap<>(realm.getBrowserSecurityHeaders()); + browserSecurityHeaders.put("xRobotsTag", "none"); + browserSecurityHeaders.put("xXSSProtection", "1; mode=block"); + + realm.setBrowserSecurityHeaders(Collections.unmodifiableMap(browserSecurityHeaders)); + } + } + + @Override + public void migrateImport(KeycloakSession session, RealmModel realm, RealmRepresentation rep, boolean skipUserDependent) { + migrateRealm(realm); + + } + @Override public ModelVersion getVersion() { return VERSION; diff --git a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo3_2_0.java b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo3_2_0.java index 98686af7a0..b2935a1469 100644 --- a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo3_2_0.java +++ b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo3_2_0.java @@ -28,6 +28,7 @@ import org.keycloak.models.KeycloakSession; import org.keycloak.models.PasswordPolicy; import org.keycloak.models.RealmModel; import org.keycloak.models.utils.DefaultAuthenticationFlows; +import org.keycloak.representations.idm.RealmRepresentation; public class MigrateTo3_2_0 implements Migration { @@ -36,41 +37,55 @@ public class MigrateTo3_2_0 implements Migration { @Override public void migrate(KeycloakSession session) { for (RealmModel realm : session.realms().getRealms()) { - PasswordPolicy.Builder builder = realm.getPasswordPolicy().toBuilder(); - if (!builder.contains(PasswordPolicy.HASH_ALGORITHM_ID) && "20000".equals(builder.get(PasswordPolicy.HASH_ITERATIONS_ID))) { - realm.setPasswordPolicy(builder.remove(PasswordPolicy.HASH_ITERATIONS_ID).build(session)); - } + migrateRealm(session, realm); - if (realm.getDockerAuthenticationFlow() == null) { - DefaultAuthenticationFlows.dockerAuthenticationFlow(realm); - } + } + } - ClientModel realmAccess = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID); - if (realmAccess != null) { - addRoles(realmAccess); - } - ClientModel masterAdminClient = realm.getMasterAdminClient(); - if (masterAdminClient != null) { - addRoles(masterAdminClient); + @Override + public void migrateImport(KeycloakSession session, RealmModel realm, RealmRepresentation rep, boolean skipUserDependent) { + migrateRealm(session, realm); + } - } + protected void migrateRealm(KeycloakSession session, RealmModel realm) { + PasswordPolicy.Builder builder = realm.getPasswordPolicy().toBuilder(); + if (!builder.contains(PasswordPolicy.HASH_ALGORITHM_ID) && "20000".equals(builder.get(PasswordPolicy.HASH_ITERATIONS_ID))) { + realm.setPasswordPolicy(builder.remove(PasswordPolicy.HASH_ITERATIONS_ID).build(session)); + } + + if (realm.getDockerAuthenticationFlow() == null) { + DefaultAuthenticationFlows.dockerAuthenticationFlow(realm); + } + + ClientModel realmAccess = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID); + if (realmAccess != null) { + addRoles(realmAccess); + } + ClientModel masterAdminClient = realm.getMasterAdminClient(); + if (masterAdminClient != null) { + addRoles(masterAdminClient); } } public void addRoles(ClientModel realmAccess) { - RoleModel queryClients = realmAccess.addRole(AdminRoles.QUERY_CLIENTS); - RoleModel queryUsers = realmAccess.addRole(AdminRoles.QUERY_USERS); - RoleModel queryGroups = realmAccess.addRole(AdminRoles.QUERY_GROUPS); - - RoleModel viewClients = realmAccess.getRole(AdminRoles.VIEW_CLIENTS); - if (viewClients != null) { - viewClients.addCompositeRole(queryClients); + RoleModel queryClients = realmAccess.getRole(AdminRoles.QUERY_CLIENTS); + if (queryClients == null) { + queryClients = realmAccess.addRole(AdminRoles.QUERY_CLIENTS); + RoleModel viewClients = realmAccess.getRole(AdminRoles.VIEW_CLIENTS); + if (viewClients != null) { + viewClients.addCompositeRole(queryClients); + } } + RoleModel queryUsers = realmAccess.getRole(AdminRoles.QUERY_USERS); + if (queryUsers == null) queryUsers = realmAccess.addRole(AdminRoles.QUERY_USERS); + RoleModel queryGroups = realmAccess.getRole(AdminRoles.QUERY_GROUPS); + if (queryGroups == null) queryGroups = realmAccess.addRole(AdminRoles.QUERY_GROUPS); + RoleModel viewUsers = realmAccess.getRole(AdminRoles.VIEW_USERS); if (viewUsers != null) { - viewUsers.addCompositeRole(queryUsers); - viewUsers.addCompositeRole(queryGroups); + if (!viewUsers.hasRole(queryUsers)) viewUsers.addCompositeRole(queryUsers); + if (!viewUsers.hasRole(queryGroups)) viewUsers.addCompositeRole(queryGroups); } } diff --git a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo3_4_0.java b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo3_4_0.java index 53e152f3e0..8e6c13316c 100644 --- a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo3_4_0.java +++ b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo3_4_0.java @@ -17,9 +17,12 @@ package org.keycloak.migration.migrators; +import org.keycloak.keys.KeyProvider; import org.keycloak.migration.ModelVersion; import org.keycloak.models.KeycloakSession; +import org.keycloak.models.RealmModel; import org.keycloak.models.utils.DefaultKeyProviders; +import org.keycloak.representations.idm.RealmRepresentation; import java.util.Collections; import java.util.HashMap; @@ -36,19 +39,29 @@ public class MigrateTo3_4_0 implements Migration { public void migrate(KeycloakSession session) { session.realms().getRealms().stream().forEach( r -> { - DefaultKeyProviders.createAesProvider(r); - Map securityHeaders = r.getBrowserSecurityHeaders(); - if (securityHeaders != null) { - - Map browserSecurityHeaders = new HashMap<>(securityHeaders); - browserSecurityHeaders.put("strictTransportSecurity", "max-age=31536000; includeSubDomains"); - - r.setBrowserSecurityHeaders(Collections.unmodifiableMap(browserSecurityHeaders)); - } + migrateRealm(r); } ); } + @Override + public void migrateImport(KeycloakSession session, RealmModel realm, RealmRepresentation rep, boolean skipUserDependent) { + migrateRealm(realm); + + } + + protected void migrateRealm(RealmModel r) { + DefaultKeyProviders.createAesProvider(r); + Map securityHeaders = r.getBrowserSecurityHeaders(); + if (securityHeaders != null) { + + Map browserSecurityHeaders = new HashMap<>(securityHeaders); + browserSecurityHeaders.put("strictTransportSecurity", "max-age=31536000; includeSubDomains"); + + r.setBrowserSecurityHeaders(Collections.unmodifiableMap(browserSecurityHeaders)); + } + } + @Override public ModelVersion getVersion() { return VERSION; diff --git a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo3_4_1.java b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo3_4_1.java index 5df34f6ed7..c855643b2f 100644 --- a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo3_4_1.java +++ b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo3_4_1.java @@ -21,6 +21,7 @@ package org.keycloak.migration.migrators; import org.keycloak.migration.ModelVersion; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; +import org.keycloak.representations.idm.RealmRepresentation; import java.util.Collections; import java.util.HashMap; @@ -38,16 +39,25 @@ public class MigrateTo3_4_1 implements Migration { public void migrate(KeycloakSession session) { session.realms().getRealms().stream().forEach( r -> { - Map securityHeaders = new HashMap<>(r.getBrowserSecurityHeaders()); - securityHeaders.entrySet().stream() - .filter(Objects::nonNull) - .filter(entry -> entry.getValue().equals("frame-src 'self'")) - .forEach(entry -> entry.setValue("frame-src 'self'; frame-ancestors 'self'; object-src 'none';")); - r.setBrowserSecurityHeaders(Collections.unmodifiableMap(securityHeaders)); + migrateRealm(r); } ); } + @Override + public void migrateImport(KeycloakSession session, RealmModel realm, RealmRepresentation rep, boolean skipUserDependent) { + migrateRealm(realm); + } + + protected void migrateRealm(RealmModel r) { + Map securityHeaders = new HashMap<>(r.getBrowserSecurityHeaders()); + securityHeaders.entrySet().stream() + .filter(Objects::nonNull) + .filter(entry -> entry.getValue().equals("frame-src 'self'")) + .forEach(entry -> entry.setValue("frame-src 'self'; frame-ancestors 'self'; object-src 'none';")); + r.setBrowserSecurityHeaders(Collections.unmodifiableMap(securityHeaders)); + } + @Override public ModelVersion getVersion() { return VERSION; diff --git a/server-spi-private/src/main/java/org/keycloak/migration/migrators/Migration.java b/server-spi-private/src/main/java/org/keycloak/migration/migrators/Migration.java index e37dad29f9..c92dbbcfd3 100644 --- a/server-spi-private/src/main/java/org/keycloak/migration/migrators/Migration.java +++ b/server-spi-private/src/main/java/org/keycloak/migration/migrators/Migration.java @@ -19,6 +19,8 @@ package org.keycloak.migration.migrators; import org.keycloak.migration.ModelVersion; import org.keycloak.models.KeycloakSession; +import org.keycloak.models.RealmModel; +import org.keycloak.representations.idm.RealmRepresentation; /** * @author Stian Thorgersen @@ -27,6 +29,22 @@ public interface Migration { void migrate(KeycloakSession session); + /** + * Called after full import of representation. + * + * Implementations of this method should try not make assumptions about what was imported from the representations. + * We have no idea what the user will do to an exported json file. + * + * @param session + * @param realm + * @param rep + * @param skipUserDependent + */ + default + void migrateImport(KeycloakSession session, RealmModel realm, RealmRepresentation rep, boolean skipUserDependent) { + + } + ModelVersion getVersion(); } diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/DefaultKeyProviders.java b/server-spi-private/src/main/java/org/keycloak/models/utils/DefaultKeyProviders.java index fbc01ed27d..288f9e19a2 100644 --- a/server-spi-private/src/main/java/org/keycloak/models/utils/DefaultKeyProviders.java +++ b/server-spi-private/src/main/java/org/keycloak/models/utils/DefaultKeyProviders.java @@ -22,29 +22,34 @@ import org.keycloak.component.ComponentModel; import org.keycloak.keys.KeyProvider; import org.keycloak.models.RealmModel; +import java.util.List; + /** * @author Stian Thorgersen */ public class DefaultKeyProviders { public static void createProviders(RealmModel realm) { - ComponentModel generated = new ComponentModel(); - generated.setName("rsa-generated"); - generated.setParentId(realm.getId()); - generated.setProviderId("rsa-generated"); - generated.setProviderType(KeyProvider.class.getName()); + if (!hasProvider(realm, "rsa-generated")) { + ComponentModel generated = new ComponentModel(); + generated.setName("rsa-generated"); + generated.setParentId(realm.getId()); + generated.setProviderId("rsa-generated"); + generated.setProviderType(KeyProvider.class.getName()); - MultivaluedHashMap config = new MultivaluedHashMap<>(); - config.putSingle("priority", "100"); - generated.setConfig(config); + MultivaluedHashMap config = new MultivaluedHashMap<>(); + config.putSingle("priority", "100"); + generated.setConfig(config); - realm.addComponentModel(generated); + realm.addComponentModel(generated); + } createSecretProvider(realm); createAesProvider(realm); } public static void createSecretProvider(RealmModel realm) { + if (hasProvider(realm, "hmac-generated")) return; ComponentModel generated = new ComponentModel(); generated.setName("hmac-generated"); generated.setParentId(realm.getId()); @@ -59,6 +64,7 @@ public class DefaultKeyProviders { } public static void createAesProvider(RealmModel realm) { + if (hasProvider(realm, "aes-generated")) return; ComponentModel generated = new ComponentModel(); generated.setName("aes-generated"); generated.setParentId(realm.getId()); @@ -72,22 +78,34 @@ public class DefaultKeyProviders { realm.addComponentModel(generated); } - public static void createProviders(RealmModel realm, String privateKeyPem, String certificatePem) { - ComponentModel rsa = new ComponentModel(); - rsa.setName("rsa"); - rsa.setParentId(realm.getId()); - rsa.setProviderId("rsa"); - rsa.setProviderType(KeyProvider.class.getName()); - - MultivaluedHashMap config = new MultivaluedHashMap<>(); - config.putSingle("priority", "100"); - config.putSingle("privateKey", privateKeyPem); - if (certificatePem != null) { - config.putSingle("certificate", certificatePem); + protected static boolean hasProvider(RealmModel realm, String providerId) { + List currentComponents = realm.getComponents(realm.getId(), KeyProvider.class.getName()); + for (ComponentModel current : currentComponents) { + if (current.getProviderId().equals(providerId)) { + return true; + } } - rsa.setConfig(config); + return false; + } - realm.addComponentModel(rsa); + public static void createProviders(RealmModel realm, String privateKeyPem, String certificatePem) { + if (!hasProvider(realm, "rsa")) { + ComponentModel rsa = new ComponentModel(); + rsa.setName("rsa"); + rsa.setParentId(realm.getId()); + rsa.setProviderId("rsa"); + rsa.setProviderType(KeyProvider.class.getName()); + + MultivaluedHashMap config = new MultivaluedHashMap<>(); + config.putSingle("priority", "100"); + config.putSingle("privateKey", privateKeyPem); + if (certificatePem != null) { + config.putSingle("certificate", certificatePem); + } + rsa.setConfig(config); + + realm.addComponentModel(rsa); + } createSecretProvider(realm); createAesProvider(realm); 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 bab044077d..e3643bb910 100755 --- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java +++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java @@ -18,6 +18,7 @@ package org.keycloak.services.managers; import org.keycloak.Config; import org.keycloak.common.enums.SslRequired; +import org.keycloak.migration.MigrationModelManager; import org.keycloak.models.AccountRoles; import org.keycloak.models.AdminRoles; import org.keycloak.models.BrowserSecurityHeaders; @@ -534,6 +535,10 @@ public class RealmManager { setupAuthorizationServices(realm); setupClientRegistrations(realm); + if (rep.getKeycloakVersion() != null) { + MigrationModelManager.migrateImport(session, realm, rep, skipUserDependent); + } + fireRealmPostCreate(realm); return realm; diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/AbstractJsonFileImportMigrationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/AbstractJsonFileImportMigrationTest.java new file mode 100644 index 0000000000..1376a47a03 --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/AbstractJsonFileImportMigrationTest.java @@ -0,0 +1,65 @@ +/* + * Copyright 2016 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.testsuite.migration; + +import org.junit.Before; +import org.keycloak.representations.idm.ClientRepresentation; +import org.keycloak.representations.idm.GroupRepresentation; +import org.keycloak.representations.idm.RealmRepresentation; +import org.keycloak.representations.idm.RoleRepresentation; +import org.keycloak.representations.idm.UserRepresentation; + +import static org.keycloak.testsuite.auth.page.AuthRealm.MASTER; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public abstract class AbstractJsonFileImportMigrationTest extends AbstractMigrationTest { + protected RealmRepresentation masterRep; + + @Before + public void beforeMigrationTest() { + migrationRealm = adminClient.realms().realm(MIGRATION); + migrationRealm2 = adminClient.realms().realm(MIGRATION2); + migrationRealm3 = adminClient.realms().realm("authorization"); + masterRealm = adminClient.realms().realm(MASTER); + + + + // hack to reuse AbstractMigrationTest + RoleRepresentation newRole = new RoleRepresentation(); + newRole.setName("master-test-realm-role"); + + masterRealm.roles().create(newRole); + ClientRepresentation newClient = new ClientRepresentation(); + newClient.setClientId("master-test-client"); + masterRealm.clients().create(newClient); + newClient = masterRealm.clients().findByClientId("master-test-client").get(0); + newRole.setName("master-test-client-role"); + masterRealm.clients().get(newClient.getId()).roles().create(newRole); + + for (GroupRepresentation group : masterRep.getGroups()) { + group.setId(null); + masterRealm.groups().add(group); + } + for (UserRepresentation user : masterRep.getUsers()) { + user.setId(null); + if (!user.getUsername().equals("admin")) masterRealm.users().create(user); + } + } +} 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 new file mode 100644 index 0000000000..47de4846af --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/AbstractMigrationTest.java @@ -0,0 +1,422 @@ +/* + * Copyright 2016 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.testsuite.migration; + +import org.keycloak.admin.client.resource.ClientResource; +import org.keycloak.admin.client.resource.RealmResource; +import org.keycloak.admin.client.resource.RoleResource; +import org.keycloak.common.constants.KerberosConstants; +import org.keycloak.component.PrioritizedComponentModel; +import org.keycloak.keys.KeyProvider; +import org.keycloak.models.AdminRoles; +import org.keycloak.models.AuthenticationExecutionModel; +import org.keycloak.models.Constants; +import org.keycloak.models.LDAPConstants; +import org.keycloak.models.UserModel; +import org.keycloak.models.utils.DefaultAuthenticationFlows; +import org.keycloak.representations.AccessToken; +import org.keycloak.representations.idm.AuthenticationExecutionExportRepresentation; +import org.keycloak.representations.idm.AuthenticationFlowRepresentation; +import org.keycloak.representations.idm.ClientRepresentation; +import org.keycloak.representations.idm.ClientTemplateRepresentation; +import org.keycloak.representations.idm.ComponentRepresentation; +import org.keycloak.representations.idm.ProtocolMapperRepresentation; +import org.keycloak.representations.idm.RealmRepresentation; +import org.keycloak.representations.idm.RequiredActionProviderRepresentation; +import org.keycloak.representations.idm.RoleRepresentation; +import org.keycloak.representations.idm.authorization.PolicyRepresentation; +import org.keycloak.storage.UserStorageProvider; +import org.keycloak.testsuite.AbstractKeycloakTest; +import org.keycloak.testsuite.Assert; +import org.keycloak.testsuite.runonserver.RunHelpers; +import org.keycloak.testsuite.util.OAuthClient; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.keycloak.models.AccountRoles.MANAGE_ACCOUNT; +import static org.keycloak.models.AccountRoles.MANAGE_ACCOUNT_LINKS; +import static org.keycloak.models.Constants.ACCOUNT_MANAGEMENT_CLIENT_ID; +import static org.keycloak.testsuite.Assert.assertNames; +import static org.keycloak.testsuite.auth.page.AuthRealm.MASTER; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public abstract class AbstractMigrationTest extends AbstractKeycloakTest { + public static final String MIGRATION = "Migration"; + public static final String MIGRATION2 = "Migration2"; + protected RealmResource migrationRealm; + protected RealmResource migrationRealm2; + protected RealmResource migrationRealm3; + protected RealmResource masterRealm; + + protected void testMigratedData() { + log.info("testing migrated data"); + //master realm + assertNames(masterRealm.roles().list(), "offline_access", "uma_authorization", "create-realm", "master-test-realm-role", "admin"); + assertNames(masterRealm.clients().findAll(), "admin-cli", "security-admin-console", "broker", "account", + "master-realm", "master-test-client", "Migration-realm", "Migration2-realm"); + String id = masterRealm.clients().findByClientId("master-test-client").get(0).getId(); + assertNames(masterRealm.clients().get(id).roles().list(), "master-test-client-role"); + assertNames(masterRealm.users().search("", 0, 5), "admin", "master-test-user"); + assertNames(masterRealm.groups().groups(), "master-test-group"); + //migrationRealm + assertNames(migrationRealm.roles().list(), "offline_access", "uma_authorization", "migration-test-realm-role"); + assertNames(migrationRealm.clients().findAll(), "account", "admin-cli", "broker", "migration-test-client", "realm-management", "security-admin-console"); + String id2 = migrationRealm.clients().findByClientId("migration-test-client").get(0).getId(); + assertNames(migrationRealm.clients().get(id2).roles().list(), "migration-test-client-role"); + assertNames(migrationRealm.users().search("", 0, 5), "migration-test-user"); + assertNames(migrationRealm.groups().groups(), "migration-test-group"); + } + + /** + * @see org.keycloak.migration.migrators.MigrateTo2_0_0 + */ + protected void testMigrationTo2_0_0() { + testAuthorizationServices(masterRealm, migrationRealm); + } + + /** + * @see org.keycloak.migration.migrators.MigrateTo2_1_0 + */ + protected void testMigrationTo2_1_0() { + testNameOfOTPRequiredAction(masterRealm, migrationRealm); + } + + /** + * @see org.keycloak.migration.migrators.MigrateTo2_2_0 + */ + protected void testMigrationTo2_2_0() { + testIdentityProviderAuthenticator(masterRealm, migrationRealm); + //MigrateTo2_2_0#migrateRolePolicies is not relevant any more + } + + /** + * @see org.keycloak.migration.migrators.MigrateTo2_3_0 + */ + protected void testMigrationTo2_3_0() { + testUpdateProtocolMappers(masterRealm, migrationRealm); + testExtractRealmKeysMasterRealm(masterRealm); + testExtractRealmKeysMigrationRealm(migrationRealm); + } + + /** + * @see org.keycloak.migration.migrators.MigrateTo2_5_0 + */ + protected void testMigrationTo2_5_0() { + testLdapKerberosMigration_2_5_0(); + //https://github.com/keycloak/keycloak/pull/3630 + testDuplicateEmailSupport(masterRealm, migrationRealm); + } + + protected void testMigrationTo2_5_1() throws Exception { + testOfflineTokenLogin(); + } + + /** + * @see org.keycloak.migration.migrators.MigrateTo3_0_0 + */ + protected void testMigrationTo3_0_0() { + testRoleManageAccountLinks(masterRealm, migrationRealm); + } + + protected void testMigrationTo3_2_0() { + assertNull(masterRealm.toRepresentation().getPasswordPolicy()); + assertNull(migrationRealm.toRepresentation().getPasswordPolicy()); + + testDockerAuthenticationFlow(masterRealm, migrationRealm); + } + + protected void testMigrationTo3_4_0() { + Map securityHeaders = masterRealm.toRepresentation().getBrowserSecurityHeaders(); + if (securityHeaders != null) { + assertEquals("max-age=31536000; includeSubDomains", + securityHeaders.get("strictTransportSecurity")); + } else { + fail("Browser security headers not found"); + } + } + + protected void testMigrationTo3_4_1() { + Map securityHeaders = masterRealm.toRepresentation().getBrowserSecurityHeaders(); + if (securityHeaders != null) { + assertEquals("frame-src 'self'; frame-ancestors 'self'; object-src 'none';", + securityHeaders.get("contentSecurityPolicy")); + } else { + fail("Browser security headers not found"); + } + } + + protected void testDockerAuthenticationFlow(RealmResource... realms) { + for (RealmResource realm : realms) { + AuthenticationFlowRepresentation flow = null; + for (AuthenticationFlowRepresentation f : realm.flows().getFlows()) { + if (DefaultAuthenticationFlows.DOCKER_AUTH.equals(f.getAlias())) { + flow = f; + } + } + assertNotNull(flow); + } + } + + protected void testRoleManageAccountLinks(RealmResource... realms) { + log.info("testing role manage account links"); + for (RealmResource realm : realms) { + List clients = realm.clients().findByClientId(ACCOUNT_MANAGEMENT_CLIENT_ID); + if (!clients.isEmpty()) { + String accountClientId = clients.get(0).getId(); + ClientResource accountClient = realm.clients().get(accountClientId); + accountClient.roles().get(MANAGE_ACCOUNT_LINKS).toRepresentation(); //the role should be presented, it'll throw javax.ws.rs.NotFoundException in case the role is not found + + Set roleComposites = accountClient.roles().get(MANAGE_ACCOUNT).getRoleComposites(); + boolean success = false; + for (RoleRepresentation roleComposite : roleComposites) { + if (roleComposite.getName().equals(MANAGE_ACCOUNT_LINKS)) { + success = true; + } + } + if (!success) { + fail("'manage-account' role of client 'account' should have composite role 'manage-account-links'."); + } + } + } + } + + protected void testExtractRealmKeysMasterRealm(RealmResource masterRealm) { + log.info("testing extract realm keys"); + String expectedMasterRealmKey = "MIIEowIBAAKCAQEAiU54OXoCbHy0L0gHn1yasctcnKHRU1pHFIJnWvaI7rClJydet9dDJaiYXOxMKseiBm3eYznfN3cPyU8udYmRnMuKjiocZ77LT2IEttAjXb6Ggazx7loriFHRy0IOJeX4KxXhAPWmxqa3mkFNfLBEvFqVaBgUDHQ60cmnPvNSHYudBTW9K80s8nvmP2pso7HTwWJ1+Xatj1Ey/gTmB3CXlyqBegGWC9TeuErEYpYhdh+11TVWasgMBZyUCtL3NRPaBuhaPg1LpW8lWGk05nS+YM6dvTk3Mppv+z2RygEpxyO09oT3b4G+Zfwit1STqn0AvDTGzINdoKcNtFScV0j8TwIDAQABAoIBAHcbPKsPLZ8SJfOF1iblW8OzFulAbaaSf2pJHIMJrQrw7LKkMkPjVXoLX+/rgr7xYZmWIP2OLBWfEHCeYTzQUyHiZpSf7vgHx7Fa45/5uVQOe/ttHIiYa37bCtP4vvEdJkOpvP7qGPvljwsebqsk9Ns28LfVez66bHOjK5Mt2yOIulbTeEs7ch//h39YwKJv96vc+CHbV2O6qoOxZessO6y+287cOBvbFXmS2GaGle5Nx/EwncBNS4b7czoetmm70+9ht3yX+kxaP311YUT31KQjuaJt275kOiKsrXr27PvgO++bsIyGuSzqyS7G7fmxF2zUyphEqEpalyDGMKMnrAECgYEA1fCgFox03rPDjm0MhW/ThoS2Ld27sbWQ6reS+PBMdUTJZVZIU1D2//h6VXDnlddhk6avKjA4smdy1aDKzmjz3pt9AKn+kgkXqtTC2fD3wp+fC9hND0z+rQPGe/Gk7ZUnTdsqnfyowxr+woIgzdnRukOUrG+xQiP3RUUT7tt6NQECgYEApEz2xvgqMm+9/f/YxjLdsFUfLqc4WlafB863stYEVqlCYy5ujyo0VQ0ahKSKJkLDnf52+aMUqPOpwaGePpu3O6VkvpcKfPY2MUlZW7/6Sa9et9hxNkdTS7Gui2d1ELpaCBe1Bc62sk8EA01iHXE1PpvyUqDWrhNh+NrDICA9oU8CgYBgGDYACtTP11TmW2r9YK5VRLUDww30k4ZlN1GnyV++aMhBYVEZQ0u+y+A/EnijIFwu0vbo70H4OGknNZMCxbeMbLDoJHM5KyZbUDe5ZvgSjloFGwH59m6KTiDQOUkIgi9mVCQ/VGaFRFHcElEjxUvj60kTbxPijn8ZuR5r8l9hAQKBgQCQ9jL5pHWeoIayN20smi6M6N2lTPbkhe60dcgQatHTIG2pkosLl8IqlHAkPgSB84AiwyR351JQKwRJCm7TcJI/dxMnMZ6YWKfB3qSP1hdfsfJRJQ/mQxIUBAYrizF3e+P5peka4aLCOgMhYsJBlePThMZN7wja99EGPwXQL4IQ8wKBgB8Nis1lQK6Z30GCp9u4dYleGfEP71Lwqvk/eJb89/uz0fjF9CTpJMULFc+nA5u4yHP3LFnRg3zCU6aEwfwUyk4GH9lWGV/qIAisQtgrCEraVe4qxz0DVE59C7qjO26IhU2U66TEzPAqvQ3zqey+woDn/cz/JMWK1vpcSk+TKn3K"; + List components = masterRealm.components().query(MASTER, KeyProvider.class.getName()); + assertEquals(3, components.size()); + + components = masterRealm.components().query(MASTER, KeyProvider.class.getName(), "rsa"); + assertEquals(1, components.size()); + + ComponentRepresentation component = testingClient.server(MASTER).fetch(RunHelpers.internalComponent(components.get(0).getId())); + assertEquals(expectedMasterRealmKey, component.getConfig().getFirst("privateKey")); + + components = masterRealm.components().query(MASTER, KeyProvider.class.getName(), "hmac-generated"); + assertEquals(1, components.size()); + + } + + protected void testExtractRealmKeysMigrationRealm(RealmResource migrationRealm) { + log.info("testing extract realm keys"); + String expectedMigrationRealmKey = "MIIEpAIBAAKCAQEApt6gCllWkVTZ7fy/oRIx6Bxjt9x3eKKyKGFXvN4iaafrNqpYU9lcqPngWJ9DyXGqUf8RpjPaQWiLWLxjw3xGBqLk2E1/Frb9e/dy8rj//fHGq6bujN1iguzyFwxPGT5Asd7jflRI3qU04M8JE52PArqPhGL2Fn+FiSK5SWRIGm+hVL7Ck/E/tVxM25sFG1/UTQqvrROm4q76TmP8FsyZaTLVf7cCwW2QPIX0N5HTVb3QbBb5KIsk4kKmk/g7uUxS9r42tu533LISzRr5CTyWZAL2XFRuF2RrKdE8gwqkEubw6sDmB2mE0EoPdY1DUhBQgVP/5rwJrCtTsUBR2xdEYQIDAQABAoIBAFbbsNBSOlZBpYJUOmcb8nBQPrOYhXN8tGGCccn0klMOvcdhmcJjdPDbyCQ5Gm7DxJUTwNsTSHsdcNMKlJ9Pk5+msJnKlOl87KrXXbTsCQvlCrWUmb0nCzz9GvJWTOHl3oT3cND0DE4gDksqWR4luCgCdevCGzgQvrBoK6wBD+r578uEW3iw10hnJ0+wnGiw8IvPzE1a9xbY4HD8/QrYdaLxuLb/aC1PDuzrz0cOjnvPkrws5JrbUSnbFygJiOv1z4l2Q00uGIxlHtXdwQBnTZZjVi4vOec2BYSHffgwDYEZIglw1mnrV7y0N1nnPbtJK/cegIkXoBQHXm8Q99TrWMUCgYEA9au86qcwrXZZg5H4BpR5cpy0MSkcKDbA1aRL1cAyTCqJxsczlAtLhFADF+NhnlXj4y7gwDEYWrz064nF73I+ZGicvCiyOy+tCTugTyTGS+XR948ElDMS6PCUUXsotS3dKa0b3c9wd2mxeddTjq/ArfgEVZJ6fE1KtjLt9dtfA+8CgYEAreK3JsvjR5b/Xct28TghYUU7Qnasombb/shqqy8FOMjYUr5OUm/OjNIgoCqhOlE8oQDJ4dOZofNSa7tL+oM8Gmbal+E3fRzxnx/9/EC4QV6sVaPLTIyk7EPfKTcZuzH7+BNZtAziTxJw9d6YJQRbkpg92EZIEoR8iDj2Xs5xrK8CgYEAwMVWwwYX8zT3vn7ukTM2LRH7bsvkVUXJgJqgCwT6Mrv6SmkK9vL5+cPS+Y6pjdW1sRGauBSOGL1Grf/4ug/6F03jFt4UJM8fRyxreU7Q7sNSQ6AMpsGA6BnHODycz7ZCYa59PErG5FyiL4of/cm5Nolz1TXQOPNpWZiTEqVlZC8CgYA4YPbjVF4nuxSnU64H/hwMjsbtAM9uhI016cN0J3W4+J3zDhMU9X1x+Tts0wWdg/N1fGz4lIQOl3cUyRCUc/KL2OdtMS+tmDHbVyMho9ZaE5kq10W2Vy+uDz+O/HeSU12QDK4cC8Vgv+jyPy7zaZtLR6NduUPrBRvfiyCOkr8WrwKBgQCY0h4RCdNFhr0KKLLmJipAtV8wBCGcg1jY1KoWKQswbcykfBKwHbF6EooVqkRW0ITjWB7ZZCf8TnSUxe0NXCUAkVBrhzS4DScgtoSZYOOUaSHgOxpfwgnQ3oYotKi98Yg3IsaLs1j4RuPG5Sp1z6o+ELP1uvr8azyn9YlLa+523Q=="; + + List components = migrationRealm.components().query(MIGRATION, KeyProvider.class.getName()); + assertEquals(3, components.size()); + + components = migrationRealm.components().query(MIGRATION, KeyProvider.class.getName(), "rsa"); + assertEquals(1, components.size()); + + ComponentRepresentation component = testingClient.server(MIGRATION).fetch(RunHelpers.internalComponent(components.get(0).getId())); + assertEquals(expectedMigrationRealmKey, component.getConfig().getFirst("privateKey")); + + components = migrationRealm.components().query(MIGRATION, KeyProvider.class.getName(), "hmac-generated"); + assertEquals(1, components.size()); + } + + protected void testLdapKerberosMigration_2_5_0() { + log.info("testing ldap kerberos migration"); + RealmRepresentation realmRep = migrationRealm2.toRepresentation(); + List components = migrationRealm2.components().query(realmRep.getId(), UserStorageProvider.class.getName()); + assertEquals(2, components.size()); + boolean testedLdap = false; + boolean testedKerberos = false; + + for (ComponentRepresentation component : components) { + if (component.getName().equals("ldap-provider")) { + assertEquals("2", component.getConfig().getFirst(PrioritizedComponentModel.PRIORITY)); + assertEquals("READ_ONLY", component.getConfig().getFirst(LDAPConstants.EDIT_MODE)); + assertEquals("true", component.getConfig().getFirst(LDAPConstants.SYNC_REGISTRATIONS)); + assertEquals(LDAPConstants.VENDOR_RHDS, component.getConfig().getFirst(LDAPConstants.VENDOR)); + assertEquals("uid", component.getConfig().getFirst(LDAPConstants.USERNAME_LDAP_ATTRIBUTE)); + assertEquals("uid", component.getConfig().getFirst(LDAPConstants.RDN_LDAP_ATTRIBUTE)); + assertEquals("nsuniqueid", component.getConfig().getFirst(LDAPConstants.UUID_LDAP_ATTRIBUTE)); + assertEquals("inetOrgPerson, organizationalPerson", component.getConfig().getFirst(LDAPConstants.USER_OBJECT_CLASSES)); + assertEquals("http://localhost", component.getConfig().getFirst(LDAPConstants.CONNECTION_URL)); + assertEquals("dn", component.getConfig().getFirst(LDAPConstants.USERS_DN)); + assertEquals(LDAPConstants.AUTH_TYPE_NONE, component.getConfig().getFirst(LDAPConstants.AUTH_TYPE)); + assertEquals("true", component.getConfig().getFirst(KerberosConstants.ALLOW_KERBEROS_AUTHENTICATION)); + assertEquals("realm", component.getConfig().getFirst(KerberosConstants.KERBEROS_REALM)); + assertEquals("principal", component.getConfig().getFirst(KerberosConstants.SERVER_PRINCIPAL)); + assertEquals("keytab", component.getConfig().getFirst(KerberosConstants.KEYTAB)); + testedLdap = true; + } else if (component.getName().equals("kerberos-provider")) { + assertEquals("3", component.getConfig().getFirst(PrioritizedComponentModel.PRIORITY)); + assertEquals("realm", component.getConfig().getFirst(KerberosConstants.KERBEROS_REALM)); + assertEquals("principal", component.getConfig().getFirst(KerberosConstants.SERVER_PRINCIPAL)); + assertEquals("keytab", component.getConfig().getFirst(KerberosConstants.KEYTAB)); + } + } + } + + protected void testDroolsToRulesPolicyTypeMigration() { + log.info("testing drools to rules in authorization services"); + List client = migrationRealm3.clients().findByClientId("photoz-restful-api"); + + assertEquals(1, client.size()); + + ClientRepresentation representation = client.get(0); + + List policies = migrationRealm3.clients().get(representation.getId()).authorization().policies().policies(); + + List migratedRulesPolicies = policies.stream().filter(policyRepresentation -> "rules".equals(policyRepresentation.getType())).collect(Collectors.toList()); + + assertEquals(1, migratedRulesPolicies.size()); + } + + protected void testAuthorizationServices(RealmResource... realms) { + log.info("testing authorization services"); + for (RealmResource realm : realms) { + //test setup of authorization services + for (String roleName : Constants.AUTHZ_DEFAULT_AUTHORIZATION_ROLES) { + RoleResource role = realm.roles().get(roleName); //throws javax.ws.rs.NotFoundException if not found + + assertFalse("Role's scopeParamRequired should be false.", role.toRepresentation().isScopeParamRequired()); + assertFalse("Role shouldn't be composite should be false.", role.toRepresentation().isComposite()); + + assertTrue("role should be added to default roles for new users", realm.toRepresentation().getDefaultRoles().contains(roleName)); + } + //test admin roles - master admin client + List clients = realm.clients().findByClientId(realm.toRepresentation().getRealm() + "-realm"); + if (!clients.isEmpty()) { + ClientResource masterAdminClient = realm.clients().get(clients.get(0).getId()); + masterAdminClient.roles().get(AdminRoles.VIEW_AUTHORIZATION).toRepresentation(); + masterAdminClient.roles().get(AdminRoles.MANAGE_AUTHORIZATION).toRepresentation(); + //test admin roles - admin role composite + Set roleNames = new HashSet<>(); + for (RoleRepresentation role : realm.roles().get(AdminRoles.ADMIN).getRoleComposites()) { + roleNames.add(role.getName()); + } + assertTrue(AdminRoles.VIEW_AUTHORIZATION + " should be composite role of " + AdminRoles.ADMIN, roleNames.contains(AdminRoles.VIEW_AUTHORIZATION)); + assertTrue(AdminRoles.MANAGE_AUTHORIZATION + " should be composite role of " + AdminRoles.ADMIN, roleNames.contains(AdminRoles.MANAGE_AUTHORIZATION)); + } + } + } + + protected void testNameOfOTPRequiredAction(RealmResource... realms) { + log.info("testing OTP Required Action"); + for (RealmResource realm : realms) { + RequiredActionProviderRepresentation otpAction = realm.flows().getRequiredAction(UserModel.RequiredAction.CONFIGURE_TOTP.name()); + + assertEquals("The name of CONFIGURE_TOTP required action should be 'Configure OTP'.", "Configure OTP", otpAction.getName()); + } + } + + protected void testIdentityProviderAuthenticator(RealmResource... realms) { + log.info("testing identity provider authenticator"); + for (RealmResource realm : realms) { + boolean success = false; + for (AuthenticationFlowRepresentation flow : realm.flows().getFlows()) { + if (flow.getAlias().equals(DefaultAuthenticationFlows.BROWSER_FLOW)) { + for (AuthenticationExecutionExportRepresentation execution : flow.getAuthenticationExecutions()) { + if ("identity-provider-redirector".equals(execution.getAuthenticator())) { + assertEquals("Requirement should be ALTERNATIVE.", AuthenticationExecutionModel.Requirement.ALTERNATIVE.name(), execution.getRequirement()); + assertTrue("Priority should be 25.", execution.getPriority() == 25); + success = true; + } + } + } + } + if (!success) { + fail("BROWSER_FLOW should contain execution: 'identity-provider-redirector' authenticator."); + } + } + } + + protected void testUpdateProtocolMappers(RealmResource... realms) { + log.info("testing updated protocol mappers"); + for (RealmResource realm : realms) { + for (ClientRepresentation client : realm.clients().findAll()) { + for (ProtocolMapperRepresentation protocolMapper : client.getProtocolMappers()) { + testUpdateProtocolMapper(protocolMapper); + } + } + for (ClientTemplateRepresentation clientTemlate : realm.clientTemplates().findAll()) { + for (ProtocolMapperRepresentation protocolMapper : clientTemlate.getProtocolMappers()) { + testUpdateProtocolMapper(protocolMapper); + } + } + } + } + + protected void testUpdateProtocolMapper(ProtocolMapperRepresentation protocolMapper) { + if (protocolMapper.getConfig().get("id.token.claim") != null) { + assertEquals("ProtocolMapper's config should contain key 'userinfo.token.claim'.", + protocolMapper.getConfig().get("id.token.claim"), protocolMapper.getConfig().get("userinfo.token.claim")); + } + } + + protected void testDuplicateEmailSupport(RealmResource... realms) { + log.info("testing duplicate email"); + for (RealmResource realm : realms) { + RealmRepresentation rep = realm.toRepresentation(); + assertTrue("LoginWithEmailAllowed should be enabled.", rep.isLoginWithEmailAllowed()); + assertFalse("DuplicateEmailsAllowed should be disabled.", rep.isDuplicateEmailsAllowed()); + } + } + + protected void testOfflineTokenLogin() throws Exception { + if (isImportMigrationMode()) { + log.info("Skip offline token login test in the 'import' migrationMode"); + } else { + log.info("test login with old offline token"); + String oldOfflineToken = suiteContext.getMigrationContext().loadOfflineToken(); + Assert.assertNotNull(oldOfflineToken); + + oauth.realm(MIGRATION); + oauth.clientId("migration-test-client"); + OAuthClient.AccessTokenResponse response = oauth.doRefreshTokenRequest(oldOfflineToken, "b2c07929-69e3-44c6-8d7f-76939000b3e4"); + AccessToken accessToken = oauth.verifyToken(response.getAccessToken()); + assertEquals("migration-test-user", accessToken.getPreferredUsername()); + } + } + + protected String getMigrationMode() { + return System.getProperty("migration.mode"); + } + + protected boolean isImportMigrationMode() { + String mode = getMigrationMode(); + return "import".equals(mode); + } + protected void testMigrationTo3_x() { + // NOTE: + testMigrationTo3_0_0(); + testMigrationTo3_2_0(); + testMigrationTo3_4_0(); + testMigrationTo3_4_1(); + } + + + protected void testMigrationTo3_x_and_higher() { + // NOTE: add future methods + testMigrationTo3_x(); + } +} 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 new file mode 100644 index 0000000000..3d721bdcfc --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport198MigrationTest.java @@ -0,0 +1,74 @@ +/* + * Copyright 2016 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.testsuite.migration; + +import org.junit.Test; +import org.keycloak.exportimport.util.ImportUtils; +import org.keycloak.representations.idm.RealmRepresentation; +import org.keycloak.testsuite.util.IOUtil; +import org.keycloak.util.JsonSerialization; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +/** + * Tests that we can import json file from previous version. MigrationTest only tests DB. + * + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class JsonFileImport198MigrationTest extends AbstractJsonFileImportMigrationTest { + + @Override + public void addTestRealms(List testRealms) { + Map reps = null; + try { + reps = ImportUtils.getRealmsFromStream(JsonSerialization.mapper, IOUtil.class.getResourceAsStream("/migration-test/migration-realm-1.9.8.Final.json")); + masterRep = reps.remove("master"); + } catch (IOException e) { + throw new RuntimeException(e); + } + for (RealmRepresentation rep : reps.values()) { + testRealms.add(rep); + } + + + } + + @Test + public void migration1_9_8Test() throws Exception { + testMigratedData(); + testMigrationTo2_0_0(); + testMigrationTo2_1_0(); + testMigrationTo2_2_0(); + testMigrationTo2_3_0(); + testMigrationTo2_5_0(); + //testMigrationTo2_5_1(); // todo do not know how to fix + testMigrationTo3_x_and_higher(); + } + + protected void testMigrationTo2_3_0() { + testUpdateProtocolMappers(migrationRealm); + testExtractRealmKeysMigrationRealm(migrationRealm); + } + + + + + +} 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 new file mode 100644 index 0000000000..c246874fc3 --- /dev/null +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport255MigrationTest.java @@ -0,0 +1,58 @@ +/* + * Copyright 2016 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.testsuite.migration; + +import org.junit.Test; +import org.keycloak.exportimport.util.ImportUtils; +import org.keycloak.representations.idm.RealmRepresentation; +import org.keycloak.testsuite.util.IOUtil; +import org.keycloak.util.JsonSerialization; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +/** + * Tests that we can import json file from previous version. MigrationTest only tests DB. + * + * @author Bill Burke + * @version $Revision: 1 $ + */ +public class JsonFileImport255MigrationTest extends AbstractJsonFileImportMigrationTest { + + @Override + public void addTestRealms(List testRealms) { + Map reps = null; + try { + reps = ImportUtils.getRealmsFromStream(JsonSerialization.mapper, IOUtil.class.getResourceAsStream("/migration-test/migration-realm-2.5.5.Final.json")); + masterRep = reps.remove("master"); + } catch (IOException e) { + throw new RuntimeException(e); + } + for (RealmRepresentation rep : reps.values()) { + testRealms.add(rep); + } + + + } + + @Test + public void migration2_5_5Test() throws Exception { + testMigrationTo3_x_and_higher(); + } + + } 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 74fce03280..83954037f7 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 @@ -21,49 +21,17 @@ import org.jboss.arquillian.container.test.api.TargetsContainer; import org.jboss.shrinkwrap.api.spec.WebArchive; import org.junit.Before; import org.junit.Test; -import org.keycloak.admin.client.resource.ClientResource; import org.keycloak.admin.client.resource.RealmResource; -import org.keycloak.admin.client.resource.RoleResource; -import org.keycloak.common.constants.KerberosConstants; -import org.keycloak.component.PrioritizedComponentModel; -import org.keycloak.keys.KeyProvider; -import org.keycloak.models.AdminRoles; -import org.keycloak.models.AuthenticationExecutionModel; -import org.keycloak.models.Constants; -import org.keycloak.models.LDAPConstants; -import org.keycloak.models.UserModel; -import org.keycloak.models.utils.DefaultAuthenticationFlows; -import org.keycloak.representations.AccessToken; -import org.keycloak.representations.idm.AuthenticationExecutionExportRepresentation; -import org.keycloak.representations.idm.AuthenticationFlowRepresentation; -import org.keycloak.representations.idm.ClientRepresentation; -import org.keycloak.representations.idm.ClientTemplateRepresentation; -import org.keycloak.representations.idm.ComponentRepresentation; -import org.keycloak.representations.idm.ProtocolMapperRepresentation; import org.keycloak.representations.idm.RealmRepresentation; -import org.keycloak.representations.idm.RequiredActionProviderRepresentation; -import org.keycloak.representations.idm.RoleRepresentation; -import org.keycloak.representations.idm.authorization.PolicyRepresentation; -import org.keycloak.storage.UserStorageProvider; -import org.keycloak.testsuite.AbstractKeycloakTest; -import org.keycloak.testsuite.Assert; import org.keycloak.testsuite.arquillian.DeploymentTargetModifier; import org.keycloak.testsuite.arquillian.migration.Migration; -import org.keycloak.testsuite.runonserver.RunHelpers; import org.keycloak.testsuite.runonserver.RunOnServerDeployment; -import org.keycloak.testsuite.util.OAuthClient; import javax.ws.rs.NotFoundException; -import java.util.HashSet; import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; + import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; -import static org.keycloak.models.AccountRoles.MANAGE_ACCOUNT; -import static org.keycloak.models.AccountRoles.MANAGE_ACCOUNT_LINKS; -import static org.keycloak.models.Constants.ACCOUNT_MANAGEMENT_CLIENT_ID; import static org.keycloak.testsuite.Assert.assertEquals; import static org.keycloak.testsuite.Assert.assertFalse; import static org.keycloak.testsuite.Assert.assertNames; @@ -74,15 +42,7 @@ import static org.keycloak.testsuite.auth.page.AuthRealm.MASTER; /** * @author Vlastislav Ramik */ -public class MigrationTest extends AbstractKeycloakTest { - - public static final String MIGRATION = "Migration"; - public static final String MIGRATION2 = "Migration2"; - - private RealmResource migrationRealm; - private RealmResource migrationRealm2; - private RealmResource migrationRealm3; - private RealmResource masterRealm; +public class MigrationTest extends AbstractMigrationTest { @Deployment @TargetsContainer(DeploymentTargetModifier.AUTH_SERVER_CURRENT) @@ -115,8 +75,7 @@ public class MigrationTest extends AbstractKeycloakTest { @Migration(versionFrom = "2.5.5.Final") public void migration2_5_5Test() { testMigratedData(); - testMigrationTo3_0_0(); - testMigrationTo3_4_1(); + testMigrationTo3_x_and_higher(); } @Test @Migration(versionFrom = "1.9.8.Final") @@ -128,328 +87,13 @@ public class MigrationTest extends AbstractKeycloakTest { testMigrationTo2_3_0(); testMigrationTo2_5_0(); testMigrationTo2_5_1(); - testMigrationTo3_0_0(); - testMigrationTo3_2_0(); - testMigrationTo3_4_0(); - testMigrationTo3_4_1(); + testMigrationTo3_x_and_higher(); } + @Test @Migration(versionFrom = "2.2.1.Final") public void migrationInAuthorizationServicesTest() { testDroolsToRulesPolicyTypeMigration(); } - private void testMigratedData() { - log.info("testing migrated data"); - //master realm - assertNames(masterRealm.roles().list(), "offline_access", "uma_authorization", "create-realm", "master-test-realm-role", "admin"); - assertNames(masterRealm.clients().findAll(), "admin-cli", "security-admin-console", "broker", "account", - "master-realm", "master-test-client", "Migration-realm", "Migration2-realm"); - String id = masterRealm.clients().findByClientId("master-test-client").get(0).getId(); - assertNames(masterRealm.clients().get(id).roles().list(), "master-test-client-role"); - assertNames(masterRealm.users().search("", 0, 5), "admin", "master-test-user"); - assertNames(masterRealm.groups().groups(), "master-test-group"); - //migrationRealm - assertNames(migrationRealm.roles().list(), "offline_access", "uma_authorization", "migration-test-realm-role"); - assertNames(migrationRealm.clients().findAll(), "account", "admin-cli", "broker", "migration-test-client", "realm-management", "security-admin-console"); - String id2 = migrationRealm.clients().findByClientId("migration-test-client").get(0).getId(); - assertNames(migrationRealm.clients().get(id2).roles().list(), "migration-test-client-role"); - assertNames(migrationRealm.users().search("", 0, 5), "migration-test-user"); - assertNames(migrationRealm.groups().groups(), "migration-test-group"); - } - /** - * @see org.keycloak.migration.migrators.MigrateTo2_0_0 - */ - private void testMigrationTo2_0_0() { - testAuthorizationServices(masterRealm, migrationRealm); - } - /** - * @see org.keycloak.migration.migrators.MigrateTo2_1_0 - */ - private void testMigrationTo2_1_0() { - testNameOfOTPRequiredAction(masterRealm, migrationRealm); - } - /** - * @see org.keycloak.migration.migrators.MigrateTo2_2_0 - */ - private void testMigrationTo2_2_0() { - testIdentityProviderAuthenticator(masterRealm, migrationRealm); - //MigrateTo2_2_0#migrateRolePolicies is not relevant any more - } - /** - * @see org.keycloak.migration.migrators.MigrateTo2_3_0 - */ - private void testMigrationTo2_3_0() { - testUpdateProtocolMappers(masterRealm, migrationRealm); - testExtractRealmKeys(masterRealm, migrationRealm); - } - /** - * @see org.keycloak.migration.migrators.MigrateTo2_5_0 - */ - private void testMigrationTo2_5_0() { - testLdapKerberosMigration_2_5_0(); - //https://github.com/keycloak/keycloak/pull/3630 - testDuplicateEmailSupport(masterRealm, migrationRealm); - } - - private void testMigrationTo2_5_1() throws Exception { - testOfflineTokenLogin(); - } - /** - * @see org.keycloak.migration.migrators.MigrateTo3_0_0 - */ - private void testMigrationTo3_0_0() { - testRoleManageAccountLinks(masterRealm, migrationRealm); - } - - private void testMigrationTo3_2_0() { - assertNull(masterRealm.toRepresentation().getPasswordPolicy()); - assertNull(migrationRealm.toRepresentation().getPasswordPolicy()); - - testDockerAuthenticationFlow(masterRealm, migrationRealm); - } - - private void testMigrationTo3_4_0() { - Map securityHeaders = masterRealm.toRepresentation().getBrowserSecurityHeaders(); - if (securityHeaders != null) { - assertEquals("max-age=31536000; includeSubDomains", - securityHeaders.get("strictTransportSecurity")); - } else { - fail("Browser security headers not found"); - } - } - - private void testMigrationTo3_4_1() { - Map securityHeaders = masterRealm.toRepresentation().getBrowserSecurityHeaders(); - if (securityHeaders != null) { - assertEquals("frame-src 'self'; frame-ancestors 'self'; object-src 'none';", - securityHeaders.get("contentSecurityPolicy")); - } else { - fail("Browser security headers not found"); - } - } - - private void testDockerAuthenticationFlow(RealmResource... realms) { - for (RealmResource realm : realms) { - AuthenticationFlowRepresentation flow = null; - for (AuthenticationFlowRepresentation f : realm.flows().getFlows()) { - if (DefaultAuthenticationFlows.DOCKER_AUTH.equals(f.getAlias())) { - flow = f; - } - } - assertNotNull(flow); - } - } - - private void testRoleManageAccountLinks(RealmResource... realms) { - log.info("testing role manage account links"); - for (RealmResource realm : realms) { - List clients = realm.clients().findByClientId(ACCOUNT_MANAGEMENT_CLIENT_ID); - if (!clients.isEmpty()) { - String accountClientId = clients.get(0).getId(); - ClientResource accountClient = realm.clients().get(accountClientId); - accountClient.roles().get(MANAGE_ACCOUNT_LINKS).toRepresentation(); //the role should be presented, it'll throw javax.ws.rs.NotFoundException in case the role is not found - - Set roleComposites = accountClient.roles().get(MANAGE_ACCOUNT).getRoleComposites(); - boolean success = false; - for (RoleRepresentation roleComposite : roleComposites) { - if (roleComposite.getName().equals(MANAGE_ACCOUNT_LINKS)) { - success = true; - } - } - if (!success) { - fail("'manage-account' role of client 'account' should have composite role 'manage-account-links'."); - } - } - } - } - private void testExtractRealmKeys(RealmResource masterRealm, RealmResource migrationRealm) { - log.info("testing extract realm keys"); - String expectedMasterRealmKey = "MIIEowIBAAKCAQEAiU54OXoCbHy0L0gHn1yasctcnKHRU1pHFIJnWvaI7rClJydet9dDJaiYXOxMKseiBm3eYznfN3cPyU8udYmRnMuKjiocZ77LT2IEttAjXb6Ggazx7loriFHRy0IOJeX4KxXhAPWmxqa3mkFNfLBEvFqVaBgUDHQ60cmnPvNSHYudBTW9K80s8nvmP2pso7HTwWJ1+Xatj1Ey/gTmB3CXlyqBegGWC9TeuErEYpYhdh+11TVWasgMBZyUCtL3NRPaBuhaPg1LpW8lWGk05nS+YM6dvTk3Mppv+z2RygEpxyO09oT3b4G+Zfwit1STqn0AvDTGzINdoKcNtFScV0j8TwIDAQABAoIBAHcbPKsPLZ8SJfOF1iblW8OzFulAbaaSf2pJHIMJrQrw7LKkMkPjVXoLX+/rgr7xYZmWIP2OLBWfEHCeYTzQUyHiZpSf7vgHx7Fa45/5uVQOe/ttHIiYa37bCtP4vvEdJkOpvP7qGPvljwsebqsk9Ns28LfVez66bHOjK5Mt2yOIulbTeEs7ch//h39YwKJv96vc+CHbV2O6qoOxZessO6y+287cOBvbFXmS2GaGle5Nx/EwncBNS4b7czoetmm70+9ht3yX+kxaP311YUT31KQjuaJt275kOiKsrXr27PvgO++bsIyGuSzqyS7G7fmxF2zUyphEqEpalyDGMKMnrAECgYEA1fCgFox03rPDjm0MhW/ThoS2Ld27sbWQ6reS+PBMdUTJZVZIU1D2//h6VXDnlddhk6avKjA4smdy1aDKzmjz3pt9AKn+kgkXqtTC2fD3wp+fC9hND0z+rQPGe/Gk7ZUnTdsqnfyowxr+woIgzdnRukOUrG+xQiP3RUUT7tt6NQECgYEApEz2xvgqMm+9/f/YxjLdsFUfLqc4WlafB863stYEVqlCYy5ujyo0VQ0ahKSKJkLDnf52+aMUqPOpwaGePpu3O6VkvpcKfPY2MUlZW7/6Sa9et9hxNkdTS7Gui2d1ELpaCBe1Bc62sk8EA01iHXE1PpvyUqDWrhNh+NrDICA9oU8CgYBgGDYACtTP11TmW2r9YK5VRLUDww30k4ZlN1GnyV++aMhBYVEZQ0u+y+A/EnijIFwu0vbo70H4OGknNZMCxbeMbLDoJHM5KyZbUDe5ZvgSjloFGwH59m6KTiDQOUkIgi9mVCQ/VGaFRFHcElEjxUvj60kTbxPijn8ZuR5r8l9hAQKBgQCQ9jL5pHWeoIayN20smi6M6N2lTPbkhe60dcgQatHTIG2pkosLl8IqlHAkPgSB84AiwyR351JQKwRJCm7TcJI/dxMnMZ6YWKfB3qSP1hdfsfJRJQ/mQxIUBAYrizF3e+P5peka4aLCOgMhYsJBlePThMZN7wja99EGPwXQL4IQ8wKBgB8Nis1lQK6Z30GCp9u4dYleGfEP71Lwqvk/eJb89/uz0fjF9CTpJMULFc+nA5u4yHP3LFnRg3zCU6aEwfwUyk4GH9lWGV/qIAisQtgrCEraVe4qxz0DVE59C7qjO26IhU2U66TEzPAqvQ3zqey+woDn/cz/JMWK1vpcSk+TKn3K"; - String expectedMigrationRealmKey = "MIIEpAIBAAKCAQEApt6gCllWkVTZ7fy/oRIx6Bxjt9x3eKKyKGFXvN4iaafrNqpYU9lcqPngWJ9DyXGqUf8RpjPaQWiLWLxjw3xGBqLk2E1/Frb9e/dy8rj//fHGq6bujN1iguzyFwxPGT5Asd7jflRI3qU04M8JE52PArqPhGL2Fn+FiSK5SWRIGm+hVL7Ck/E/tVxM25sFG1/UTQqvrROm4q76TmP8FsyZaTLVf7cCwW2QPIX0N5HTVb3QbBb5KIsk4kKmk/g7uUxS9r42tu533LISzRr5CTyWZAL2XFRuF2RrKdE8gwqkEubw6sDmB2mE0EoPdY1DUhBQgVP/5rwJrCtTsUBR2xdEYQIDAQABAoIBAFbbsNBSOlZBpYJUOmcb8nBQPrOYhXN8tGGCccn0klMOvcdhmcJjdPDbyCQ5Gm7DxJUTwNsTSHsdcNMKlJ9Pk5+msJnKlOl87KrXXbTsCQvlCrWUmb0nCzz9GvJWTOHl3oT3cND0DE4gDksqWR4luCgCdevCGzgQvrBoK6wBD+r578uEW3iw10hnJ0+wnGiw8IvPzE1a9xbY4HD8/QrYdaLxuLb/aC1PDuzrz0cOjnvPkrws5JrbUSnbFygJiOv1z4l2Q00uGIxlHtXdwQBnTZZjVi4vOec2BYSHffgwDYEZIglw1mnrV7y0N1nnPbtJK/cegIkXoBQHXm8Q99TrWMUCgYEA9au86qcwrXZZg5H4BpR5cpy0MSkcKDbA1aRL1cAyTCqJxsczlAtLhFADF+NhnlXj4y7gwDEYWrz064nF73I+ZGicvCiyOy+tCTugTyTGS+XR948ElDMS6PCUUXsotS3dKa0b3c9wd2mxeddTjq/ArfgEVZJ6fE1KtjLt9dtfA+8CgYEAreK3JsvjR5b/Xct28TghYUU7Qnasombb/shqqy8FOMjYUr5OUm/OjNIgoCqhOlE8oQDJ4dOZofNSa7tL+oM8Gmbal+E3fRzxnx/9/EC4QV6sVaPLTIyk7EPfKTcZuzH7+BNZtAziTxJw9d6YJQRbkpg92EZIEoR8iDj2Xs5xrK8CgYEAwMVWwwYX8zT3vn7ukTM2LRH7bsvkVUXJgJqgCwT6Mrv6SmkK9vL5+cPS+Y6pjdW1sRGauBSOGL1Grf/4ug/6F03jFt4UJM8fRyxreU7Q7sNSQ6AMpsGA6BnHODycz7ZCYa59PErG5FyiL4of/cm5Nolz1TXQOPNpWZiTEqVlZC8CgYA4YPbjVF4nuxSnU64H/hwMjsbtAM9uhI016cN0J3W4+J3zDhMU9X1x+Tts0wWdg/N1fGz4lIQOl3cUyRCUc/KL2OdtMS+tmDHbVyMho9ZaE5kq10W2Vy+uDz+O/HeSU12QDK4cC8Vgv+jyPy7zaZtLR6NduUPrBRvfiyCOkr8WrwKBgQCY0h4RCdNFhr0KKLLmJipAtV8wBCGcg1jY1KoWKQswbcykfBKwHbF6EooVqkRW0ITjWB7ZZCf8TnSUxe0NXCUAkVBrhzS4DScgtoSZYOOUaSHgOxpfwgnQ3oYotKi98Yg3IsaLs1j4RuPG5Sp1z6o+ELP1uvr8azyn9YlLa+523Q=="; - - List components = masterRealm.components().query(MASTER, KeyProvider.class.getName()); - assertEquals(3, components.size()); - - components = masterRealm.components().query(MASTER, KeyProvider.class.getName(), "rsa"); - assertEquals(1, components.size()); - - ComponentRepresentation component = testingClient.server(MASTER).fetch(RunHelpers.internalComponent(components.get(0).getId())); - assertEquals(expectedMasterRealmKey, component.getConfig().getFirst("privateKey")); - - components = masterRealm.components().query(MASTER, KeyProvider.class.getName(), "hmac-generated"); - assertEquals(1, components.size()); - - components = migrationRealm.components().query(MIGRATION, KeyProvider.class.getName()); - assertEquals(3, components.size()); - - components = migrationRealm.components().query(MIGRATION, KeyProvider.class.getName(), "rsa"); - assertEquals(1, components.size()); - - component = testingClient.server(MIGRATION).fetch(RunHelpers.internalComponent(components.get(0).getId())); - assertEquals(expectedMigrationRealmKey, component.getConfig().getFirst("privateKey")); - - components = migrationRealm.components().query(MIGRATION, KeyProvider.class.getName(), "hmac-generated"); - assertEquals(1, components.size()); - } - - private void testLdapKerberosMigration_2_5_0() { - log.info("testing ldap kerberos migration"); - RealmRepresentation realmRep = migrationRealm2.toRepresentation(); - List components = migrationRealm2.components().query(realmRep.getId(), UserStorageProvider.class.getName()); - assertEquals(2, components.size()); - boolean testedLdap = false; - boolean testedKerberos = false; - - for (ComponentRepresentation component : components) { - if (component.getName().equals("ldap-provider")) { - assertEquals("2", component.getConfig().getFirst(PrioritizedComponentModel.PRIORITY)); - assertEquals("READ_ONLY", component.getConfig().getFirst(LDAPConstants.EDIT_MODE)); - assertEquals("true", component.getConfig().getFirst(LDAPConstants.SYNC_REGISTRATIONS)); - assertEquals(LDAPConstants.VENDOR_RHDS, component.getConfig().getFirst(LDAPConstants.VENDOR)); - assertEquals("uid", component.getConfig().getFirst(LDAPConstants.USERNAME_LDAP_ATTRIBUTE)); - assertEquals("uid", component.getConfig().getFirst(LDAPConstants.RDN_LDAP_ATTRIBUTE)); - assertEquals("nsuniqueid", component.getConfig().getFirst(LDAPConstants.UUID_LDAP_ATTRIBUTE)); - assertEquals("inetOrgPerson, organizationalPerson", component.getConfig().getFirst(LDAPConstants.USER_OBJECT_CLASSES)); - assertEquals("http://localhost", component.getConfig().getFirst(LDAPConstants.CONNECTION_URL)); - assertEquals("dn", component.getConfig().getFirst(LDAPConstants.USERS_DN)); - assertEquals(LDAPConstants.AUTH_TYPE_NONE, component.getConfig().getFirst(LDAPConstants.AUTH_TYPE)); - assertEquals("true", component.getConfig().getFirst(KerberosConstants.ALLOW_KERBEROS_AUTHENTICATION)); - assertEquals("realm", component.getConfig().getFirst(KerberosConstants.KERBEROS_REALM)); - assertEquals("principal", component.getConfig().getFirst(KerberosConstants.SERVER_PRINCIPAL)); - assertEquals("keytab", component.getConfig().getFirst(KerberosConstants.KEYTAB)); - testedLdap = true; - } else if (component.getName().equals("kerberos-provider")) { - assertEquals("3", component.getConfig().getFirst(PrioritizedComponentModel.PRIORITY)); - assertEquals("realm", component.getConfig().getFirst(KerberosConstants.KERBEROS_REALM)); - assertEquals("principal", component.getConfig().getFirst(KerberosConstants.SERVER_PRINCIPAL)); - assertEquals("keytab", component.getConfig().getFirst(KerberosConstants.KEYTAB)); - } - } - } - - private void testDroolsToRulesPolicyTypeMigration() { - log.info("testing drools to rules in authorization services"); - List client = migrationRealm3.clients().findByClientId("photoz-restful-api"); - - assertEquals(1, client.size()); - - ClientRepresentation representation = client.get(0); - - List policies = migrationRealm3.clients().get(representation.getId()).authorization().policies().policies(); - - List migratedRulesPolicies = policies.stream().filter(policyRepresentation -> "rules".equals(policyRepresentation.getType())).collect(Collectors.toList()); - - assertEquals(1, migratedRulesPolicies.size()); - } - private void testAuthorizationServices(RealmResource... realms) { - log.info("testing authorization services"); - for (RealmResource realm : realms) { - //test setup of authorization services - for (String roleName : Constants.AUTHZ_DEFAULT_AUTHORIZATION_ROLES) { - RoleResource role = realm.roles().get(roleName); //throws javax.ws.rs.NotFoundException if not found - - assertFalse("Role's scopeParamRequired should be false.", role.toRepresentation().isScopeParamRequired()); - assertFalse("Role shouldn't be composite should be false.", role.toRepresentation().isComposite()); - - assertTrue("role should be added to default roles for new users", realm.toRepresentation().getDefaultRoles().contains(roleName)); - } - //test admin roles - master admin client - List clients = realm.clients().findByClientId(realm.toRepresentation().getRealm() + "-realm"); - if (!clients.isEmpty()) { - ClientResource masterAdminClient = realm.clients().get(clients.get(0).getId()); - masterAdminClient.roles().get(AdminRoles.VIEW_AUTHORIZATION).toRepresentation(); - masterAdminClient.roles().get(AdminRoles.MANAGE_AUTHORIZATION).toRepresentation(); - //test admin roles - admin role composite - Set roleNames = new HashSet<>(); - for (RoleRepresentation role : realm.roles().get(AdminRoles.ADMIN).getRoleComposites()) { - roleNames.add(role.getName()); - } - assertTrue(AdminRoles.VIEW_AUTHORIZATION + " should be composite role of " + AdminRoles.ADMIN, roleNames.contains(AdminRoles.VIEW_AUTHORIZATION)); - assertTrue(AdminRoles.MANAGE_AUTHORIZATION + " should be composite role of " + AdminRoles.ADMIN, roleNames.contains(AdminRoles.MANAGE_AUTHORIZATION)); - } - } - } - private void testNameOfOTPRequiredAction(RealmResource... realms) { - log.info("testing OTP Required Action"); - for (RealmResource realm : realms) { - RequiredActionProviderRepresentation otpAction = realm.flows().getRequiredAction(UserModel.RequiredAction.CONFIGURE_TOTP.name()); - - assertEquals("The name of CONFIGURE_TOTP required action should be 'Configure OTP'.", "Configure OTP", otpAction.getName()); - } - } - private void testIdentityProviderAuthenticator(RealmResource... realms) { - log.info("testing identity provider authenticator"); - for (RealmResource realm : realms) { - boolean success = false; - for (AuthenticationFlowRepresentation flow : realm.flows().getFlows()) { - if (flow.getAlias().equals(DefaultAuthenticationFlows.BROWSER_FLOW)) { - for (AuthenticationExecutionExportRepresentation execution : flow.getAuthenticationExecutions()) { - if ("identity-provider-redirector".equals(execution.getAuthenticator())) { - assertEquals("Requirement should be ALTERNATIVE.", AuthenticationExecutionModel.Requirement.ALTERNATIVE.name(), execution.getRequirement()); - assertTrue("Priority should be 25.", execution.getPriority() == 25); - success = true; - } - } - } - } - if (!success) { - fail("BROWSER_FLOW should contain execution: 'identity-provider-redirector' authenticator."); - } - } - } - private void testUpdateProtocolMappers(RealmResource... realms) { - log.info("testing updated protocol mappers"); - for (RealmResource realm : realms) { - for (ClientRepresentation client : realm.clients().findAll()) { - for (ProtocolMapperRepresentation protocolMapper : client.getProtocolMappers()) { - testUpdateProtocolMapper(protocolMapper); - } - } - for (ClientTemplateRepresentation clientTemlate : realm.clientTemplates().findAll()) { - for (ProtocolMapperRepresentation protocolMapper : clientTemlate.getProtocolMappers()) { - testUpdateProtocolMapper(protocolMapper); - } - } - } - } - private void testUpdateProtocolMapper(ProtocolMapperRepresentation protocolMapper) { - if (protocolMapper.getConfig().get("id.token.claim") != null) { - assertEquals("ProtocolMapper's config should contain key 'userinfo.token.claim'.", - protocolMapper.getConfig().get("id.token.claim"), protocolMapper.getConfig().get("userinfo.token.claim")); - } - } - private void testDuplicateEmailSupport(RealmResource... realms) { - log.info("testing duplicate email"); - for (RealmResource realm : realms) { - RealmRepresentation rep = realm.toRepresentation(); - assertTrue("LoginWithEmailAllowed should be enabled.", rep.isLoginWithEmailAllowed()); - assertFalse("DuplicateEmailsAllowed should be disabled.", rep.isDuplicateEmailsAllowed()); - } - } - - private void testOfflineTokenLogin() throws Exception { - if (isImportMigrationMode()) { - log.info("Skip offline token login test in the 'import' migrationMode"); - } else { - log.info("test login with old offline token"); - String oldOfflineToken = suiteContext.getMigrationContext().loadOfflineToken(); - Assert.assertNotNull(oldOfflineToken); - - oauth.realm(MIGRATION); - oauth.clientId("migration-test-client"); - OAuthClient.AccessTokenResponse response = oauth.doRefreshTokenRequest(oldOfflineToken, "b2c07929-69e3-44c6-8d7f-76939000b3e4"); - AccessToken accessToken = oauth.verifyToken(response.getAccessToken()); - assertEquals("migration-test-user", accessToken.getPreferredUsername()); - } - } - - private String getMigrationMode() { - return System.getProperty("migration.mode"); - } - - private boolean isImportMigrationMode() { - String mode = getMigrationMode(); - return "import".equals(mode); - } }