Introduction#

The look and feel of all user-facing screens in the Curity Identity Server is customizable. Each profile — the authentication profile, the token profile, the user management profile and application profile — has specific resources that can be customized, and the process is the same for all. In this section, we explain the customization process in general and refer to the specific details that vary per profile (e.g., template names).

Understanding the Templating System#

All screens that are presented to the user are based on templates. The Curity Identity Server uses the Velocity templating language to allow for reusability between screens. The delivered templates use an include hierarchy that can be reused if desired. However the system allows for complete freedom to customize everything with your own template hierarchy.

A normal page without any modifications has the following template components:

Template layout of a login screen

The entry point for the screen is the inner most template like authenticator/html-form/authenticate/get.vm. This inner template defines the form as a body variable. In the end of the file it includes a layout. For a single column page, it includes the layouts/default.vm layout.

The layout is the common ground for all pages with similar characteristic. It in turn pulls in the fragments/logo.vm as well as the fragments/alerts.vm which is included if the page has any errors in the $_errors velocity variable.

#define ($_body)
<form method="post" action="$_authUrl">

    ...
    <label for="userName" class="$!_errorClass">#message("authenticator.html-form.authenticate.view.username")</label>
    <input type="text" name="userName" class="block full-width mb1 field-light $!_errorClass" autocapitalize="none"
           value="$!userNameValue">


    <label>#message("authenticator.html-form.authenticate.view.password")</label>
    <input type="password" name="password" class="block full-width mb1 field-light">

    <button type="submit" class="button button-fullwidth button-primary">#message(
        "authenticator.html-form.authenticate.view.authenticate")</button>

    <div class="mt3 clearfix">
        <div class="sm-col-12 center py2">
            <a href="$_authUrl/forgot-password">#message(
                "authenticator.html-form.authenticate.view.forgot-password")</a> <br/>
            <a href="$_authUrl/forgot-account-id">#message(
                "authenticator.html-form.authenticate.view.forgot-account-id")</a>
        </div>
        #if ($_registerUrl)
            <div class="sm-col-12 center">
                <a href="$_registerUrl" class="button button-light-grey button-fullwidth">#message(
                    "${_templatePrefix}.view.no-account")</a>
            </div>
        #end
    </div>

</form>
#end

#parse("layouts/default")

The highlighted line in the end shows how the template pulls in the layout. Another important note is that the template itself only defines a variable called $_body. This variable is used in layouts/default.vm to place the main content in the appropriate place for that type of layout.

The layout also pulls in things like headers, scripts, css definitions to make those easily customizable without touching many files.

<main class="container clearfix" role="main">

    <div class="login-well">

        #parse("fragments/logo")

        #if ($_errors || $_warnings || $_infoMessages)
            <div class="mt3 px3 lg-px4">
                #parse("fragments/alerts")
            </div>
        #end

        $!_body

        <div class="login-help center p2">
            <a href="">
                <i class="icon ion-information-circled"></i>
                #message("page.problems-logging-in")
            </a>
        </div>
    </div> ##login-well
</main>

#parse("fragments/footer")

Looking at the layout it becomes more clear how it pulls in the logo and the alerts. Line 13 highlights how it places the content of the $_body variable in the page.

The Template Override System#

The Curity Identity Server ships with a complete set of screens. The are referred to as core templates. These templates are used as fallbacks when there is no override template defined. The Curity Identity Server uses three levels of templates.

  1. Template Areas templates
  2. Overrides templates
  3. Core templates

Template hierarchy

When a template is included via the #parse velocity directive, the Curity Identity Server will first look in the Template Areas location for it. If the Curity Identity Server cannot find the template in there, it will look in the Overrides location, and then finally in Core.

A page can be made up of both Core templates and overridden templates. Lets look at a small example:

Example of overridden template

The example above shows the login template but with updated colors and updated logo. You can achieve this by overriding two templates and letting the rest be reused from core.

  1. Override fragments/logo.vm.
  2. Override fragments/css.vm to point to your custom css file.

With these two overrides all screens using the logo and stylesheets from the fragments includes will have a new look. Split apart it looks like this:

Structure of overrides

Overrides#

The overrides serve as server wide overrides. This means all screens may be affected by the override. It does not take into consideration which client or application is making the request, the overrides is always served if it exist. This is useful when you want to make a default look and feel, that is your organizations standard look. It can be anything from changing the logo and colors to completely rewriting the structure of the template include system.

To override a template, locate the template you want to override in $IDSVR_HOME/usr/share/templates/core. Create a copy and place the new template in the same relative path under $IDSVR_HOME/usr/share/templates/overrides. Modify the override template as needed.

Example: Overriding the Logotype#

  1. Locate the template $IDSVR_HOME/usr/share/templates/core/fragments/logo.vm
  2. Duplicate it as $IDSVR_HOME/usr/share/templates/overrides/fragments/logo.vm.
  3. Update the duplicate to point to another logotype image.

Notice how the relative path to the templates directory is kept when placing it in overrides - fragments/ is still there. This is important, since the main template, layouts/default.vm is looking for an include called fragments/logo.vm. So when the Curity Identity Server is trying to resolve the logo.vm it will start by looking in template-areas, then in overrides and finally in core.

As good practice, avoid updating any templates in core directly. Always place the updated template the overrides directory. This will ensure that future upgrades of the Curity Identity Server won’t collide with any changes made to the templates.

Template Areas#

Templates areas are a more advanced override technique. They allow for app-specific, authenticator or authentication action specific overrides, without changing every screen in the system.

Consider the following use-case.

Company Jivea has a sub-branded web-site where customers can buy shoes. It is quite different in it’s look and feel, so when a customer logs in to the shoe website the company wants to make sure that the feeling is still kept, and when they login to the regular website it must reflect that, with the logo kept etc.

Each site is represented by an Open ID Connect client. In the Curity Identity Server it’s possible to define a Template Area. The template area is set in the session when the clients requests authentication. When such a template area is found, the Curity Identity Server will first try to locate the template in that speciffic template area, if not found, it will look in the overrides, and if not found there, it will look in core.

Lets revisit the override example but also with a template area defined.

Example when using template areas

Of course there is nothing preventing you from overriding the entire layout to create a completely different feeling when authenticating from certain websites or apps. You can achieve such a behavior by overriding the layouts/default.vm template.

Deploying a Template Area#

In contrast to the overrides, the template areas are named. There can be many template areas serving different clients. So when deploying a template area, follow the same procedure as when deploying an override template but place the template in a directory with the same name as the template area that is configured for the client.

To deploy fragments/logo.vm for a template area called shoe-store place it in the following directory:

$IDSVR_HOME/usr/share/templates/template-areas/shoe-store/fragments/logo.vm

Message keys used by templates can also be specialized for each template area, as explained in the message lookup algorithm.

Loading Resources From the File System#

Template files are loaded from the <installation-dir>/usr/share/templates directory.

Message files are loaded from the <installation-dir>/usr/share/messages directory.

As with templates, the “root” directories are: core, overrides and template-areas/<template-area>.

Each messages directory is further sub-divided into Locales (e.g., sv, en_US, en, etc.).

Each of the Locale subdirectories and the templates directory share a common structure, described below. The Curity Identity Server uses this structure to locate the right message files and templates when rendering the resulting UI page.

The structure of both locale and templates directories is composed of the following subdirectories:

Templates#

Templates are searched for in the following “root” directories, in this order:

  1. template-areas/<template-area>
  2. overrides
  3. core

The template-areas directory contains instance-specific overrides. Each of the following places can be configured to use a specific template area to make it look and feel as an integral part of the application that is calling it:

  • Authenticator
  • Authentication Action
  • OAuth client
  • Service Provider

Example of selecting the template areas

Any general overrides that are not instance specific should be placed in the overrides directory which serves as a general override area.

The last area is the core. This is where the delivered templates are located. This area should not be modified, instead the overrides or the template-areas should be used to override the delivered templates. This convention makes sure that future upgrades of the server will be painless since all modifications are kept separate from the delivered templates.

An example of this hierarchy is shown in the following figure:

usr/share/messages
├── core
    └── ...
├── overrides
   ├── en
   └── messages
   └── sv
       └── messages
└── template-areas
    ├── custom-template-area
   ├── en
   ├── messages
   └── authenticator
       └── html-form
           └── messages
   └── sv
       └── messages
    └── another-template-area
        └── ...

usr/share/templates
├── core
    └── ...
├── overrides
   └── authenticator
       └── html-form
           └── get.vm
├── site.vm
└── template-areas
    ├── custom-template-area
   └── authenticator
       └── html-form
           └── get.vm
    └── another-template-area
        └── ...

Serving Templates via the Anonymous Endpoint#

It is possible to serve templates directly via the anonymous endpoint.

For example: suppose you would like to provide a Contact Information page. One way to do it would be to create a template under the anonymous views directory. For example, under the overrides directory:

  • <installation-dir>/usr/share/templates/overrides/views/anonymous/help/contact.vm

The template is located by following the logic described in the previous section. To be more specific, when the server receives a request to the /<anonymous-endpoint>/help/contact path, it will try to locate a template in the following locations, in this order:

  1. /overrides/views/anonymous/help/contact.vm
  2. /core/views/anonymous/help/contact.vm

Error Templates#

The Curity Identity Server error pages are defined in separate files based on the HTTP error code returned views/error/<HTTP_ERROR>/index.vm. These files use the layouts/error.vm, which, depending on where the error is originating and whether expose-detailed-error-messages is set in the profiles, might contain a detailed description of the error (this shouldn’t be enabled in a production environment). Also, the layout defines an _errorIdentifier, which is a combination of the $RequestId and possibly the $SessionId. This is shown in the templates so that when a user stumbles upon an error, it can be easier to find the logs from the request that produced the error and figure out the root cause.

Common Template Variables#

There are certain variables available in the context of the template. Those are summarized in the following table:

NameExplanationExample
$GuidExposes one method, generate, that can create a secure random GUID (UUID)$Guid.generate()
$RequestIdThe request IDrequest ID = $RequestId
$SessionIdThe session ID of the user (if available)session ID = $SessionId
$RegexUtilA utility that can be used to evaluate regular expressions$RegexUtil.replaceGroups($_recipientOfCommunication, "(.*?)(.{4})", [1], "x")
$_trA utility that can be used to transform text, namely encoding for HTML and EcmaScript$_tr.encodeHtml('<p>&"</p>') $_tr.encodeEcmaScript($myVar)
$ErrorCreates an error for a some message ID$Error.create("some.messageId.error")

The following methods are available in the $_tr variable. All take a string as input and return the converted string. If null is supplied, the same value is returned.

  • encodeHtml(input)
  • encodeHtmlAttribute(input)
  • encodeEcmaScript(input)
  • encodeJson(input)
  • encodeUrl(input)
  • encodeCss(input)
  • decodeHtml(input)
  • decodeHtmlAttribute(input)
  • decodeEcmaScript(input)
  • decodeJson(input)
  • decodeUrl(input)
  • decodeCss(input)

Authentication Profile Template Variables#

In addition to the common variables, the following variables are available in the context of templates of an Authenticator or Authentication Action:

NameExplanationExample
$_authUrlURL for the authentication endpoint of the current Authenticator
$_registerUrlURL for the registration endpoint of the current Authenticator
$_anonymousUrlURL for the anonymous endpoint of the current Authenticator
$_requestingOAuthClientData about the OAuth client that initiated the OAuth flow leading to the ongoing authentication flow. If the authentication flow is not related to an OAuth flow, this is an “empty” object.$_requestingOAuthClient.id $_requestingOAuthClient.properties.example
$_authFailUrlURL for an endpoint that allows ending the ongoing authentication flow with a failure, taking the user back to the originating application.

The following properties are exposed in the $_requestingOAuthClient variable:

  • id - The ID of the OAuth client, or null if a client is not available.
  • properties - The properties (map) of the OAuth client, or an empty map if a client is not available.

Note that accessing the $_requestingOAuthClient variable may require the Curity Identity Server to fetch client data from a Data Source (e.g. dynamically registered clients), adding some overhead to the ongoing request. This will be done at most once per request.

The following variables are also available in the context of templates of an Authentication Action:

NameExplanationExample
$_usernameContains the username of the intermediate authentication state that is active when an authentication action runs. This variable’s value must be properly encoded before being added into an HTML document$_tr.encodeHtml($_username)

Never Remove CSP#

One of the core templates is called csp.vm. This template produces Content Security Policies (CSP). CSPs close many dangerous attack vectors in all modern browsers.

Overriding the CSP template is possible, but you should only do so with care. Do not remove CSP entirely because you then most likely introduce security vulnerabilities.

Was this helpful?