diff --git a/docs/documentation/upgrading/topics/changes/changes-26_6_0.adoc b/docs/documentation/upgrading/topics/changes/changes-26_6_0.adoc index e04a23cd5e5..de7ba7a52e4 100644 --- a/docs/documentation/upgrading/topics/changes/changes-26_6_0.adoc +++ b/docs/documentation/upgrading/topics/changes/changes-26_6_0.adoc @@ -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 diff --git a/docs/guides/ui-customization/themes.adoc b/docs/guides/ui-customization/themes.adoc index 866fb46454f..c9743e0b79e 100644 --- a/docs/guides/ui-customization/themes.adoc +++ b/docs/guides/ui-customization/themes.adoc @@ -130,6 +130,7 @@ Theme properties are set in the file `/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 diff --git a/server-spi/src/main/java/org/keycloak/theme/Theme.java b/server-spi/src/main/java/org/keycloak/theme/Theme.java index fd0c0e44149..66e2328ba69 100755 --- a/server-spi/src/main/java/org/keycloak/theme/Theme.java +++ b/server-spi/src/main/java/org/keycloak/theme/Theme.java @@ -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 abstract 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)); + } + } diff --git a/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java index 1ccfc3aee59..f232c0e3733 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java @@ -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); diff --git a/services/src/main/java/org/keycloak/theme/DefaultThemeManager.java b/services/src/main/java/org/keycloak/theme/DefaultThemeManager.java index 0d1eb1139e8..e412c3ac0e2 100755 --- a/services/src/main/java/org/keycloak/theme/DefaultThemeManager.java +++ b/services/src/main/java/org/keycloak/theme/DefaultThemeManager.java @@ -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) { diff --git a/tests/base/src/test/java/org/keycloak/tests/admin/ServerInfoTest.java b/tests/base/src/test/java/org/keycloak/tests/admin/ServerInfoTest.java index f716a8643bb..15cfabbd659 100644 --- a/tests/base/src/test/java/org/keycloak/tests/admin/ServerInfoTest.java +++ b/tests/base/src/test/java/org/keycloak/tests/admin/ServerInfoTest.java @@ -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()); diff --git a/themes/src/main/resources-community/theme/base/account/theme.properties b/themes/src/main/resources-community/theme/base/account/theme.properties index f1e814de81e..ab156ceaa81 100644 --- a/themes/src/main/resources-community/theme/base/account/theme.properties +++ b/themes/src/main/resources-community/theme/base/account/theme.properties @@ -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 diff --git a/themes/src/main/resources-community/theme/base/admin/theme.properties b/themes/src/main/resources-community/theme/base/admin/theme.properties index f7a801cd02e..3ddde33ad94 100644 --- a/themes/src/main/resources-community/theme/base/admin/theme.properties +++ b/themes/src/main/resources-community/theme/base/admin/theme.properties @@ -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 diff --git a/themes/src/main/resources-community/theme/base/email/theme.properties b/themes/src/main/resources-community/theme/base/email/theme.properties index c7ae20bab28..3dc3dd09f7d 100644 --- a/themes/src/main/resources-community/theme/base/email/theme.properties +++ b/themes/src/main/resources-community/theme/base/email/theme.properties @@ -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 diff --git a/themes/src/main/resources-community/theme/base/login/theme.properties b/themes/src/main/resources-community/theme/base/login/theme.properties index 07107cffc4a..383690c572d 100644 --- a/themes/src/main/resources-community/theme/base/login/theme.properties +++ b/themes/src/main/resources-community/theme/base/login/theme.properties @@ -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