Tips & tricks for installing and running IBM products

JSON.stringify in ISAM

Tom Bosmans  30 October 2020 14:32:19
When using JSON.stringify, I get a lot these errors:

Caused by: org.mozilla.javascript.EvaluatorException: Access to Java class "java.lang.reflect.Constructor" is prohibite

This was driving me crazy, because it seemed to be very random.

Now thinking about it a bit more, it occured to me that the reason for this is that JSON.stringify needs to operate on a javascript object.
You don't always have a String object , though.  So if you try to do that on a string literal, it throws the error above.

Sometimes you can resolve this by first using JSON.parse, but that does not always work either.

The solution is simple:  just add an explicit cast to String to your string literal :


Fedora 31 and Notes Client

Tom Bosmans  26 March 2020 10:04:04
My Notes client failed to start on my new Fedora Linux with an error "error while loading shared libraries: cannot open shared object file: No such file or directory "

The shared library is however included in the /opt/ibm/notes/lib directory.

So I just added that directory to the /etc/ configuration :


Then , run

sudo ldconfig

I probably should have created a separate file to put into /etc/ , but the end result is the same.
And it works fine now.  Not sure if I have now introduced other problems though :-)

ISAM Do not use LACP Bonding on the management interface

Tom Bosmans  15 October 2019 14:31:42
The isam appliances allow you to use bonding or network aggregation (

This is a good idea for the "data" interfaces, IF
- you are using the hardware appliance
- have only a single network you connect to (single subnet)
- you have a need for higher total throughput
- your network switch supports LACP (         802.3ad )

It is also possible to setup Dynamic Link Aggregation (lacp) for the management interfaces - although you can use the interfaces on the hardware appliance for whatever you want them to do, the first 2 are marked on the box as "management" .  
It sounded like a good idea to do this - create a bond between the first 2 interfaces (albeit a bit overkill, because there is no need for the higher throughput on the management interfaces).

But it turns out, it can be a bad idea in recovery situations (depending on how close you are with your network team ).  

To activate LACP , you first have to configure the bonding configuration on the appliance and then change the network ports on the switch you connect to from static ports to aggregate ports (terminology may vary).
ISAM will then briefly disconnect and reconnect, with a working bonding interface.

So far , so good.  

The problem begins when you run into problems and want to reset the appliance (of you don't have problems, you just want to reset the appliance).

The appliance then goes back to a default configuration, where the first interface tries to obtain an ip address over dhcp.

This fails, because the switch is still configured for LACP , and not for a simple static port.  The appliance does not get an ip address.

No worries, you can connect to the appliance using the serial console interface (a connector is included with the appliance).  You can then use putty or securecrt or some terminal program to open a serial connection to the appliance.

Now for the problem :   the console interface does not provide possibility to configure bonding on the interfaces.  This means you cannot get the management interface up and running , so you cannot access the LMI.

Note that this not have to be a huge problem, depending on your organization.  
- you can activate/configure another interface as management interface, where you can connect to the LMI on
- you can ask your network team to de-activate LACP on the switch
- you could use a different type of bonding/link aggregation , that works with normal static ports (I have not investigated other modes in detail)

But in large organizations, getting every part of it to do exactly what you want at the right time can be challenging .  The simpler solution is to not use bonding at all for the management interface, and keep the second management interface as a backup (unconfigured).  In case of failure of the first interface, you can activate the second interface using the serial console.

ISAM SPNEGO configuration

Tom Bosmans  11 September 2019 09:18:07
SPNEGO challenge when reverse dns lookup does not match the requested hostname
The challenge with SPNEGO or rather the Kerberos implementation on ISAM is that it depends on reverse DNS lookups (on the ip address) by default to verify that the hostname you want to connect to.
This means that even though you have keytabs for the hostname you connect to, the SSO will fail if the reverse dns lookup returns another hostname for that IP address.

Typically , you'll see errors in your log similar to this :

483       2019-09-10-17:13:53.304+02:00I----- 0x30923082 webseald ERROR bst general amstli.c 2764 0x7f55c50de700 -- HPDST0130E   The security service function gss_accept_sec_context returned the error 'Request ticket server HTTP/ not found in keytab (ticket kvno 3)' (code 0x96c73a23/-1765328349).

2 solutions exist.  The first one, changing DNS , is sometimes difficult to explain (because not all Kerberos implementations are equal , and SPNEGO works for other servers, the client may not understand why it's necessary).
So there is a second solution, by using some of the newer kerberos parameters (NEW in Kerberos 1.10).
So this may not be possible on your ISAM version !  I am using 9.0.6 in this case, which comes with Kerberos 1.12 .


The old way to resolve this, is to make sure the reverse dns lookup for your ip address returns the hostname of your WebSeal proxy (the one users connect to).  In this way, you just need the 1 SPN in your keytab.

Configuration with additional keytabs

You need to have a keytab that contains the hostname for the url the user accesses, and the hostname for all backend servers (ie. what's in the reverse dns lookup and A records) as SPN.
You can combine them in ISAM.

Then , you can add these 2 parameters to the Defaults section in Kerberos configuration.  Rdns is false does not really seem to have a lot of effect, to be honest, but ignore_acceptor_hostname is the golden ticket here.

ignore_acceptor_hostname = true
rdns = false

Image:ISAM SPNEGO configuration


Virtual host junctions and federation on ISAM

Tom Bosmans  9 August 2019 10:15:40
I recently struggled with a setup of an OIDC federation setup on IBM Security Access Manager.

Instead of using standard, transparant path junctions, I was now using Virttual Host Junctions.
And I could not get the federation to work.

After a while, the penny dropped , and I realised that the /mga junction is not avaiable in the Virtual host junction.  Which I should have realised from the beginning of course...

So there's 2 options

match-vhj-first and session sharing

The "match-vhj-first " is set to yes by default, and this means that you cannot access the /mga junction (and hence cannot kick off the federation etc).  Set this parameter to "false", and the /mga junction is available in the Virtual Host Junction.
For federation, you may get away with just that change, as long as you setup seperate federations per virtual host.

See this older article by Philip Nye on the related topic of Context Based Access control:

Single federation per Reverse Proxy instance and session sharing

For the OIDC Federation, I opted for a slightly different approach though.  There is no real need to change the default "match-vhj-first" setting.  What is important in setting up Federations, is that the hostnames used are constant throughout the OIDC federation flow.  And by setting up a "master" federation partner, I can kick off federation on all virtual host junctions on the same reverse proxy - no need to change anything in the federation setup when adding a new virtual host junction.

Webseal configuration

In the Webseald.conf configuration file , I set fhe following parameters:

match-vhj-first = yes

domain = mydomain.tld

shared-domain-cookie = yes
tcp-session-cookie-name = PD-H-SESSION-ID-rp1
ssl-session-cookie-name = PD-S-SESSION-ID-rp1

This enables the sharing of the webseal session between the junctions (including virtual host junctions) within a reverse proxy (webseal).
This is not necessary if you use DSC , and this does not work if you don't have a single "cookie domain" .


Key here is to have a single OIDC Federation set up against the "base" webseal reverse proxy, eg. the ip address or hostname you used to setup the reverse proxy.

The URLs to use in the Federation components (  redirectUriPrefix, providerId ) need to point to that base webseal reverse proxy.
Make sure to not mix the hostnames here, because then the Federation will fail.

If you enabled local-response-redirect, you can then use the following kickoff URL to start the Federation.

local-response-redirect-uri = https://mywebseal.mydomain.tld/mga/sps/oidc/rp//kickoff/

After a successful federation, thanks to the session sharing, you are also logged into your Virtual Host Junction.

The only correct way to setup the ISAM RTE with basic users for the UserLookupHelper

Tom Bosmans  2 August 2019 09:03:41
I've been struggling a bit to get the UserLookupHelper work correctly in a custom authenticatiion mechanism I am building for Username / Password authentication.  I am using the ISAM "all-in-one" deployment pattern , that is becoming quite popular these days.  This basically consists of identical ISAM appliances that have all functions (reverse proxy, AAC, federation) and operate independently.  The environment provides high availability by adding identical appliances (typically using automation).  The identital appliances do share some resources, notably the High Volume database and the federated ldap repositories.
This pattern also relies on using Basic users in Federated repositories.

The problem I came across is that in this setup, the UserLookupHelper is very difficult to get to working correctly using the ISAM RTE.
Recentlly a technote was published ( ) , but that only describes what is causing the problem, not the detailed steps to resolve or avoid it.

I tried various workarounds, and a workaround that is suggested a lot is to use an LDAP connection to (1 of the) federated repositories.   While that may work for you, it is NOT what I want - I want to use ALL of the configured federated directories .

In the end , I found that a simple recommendation in setting up ISAM can avoid all these problems, so I'll start with that


In the "all-in-one" deployment pattern, with Basic users in remote ldap repositories, there is only 1 correct ISAM Runtime server setup : Local Policy Server/Remote LDAP Server (lmi / ssl) .

When initially configuring the Runtime environment, select a local Policy server and a remote LDAP server pointing to your embedded ldap (instead of local Policy Server/local LDAP server).
Configure the connection to your local embedded LDAP using:
- hostname: your appliance's LMI hostname
- port: 636
- enable ssl

Select a keystore that contains the CA certificates of ALL the federated repositories you want to connect to and also the CA for your embedded ldap.

The embedded LDAP does not listen on port 636 on the localhost/loopback/ interface !

You need to make 2 small modification afterwards to ldap.conf


host =

port = 389
-> port = 636

ssl-port = 636

And under [bind-credentials], you must add the bind-dn and bind-pwd for a user that can read your embedded ldap (eg. the root user), like this :


bind-dn = cn=root,secAuthority=Default

bind-pwd = your-root-password-i-hope-it-is-not-passw0rd

See the technote for the explanation.

This setup will enable you to use :
- UserName / Password AAC Authentication mechanism using the ISAM RTE
- the UserLookupHelper connecting to ISAM RTE (and all the configured federated repositories with basic users)
- the SCIM prerequisites

Errors & what does not work

UserLookupHelper does not work

So your userlookuphelper does not work in your setup with Basic Users - it cannot contact the ISAM RTE or it cannot contact the federated repositories you defined.

You MUST use the ISAM RTE way of initialisation, that is the only way that will work for Federated Repostitories with Basic users !
You MUST have set the bind-dn and bind-pwd under [bind-credentials] in ldap.conf .

Following snippet shows how to correctly initialize the UserLookupHelper, in this case for a username that is submitted in a form.

var username = context.get(Scope.REQUEST, "urn:ibm:security:asf:request:parameter", "username");

var userLookupHelper = new UserLookupHelper();

// Use ISAM RTE with false

// configure bind-dn and bind-pw in ldap.conf

// need to have all certificates in the keystore that is used in ldap.conf (to ad and to rte)

// set 636 as non-ssl port

// MUST use false, because this is the only way Basic Users and Federated repositories will work

// check here

reportmsg("Init ... [" + username + "]",false);

if( userLookupHelper.isReady() ) {

  IDMappingExtUtils.traceString("User Lookup Helper is ready for  ... [" + username + "]");

  var user = userLookupHelper.getUser(username);


But this likely does not work for you.

Enable tracing

When you start working on your InfoMap with UserLookupHelper, you probably want to enable tracing .
Go to "Secure Access Control" , "Global Settings" , "Runtime Parameters", and go the "Runtime Tracing" tab

Image:The only correct way to setup the ISAM RTE with basic users for the UserLookupHelper
Add this trace specification:


The trace.log you can then view in "Monitor / Application Logs" (https://lmi/isam/application_logs)  
Under access_control/runtime/trace.log

Errors indication the problem

If you use Basic users in LDAP directories that require SSL, and you have setup your ISAM with local Policy Server/local LDAP, you will likely see errors like this :
The runtime trace shows that the connection uses :389:readwrite:5.

Other errors may look like this:

[7/31/19 11:48:41:962 CEST] 000000bd id=00000000                I getUser com.tivoli.pd.rgy.exception.DomainNotFoundRgyException: HPDAA0266E   The Security Access Manager domain Default does not exist.

or another typical one:

com.tivoli.pd.rgy.exception.ServerDownRgyException: HPDAA0278E   None of the configured LDAP servers of the appropriate type for the operation can be contacted.

Manually configuring ISAM

So how do I fix this ?
The root cause information is correct in the technote, but it does not fully explain how to fix the problem.
Changing the port is only part of the solution, because the embedded LDAP server listens on port 636 of the management interface of the appliance by default, not on localhost. The administrator can choose a port other than the default by modifying the advanced tuning parameter wga.rte.embedded.ldap.ssl.port. The advanced tuning parameters are accessed through Manage System Settings > Advanced Tuning Parameters. After you modify this advanced tuning parameter, you must restart the Security Access Manager runtime environment for the change to take effect.

Update ldap.conf

Go to "Secure Web Settings/Manage/Runtime Component" and navigate to "Manage/Configuration Files/ldap.conf"
Set the host to the ip address or hostname of your LMI, it cannot be set to
Set the port to the same value as ssl-port (by default, 636.  To change it, see the previous paragraph).


host =

port = 636

ssl-port = 636

ssl-keyfile = yourkeystore.kdb

The keystore you set here must contain all the CA certificates for the federated ldap.  It's likely you have a value there already if you configured Federated Directories already.
In the default setup, you can export the server certificate from the keystore embedded_ldap_keys , and import it as a CA in "yourkeystore.kdb" .

Update the bind-credentials, with the username and password for a user that can access the embedded ldap (eg. cn=root)


bind-dn = cn=root,secAuthority=Default

bind-pwd = your-root-password-i-hope-it-is-not-passw0rd

The ISAM runtime will restart after these changes.

Update pd.conf

Go to "Secure Web Settings/Manage/Runtime Component" and navigate to "Manage/Configuration Files/pd.conf"

Edit the pdrte stanza.


user-reg-type = ldap

user-reg-server =

user-reg-host =

user-reg-hostport = 636

Update user-reg-server with your lmi's hostname .  Note that you may have to add a hostrecord for your lmi !
Update user-reg-host with your lmi's public ip address (in this example,
Update user-reg-hostport to match the ssl port (default 636).

In the ssl stanza, I enabled the TLS 1.1 and 1.2 versions.


tls-v10-enable = no

tls-v11-enable = yes

tls-v12-enable = yes

Update ivmgrd.conf

Go to "Secure Web Settings/Manage/Runtime Component" and navigate to "Manage/Configuration Files/ivmgrd.conf"

Enable ssl, and assign the keystore you used earlier.

ssl-enabled = true

ssl-keyfile = yourkeystore.kdb

Update your reverse proxies

The reverse proxies need to be instructed to connect over ssl.

So for every reverse proxy, open the "Secure Web Settings"/"Reverse proxy" page, select the reverse proxies one by one and open the Configuration file (webseald.conf): "Manage/Configuration/Edit Configuration file"

Find the [ldap] stanza and enable ssl :


ssl-enabled = yes

ssl-keyfile = yourkeystore.kdb

ssl-keyfile-dn =

The keystore you select here should contain the CA certificates for your embedded ldap , and the federated repositories.  
Leave the ssl-keyfile-dn empty, unless you're using Mutual TLS.

Restart the reverse proxy after these changes, and repeat for all your reverse proxies.

If the reverse proxy fails to start, look in the msg__webseald-.log file (via Monitor/Reverse proxy log files) for errors indicating connection problems, for instance these:

2019-08-01-14:43:48.521+02:00I----- 0x16B480C9 webseald ERROR rgy ira ira_handle.c 1489 0x7f95100a6840 -- HPDRG0201E   Error code 0x51 was received from the LDAP server. Error text: "Can't contact LDAP server".

206       2019-08-01-14:43:48.525+02:00I----- 0x1354A0C0 webseald WARNING ivc general azn_maint.cpp 1136 0x7f94f1b8a700 -- HPDCO0192W   LDAP server has failed.

Possible causes are missing ssl certificates , or errors in ip addresses and hostnames in your configuration.

Look for messages like this: No trusted certificate found
javax.naming.CommunicationException: simple bind failed: [Root exception is No trusted certificate

Ansible configuration

I've published Ansible playbook that performs all these tasks for you  
It requires you have setup Ansible to work with ISAM (with the roles and the modules found here :

Congratulations, now you should have a working environment

You should now have a working environment :
- you can use a standard pkmslogin to webseal with a basic user
- the UserLookupHelper works correctly (init(false) or init()) and can locate basic users
- the Username/Password mechanism can be configured
- the SCIM setup can use the ISAM RTE

A remark on Point of Contact configuration

This setup is applicable if you have your ISAM appliance set to "Access Manager Credential" or "Access Manager Username and extended attributes".  It is not applicable for the External Users model (since you probably won't have basic users configured ).

A remark LMI Configuration

I noticed that if I set the LMI to only use TLSv1.2, the UserLookupHelper no longer works (or rather, that the ISAM RTE connection fails on an LMIRest call ).  So I re-enabled all TLS protocols for the LMI to resolve this.
I need to get to the bottom of this, though .

Alternative solution that will only work if your federated repositories do not use SSL

If your federated repositories do not use SSL (which will never happen in real life, I hope), you can get away with a simpler change.   However, I do not recommend this

So keep the runtime configured with local Policy Server and local LDAP.

Open ldap.conf, and remove the ssl_keyfile parameter completely.  This will disable all SSL usage for your embedded ldap and for the federated repositories.

Restart everything.

Download the Brave browser and earn BAT tokens

Tom Bosmans  27 April 2019 21:54:04
The Brave browser promises better privacy ; and to directly pay the user for the ads you're looking at .
The payout is in BAT (Basic Attention Tokens).

I think this looks promising .

Download the browser here :

ISAM with VirtualBox and Vagrant for development

Tom Bosmans  15 March 2019 13:36:28

How to run ISAM on Virtual Box (and how to run it using Vagrant)

The goal of this post is to get IBM Security Access Manager running on Virtual Box ( ), on my local machine.  This will allow me to test the Ansible playbooks I'm preparing locally before commiting them onto the Git repository.
As a small addition, I have Vagrant , to quickly set up a new clean instance.  Vagrant does not really bring a whole lot of value in this case, because ISAM is a locked down appliance and Vagrant can't really do a lot.  

Download the ISAM 9.0.6 ISO file

Get the ISAM 9.0.6 (or whatever the most recent version is) from Passport Advantage.

Setup Virtual Box

Under File/Preferences/Network , create a new NAT network.
You can just accept the defaults.

Create new Virtual Machine

Create a new virtual machine.  

- Configure 2 NIC's, both configured with the Intel E1000 adapter
Connect the first NIC to the NAT Network you prepared.
Connect the second NIC to the Host-Only Network.

- Configure Storage : create a new SCSI controller, with LSI Logic adapter
Create a new disk, with a size of at least 8 GB (recommended is 100Gb)

- Connect the CD/DVD to the ISO file you downloaded earlier with ISAM on it

- Assign 2048 Mb of memory  

- Disable Audio

Advanced configuration for the Virtual Machine

To run the ISAM appliance on Virtual Box, we need to trick it to think it's running on VMWare.

Open a command prompt and navigate to the Virtual Box installation folder.
Run the "list vms" command to get a list of your virtual machines.

C:\Program Files\Oracle\VirtualBox>

VBoxManage.exe list vms

"isam905" {1c548e84-f7cd-4283-a36a-71843757d1af}

Run the following command to “fake” Vmware .  Use the output of the previous command for the vm info.
This is the "magic" command that makes everything work:

VBoxManage setextradata "isam905" "VBoxInternal/Devices/pcbios/0/Config/DmiBIOSVendor"  "VMware Virtual Platform"

These commands configure port forwarding for initial configuration:

VBoxManage modifyvm "isam905" --natpf1 "guestssh,tcp,,2222,,22"

VBoxManage modifyvm "isam905" --natpf1 "lmi,tcp,,4443,,443"

Configure ISAM

Start the vm and configure it.
After initial booting from the dvd and installing the image, you must disconnect the dvd pointing to the iso file.

Then reboot the machine again; and it should boot to the console .

Access the LMI

You can now access the LMI on

The console is available by ssh on port 2222:

ssh -p 2222 admin@

Next steps

I can now use Ansible to configure the ISAM vm, specifically :
- perform first steps , activation etc.
- configure the second interface on the Host Only adapter, so ISAM is accessible on a "normal" address as well (without port forwarding).

Another thing I'm working on, is to use Vagrant to be able to rapidly start up a temporary ISAM appliance .


Using Atom as text editor - let’s say I’m not convinced

Tom Bosmans  27 February 2019 13:56:54
I'm working with Atom ( since a few days , because it has integrated Git/Github support and it is available cross-platform, but boy ... I hate it.

It does not do any of the basic stuff I expect an editor to do

- why is searching so hard ?
- when I open a file again in the tree , it OPENS THE FILE AGAIN instead of going to the Tab where the file is already open .  Other (free) editors give at least a warning if you try to do that.
- because of that (?),  it overwrites my changes from time to time, seemingly at random
- sloooow

Also the integration with Git/Github seems random at best.  I regularly need to restart the editor, because I can't access the Git/Github functions .

I hate it ...  I even prefer vi .

There are things that I like as well, but I have not found anything yet that would make me recommend Atom over anything else ....

Logout everywhere for OIDC/OAuth2 on ISAM

Tom Bosmans  22 January 2019 12:00:40

Single sign on

We have an environment where multiple websites are configured to use OIDC authentication (authorization code flow) to an IBM ISAM acting as the Idp (Identity Provider).
All these websites expect different scopes in their tokens (eg. access tokens and id tokens) .

Of course, the user can also use mulitple devices (browsers) to access the sites.

The IDP thus can hand out a number of different tokens for a single user.

We also created a custom "Remember Me" function ; that relies on an Oauth access token stored in a cookie (more on that some other time).

So a user effectively has single sign on between all the websites now : every time a new access token is requested (eg. with a different scope); the user is redirected to the idp.  But because of the "Remember Me" cookie, the user is logged on automatically to the idp.  The idp then hands out the new access token.  

The challenge in this case now, is to implement a Logout function, that not only invalidates the current access token in use for that particular website; but also all other active tokens (access tokens, refresh tokens; ...).


We want to terminate ALL active tokens (from all different applications (client_id), but also from all logged in devices - logout everywhere.

To remove all tokens for a particular (logged in) user; there are methods in the API


That would do what we need.   Note that this removes the Oauth tokens that exist for the user across ALL devices the user is using.

WebSeal's Single-signoff-uri

Our initial idea was that we could use WebSeal's single-signoff-uri parameter.  This is intended as a mechanism to log the user out of any backend applications when the WebSeal session is terminated.
There are four different mechanisms that can terminate a WebSEAL session:

User request by accessing pkmslogout.
Session timeout.
EAI session termination command.
Session terminate command from the pdadmin tool.

When the WebSeal session terminates, it sends (GET) requests to the url's you configure here; including cookies and headers from the incoming request.
By default (after you've configure the OIDC and API Connect features); there's an entry already for Oauth:

single-signoff-uri = /mga/sps/oauth/oauth20/logout

So adding a single-signoff-uri that points to our custom infomap; would be triggered when the WebSeal session terminates ...
The problem with this configuration in our scenario; is that it would mean that every time you are logged out of the IdP, it would trigger the logout mechanism .  We only want to trigger it when the user clicks "Logout" !

Logout everywhere

Infomap setup

The infomap can obviously also be called directly by the enduser.

By using the api endpoint, we can furthermore do the calls in an Ajax call (json returned).  Note that this requires a CORS configuration in most cases .

So assuming my ISAM that acts as the IDP is on , the call to the infomap could look like this .  Note the difference in the uri (apiauthsvc vs. authsvc).
API Call (return JSON)

For the API call to succeed; you must add an Accept Header to your GET call with the value "application/json" (see here , for instance : )

You need to have the necessary template files in place; you need


The html file is returned for the Browser call, the json file when you use the API call

I've used this excellent blog entry from my colleague Shane Weeden as an example and a source for code :

Infomap code

Now this code does 2 things : it calls the deleteAllTokensForUser function to remove all tokens for the logged in user, and then it performs a logout by using a REST call to the pdadmin utility , to run the command

server task terminate all_sessions

This code depends on a Server Connection to exist ; named "ISAM Runtime REST" , that should point to your LMI; with the userid and password for an admin user.
The details to run the pdadmin command are hardcoded in this example:

What is missing from this code, is the possibility to pass a redirect URL.  This would make sense in the "Browser" version, less for the API version of the infomap.

The infomap code :


* Utility to get the username from the the Infomap context
function getInfomapUsername() {
            // get username from already authenticated user
            var result = context.get(Scope.REQUEST,
                                              "urn:ibm:security:asf:request:token:attribute", "username");
            IDMappingExtUtils.traceString("[FEDLOGOUT] : username from existing token: " + result);

            // if not there, try getting from session (e.g. UsernamePassword module)
            if (result == null) {
                             result = context.get(Scope.SESSION,
                                                               "urn:ibm:security:asf:response:token:attributes", "username");
                             IDMappingExtUtils.traceString("[FEDLOGOUT] : username from session: " + result);

            return result;

* Utility to html encode a string
function htmlEncode(str) {
               return String(str).replace(/&/g, '&').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
*    perform pdadmin session deletion
function deleteAllSessions(username) {
            IDMappingExtUtils.traceString("[FEDLOGOUT] Entering deleteAllSessions()");
            // Get the Web Server Connection Details for ISAM Runtime
            servername = "ISAM Runtime REST";
            var ws1 = ServerConnectionFactory.getWebConnectionByName(servername);
            if (ws1 == null) {
                             IDMappingExtUtils.traceString("[FEDLOGOUT] Could not find the server data for " + servername);
                             next = "abort";
            var restURL = ws1.getUrl()+"/isam/pdadmin";
            var adminUser = ws1.getUser();
            var adminPwd = ws1.getPasswd();
            IDMappingExtUtils.traceString("[FEDLOGOUT] url : "+restURL+" adminUser  " + adminUser + " password: "+ adminPwd );
            var headers = new Headers();
            headers.addHeader("Content-Type", "application/json");
            headers.addHeader("Accept", "application/json");
var respbody = '{"admin_id":"sec_master", "admin_pwd":"<sec_master_password>", "commands":"server task <websealinstance> terminate all_sessions ' + username + '"}';
            var hr = HttpClient.httpPost(restURL, headers, respbody, null, adminUser, adminPwd, null, null);
            if(hr != null) {
                             var rc = hr.getCode();
                             IDMappingExtUtils.traceString("[FEDLOGOUT] got a response code: " + rc);
                             var body = hr.getBody();
                             if (rc == 200) {
                                              if (body != null) {
                                                              IDMappingExtUtils.traceString("[FEDLOGOUT] got a response body: " + body);
                                              } else {
                                                               IDMappingExtUtils.traceString("[FEDLOGOUT] body of response from pdadmin is null?");
                             } else {
                                              IDMappingExtUtils.traceString("[FEDLOGOUT] HTTP response code from pdadmin is " + rc);
            } else {
                             IDMappingExtUtils.traceString("[FEDLOGOUT] HTTP post to pdadmin failed");
            return true;                

// infomap that returns a page indicating if you are authenticated and who you are
var username = getInfomapUsername();
// We must have a logged in session, otherwise we cannot logout ....
// this is a bit annoying and I'm not sure how to make sure
if ( username != null ) {
var tokens_for_user = OAuthMappingExtUtils.getAllTokensForUser(username);
            var tokens = [];
            for (i = 0; i < tokens_for_user.length; i++) {
                                              var a = tokens_for_user[i];
                                              tokens.push(a.getClientId() + "---" + a.getId() + "---"+a.getType();
                                              IDMappingExtUtils.traceString("[FEDLOGOUT] : Active Token ID " + a.getId() +  ", ClientID " + a.getClientId() + " getType " + a.getType() );
            IDMappingExtUtils.traceString("[FEDLOGOUT] : Deleted all tokens for : " + username );
            * Now invalidate the session for the idp
            IDMappingExtUtils.traceString("[FEDLOGOUT] : Trying to logout : " + username );
            * Now return the page ... the page should actually never be shown ...  logout.json should exist as well
            macros.put("@AUTHENTICATED@", ''+(username != null));
            macros.put("@USERNAME@", (username != null ? htmlEncode(username) : ""));
            macros.put("@TOKENS@", tokens.join(";");
            // we never actually perform a login with this infomap
} else {
            IDMappingExtUtils.traceString("[FEDLOGOUT] : Anonymous session; no logout performed");