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