Template page scripting
We can use JavaScript to add server-side scripting for Advanced Access Control and Federation template pages. We can use JavaScript functions, closures, objects, and delegations. We can customize template files or pages on the server. For example, we can customize an error message displayed by the runtime server. The template files menu is located under both the Federation and AAC menus.
To edit a Federation template file, go to...
Federation > Template Files > template file > Edit
To edit an AAC template file, go to...
AAC > Template Files > template file > Edit
The JavaScript engine supports the following syntax:
- Insert JavaScript code between <% and %>.
- Embed JavaScript expressions between <%= and %>.
Example tasks:
- Access whitelisted Java classes.
var javaStr = new java.lang.String("Hello")
- Access all the macro variables through templateContext. The standard object to access a Java object is templateContext.
templateContext.macros["@TIMESTAMP@"]
- Use the document.write function to write content to the output stream.
templateContext.response.body.write("Hello")
Examples
Template HTML Output <% var contents = {product:"Verify Access",department:"Lab",country:"SG",region:"Asia"};
templateContext.response.body.write(contents.product); %>Verify Access <% var date = templateContext.macros["@TIMESTAMP@"].substring(0, 10);
templateContext.response.body.write(date); %>2017-01-25
The following code example shows how to use repeatable macros. The following example shows an OAuth consent page.
<% var test = templateContext.macros["oauthTokenScopeNewApprovalRepeatable"]; n = test.length; for (i=0; i<n; i++){ var scope = test[i]["@OAUTH_TOKEN_SCOPE_REPEAT@"]; if (scope == "contacts"){ label ="Do you grant permission to the client to access your phone book"; } else if (scope == "photos"){ label ="Do you grant permission to the client to access your photos"; } else if (scope == "messages"){ label ="Do you grant permission to the client to access your WhatsApp messages"; } else{ label ="Do you grant permission to the client to access your "+scope; }%>Set an HTTP response header
We can use templateContext.response.setHeader(HeaderName, HeaderValue) to set an HTTP response header. For example, we can set the Content-Type to support both a mobile-based browser and a traditional browser. A mobile-based browser might expect JSON format while a traditional browser expects forms-based HTML.
<%
templateContext.response.setHeader("Content-Type","application/json");
var myObj = { "name":"John", "age":31, "city":"New York" };
templateContext.response.body.write(JSON.stringify(myObj)); %>To set an HTTP header that uses forms-based HTML:
templateContext.response.setHeader("Content-Type","text/html");
Set an HTTP status code
Use templateContext.response.setStatus(Code) to set an HTTP response status code. For example, to set the status to 400 (standard code for a bad request):
templateContext.response.setStatus(400);
Set a Redirect URL
We can use templateContext.response.sendRedirect(URL) to redirect the HTTP response to a different URL. For example, when we configure single logout, we can redirect the response to a specific target page, based on the federation name. An example scenario is a deployment that has one SAML 2.0 federation with two partner federations. The partner federations are named saml20app2 and saml20sp. The saml20app2 federation uses an application that is named jkebank. The saml20sp federation uses an application that is named jkeschool. The page to display on logout is determined by the federation name.
var fedName = templateContext.macros[@FEDERATION_NAME@"]; if (fedName == "saml20app2") { templateContext.response.sendRedirect("http://jkebank:1337"); }else if { (fedName == "saml20sp") { templateContext.response.sendRedirect("http://jkeschool:1400"); }Obtain a list of macros available for a template page
In some scenarios, we might want to write JavaScript based on configuration values in the deployment. For example, we might implement one action based on the authentication type, such as if the OTP type is TOTP. Another example is we might implement an action if the Federation name of the single sign-on partner matches a certain value.
Information such as the OTP type and partner name can be retrieved only through the template page macros. To use such information, we need to know which macros are used by the page. The JavaScript engine support provides a utility that can print the available macros for a page.
To obtain a list of the available macros.
<% templateContext.response.body.write(JSON.stringify(templateContext.macros)); %>
The following sample code prints the macros from a template page that ran a single sign-on flow with a partner that does not exist.
{ "@PAGE_IDENTIFIER@": "/saml20/invalid_init_msg.html", "@TARGET@": "https://www.mysp.ibm.com/isam/mobile-demo/diag", "@PARTNER_ENTITY_ID@": "", "@ERROR_MESSAGE@": "FBTSML002E The value https://saml.partner.com for attribute PartnerId is not valid.", "@FEDERATION_NAME@": "saml20idp", "@FEDERATION_ENTITY_ID@": "https://www.myidp.ibm.com/isam/sps/saml20idp/saml20", "@REQ_ADDR@": "/sps/saml20idp/saml20/logininitial", "@ERROR_CODE@": "FBTSML002E", "@EXCEPTION_STACK@": "", "@PARTNER_NAME@": "", "@TIMESTAMP@": "2017-06-22T03:34:39Z", "@SAMLSTATUS@": "<fim:FIMStatusCollection xmlns:fim=\"urn:ibm:names:ITFIM:saml\" xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\"><fim:FIMStatusCollectionEntry> <samlp:Status><samlp:StatusCode Value=\"urn:oasis:names:tc:SAML:2.0:status:Responder\"></samlp:StatusCode> <samlp:StatusDetail><fim:FIMStatusDetail MessageID=\"invalid_attribute_value\"> <fim:SubstitutionString>https://saml.salesforce.com</fim:SubstitutionString> <fim:SubstitutionString>PartnerId</fim:SubstitutionString></fim:FIMStatusDetail> </samlp:StatusDetail></samlp:Status></fim:FIMStatusCollectionEntry></fim:FIMStatusCollection>", "@EXCEPTION_MSG@": "" }The format is JSON { "name1":"value1","name2":"value2"}
Limitations
- JavaScript validation is done only when a template file is edited (imported) or created. A template file that is imported as a part of an Import compressed file is not validated.
- Restart the runtime manually to activate changes to OpenID Connect template files. In the administrative interface, click...
Federation -> Runtime Tuning -> Restart Runtime
- When accessing a variable, do not end the variable name with a semicolon. For example, in the following JavaScript, do not end <%=example%> with a semicolon <%=example;%>.
<%var example = "Hello World"; %> <%=example%>The correct syntax is <%=example%>. Do not use the incorrect syntax <%=example;%>.
Parent topic: Manage trust chains