Introduction and Background
This post will provide guidance on adding login footers and headers in various areas of the Citrix Gateway / AAA-TM logon page on Citrix ADCs for use with RfWebUI-based themes (as of 2022 the rest are or are being deprecated, X1 included) for use in nFactor or non-nFactor login pages. Littered throughout the Internet are countless guides on adding such items to logon pages. Still, many have not aged well (product changes) and add to the confusion and wasted time for what is otherwise a relatively simple task.
Although we can add custom text to a Citrix authentication page via login schemas, it’s easy enough to do so via the AppExpert Rewrite capabilities of the Citrix ADC, a common means of adding in such things as EULA logon footers in the past. This has the added benefit of easily swapping in and out different configurations to say, update a message of the day, advise of maintenance, etc. We’ll be making use of this feature through this guide to customize the login page. Special thanks to our Allen Perry for assistance in fleshing out the various page elements optimal for injecting text or images for use in this guide.
We will be walking through the creation of several rewrite policies and actions as per below screenshots.
Example 1 – Form-Content Element
There are multiple places to insert customizations and depending on which you choose, the results will be different. The most aesthetically pleasing (in our mind) is within the form-content element.
With RFWebUI the page content is centered horizontally and vertically in a div element <div class=”form-content”>. Text and info added within this area will appear relatively centered to the overall page as opposed to some of the other examples we will walk through.
If you want the custom content to scale within the boundaries of the established theme, any custom elements must be inserted within this div element.
In order to place a top logo or text that scales with the form content it must be inserted directly after <div class=”form-content”> and before <div class=”form-container”>.
In the following example, we will create a rewrite action that when linked to an appropriate policy and bound to a Citrix Gateway vServer (Rewrite-Response) will render HTML text directly under the “Log On” button.
add rewrite action rw_act_custom_logon_text_form-content insert_after_all "HTTP.RES.BODY(300000).SET_TEXT_MODE(IGNORECASE)" "\"<div id=customHelp><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p></div>\"" -search q{text("<p class=\"back-to-choices\"><a href=\"#\" class=\"authentication-link _ctxstxt_UseAnotherLogonOption\"></a></p>")} add rewrite policy rw_pol_custom_logon_text "HTTP.REQ.URL.CONTAINS(\"/tmindex.html\") || HTTP.REQ.URL.CONTAINS(\"/index.html\")" rw_act_custom_logon_text_form-content
Our result outcome is presented here.
We can also inject an image in the header area as seen in this example’s first image, by use of the following action and policy, swapping out the image link for one found on your website or hosted within the portal theme directory of the Citrix ADC. Note that this is an additional rewrite policy to be added to the vServer separate from the others in this example, should you wish to combine a header/footer plus an image.
add rewrite action rw_act_custom_logon_toplogo replace_all "HTTP.RES.BODY(300000)" q{"<div class=\"form-content\"><img align=\"center\" src=\"https://subdomain.domain.com/logon/themes/Default/custom_media/logo_nsg.png\" alt=\"\" width=\"150\" height=\"75\">"} -search q/text("<div class=\"form-content\">")/ add rewrite policy rw_pol_custom_logon_toplogo "HTTP.REQ.URL.CONTAINS(\"/tmindex.html\") || HTTP.REQ.URL.CONTAINS(\"/index.html\")" rw_act_custom_logon_toplogo
Example 2 – CustomAuthBotton Element
This in-built element to the theme engine will add HTML to a similar location as above, except you’ll note it spans a much wider area of the page.
To achieve this, reference the example below.
add rewrite action rw_act_custom_logon_text_customAuthBottom insert_after_all "HTTP.RES.BODY(300000).SET_TEXT_MODE(IGNORECASE)" "\"<div id=customHelp><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p></div>\"" -search q/text("customAuthBottom\">")/ add rewrite policy rw_pol_custom_logon_text "HTTP.REQ.URL.CONTAINS(\"/tmindex.html\") || HTTP.REQ.URL.CONTAINS(\"/index.html\")" rw_act_custom_logon_text_customAuthBottom
Example 3 – CustomAuthTop Element
This is similar to Example 2, but the text that spans the login area will be placed above the authentication fields.
To achieve this, reference the example below.
add rewrite action rw_act_custom_logon_text_customAuthTop insert_after_all "HTTP.RES.BODY(300000).SET_TEXT_MODE(IGNORECASE)" "\"<div id=customHelp><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p></div>\"" -search q/text("customAuthTop\">")/ add rewrite policy rw_pol_custom_logon_text "HTTP.REQ.URL.CONTAINS(\"/tmindex.html\") || HTTP.REQ.URL.CONTAINS(\"/index.html\")" rw_act_custom_logon_text_customAuthTop
Example 4 – CustomAuthFooter Element
Another in-built theme element, this will place HTML contents at the very bottom of the login page and spans it.
To achieve this, reference the example below.
add rewrite action rw_act_custom_logon_text_customAuthFooter insert_after_all "HTTP.RES.BODY(300000).SET_TEXT_MODE(IGNORECASE)" "\"<div id=customHelp><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p></div>\"" -search q/text("customAuthFooter\">")/ add rewrite policy rw_pol_custom_logon_text "HTTP.REQ.URL.CONTAINS(\"/tmindex.html\") || HTTP.REQ.URL.CONTAINS(\"/index.html\")" rw_act_custom_logon_text_customAuthFooter
Example 5 – CustomAuthHeader Element
Similar to above, but located at the very top of the page and spans the page.
To achieve this, reference the example below.
add rewrite action rw_act_custom_logon_text_customAuthHeader insert_after_all "HTTP.RES.BODY(300000).SET_TEXT_MODE(IGNORECASE)" "\"<div id=customHelp><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p></div>\"" -search q/text("customAuthHeader\">")/ add rewrite policy rw_pol_custom_logon_text "HTTP.REQ.URL.CONTAINS(\"/tmindex.html\") || HTTP.REQ.URL.CONTAINS(\"/index.html\")" rw_act_custom_logon_text_customAuthHeader
Example 6 – Inserting a Password Reset Link
This example will use the Form-Content element. We will insert a password reset link that goes to the Microsoft SSPR URL (in the case of this example).
To achieve this, reference the example below.
add rewrite action rw_act_custom_logon_text_passReset insert_after_all "HTTP.RES.BODY(300000).SET_TEXT_MODE(IGNORECASE)" q{"<div id=customHelp><p align=\"center\" style=\"color: white; font-size:14px\">Reset your password <a href='https://passwordreset.microsoftonline.com/' style='color: white; text-decoration: underline;'><strong>here</strong></a>.</p></div>"} -search q{text("<p class=\"back-to-choices\"><a href=\"#\" class=\"authentication-link _ctxstxt_UseAnotherLogonOption\"></a></p>")} add rewrite policy rw_pol_custom_logon_text "HTTP.REQ.URL.CONTAINS(\"/tmindex.html\") || HTTP.REQ.URL.CONTAINS(\"/index.html\")" rw_act_custom_logon_text_passReset
Example 7 – Inserting Workspace App Links, Text, and Password Reset
This example will use the Form-Content element. This example will reference a common set of info customers often include on login pages such as recommendations and links to Citrix client software, service desk contact information, and password reset.
To achieve this, reference the example below.
add rewrite action rw_act_custom_logon_text_clientLinks_pass insert_after_all "HTTP.RES.BODY(300000).SET_TEXT_MODE(IGNORECASE)" q{"<div id=customHelp><p align=\"left\" style=\"color: white; font-size:12px\"> Before connecting, please be sure you have a supported version of the Citrix Workspace App installed. <br><br>For Windows, we are aligned to the Long-Term Service Release (LTSR) version 2203. You may download it from Citrix <a href='https://www.citrix.com/downloads/workspace-app/workspace-app-for-windows-long-term-service-release/workspace-app-for-windows-LTSR.html' target='_blank' style='color: white; text-decoration: underline;'> here</a>.<br><br> For MacOS, please use the latest version available from Citrix found <a href='https://www.citrix.com/downloads/workspace-app/mac/workspace-app-for-mac-latest.html' target='_blank' style='color: white; text-decoration: underline;'> here</a>.<p><p><p align=\"center\" style=\"color: white; font-size:12px\">Reset your password <a href='https://passwordreset.microsoftonline.com/' target='_blank' style='color: white; text-decoration: underline;'><strong>here</strong></a>.<br><br>For Service Desk assistance contact servicedesk@domain.com or 1-888-555-5555x5</p></div>"} -search q{text("<p class=\"back-to-choices\"><a href=\"#\" class=\"authentication-link _ctxstxt_UseAnotherLogonOption\"></a></p>")} add rewrite policy rw_pol_custom_logon_text "HTTP.REQ.URL.CONTAINS(\"/tmindex.html\") || HTTP.REQ.URL.CONTAINS(\"/index.html\")" rw_act_custom_logon_text_clientLinks_pass
Bonus Round – Login Page Caching
Citrix ADC veterans may be aware of the joys of the Citrix Gateway and AAA-TM login pages as they relate to caching. If you apply or change a rewrite used on the login page, it may not appear immediately even on a client browser in incognito/private mode. This is because the login page elements of the ADC get cached on the appliance and can lead to endless aggravation with Citrix Admins feeling the config simply is not working.
Even with Integrated Caching disabled on Citrix ADC, the elements get cached. A quick trick if you’re licensed for Integrated Caching (even if disabled) is to flush the “loginstaticobjects” which can be done via GUI or via CLI. Note: It requires that even if IC is disabled (it does not need to be enabled) it needs to be licensed. Once cleared try loading up the page in browser again or in private/incognito mode to see your modifications.
flush cache contentGroup loginstaticobjects
But what if you aren’t licensed for this feature? Well for years, this meant doing a failover or an appliance reboot, which is less than ideal to put it lightly. But, in most modern firmware versions there is a great workaround in a pinch, and great for repeated noodling and testing of your code.
In the Global AAA Parameters section of the appliance, there is a little checkbox that is on by default called “Enable Static Caching”. Uncheck this box and the appliance should stop caching the login page. The downside? The appliance won’t cache the login page elements in RAM so under user load there could be small load time increases for the page. If concerned, disable it for testing, and when satisfied, re-enable it.
Conclusion
This article has attempted to illustrate various places of inserting custom HTML content, text, and images into the Citrix Gateway or AAA-TM authentication page. It is our these examples will provide sufficient guidance for administrators to extrapolate upon to add their own custom content to their Citrix logon pages.
-
Michael Shuster
Michael is Ferroque's founder and a noted Citrix authority, overseeing operations and service delivery while keeping a hand in the technical cookie jar. He is a passionate advocate for end-user infrastructure technology, with a rich history designing and engineering solutions on Citrix, NetScaler, VMware, and Microsoft tech stacks.
Nice write up
Many thanks for this.
BIG help on the AAA caching issue. Yuck.
Mate, great writeup! I was struggling with some of the other sites but this was simple and easy to follow! Give Carl Stalhood a poke and get it added to the list there; prolly a lot of CTX Admins start there for this kind of info :).
Thanks again.
Appreciate the feedback, glad it was helpful! Carl has been kind enough to reference an article or two now and then from our site, but I do not feel it’d be our place to propose linking a specific article to him. That is for the community to voice 😉
Hello folks.
First of all thank you for sharing this great content!
I cannot bind the police no matter what I do (trying to use the password reset example with a nFactor vServer + Gateway).
*** nfactor vServer
bind authentication vserver AUTH_VSRV_NFACTOR_AZMFA -policy rw_pol_custom_logon_text -priority 100 -type AAA_RESPONSE
ERROR: Policy cannot be bound to specified policy label [Blocking for data & HTTP.RES & HTTP.RES.BODY]
***
When I bind it to Gateway, I don’t see any results.
ADC is 13.1
Any tips would be very appreciated!
Thank you
Thanks for the feedback. Yes, you want to bind these to the Gateway. If you don’t see results, you may need to clear client cache or try incongnito browser. If that does not work, I suggest using the step mentioned in the article to clear static page caching. You can also go to integrated caching and clear the login static objects by flushing them. You do not need to enable the IC feature to do this.
Michael, you are a life saver!
Not only a skilled professional but also willing to assist the whole Citrix community.
It was the cache indeed (even not enabled), now it is working perfectly.
Wish you a great Happy New Year!
Best,
Cristiano S.
Hey Michael, thanks for this!
Can you help me with a placeholder in username input?
Im using rfwebui netscaler
Have not tried it myself but I wonder if the LoginSchema would allow $AAA.USER.NAME to render in.
Hi Michael,
Nice writeup. it helps a lot. thq. I am trying to add 2 rewrite policies, one to set the Reset password link and one to set the customeauthheader to show some tex. looks like if i choose action as “inster_after” for both of them only one of them applies when the page loads. The first in the priority is applied. Do you have any suggestions to fix this behaviour?