APM Advanced Customization Examples with Modern Template, v15.1+
Introduction
This guide will walk through how the logon, webtop, and other UI pages are created by APM, how it works, and some examples.The new APM modern template has an updated look in both mobile and desktop browsers. It uses the popular Preact framework to provide a consistent and familiar end user experience.
How to activate the new customization system
New policies created in 15.1 and later default to the new Modern template. Existing policies made before 15.1 continue to use the Standard template.
When creating a new access policy:
You can see the customization types applied to all access policies in the Per-Session access policy menu:
Customization Sections
Basic, General, and Advanced Customization
APM has different ways to customize, depending on the desired complexity. Some administrators simply want to change colors, while others would prefer to completely rewrite the APM user-facing HTML and CSS so they have similar branding to other corporate web properties. As is typical with CSS, style customizations can be applied simultaneously with later style changes overriding earlier ones.
Basic Customization
Simple customization settings such as images, titles, captions, and colors are applied to resources and policies using Basic Customization. The tables and screenshot below detail the settings.
Elements in Basic Customization
Header/Footer/Title
- Header Image for Desktop (Max height: 60px)
- Header Image for Mobile (Max height: 30px)
Layout Settings
- Maximum viewport width for applying small (mobile) screen styles (px)
- Browser width for mobile clients
- Minimum viewport width for applying large (desktop) screen styles (px)
- Browser width for desktop clients
Colors (see image for sections)
- Active Links and Buttons Color
- Footer Background Color
- Form Background Color
- Header Color
- Page Background Color
- Solid Button Text Color
- Text Color
- Top Strip Color
General Customization
General Customization offers a more advanced tree view of the Basic Customization settings as well as text options for user-facing messages. Like Basic customization, the settings are applied individually to each access policy and policy item via the item’s XML file specified in the cache-path parameter of the associated customization group configuration object.
To use General Customization
- Create the policies and/or resources you would like to customize.
- Find them in the tree view.
- Make the changes.
- Perform the standard 3-step save process: Save Draft, Save, then Apply the access policy.
You use General Customization to apply changes to the informational text strings and error messages that are displayed to users. Browse the configuration tree to see the available customization areas.
The settings are divided into Branding and Text. Text are the localized messages that are displayed to the end users, including associated HTML. User-facing status and text messages can be selected in the Text tab. Branding options are about page styling, colors, fonts, and the like. These are selected in the Branding tab.
Special General Options
APM customization has a few non-branding and non-text special options in the configuration tree.
Disable all external scripts and styles
The new Modern customization includes a new resource loader feature. This feature loads all added CSS and JS resources dynamically, including 3rd party external code. You use this option like a “Revert” to restore the default branding in case there is some unknown trouble. If enabled, it disables loading of all external CSS and JS, including the APM-hosted user-XXXX.js and user-XXXX.css files.
External Javascript / CSS
You can now easily add external javascript references, for libraries such as JQuery that you would like your users to load from an external CDN. Historically this would present a security problem because the CDN content may be vulnerable to malicious injection. APM uses the W3C subresource integrity feature(https://www.w3.org/TR/SRI/) mechanism to ensure that the external files are not tampered.
You can also specify external scripts manually in user-XXXX.js, but using the inbuilt APM script-loader mechanism allows us to trap loading errors and disable all external scripts globally, in case of any problems (see the previous section).
To use this feature:
- Find the checksum* and URL of your resource. jQuery makes this very simple: It’s directly on their CDN page. Alternatively, you can compute them using srihash.org.
- Place the values into External Scripts / Styles.
- Save, Apply the access policy, and visit the access policy virtual.
*Note*: APM’s end-user pages are built using Preact with built-in libraries, so don't load another copy of Preact using this mechanism. See the Advanced Examples section below for usage ideas.
If the checksum is incorrect the stock APM javascript will function correctly, but the external resource will not be loaded and the browser will produce a “Failed to find a valid digest in the integrity attribute for resource ‘xxxxxx’” error in the console similar to this screenshot:
* Supported checksum mechanisms are SHA-256, SHA-384, or SHA-512.
Advanced Customization
Use Advanced Customization to edit or place code directly into the files that are referenced from the primary APM user-facing HTML. Common settings are available which load on all pages, along with separate CSS and JS for each policy item that is present in the policy. Generally, the CSS/JS for each policy item load after the common settings so later settings will override earlier ones.
You must first add policy items to customize before customizing them. This is a customization tree view before and after adding Logon Page to access policy:
Before
After
Operation of Advanced Customization
With Advanced Customization, you can do essentially any styling you want using standard CSS.
Advanced Customization has some common settings, agent settings, and some special settings. After making any change, Save Draft, then Save., then Apply the access policy.
Common settings
These two files (user-common.css and user-common.js) are loaded on all* APM user-facing pages, including policy evaluation (logon, message, etc), webtop, and logout.
Use these if you want to change a page style in all areas. For example, perhaps we always want to hide the header and footer and add a background image. To do that, we can simply add some CSS to user-common.css to set a few properties targeting the apmui-header, apmui-main, and apmui-footer CSS selectors.
Example: logon page customization
Hide header and footer, and add a picture:
*Note*: You should usually make logon-specific changes on the logon page rather than “common”, since the webtop places some GUI links in apmui-header. Hiding the header removes access to these links!
You can use user-common.js to load a tracker such as Google Analytics.
Example: Google Analytics
Customization Types
There are two broad categories for the customization of APM objects:
Resources are Assigned during per-session access policy execution. They include customizable icons, captions, and descriptions that are visible on the APM full webtop (sometimes called a portal).
- OAuth Client App
- OAuth Scope
- App Tunnel
- Network Access
- Remote Desktop
- SAML
- Web App (Portal Access)
- Webtop Link
- Webtop Section
Non-Resources each have different configuration properties
- General
- Framework Installation
- EPS
- Logout (Ending Denied)
- Error message
- Decision Box
- Confirm/Continue
- Ending Denied
- Message Box
- Oauth Authz
- Webtop
Screenshots
*Example*: Simple resource customization of a webtop link resource
End-User view from APM webtop:
Troubleshooting Tips: Configuration Structure
Resource customization settings, text strings, and image files are stored as interdependent configuration and file objects. When troubleshooting, check the following configuration areas.
This diagram represents the dependencies:
This table represents the item details, and troubleshooting tips:
NOTE: To create resource customization using scripting or automation, they must be created all at once using a TMSH transaction rather than individually because of the interdependency between resources, profiles, policies, policy items, agents, and customization groups. To get started, use the GUI to create a policy you like, then review the configuration objects defined in tmsh list apm. The objects inter-referred-to must be copied into a transaction. equivalent create apm xxxx commands inside of a transaction. For detail on transactions with APM policies, see
tmsh help apm policy access-policy tmsh help cli transaction
HTML Rendering Details
Access profiles, Per Request Policies and other objects (customized independently from an access profile) share similar syntax and structure. Each object has customization settings. Access Profiles have multiple groups of customization settings. Every time you change customization, it generates a set of files that are combined to form the user-displayed page.
Settings (color, font, text, and so on) for the header and footer can be defined in access profile customization. Settings for the location and alignment of the content area can also be defined in access profile customization. Settings for resources displayed in the APM Webtop can be defined in the resource's configuration area (see payroll example above).
APM Sandbox / Image Hosting
To place images or other files in APM for convenient access by end users, use the Hosted Content feature.
- On a BIG-IP system, on the Main tab, click Access > Webtops > Hosted Content > Manage Files.
- Upload an image file.
- Click Upload >> Manage Access, and make sure the checkbox for your access policy attached to the virtual server is selected.
- Access the file at the location indicated in the Publicly Accessible URI column.
General Examples
Execute external javascript code after Logon Page browser rendering is complete.
This example can be placed into user-logon.js to use the D3 library to display a small pop-up message. Additional code can be inserted for custom functions.
define(["require", "exports", "tslib", "module", "apmui/page/logon/View"], function (require, exports, tslib_1, module, View_1) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); requirejs.config({ map: { 'apmui/master/View': { 'apmui/page/logon/View': module.id, }, }, }); /* Replacement View component */ var CustomLogonView = /** @class */ (function (_super) { tslib_1.__extends(CustomLogonView, _super); function CustomLogonView() { return _super !== null && _super.apply(this, arguments) || this; } CustomLogonView.prototype.componentDidMount = function () { _super.prototype.componentDidMount.call(this); requirejs(['https://d3js.org/d3.v6.min.js'], function (d3) { // Place your code inside this function d3.select("form").append("span") .text("Hello from D3 library"); }); }; return CustomLogonView; }(View_1.default)); exports.default = CustomLogonView; });
Execute local javascript code inside Logon Page.
This example can be placed into user-logon.js to perform custom actions.
define(["require", "exports", "tslib", "module", "apmui/page/logon/View"], function (require, exports, tslib_1, module, View_1) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); requirejs.config({ map: { 'apmui/master/View': { 'apmui/page/logon/View': module.id, }, }, }); /* Replacement View component */ var CustomLogonView = /** @class */ (function (_super) { tslib_1.__extends(CustomLogonView, _super); function CustomLogonView() { return _super !== null && _super.apply(this, arguments) || this; } CustomLogonView.prototype.componentDidMount = function () { _super.prototype.componentDidMount.call(this); alert('PLACE CUSTOM CODE HERE'); }; return CustomLogonView; }(View_1.default)); exports.default = CustomLogonView; });
Advanced Examples
These use TypeScript and preact You should be familiar with these technologies and their usage. To use these examples, you need a standard TypeScript/NodeJS+NPM build environment. This can be most easily achieved by using Linux, Microsoft Windows Subsystem for Linux (WSL), or Mac, then installing NodeJS which includes NPM.
The examples are attached to this article as a ZIP archive. Download and decompress this file to a suitable location on your workstation.
Read README.md from the package. Each example here assumes you have already downloaded the package and run npm install; npm run build. The compilation result is placed in the dist directory. For each one of the examples, you simply copy the user-xxxx.css and user-xxxx.js files into the correct object in Advanced Customization.
To make changes to these examples, modify the files in src, then npm run build, as specified in README.md.
Example 1: Decision box with more options
By default, the APM Decision Box has only two choices.
We can use this advanced customization example to append additional choices. Follow this procedure:
- Add a decision box to your access policy.
- Navigate to customization-examples/dist/decisionBox-more-options and copy the contents of user-decision.js to the appropriate area in Advanced Customization.
- Click Save Draft, Save, and apply the access policy.
- As a user, navigate to the decision box on the APM virtual server.
- Now the decision box has 4 options rather than two.
- The option and icon detail are in the example user-decision.ts source file:
The result: value is the raw POST data, which is transferred from the client browser when the my.policy page is submitted. It must match an agent expression in the branch rules defined for the decision box object. As with all other agents, the branch rules must be defined in the policy-item configuration so that the additional branches are available in the VPE for use:
Once these additional branch rules are defined, they can be added to the VPE flow:
When a user makes a choice, it appears in log files thusly:
To host your own icons, you can use the APM sandbox hosting feature, discussed elsewhere in this doc.
Example 2: Logon box custom component
This example adds a custom Preact component to the Logon Box.
- Add a Logon Page to your access policy, then copy the example dist code into your user-logon.js and user-logon.css files.
- Output:
Example 3: Logon custom view
This is an example of how to obtain a JSON-formatted dump of data available programmatically.
Add the code from logon-custom-view to your APM policy files, then visit the APM virtual. You will see JSON data that provides the detailed data available.
Example 4: PIN Pad replaces standard forms logon page
This is an example of an alternative method of rendering a standard forms logon page with a polymorphic virtual PIN pad. It uses Preact and CSS to achieve this result.
Note: A similar result with a virtual keyboard is possible as well, using other modules available via npm. This requires Preact development.
As with the other examples, compile the TypeScript and place the dist’s user-logon.css and user-logon.js into the APM’s advanced customization area for your logon agent. The result when visiting this logon page is illustrated in this screenshot:
Example 5: Validation of input fields
logon-validate-domain contains a sample that has an example of input field validation:
The input validation logic can be changed with the following TypeScript:
This kind of validation logic can be extended for almost any purpose.
Example 6: Pin resource to top of webtop
Recently-used-resources implements a mechanism that uses local storage to track how many times a resource has been clicked. It also creates a new webtop section that displays most-clicked-on resources. You must have a full webtop and multiple resources assigned to the user (any type is fine).
Use this example like the others: Copy the dist directory files user-webtop.css and user-webtop.js to the advanced customization object and click Save Draft, then Save, and apply the access policy. Note that you may have to clear BIG-IP or browser cache to see the update.
Take a few minutes to examine the browser's Local Storage contents while clicking various favorites assigned to the user.
Example 7: Pin resources on full webtop
Most application portals offer some kind of system to save often-used resources at the top of the list. This example uses HTML5 Browser Local Storage to save the user’s resources and render them at the top of the webtop application portal. You must assign a full webtop and multiple resources to the user.
Use this example like the others: Copy the dist directory files user-webtop.css and user-webtop.js to the advanced customization object and click Save Draft, then Save, and apply the access policy. Note that you may have to clear BIG-IP or browser cache to see the update.
Afterwards, logon as a user to the webtop and click the corner pin icon to add the resource to Pinned Resources.
- Try to log out and back in and see that the resource(s) are saved.
- Check the browser developer tools to query the local storage contents.
Examples Conclusion
We hope these examples are helpful to performing customization of APM web pages. Please let us know of any further examples that you would like to share!
Request For Examples
We have received the following requests for examples and hope to add these soon. Let us know if you can contribute!
- Simplest way to add an HTML link and text into the logon page
- Simplest way to add a select box to a logon page
- Example virtual keyboard logon page
Attributions / Licensing / Support Status
Support Status:
F5 Support cannot provide assistance with TypeScript, JavaScript, or Preact coding or web development. To validate the operation of any of these examples, standard web development practices should be used.
F5 code:
These examples include code produced by F5 intended to showcase the possibilities of the v15.1.0 APM customization system and can be used by any APM customer. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3rd Party Code:
As with most open source software, each module in this example includes a separate license (MIT, CC, etc). Before using any of these in a production environment, please review the licensing requirements for each NPM package in node_modules.
Media:
Beach scene used in customization examples: Stones in the Beach
By Xavierfsc - Own work, CC BY 4.0, https://commons.wikimedia.org/w/index.php?curid=84430607
- DmitryTNimbostratus
Hello! how do I get an authorized user's email on the webtop page? Via the user-webtop file.js in the store object - this data is missing, session is an empty string. Thanks
import { App, EventType, PageType } from 'apmui'; const app = App.get(); app.subscribe(EventType.WEBTOP_CONFIGURATION_COMPLETE, (_, store) => { if (store.pageType !== PageType.WEBTOP) { return; } const session = '%{session}'; const sessionJSON = JSON.stringify('%{session}', null, 2); console.log({ store, session, sessionJSON }); });
- EjesNimbostratus
I would like to do Pin Pad Web Customizing.
Could you please tell me how to do it?- Lucas_ThompsonEmployee
The method to change the logon page to a PIN pad outlined in this article, in Example 4.
- EjesNimbostratus
Example 4 only says that Preact and CSS are used, and there is no explanation as to which CSS syntax should be applied to which CSS, how to use Preact, etc.
I'm not a web designer or developer, so I don't really know what Preact is.
Could you please tell me some details?
- kimhenriksenCirrostratus
Can someone share the templates? The old link is dead.
- PSilvaRet. Employee
We'll pass this on!
ps
- krazzy522Altocumulus
Dear PSilva
I have added div to JS file like below and added CSS to the divthank you for your time and support
var divlogo = document.createElement("div");
divLogo.id = "logo";
document.body.appendChild(divLogo);
var img = document.createElement("img");
img.setAttribute("src", "logo.png");
divLogo.appendChild(img); - krazzy522Altocumulus
Dear
I need the example code to customize decision box, as same as logon page.
- Jad_Tabbara__J1Cirrostratus
Hello,
Very helpfull thanks.
Just to share with the community the following example that allows you to read a session variable from the "user-logon.js".
In the "standard" customization manner the syntax in the "logon.inc" is:var plateformOS = "%{session.custom.last.platform}";
In the "modern" way, it is similar you can use in the "user-logon.js" file following:
newDiv.innerHTML = '<img id="os_img" src="%{session.custom.last.platform}" height="30" width="30">';
CCL => same syntax works also in the modern customization
- papouNimbostratus
Hi!
How can we adjust the "Execute local javascript code inside Logon Page." general example so we can perform custom actions on full webtop, after browser rendering is complete?
I want to target and add elements inside each apmui-webtop-resource with javascript.Unfortunately I am not able to find my way through the specific examples you have for webtop.
Thanks!
- JacobAxNimbostratus
Hi Lucas,
Very helpful stuff,thanks
Could you publish examples how to insert javascript after decisionbox is done rendering same with messageboxes?