Fix issue where admin2 was not enabled by default if account2 was disabled (#14914)

Refactoring ThemeSelector and DefaultThemeManager to re-use the same logic for selecting default theme as there used to be two places where one had a broken implementation

Closes #14889
This commit is contained in:
Stian Thorgersen 2022-10-17 15:17:54 +02:00 committed by GitHub
parent 90369f7540
commit f7490b7f7c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 39 additions and 42 deletions

View file

@ -17,6 +17,9 @@
package org.keycloak.theme; package org.keycloak.theme;
import org.keycloak.Config;
import org.keycloak.common.Profile;
import org.keycloak.common.Version;
import org.keycloak.provider.Provider; import org.keycloak.provider.Provider;
/** /**
@ -32,4 +35,14 @@ public interface ThemeSelectorProvider extends Provider {
*/ */
String getThemeName(Theme.Type type); String getThemeName(Theme.Type type);
default String getDefaultThemeName(Theme.Type type) {
String name = Config.scope("theme").get("default", Version.NAME.toLowerCase());
if ((type == Theme.Type.ACCOUNT) && Profile.isFeatureEnabled(Profile.Feature.ACCOUNT2)) {
name = name.concat(".v2");
} else if ((type == Theme.Type.ADMIN) && Profile.isFeatureEnabled(Profile.Feature.ADMIN2)) {
name = name.concat(".v2");
}
return name;
}
} }

View file

@ -49,12 +49,10 @@ public class DefaultThemeManager implements ThemeManager {
private final DefaultThemeManagerFactory factory; private final DefaultThemeManagerFactory factory;
private final KeycloakSession session; private final KeycloakSession session;
private List<ThemeProvider> providers; private List<ThemeProvider> providers;
private final String defaultTheme;
public DefaultThemeManager(DefaultThemeManagerFactory factory, KeycloakSession session) { public DefaultThemeManager(DefaultThemeManagerFactory factory, KeycloakSession session) {
this.factory = factory; this.factory = factory;
this.session = session; this.session = session;
this.defaultTheme = Config.scope("theme").get("default", Version.NAME.toLowerCase());
} }
@Override @Override
@ -63,44 +61,20 @@ public class DefaultThemeManager implements ThemeManager {
return getTheme(name, type); return getTheme(name, type);
} }
private String typeBasedDefault(Theme.Type type) {
boolean isProduct = Profile.isProduct();
if ((type == Theme.Type.ACCOUNT) && isAccount2Enabled()) {
return isProduct ? "rh-sso.v2" : "keycloak.v2";
}
return isProduct ? "rh-sso" : "keycloak";
}
@Override @Override
public Theme getTheme(String name, Theme.Type type) { public Theme getTheme(String name, Theme.Type type) {
if (name == null) {
name = defaultTheme;
}
Theme theme = factory.getCachedTheme(name, type); Theme theme = factory.getCachedTheme(name, type);
if (theme == null) { if (theme == null) {
theme = loadTheme(name, type); theme = loadTheme(name, type);
if (theme == null) { if (theme == null) {
theme = loadTheme(typeBasedDefault(type), type); String defaultThemeName = session.getProvider(ThemeSelectorProvider.class).getDefaultThemeName(type);
if (theme == null) { theme = loadTheme(defaultThemeName, type);
theme = loadTheme("base", type);
}
log.errorv("Failed to find {0} theme {1}, using built-in themes", type, name); log.errorv("Failed to find {0} theme {1}, using built-in themes", type, name);
} else { } else {
theme = factory.addCachedTheme(name, type, theme); theme = factory.addCachedTheme(name, type, theme);
} }
} }
if (!isAccount2Enabled() && theme.getName().equals("keycloak.v2")) {
theme = loadTheme("keycloak", type);
}
if (!isAccount2Enabled() && theme.getName().equals("rh-sso.v2")) {
theme = loadTheme("rh-sso", type);
}
return theme; return theme;
} }

View file

@ -47,12 +47,7 @@ public class DefaultThemeSelectorProvider implements ThemeSelectorProvider {
} }
if (name == null || name.isEmpty()) { if (name == null || name.isEmpty()) {
name = Config.scope("theme").get("default", Version.NAME.toLowerCase()); name = getDefaultThemeName(type);
if ((type == Theme.Type.ACCOUNT) && Profile.isFeatureEnabled(Profile.Feature.ACCOUNT2)) {
name = name.concat(".v2");
} else if ((type == Theme.Type.ADMIN) && Profile.isFeatureEnabled(Profile.Feature.ADMIN2)) {
name = name.concat(".v2");
}
} }
return name; return name;

View file

@ -13,11 +13,12 @@ import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.arquillian.annotation.DisableFeature; import org.keycloak.testsuite.arquillian.annotation.DisableFeature;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@DisableFeature(value = Profile.Feature.ACCOUNT2, skipRestart = true) // TODO remove this (KEYCLOAK-16228)
public class AdminConsoleLandingPageTest extends AbstractKeycloakTest { public class AdminConsoleLandingPageTest extends AbstractKeycloakTest {
private CloseableHttpClient client; private CloseableHttpClient client;
@ -44,16 +45,14 @@ public class AdminConsoleLandingPageTest extends AbstractKeycloakTest {
public void landingPage() throws IOException { public void landingPage() throws IOException {
String body = SimpleHttp.doGet(suiteContext.getAuthServerInfo().getContextRoot() + "/auth/admin/master/console", client).asString(); String body = SimpleHttp.doGet(suiteContext.getAuthServerInfo().getContextRoot() + "/auth/admin/master/console", client).asString();
String authUrl = body.substring(body.indexOf("var authUrl = '") + 15); Map<String, String> config = getConfig(body);
authUrl = authUrl.substring(0, authUrl.indexOf("'")); String authUrl = config.get("authUrl");
Assert.assertEquals(suiteContext.getAuthServerInfo().getContextRoot() + "/auth", authUrl); Assert.assertEquals(suiteContext.getAuthServerInfo().getContextRoot() + "/auth", authUrl);
String resourceUrl = body.substring(body.indexOf("var resourceUrl = '") + 19); String resourceUrl = config.get("resourceUrl");
resourceUrl = resourceUrl.substring(0, resourceUrl.indexOf("'")); Assert.assertTrue(resourceUrl.matches("/auth/resources/[^/]*/admin/keycloak.v2"));
Assert.assertTrue(resourceUrl.matches("/auth/resources/[^/]*/admin/([a-z]*|[a-z]*-[a-z]*)"));
String consoleBaseUrl = body.substring(body.indexOf("var consoleBaseUrl = '") + 22); String consoleBaseUrl = config.get("consoleBaseUrl");
consoleBaseUrl = consoleBaseUrl.substring(0, consoleBaseUrl.indexOf("'"));
Assert.assertEquals(consoleBaseUrl, "/auth/admin/master/console/"); Assert.assertEquals(consoleBaseUrl, "/auth/admin/master/console/");
Pattern p = Pattern.compile("link href=\"([^\"]*)\""); Pattern p = Pattern.compile("link href=\"([^\"]*)\"");
@ -77,4 +76,20 @@ public class AdminConsoleLandingPageTest extends AbstractKeycloakTest {
} }
} }
private static Map<String, String> getConfig(String body) {
Map<String, String> variables = new HashMap<>();
String start = "<script id=\"environment\" type=\"application/json\">";
String end = "</script>";
String config = body.substring(body.indexOf(start) + start.length());
config = config.substring(0, config.indexOf(end)).trim();
Matcher matcher = Pattern.compile(".*\"(.*)\": \"(.*)\"").matcher(config);
while (matcher.find()) {
variables.put(matcher.group(1), matcher.group(2));
}
return variables;
}
} }