keycloak-aplcache
Changes
docbook/reference/en/en-US/modules/themes.xml 174(+138 -36)
Details
docbook/reference/en/en-US/modules/themes.xml 174(+138 -36)
diff --git a/docbook/reference/en/en-US/modules/themes.xml b/docbook/reference/en/en-US/modules/themes.xml
index 3996b3a..db3d659 100755
--- a/docbook/reference/en/en-US/modules/themes.xml
+++ b/docbook/reference/en/en-US/modules/themes.xml
@@ -2,18 +2,18 @@
<title>Themes</title>
<para>
- Keycloak provides theme support for login forms and account management. This allows customizing the look
- and feel of end-user facing pages so they can be integrated with your brand and applications.
+ Keycloak provides theme support for web pages and emails. This allows customizing the look
+ and feel of end-user facing pages so they can be integrated with your applications.
</para>
<section>
<title>Theme types</title>
<para>
- There are several types of themes in Keycloak:
+ A theme can support several types to customize different aspects of Keycloak. The types currently available
+ are:
<itemizedlist>
<listitem>Account - Account management</listitem>
<listitem>Admin - Admin console</listitem>
- <listitem>Common - Shared resources for themes</listitem>
<listitem>Email - Emails</listitem>
<listitem>Login - Login forms</listitem>
<listitem>Welcome - Welcome pages</listitem>
@@ -29,6 +29,11 @@
from the drop-down box in the top left corner. Under <literal>Settings</literal> click on <literal>Theme</literal>.
</para>
<para>
+ To set the theme for the <literal>master</literal> Keycloak admin console set the admin console theme for
+ the <literal>master</literal> realm. To set the theme for per realm admin access control set the admin console
+ theme for the corresponding realm.
+ </para>
+ <para>
To change the welcome theme you need to edit <literal>standalone/configuration/keycloak-server.json</literal>
and add <literal>welcomeTheme</literal> to the theme element, for example:
<programlisting>
@@ -43,9 +48,8 @@
<section>
<title>Default themes</title>
<para>
- Keycloak comes bundled with default themes in <literal>standalone/configuration/themes</literal>. It is
- not recommended to edit these themes directly. Instead you should create a new theme to extend a default
- theme. A good reference is to copy the keycloak themes as these extend the base theme to add styling.
+ Keycloak comes bundled with default themes in <literal>standalone/configuration/themes</literal>. You should
+ not edit the bundled themes directly. Instead create a new theme that extends a bundled theme.
</para>
</section>
@@ -65,24 +69,63 @@
<para>
A theme can extend another theme. When extending a theme you can override individual files (templates, stylesheets, etc.).
The recommended way to create a theme is to extend the base theme. The base theme provides templates
- and a default message bundle. It should be possible to achieve the customization required by styling these
- templates.
+ and a default message bundle. If you decide to override templates bear in mind that you may need to update
+ your templates when upgrading to a new release to include any changes made to the original template.
+ </para>
+ <para>
+ Before creating a theme it's a good idea to disable caching as this makes it possible to edit theme resources
+ without restarting the server. To do this open <literal>../standalone/configuration/keycloak-server.json</literal>
+ for <literal>theme</literal> set <literal>staticMaxAge</literal> to <literal>-1</literal> and
+ <literal>cacheTemplates</literal> and <literal>cacheThemes</literal> to <literal>false</literal>. For example:
+<programlisting>[<![CDATA[
+"theme": {
+ "default": "keycloak",
+ "staticMaxAge": 01,
+ "cacheTemplates": false,
+ "cacheThemes": false,
+ "folder": {
+ "dir": "${jboss.server.config.dir}/themes"
+ }
+},
+]]></programlisting>
+ Remember to re-enable caching in production as it will significantly impact performance.
</para>
<para>
- To create a new theme, create a folder in <literal>.../standalone/configuration/themes/<theme type></literal>.
- The name of the folder is the name of the theme. Then create a file <literal>theme.properties</literal> inside the theme folder.
- The contents of the file should be:
+ To create a new theme create a directory for the theme in <literal>.../standalone/configuration/themes</literal>.
+ The name of the directory should be the name of the theme. For example to create a theme called <literal>example-theme</literal>
+ create the directory <literal>.../standalone/configuration/themes/example-theme</literal>. Inside the theme
+ directory you then need to create a directory for each of the types your theme is going to provide. For example
+ to add the login type to the <literal>example-theme</literal> theme create the directory
+ <literal>.../standalone/configuration/themes/example-theme/login</literal>.
</para>
- <programlisting>parent=base</programlisting>
<para>
- You have now created your theme. Check that it works by configuring it for a realm. It should look the same
- as the base theme as you've not added anything to it yet. The next sections will describe how to modify
- the theme.</para>
+ For each type create a file <literal>theme.properties</literal> which allows setting some configuration for
+ the theme, for example what theme it overrides and if it should import any themes. For the above example we
+ want to override the base theme and import common resources from the Keycloak theme. To do this create the
+ file <literal>.../standalone/configuration/themes/example-theme/login/theme.properties</literal> with the
+ following contents:
+<programlisting>[<![CDATA[
+parent=base
+import=common/keycloak
+]]></programlisting>
+ </para>
+ <para>
+ You have now created a theme with support for the login type. To check that it works open the admin console.
+ Select your realm and click on <literal>Themes</literal>. For <literal>Login Theme</literal> select
+ <literal>example-theme</literal> and click <literal>Save</literal>. Then open the login page for the realm.
+ You can do this either by login through your application or by opening <literal>http://localhost:8080/realms/<realm name>/account</literal>.
+ </para>
+ <para>
+ To see the effect of changing the parent theme, set <literal>parent=keycloak</literal> in <literal>theme.properties</literal>
+ and refresh the login page. To follow the rest of the documentation set it back to <literal>parent=base</literal>
+ before continuing.
+ </para>
<section>
<title>Stylesheets</title>
<para>
- A theme can have one or more stylesheets, to add a stylesheet create a file inside <literal>resources/css</literal> (for example <literal>resources/css/styles.css</literal>)
- inside your theme folder. Then registering it in <literal>theme.properties</literal> by adding:
+ A theme can have one or more stylesheets, to add a stylesheet create a file inside <literal>resources/css</literal>
+ (for example <literal>resources/css/styles.css</literal>) inside your theme folder. Then registering it
+ in <literal>theme.properties</literal> by adding:
</para>
<programlisting>styles=css/styles.css</programlisting>
<para>
@@ -90,6 +133,17 @@
as you want. For example:
</para>
<programlisting>styles=css/styles.css css/more-styles.css</programlisting>
+ For the example-theme above add <literal>example-theme/login/resources/css/styles.css</literal> with the
+ following content:
+<programlisting>[<![CDATA[
+#kc-form {
+ background-color: #000;
+ color: #fff;
+ padding: 20px;
+}]]></programlisting>
+ Then edit <literal>example-theme/login/theme.properties</literal> and add <programlisting>styles=css/styles.css</programlisting>.
+ Refresh the login page to see your changes. It's not pretty, but you can see how easily you can modify the
+ styles for your theme.
</section>
<section>
<title>Scripts</title>
@@ -121,9 +175,8 @@
<section>
<title>Messages</title>
<para>
- Text in the templates are loaded from message bundles. Currently internationalization isn't supported,
- but that will be added in a later release. A theme that extends another theme will inherit all messages
- from the parents message bundle, but can override individual messages. For example to replace
+ Text in the templates are loaded from message bundles. A theme that extends another theme will inherit
+ all messages from the parents message bundle, but can override individual messages. For example to replace
<literal>Username</literal> on the login form with <literal>Your Username</literal> create the file
<literal>messages/messages.properties</literal> inside your theme folder and add the following content:
</para>
@@ -134,31 +187,80 @@
<para>
Keycloak uses <ulink url="http://freemarker.org">Freemarker Templates</ulink> in order to generate HTML.
These templates are defined in <literal>.ftl</literal> files and can be overriden from the base theme.
- Check out the Freemarker website on how to form a template file.
+ Check out the Freemarker website on how to form a template file. To override the login template for the
+ <literal>example-theme</literal> copy <literal>../standalone/configuration/themes/base/login/login.ftl</literal>
+ to <literal>../standalone/configuration/themes/example-theme/login</literal> and open it in an editor. After
+ the first line (<#import ...>) add <literal><h1>HELLO WORLD!</h1></literal> then refresh
+ the page.
</para>
</section>
</section>
<section>
+ <title>Deploying themes</title>
+ <para>
+ Themes can be deployed to Keycloak by copying the theme directory to <literal>../standalone/configuration/themes</literal>
+ or it can be deployed as a module. For a single server or during development just copying the theme is fine, but
+ in a cluster or domain it's recommended to deploy as a module.
+ </para>
+ <para>
+ To deploy a theme as a module you need to create an jar (it's basically just a zip with jar extension) with
+ the theme resources and a file <literal>META/keycloak-server.json</literal> that describes the themes contained
+ in the archive. For example <literal>example-theme.jar</literal> with the contents:
+ <itemizedlist>
+ <listitem>META-INF/keycloak-themes.json</listitem>
+ <listitem>theme/example-theme/login/theme.properties</listitem>
+ <listitem>theme/example-theme/login/login.ftl</listitem>
+ <listitem>theme/example-theme/login/resources/css/styles.css</listitem>
+ </itemizedlist>
+ The contents of META-INF/keycloak-server.json in this case would be:
+<programlisting>[<![CDATA[
+{
+ "themes": [{
+ "name" : "example-theme",
+ "types": [ "login" ]
+ }]
+}
+]]></programlisting>
+ As you can see a single jar can contain multiple themes and each theme can support one or more types.
+ </para>
+ <para>
+ The deploy the jar as a module to Keycloak you can either manually create the module or use <literal>jboss-cli</literal>.
+ It's simplest to use <literal>jboss-cli</literal> as it creates the required directories and module descriptor
+ for you. To deploy the above jar <literal>jboss-cli</literal> run:
+<programlisting>[<![CDATA[
+ KEYCLOAK_HOME/bin/jboss-cli.sh --command="module add --name=org.example.exampletheme --resources=example-theme.jar"
+]]></programlisting>
+ If you're on windows run <programlisting>KEYCLOAK_HOME/bin/jboss-cli.bat</programlisting>.
+ </para>
+ <para>
+ This command creates <literal>modules/org/example/exampletheme/main</literal> containing <literal>example-theme.jar</literal>
+ and <literal>module.xml</literal>.
+ </para>
+ <para>
+ Once you've created the module you need to register it with Keycloak do this by editing
+ <literal>../standalone/configuration/keycloak-server.json</literal> and adding the module to <literal>theme/module/modules</literal>. For example:
+<programlisting>[<![CDATA[
+"theme": {
+ ...
+ "module": {
+ "modules": [ "org.example.exampletheme" ]
+ }
+}
+]]></programlisting>
+ </para>
+ <para>
+ If a theme is deployed to <literal>../standalone/configuration/themes</literal> and as a module the first
+ is used.
+ </para>
+ </section>
+
+ <section>
<title>SPIs</title>
<para>
For full control of login forms and account management Keycloak provides a number of SPIs.
</para>
<section>
- <title>Theme SPI</title>
- <para>
- The Theme SPI allows creating different mechanisms to load themes for the default FreeMarker based
- implementations of login forms and account management. To create a theme provider you will need to implement
- <literal>org.keycloak.freemarker.ThemeProviderFactory</literal> and <literal>org.keycloak.freemarker.ThemeProvider</literal>.
- </para>
- <para>
- Keycloak comes with two theme providers, one that loads themes from the classpath (used by default themes)
- and another that loads themes from a folder (used by custom themes). Looking at these
- would be a good place to start to create your own theme provider. You can find them inside
- <literal>forms/common-themes</literal> on GitHub or the source download.
- </para>
- </section>
- <section>
<title>Account SPI</title>
<para>
The Account SPI allows implementing the account management pages using whatever web framework or templating
diff --git a/forms/common-freemarker/src/main/java/org/keycloak/freemarker/ExtendingThemeManagerFactory.java b/forms/common-freemarker/src/main/java/org/keycloak/freemarker/ExtendingThemeManagerFactory.java
index 2fdaf05..42fa50e 100755
--- a/forms/common-freemarker/src/main/java/org/keycloak/freemarker/ExtendingThemeManagerFactory.java
+++ b/forms/common-freemarker/src/main/java/org/keycloak/freemarker/ExtendingThemeManagerFactory.java
@@ -11,9 +11,7 @@ import java.util.concurrent.ConcurrentHashMap;
*/
public class ExtendingThemeManagerFactory implements ThemeProviderFactory {
- private ConcurrentHashMap<ThemeKey, Theme> themeCache = new ConcurrentHashMap<ThemeKey, Theme>();
-
- private ExtendingThemeManager themeManager;
+ private ConcurrentHashMap<ThemeKey, Theme> themeCache;
@Override
public ThemeProvider create(KeycloakSession session) {
@@ -23,7 +21,7 @@ public class ExtendingThemeManagerFactory implements ThemeProviderFactory {
@Override
public void init(Config.Scope config) {
if(Config.scope("theme").getBoolean("cacheThemes", true)) {
- themeCache = new ConcurrentHashMap<ThemeKey, Theme>();
+ themeCache = new ConcurrentHashMap<>();
}
}
diff --git a/forms/common-freemarker/src/main/java/org/keycloak/freemarker/FreeMarkerUtil.java b/forms/common-freemarker/src/main/java/org/keycloak/freemarker/FreeMarkerUtil.java
index 8f2dc0e..e41d671 100755
--- a/forms/common-freemarker/src/main/java/org/keycloak/freemarker/FreeMarkerUtil.java
+++ b/forms/common-freemarker/src/main/java/org/keycloak/freemarker/FreeMarkerUtil.java
@@ -20,7 +20,7 @@ public class FreeMarkerUtil {
public FreeMarkerUtil() {
if (Config.scope("theme").getBoolean("cacheTemplates", true)) {
- cache = new ConcurrentHashMap<String, Template>();
+ cache = new ConcurrentHashMap<>();
}
}
diff --git a/forms/common-themes/src/main/java/org/keycloak/theme/FolderTheme.java b/forms/common-themes/src/main/java/org/keycloak/theme/FolderTheme.java
index 0edc92e..7d9ce2a 100644
--- a/forms/common-themes/src/main/java/org/keycloak/theme/FolderTheme.java
+++ b/forms/common-themes/src/main/java/org/keycloak/theme/FolderTheme.java
@@ -18,11 +18,13 @@ public class FolderTheme implements Theme {
private String parentName;
private String importName;
private File themeDir;
+ private String name;
private Type type;
private final Properties properties;
- public FolderTheme(File themeDir, Type type) throws IOException {
+ public FolderTheme(File themeDir, String name, Type type) throws IOException {
this.themeDir = themeDir;
+ this.name = name;
this.type = type;
this.properties = new Properties();
@@ -36,7 +38,7 @@ public class FolderTheme implements Theme {
@Override
public String getName() {
- return themeDir.getName();
+ return name;
}
@Override
diff --git a/forms/common-themes/src/main/java/org/keycloak/theme/FolderThemeProvider.java b/forms/common-themes/src/main/java/org/keycloak/theme/FolderThemeProvider.java
index df65369..90d8ba6 100755
--- a/forms/common-themes/src/main/java/org/keycloak/theme/FolderThemeProvider.java
+++ b/forms/common-themes/src/main/java/org/keycloak/theme/FolderThemeProvider.java
@@ -29,7 +29,7 @@ public class FolderThemeProvider implements ThemeProvider {
@Override
public Theme getTheme(String name, Theme.Type type) throws IOException {
File themeDir = getThemeDir(name, type);
- return themeDir.isDirectory() ? new FolderTheme(themeDir, type) : null;
+ return themeDir.isDirectory() ? new FolderTheme(themeDir, name, type) : null;
}
@Override