Add abstract property for themes and do not display base for selection

Closes #41924

Signed-off-by: rmartinc <rmartinc@redhat.com>
This commit is contained in:
rmartinc 2026-01-20 16:13:01 +01:00 committed by Marek Posolda
parent ea2083ed2c
commit 7e20b87136
10 changed files with 31 additions and 5 deletions

View file

@ -50,6 +50,10 @@ To analyze rejected requests in the server log, enable debug logging for `org.ke
To revert to the previous behavior and to accept matrix parameters set the option `http-accept-non-normalized-paths` to `true`.
With this configuration, enable and review the HTTP access log to identify problematic requests.
=== The base themes are now abstract
All the `base` themes are now tagged as **abstract**, and they are not listed in the admin console to be selected (**Realm Settings** -> **Themes** tab). They were always intended to be only extended but not used directly. If you use one of them, it will continue working (or not working) in the same way but cannot be selected using the admin console anymore. Please select one of the available default themes or create your own one.
// ------------------------ Deprecated features ------------------------ //
== Deprecated features

View file

@ -130,6 +130,7 @@ Theme properties are set in the file `<THEME TYPE>/theme.properties` in the them
* parent - Parent theme to extend
* import - Import resources from another theme
* abstract - Boolean that, when present and `true`, marks the theme is only used as base for other extensions and is not displayed to be selected in the admin console on the realm themes page. Examples of this are the `base` themes described on this guide.
* common - Override the common resource path. The default value is `common/keycloak` when not specified. This value would be used as value of suffix of ${r"`${url.resourcesCommonPath}`"}, which is used typically in freemarker templates (prefix of ${r"`${url.resoucesCommonPath}`"} value is theme root uri).
* styles - Space-separated list of styles to include
* locales - Comma-separated list of supported locales

View file

@ -32,6 +32,7 @@ public interface Theme {
String ACCOUNT_RESOURCE_PROVIDER_KEY = "accountResourceProvider";
String CONTENT_HASH_PATTERN = "contentHashPattern";
String ABSTRACT_PROPERTY = "abstract";
enum Type { LOGIN, ACCOUNT, ADMIN, EMAIL, WELCOME, COMMON };
@ -102,4 +103,14 @@ public interface Theme {
}
}
/**
* Method to know if the theme is just an abstract theme (only to be extended by
* other themes). By default it just checks the <em>abstract</em> property.
* @return true if abstract, false if not
* @throws IOException Some error reading the properties
*/
default boolean isAbstract() throws IOException {
return Boolean.parseBoolean(getProperties().getProperty(ABSTRACT_PROPERTY));
}
}

View file

@ -233,7 +233,8 @@ public class ServerInfoAdminResource {
try {
Theme theme = session.theme().getTheme(name, type);
// Different name means the theme itself was not found and fallback to default theme was needed
if (theme != null && name.equals(theme.getName())) {
// Do not include abstract themes that can only be extended (like base)
if (theme != null && name.equals(theme.getName()) && !theme.isAbstract()) {
ThemeInfoRepresentation ti = new ThemeInfoRepresentation();
ti.setName(name);

View file

@ -208,6 +208,11 @@ public class DefaultThemeManager implements ThemeManager {
return themes.get(0).getType();
}
@Override
public boolean isAbstract() throws IOException {
return themes.get(0).isAbstract();
}
@Override
public URL getTemplate(String name) throws IOException {
for (Theme t : themes) {

View file

@ -65,10 +65,10 @@ public class ServerInfoTest {
assertNotNull(info.getThemes());
assertNotNull(info.getThemes().get("account"));
Assert.assertNames(info.getThemes().get("account"), "base", "keycloak.v3");
Assert.assertNames(info.getThemes().get("admin"), "base", "keycloak.v2");
Assert.assertNames(info.getThemes().get("email"), "base", "keycloak");
Assert.assertNames(info.getThemes().get("login"), "base", "keycloak", "keycloak.v2");
Assert.assertNames(info.getThemes().get("account"), "keycloak.v3");
Assert.assertNames(info.getThemes().get("admin"), "keycloak.v2");
Assert.assertNames(info.getThemes().get("email"), "keycloak");
Assert.assertNames(info.getThemes().get("login"), "keycloak", "keycloak.v2");
Assert.assertNames(info.getThemes().get("welcome"), "keycloak");
assertNotNull(info.getEnums());

View file

@ -1 +1,2 @@
locales=ar,az,ca,cs,da,de,el,en,es,eu,fa,fr,fi,hr,hu,it,ja,kk,ky,lt,lv,nl,no,pl,pt,pt-BR,ro,ru,sk,sl,sv,th,tr,uk,zh-CN,zh-TW
abstract=true

View file

@ -1 +1,2 @@
locales=ar,ca,de,el,en,es,eu,fa,fr,fi,hr,it,ja,kk,ky,lt,lv,nl,no,pl,pt,pt-BR,ro,ru,sl,sv,uk,zh-CN,zh-TW
abstract=true

View file

@ -1 +1,2 @@
locales=ar,az,ca,cs,da,de,el,en,es,eu,fa,fr,fi,hr,hu,it,ja,kk,ky,lt,nl,no,pl,pt,pt-BR,ro,ru,sk,sl,sv,th,tr,uk,zh-CN,zh-TW
abstract=true

View file

@ -1 +1,2 @@
locales=ar,az,ca,cs,da,de,el,en,es,eu,fa,fr,fi,hr,hu,it,ja,kk,ko,ky,lt,lv,nl,no,pl,pt,pt-BR,ro,ru,sk,sl,sv,th,tr,uk,zh-CN,zh-TW
abstract=true