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 7297d36397..2a828915f3 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 @@ -47,6 +47,7 @@ import org.keycloak.migration.migrators.MigrateTo4_2_0; import org.keycloak.migration.migrators.MigrateTo4_6_0; import org.keycloak.migration.migrators.MigrateTo6_0_0; import org.keycloak.migration.migrators.MigrateTo8_0_0; +import org.keycloak.migration.migrators.MigrateTo9_0_0; import org.keycloak.migration.migrators.Migration; import org.keycloak.models.KeycloakSession; import org.keycloak.models.RealmModel; @@ -84,7 +85,8 @@ public class MigrationModelManager { new MigrateTo4_2_0(), new MigrateTo4_6_0(), new MigrateTo6_0_0(), - new MigrateTo8_0_0() + new MigrateTo8_0_0(), + new MigrateTo9_0_0() }; public static void migrate(KeycloakSession session) { diff --git a/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo9_0_0.java b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo9_0_0.java new file mode 100644 index 0000000000..445a810588 --- /dev/null +++ b/server-spi-private/src/main/java/org/keycloak/migration/migrators/MigrateTo9_0_0.java @@ -0,0 +1,89 @@ +/* + * Copyright 2019 Red Hat, Inc. and/or its affiliates + * and other contributors as indicated by the @author tags. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.keycloak.migration.migrators; + +import org.jboss.logging.Logger; +import org.keycloak.migration.ModelVersion; +import org.keycloak.models.AccountRoles; +import org.keycloak.models.AuthenticationExecutionModel; +import org.keycloak.models.AuthenticationFlowModel; +import org.keycloak.models.ClientModel; +import org.keycloak.models.Constants; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.ProtocolMapperModel; +import org.keycloak.models.RealmModel; +import org.keycloak.models.utils.KeycloakModelUtils; +import org.keycloak.representations.idm.RealmRepresentation; + +import java.util.Collections; + +/** + * @author Marek Posolda + */ +public class MigrateTo9_0_0 implements Migration { + + public static final ModelVersion VERSION = new ModelVersion("9.0.0"); + + private static final Logger LOG = Logger.getLogger(MigrateTo9_0_0.class); + + @Override + public ModelVersion getVersion() { + return VERSION; + } + + @Override + public void migrate(KeycloakSession session) { + session.realms().getRealms().stream().forEach(realm -> addAccountConsoleClient(realm)); + } + + @Override + public void migrateImport(KeycloakSession session, RealmModel realm, RealmRepresentation rep, boolean skipUserDependent) { + migrateRealmCommon(realm); + } + + protected void migrateRealmCommon(RealmModel realm) { + addAccountConsoleClient(realm); + } + + protected void addAccountConsoleClient(RealmModel realm) { + if (realm.getClientByClientId(Constants.ACCOUNT_CONSOLE_CLIENT_ID) == null) { + ClientModel client = KeycloakModelUtils.createClient(realm, Constants.ACCOUNT_CONSOLE_CLIENT_ID); + client.setName("${client_" + Constants.ACCOUNT_CONSOLE_CLIENT_ID + "}"); + client.setEnabled(true); + client.setFullScopeAllowed(false); + client.setPublicClient(true); + client.setDirectAccessGrantsEnabled(false); + + client.setRootUrl(Constants.AUTH_BASE_URL_PROP); + String baseUrl = "/realms/" + realm.getName() + "/account/"; + client.setBaseUrl(baseUrl); + client.addRedirectUri(baseUrl + "*"); + + client.setProtocol("openid-connect"); + + client.addScopeMapping(realm.getClientByClientId(Constants.ACCOUNT_MANAGEMENT_CLIENT_ID).getRole(AccountRoles.MANAGE_ACCOUNT)); + + ProtocolMapperModel audienceMapper = new ProtocolMapperModel(); + audienceMapper.setName("audience resolve"); + audienceMapper.setProtocol("openid-connect"); + audienceMapper.setProtocolMapper("oidc-audience-resolve-mapper"); + + client.addProtocolMapper(audienceMapper); + } + } +} diff --git a/server-spi-private/src/main/java/org/keycloak/models/Constants.java b/server-spi-private/src/main/java/org/keycloak/models/Constants.java index aefcd43ce5..9cb07fdf51 100755 --- a/server-spi-private/src/main/java/org/keycloak/models/Constants.java +++ b/server-spi-private/src/main/java/org/keycloak/models/Constants.java @@ -33,6 +33,7 @@ public final class Constants { public static final String ADMIN_CLI_CLIENT_ID = "admin-cli"; public static final String ACCOUNT_MANAGEMENT_CLIENT_ID = "account"; + public static final String ACCOUNT_CONSOLE_CLIENT_ID = "account-console"; public static final String BROKER_SERVICE_CLIENT_ID = "broker"; public static final String REALM_MANAGEMENT_CLIENT_ID = "realm-management"; 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 c720214853..bf019d5577 100755 --- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java +++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java @@ -42,6 +42,7 @@ import org.keycloak.models.utils.RepresentationToModel; import org.keycloak.protocol.ProtocolMapperUtils; import org.keycloak.protocol.oidc.OIDCLoginProtocol; import org.keycloak.protocol.oidc.OIDCLoginProtocolFactory; +import org.keycloak.protocol.oidc.mappers.AudienceResolveProtocolMapper; import org.keycloak.representations.idm.ApplicationRepresentation; import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.ClientScopeRepresentation; @@ -401,29 +402,54 @@ public class RealmManager { private void setupAccountManagement(RealmModel realm) { - ClientModel client = realm.getClientByClientId(Constants.ACCOUNT_MANAGEMENT_CLIENT_ID); - if (client == null) { - client = KeycloakModelUtils.createClient(realm, Constants.ACCOUNT_MANAGEMENT_CLIENT_ID); - client.setName("${client_" + Constants.ACCOUNT_MANAGEMENT_CLIENT_ID + "}"); - client.setEnabled(true); - client.setFullScopeAllowed(false); + ClientModel accountClient = realm.getClientByClientId(Constants.ACCOUNT_MANAGEMENT_CLIENT_ID); + if (accountClient == null) { + accountClient = KeycloakModelUtils.createClient(realm, Constants.ACCOUNT_MANAGEMENT_CLIENT_ID); + accountClient.setName("${client_" + Constants.ACCOUNT_MANAGEMENT_CLIENT_ID + "}"); + accountClient.setEnabled(true); + accountClient.setFullScopeAllowed(false); - client.setRootUrl(Constants.AUTH_BASE_URL_PROP); + accountClient.setRootUrl(Constants.AUTH_BASE_URL_PROP); String baseUrl = "/realms/" + realm.getName() + "/account/"; - client.setBaseUrl(baseUrl); - client.addRedirectUri(baseUrl + "*"); + accountClient.setBaseUrl(baseUrl); + accountClient.addRedirectUri(baseUrl + "*"); - client.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL); + accountClient.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL); for (String role : AccountRoles.ALL) { - client.addDefaultRole(role); - RoleModel roleModel = client.getRole(role); + accountClient.addDefaultRole(role); + RoleModel roleModel = accountClient.getRole(role); roleModel.setDescription("${role_" + role + "}"); } - RoleModel manageAccountLinks = client.addRole(AccountRoles.MANAGE_ACCOUNT_LINKS); + RoleModel manageAccountLinks = accountClient.addRole(AccountRoles.MANAGE_ACCOUNT_LINKS); manageAccountLinks.setDescription("${role_" + AccountRoles.MANAGE_ACCOUNT_LINKS + "}"); - RoleModel manageAccount = client.getRole(AccountRoles.MANAGE_ACCOUNT); + RoleModel manageAccount = accountClient.getRole(AccountRoles.MANAGE_ACCOUNT); manageAccount.addCompositeRole(manageAccountLinks); + + ClientModel accountConsoleClient = realm.getClientByClientId(Constants.ACCOUNT_CONSOLE_CLIENT_ID); + if (accountConsoleClient == null) { + accountConsoleClient = KeycloakModelUtils.createClient(realm, Constants.ACCOUNT_CONSOLE_CLIENT_ID); + accountConsoleClient.setName("${client_" + Constants.ACCOUNT_CONSOLE_CLIENT_ID + "}"); + accountConsoleClient.setEnabled(true); + accountConsoleClient.setFullScopeAllowed(false); + accountConsoleClient.setPublicClient(true); + accountConsoleClient.setDirectAccessGrantsEnabled(false); + + accountConsoleClient.setRootUrl(Constants.AUTH_BASE_URL_PROP); + accountConsoleClient.setBaseUrl(baseUrl); + accountConsoleClient.addRedirectUri(baseUrl + "*"); + + accountConsoleClient.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL); + + accountConsoleClient.addScopeMapping(accountClient.getRole(AccountRoles.MANAGE_ACCOUNT)); + + ProtocolMapperModel audienceMapper = new ProtocolMapperModel(); + audienceMapper.setName(OIDCLoginProtocolFactory.AUDIENCE_RESOLVE); + audienceMapper.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL); + audienceMapper.setProtocolMapper(AudienceResolveProtocolMapper.PROVIDER_ID); + + accountConsoleClient.addProtocolMapper(audienceMapper); + } } } diff --git a/services/src/main/java/org/keycloak/services/resources/account/AccountConsole.java b/services/src/main/java/org/keycloak/services/resources/account/AccountConsole.java index 0cda7d4fd6..5fe4127a5d 100644 --- a/services/src/main/java/org/keycloak/services/resources/account/AccountConsole.java +++ b/services/src/main/java/org/keycloak/services/resources/account/AccountConsole.java @@ -86,7 +86,12 @@ public class AccountConsole { URI baseUri = session.getContext().getUri().getBaseUri(); - map.put("authUrl", session.getContext().getUri(UrlType.FRONTEND).getBaseUri().toString()); + String authServerBaseUrl = baseUri.toString(); + if (authServerBaseUrl.endsWith("/")) { + authServerBaseUrl = authServerBaseUrl.substring(0, authServerBaseUrl.length() - 1); + } + + map.put("authUrl", authServerBaseUrl); map.put("baseUrl", session.getContext().getUri(UrlType.FRONTEND).getBaseUriBuilder().replacePath("/realms/" + realm.getName() + "/account").build().toString()); map.put("realm", realm); map.put("resourceUrl", Urls.themeRoot(baseUri).getPath() + "/account/" + theme.getName()); @@ -170,20 +175,6 @@ public class AccountConsole { return Response.status(302).location(session.getContext().getUri().getRequestUriBuilder().path("../").build()).build(); } - @GET - @Path("keycloak.json") - @Produces(MediaType.APPLICATION_JSON) - @NoCache - public ClientManager.InstallationAdapterConfig getConfig() { - ClientModel accountClient = realm.getClientByClientId(Constants.ACCOUNT_MANAGEMENT_CLIENT_ID); - if (accountClient == null) { - throw new javax.ws.rs.NotFoundException("Account console client not found"); - } - RealmManager realmMgr = new RealmManager(session); - URI baseUri = session.getContext().getUri().getBaseUri(); - return new ClientManager(realmMgr).toInstallationRepresentation(realm, accountClient, baseUri); - } - // TODO: took this code from elsewhere - refactor private String[] getReferrer() { String referrer = session.getContext().getUri().getQueryParameters().getFirst("referrer"); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountFormServiceTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountFormServiceTest.java index ab5ad6496a..78bdb1af7c 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountFormServiceTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountFormServiceTest.java @@ -1110,7 +1110,7 @@ public class AccountFormServiceTest extends AbstractTestRealmKeycloakTest { Map apps = applicationsPage.getApplications(); Assert.assertThat(apps.keySet(), containsInAnyOrder( - /* "root-url-client", */ "Account", "test-app", "test-app-scope", "third-party", "test-app-authz", "My Named Test App", "Test App Named - ${client_account}", "direct-grant")); + /* "root-url-client", */ "Account", "Account Console", "test-app", "test-app-scope", "third-party", "test-app-authz", "My Named Test App", "Test App Named - ${client_account}", "direct-grant")); rsu.add(testRealm().roles().get("user").toRepresentation()) .update(); @@ -1118,7 +1118,7 @@ public class AccountFormServiceTest extends AbstractTestRealmKeycloakTest { driver.navigate().refresh(); apps = applicationsPage.getApplications(); Assert.assertThat(apps.keySet(), containsInAnyOrder( - "root-url-client", "Account", "test-app", "test-app-scope", "third-party", "test-app-authz", "My Named Test App", "Test App Named - ${client_account}", "direct-grant")); + "root-url-client", "Account", "Account Console", "test-app", "test-app-scope", "third-party", "test-app-authz", "My Named Test App", "Test App Named - ${client_account}", "direct-grant")); } } @@ -1136,7 +1136,7 @@ public class AccountFormServiceTest extends AbstractTestRealmKeycloakTest { Map apps = applicationsPage.getApplications(); Assert.assertThat(apps.keySet(), containsInAnyOrder( - "root-url-client", "Account", "test-app", "test-app-scope", "third-party", "test-app-authz", "My Named Test App", "Test App Named - ${client_account}", "direct-grant")); + "root-url-client", "Account", "Account Console", "test-app", "test-app-scope", "third-party", "test-app-authz", "My Named Test App", "Test App Named - ${client_account}", "direct-grant")); } } @@ -1150,7 +1150,7 @@ public class AccountFormServiceTest extends AbstractTestRealmKeycloakTest { applicationsPage.assertCurrent(); Map apps = applicationsPage.getApplications(); - Assert.assertThat(apps.keySet(), containsInAnyOrder("root-url-client", "Account", "Broker", "test-app", "test-app-scope", "third-party", "test-app-authz", "My Named Test App", "Test App Named - ${client_account}", "direct-grant")); + Assert.assertThat(apps.keySet(), containsInAnyOrder("root-url-client", "Account", "Account Console", "Broker", "test-app", "test-app-scope", "third-party", "test-app-authz", "My Named Test App", "Test App Named - ${client_account}", "direct-grant")); AccountApplicationsPage.AppEntry accountEntry = apps.get("Account"); Assert.assertThat(accountEntry.getRolesAvailable(), containsInAnyOrder( diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ClientTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ClientTest.java index 905f29c075..4c67407bf2 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ClientTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ClientTest.java @@ -66,7 +66,7 @@ public class ClientTest extends AbstractAdminTest { @Test public void getClients() { - Assert.assertNames(realm.clients().findAll(), "account", "realm-management", "security-admin-console", "broker", Constants.ADMIN_CLI_CLIENT_ID); + Assert.assertNames(realm.clients().findAll(), "account", "account-console", "realm-management", "security-admin-console", "broker", Constants.ADMIN_CLI_CLIENT_ID); } private ClientRepresentation createClient() { @@ -93,7 +93,7 @@ public class ClientTest extends AbstractAdminTest { String id = createClient().getId(); assertNotNull(realm.clients().get(id)); - Assert.assertNames(realm.clients().findAll(), "account", "realm-management", "security-admin-console", "broker", "my-app", Constants.ADMIN_CLI_CLIENT_ID); + Assert.assertNames(realm.clients().findAll(), "account", "account-console", "realm-management", "security-admin-console", "broker", "my-app", Constants.ADMIN_CLI_CLIENT_ID); } @Test diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/realm/RealmTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/realm/RealmTest.java index e5ccef0609..f93f3a00fd 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/realm/RealmTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/realm/RealmTest.java @@ -70,8 +70,10 @@ import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import javax.ws.rs.BadRequestException; +import static org.hamcrest.Matchers.containsInAnyOrder; import static org.junit.Assert.*; import org.keycloak.events.EventType; import org.keycloak.events.log.JBossLoggingEventListenerProviderFactory; @@ -153,6 +155,9 @@ public class RealmTest extends AbstractAdminTest { Assert.assertNames(adminClient.realms().findAll(), "master", AuthRealm.TEST, REALM_NAME, "new-realm"); + List clients = adminClient.realms().realm("new-realm").clients().findAll().stream().map(ClientRepresentation::getClientId).collect(Collectors.toList()); + assertThat(clients, containsInAnyOrder("account", "account-console", "admin-cli", "broker", "realm-management", "security-admin-console")); + adminClient.realms().realm("new-realm").remove(); Assert.assertNames(adminClient.realms().findAll(), "master", AuthRealm.TEST, REALM_NAME); @@ -663,7 +668,7 @@ public class RealmTest extends AbstractAdminTest { GlobalRequestResult globalRequestResult = realm.pushRevocation(); assertAdminEvents.assertEvent(realmId, OperationType.ACTION, "push-revocation", globalRequestResult, ResourceType.REALM); - assertThat(globalRequestResult.getSuccessRequests(), Matchers.containsInAnyOrder(oauth.AUTH_SERVER_ROOT + "/realms/master/app/admin")); + assertThat(globalRequestResult.getSuccessRequests(), containsInAnyOrder(oauth.AUTH_SERVER_ROOT + "/realms/master/app/admin")); assertNull(globalRequestResult.getFailedRequests()); PushNotBeforeAction adminPushNotBefore = testingClient.testApp().getAdminPushNotBefore(); @@ -685,8 +690,8 @@ public class RealmTest extends AbstractAdminTest { GlobalRequestResult globalRequestResult = realm.pushRevocation(); assertAdminEvents.assertEvent(realmId, OperationType.ACTION, "push-revocation", globalRequestResult, ResourceType.REALM); - assertThat(globalRequestResult.getSuccessRequests(), Matchers.containsInAnyOrder(oauth.AUTH_SERVER_ROOT + "/realms/master/app/admin")); - assertThat(globalRequestResult.getFailedRequests(), Matchers.containsInAnyOrder(oauth.AUTH_SERVER_ROOT + "/realms/master/saml-app/saml")); + assertThat(globalRequestResult.getSuccessRequests(), containsInAnyOrder(oauth.AUTH_SERVER_ROOT + "/realms/master/app/admin")); + assertThat(globalRequestResult.getFailedRequests(), containsInAnyOrder(oauth.AUTH_SERVER_ROOT + "/realms/master/saml-app/saml")); PushNotBeforeAction adminPushNotBefore = testingClient.testApp().getAdminPushNotBefore(); assertEquals(time, adminPushNotBefore.getNotBefore()); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportUtil.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportUtil.java index 249c077d13..c614a18672 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportUtil.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportUtil.java @@ -110,7 +110,7 @@ public class ExportImportUtil { Assert.assertEquals(0, userRsc.getFederatedIdentity().size()); List resources = realmRsc.clients().findAll(); - Assert.assertEquals(9, resources.size()); + Assert.assertEquals(10, resources.size()); // Test applications imported ClientRepresentation application = ApiUtil.findClientByClientId(realmRsc, "Application").toRepresentation(); @@ -121,7 +121,7 @@ public class ExportImportUtil { Assert.assertNotNull(otherApp); Assert.assertNull(nonExisting); List clients = realmRsc.clients().findAll(); - Assert.assertEquals(9, clients.size()); + Assert.assertEquals(10, clients.size()); Assert.assertTrue(hasClient(clients, application)); Assert.assertTrue(hasClient(clients, otherApp)); Assert.assertTrue(hasClient(clients, accountApp)); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/AbstractMigrationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/AbstractMigrationTest.java index b6e4969099..a1eebf152f 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/AbstractMigrationTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/AbstractMigrationTest.java @@ -28,6 +28,7 @@ import org.keycloak.broker.provider.util.SimpleHttp; import org.keycloak.common.constants.KerberosConstants; import org.keycloak.component.PrioritizedComponentModel; import org.keycloak.keys.KeyProvider; +import org.keycloak.models.AccountRoles; import org.keycloak.models.AdminRoles; import org.keycloak.models.AuthenticationExecutionModel; import org.keycloak.models.ClientModel; @@ -75,9 +76,11 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; +import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -116,7 +119,7 @@ public abstract class AbstractMigrationTest extends AbstractKeycloakTest { protected void testMigratedMigrationData(boolean supportsAuthzService) { assertNames(migrationRealm.roles().list(), "offline_access", "uma_authorization", "migration-test-realm-role"); - List expectedClientIds = new ArrayList<>(Arrays.asList("account", "admin-cli", "broker", "migration-test-client", "realm-management", "security-admin-console")); + List expectedClientIds = new ArrayList<>(Arrays.asList("account", "account-console", "admin-cli", "broker", "migration-test-client", "realm-management", "security-admin-console")); if (supportsAuthzService) { expectedClientIds.add("authz-servlet"); @@ -132,7 +135,7 @@ public abstract class AbstractMigrationTest extends AbstractKeycloakTest { protected void testMigratedMasterData() { 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", + assertNames(masterRealm.clients().findAll(), "admin-cli", "security-admin-console", "broker", "account", "account-console", "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"); @@ -270,6 +273,11 @@ public abstract class AbstractMigrationTest extends AbstractKeycloakTest { testResourceTag(); } + protected void testMigrationTo9_0_0() { + testAccountConsoleClient(masterRealm); + testAccountConsoleClient(migrationRealm); + } + private void testAdminClientUrls(RealmResource realm) { ClientRepresentation adminConsoleClient = realm.clients().findByClientId(Constants.ADMIN_CONSOLE_CLIENT_ID).get(0); @@ -292,6 +300,29 @@ public abstract class AbstractMigrationTest extends AbstractKeycloakTest { assertEquals(1, accountConsoleClient.getRedirectUris().size()); } + private void testAccountConsoleClient(RealmResource realm) { + ClientRepresentation accountConsoleClient = realm.clients().findByClientId(Constants.ACCOUNT_CONSOLE_CLIENT_ID).get(0); + + assertEquals(Constants.AUTH_BASE_URL_PROP, accountConsoleClient.getRootUrl()); + assertEquals("/realms/" + realm.toRepresentation().getRealm() + "/account/", accountConsoleClient.getBaseUrl()); + assertTrue(accountConsoleClient.isPublicClient()); + assertFalse(accountConsoleClient.isFullScopeAllowed()); + assertTrue(accountConsoleClient.isStandardFlowEnabled()); + assertFalse(accountConsoleClient.isDirectAccessGrantsEnabled()); + + ClientResource clientResource = realm.clients().get(accountConsoleClient.getId()); + + MappingsRepresentation scopes = clientResource.getScopeMappings().getAll(); + assertNull(scopes.getRealmMappings()); + assertEquals(1, scopes.getClientMappings().size()); + assertEquals(1, scopes.getClientMappings().get(ACCOUNT_MANAGEMENT_CLIENT_ID).getMappings().size()); + assertEquals(MANAGE_ACCOUNT, scopes.getClientMappings().get(ACCOUNT_MANAGEMENT_CLIENT_ID).getMappings().get(0).getName()); + + List mappers = clientResource.getProtocolMappers().getMappers(); + assertEquals(1, mappers.size()); + assertEquals("oidc-audience-resolve-mapper", mappers.get(0).getProtocolMapper()); + } + private void testDecisionStrategySetOnResourceServer() { ClientsResource clients = migrationRealm.clients(); ClientRepresentation clientRepresentation = clients.findByClientId("authz-servlet").get(0); @@ -431,7 +462,7 @@ public abstract class AbstractMigrationTest extends AbstractKeycloakTest { ClientsResource clients = migrationRealm.clients(); ClientRepresentation clientRepresentation = clients.findByClientId("authz-servlet").get(0); ResourceRepresentation resource = clients.get(clientRepresentation.getId()).authorization().resources().findByName("Protected Resource").get(0); - org.junit.Assert.assertThat(resource.getUris(), Matchers.containsInAnyOrder("/*")); + org.junit.Assert.assertThat(resource.getUris(), containsInAnyOrder("/*")); } protected void testAuthorizationServices(RealmResource... realms) { @@ -741,6 +772,9 @@ public abstract class AbstractMigrationTest extends AbstractKeycloakTest { protected void testMigrationTo8_x() { testMigrationTo8_0_0(); } + protected void testMigrationTo9_x() { + testMigrationTo9_0_0(); + } protected void testMigrationTo7_x(boolean supportedAuthzServices) { if (supportedAuthzServices) { diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport198MigrationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport198MigrationTest.java index a8410e15b3..b51e67538f 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport198MigrationTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport198MigrationTest.java @@ -77,6 +77,7 @@ public class JsonFileImport198MigrationTest extends AbstractJsonFileImportMigrat testMigrationTo6_x(); testMigrationTo7_x(false); testMigrationTo8_x(); + testMigrationTo9_x(); } @Override diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport255MigrationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport255MigrationTest.java index 134f744b95..a473fce1a9 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport255MigrationTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport255MigrationTest.java @@ -70,6 +70,7 @@ public class JsonFileImport255MigrationTest extends AbstractJsonFileImportMigrat testMigrationTo6_x(); testMigrationTo7_x(true); testMigrationTo8_x(); + testMigrationTo9_x(); } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport343MigrationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport343MigrationTest.java index c0a664594b..611a565a0c 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport343MigrationTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport343MigrationTest.java @@ -69,6 +69,7 @@ public class JsonFileImport343MigrationTest extends AbstractJsonFileImportMigrat testMigrationTo6_x(); testMigrationTo7_x(true); testMigrationTo8_x(); + testMigrationTo9_x(); } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport483MigrationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport483MigrationTest.java index f822daf548..de7f872397 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport483MigrationTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/JsonFileImport483MigrationTest.java @@ -63,6 +63,7 @@ public class JsonFileImport483MigrationTest extends AbstractJsonFileImportMigrat testMigrationTo6_x(); testMigrationTo7_x(true); testMigrationTo8_x(); + testMigrationTo9_x(); } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/MigrationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/migration/MigrationTest.java index b14f2432bf..b585f2b7d4 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 @@ -73,6 +73,7 @@ public class MigrationTest extends AbstractMigrationTest { testMigrationTo6_x(); testMigrationTo7_x(true); testMigrationTo8_x(); + testMigrationTo9_x(); } @Test @@ -84,6 +85,7 @@ public class MigrationTest extends AbstractMigrationTest { testMigrationTo6_x(); testMigrationTo7_x(true); testMigrationTo8_x(); + testMigrationTo9_x(); } @Test @@ -96,6 +98,7 @@ public class MigrationTest extends AbstractMigrationTest { testMigrationTo6_x(); testMigrationTo7_x(true); testMigrationTo8_x(); + testMigrationTo9_x(); } @Test @@ -109,6 +112,7 @@ public class MigrationTest extends AbstractMigrationTest { testMigrationTo6_x(); testMigrationTo7_x(false); testMigrationTo8_x(); + testMigrationTo9_x(); } } diff --git a/themes/src/main/resources/theme/base/account/messages/messages_en.properties b/themes/src/main/resources/theme/base/account/messages/messages_en.properties index cb376f4444..77ebc10aa4 100755 --- a/themes/src/main/resources/theme/base/account/messages/messages_en.properties +++ b/themes/src/main/resources/theme/base/account/messages/messages_en.properties @@ -84,6 +84,7 @@ role_read-token=Read token role_offline-access=Offline access role_uma_authorization=Obtain permissions client_account=Account +client_account-console=Account Console client_security-admin-console=Security Admin Console client_admin-cli=Admin CLI client_realm-management=Realm Management diff --git a/themes/src/main/resources/theme/base/login/messages/messages_en.properties b/themes/src/main/resources/theme/base/login/messages/messages_en.properties index 9ee8674d97..6aff85e12b 100755 --- a/themes/src/main/resources/theme/base/login/messages/messages_en.properties +++ b/themes/src/main/resources/theme/base/login/messages/messages_en.properties @@ -150,6 +150,7 @@ role_manage-account-links=Manage account links role_read-token=Read token role_offline-access=Offline access client_account=Account +client_account-console=Account Console client_security-admin-console=Security Admin Console client_admin-cli=Admin CLI client_realm-management=Realm Management diff --git a/themes/src/main/resources/theme/keycloak-preview/account/index.ftl b/themes/src/main/resources/theme/keycloak-preview/account/index.ftl index cf1a136149..22f46bbbba 100644 --- a/themes/src/main/resources/theme/keycloak-preview/account/index.ftl +++ b/themes/src/main/resources/theme/keycloak-preview/account/index.ftl @@ -86,7 +86,11 @@