I was recently asked to help with a use case, the solution of which has general purpose interest for IBM Security Verify Access (ISVA) practitioners. Today I thought I'd share the solution pattern with a wider audience. It is quite simple to understand, yet very powerful when you see what it can do.
The particular use case in question was to accept client certificate authentication (processed with a certificate EAI), but apply a different max-concurrent-sessions policy to certificate-based login compared to other methods of authentication. That's not the only use case this solution applies to however. This solution allows an Infomap AAC mechanism to act as a more generic EAI authentication technology than the built-in AAC authentication service typically offers. To illustrate, lets look at how a typical Infomap completes login for a user:
// logic to determine who to login as typically precedes these types of commands to complete login in an Infomap
context.set(Scope.SESSION, "urn:ibm:security:asf:response:token:attributes", "username", "testuser");
context.set(Scope.SESSION, "urn:ibm:security:asf:response:token:attributes", "AUTHENTICATION_LEVEL", "2");
success.setValue(true);
What this actually does is set session context variables which are later processed by the AAC runtime and turned into EAI response headers - the exact headers and values used depends on how the AAC -> Point of Contact is configured.
This is very straight forward and works fine in most use cases. Occassionally though you want to be able to take advantage of more advanced EAI and response header capabilities, including:
- overriding what the point of contact does, such as returning a pre-built PAC instead of a "username + extended attributes"
- making use of special am-eai-flags response headers
- sending a HTTP redirect
- I'm sure there are others not listed here
It turns out you can still do this with Infomap, but you have to think outside the box a little. The way this solution works is to not use the AAC built-in engine to generate EAI response headers, but instead build them use yourself using a page template and server-side template page scripting. Let's re-write the previous example Infomap, using this approach. There are two portions - first the Infomap JS code, then the page template.
Infomap JS code:
// after you work out your login logic....
macros.put("@USERNAME@", "testuser");
macros.put("@AUTHENTICATION_LEVEL@", "2");
page.setValue("/authsvc/authenticator/eailogin.html");
success.setValue(false);
Page template C/authsvc/authenticator/eailogin.html
:
<%
templateContext.response.setHeader("am-eai-user-id", templateContext.macros["@USERNAME@"]);
templateContext.response.setHeader("am-eai-xattrs", "AUTHENTICATION_LEVEL");
templateContext.response.setHeader("AUTHENTICATION_LEVEL", templateContext.macros["@AUTHENTICATION_LEVEL@"]);
@"]);
%>
This should never be seen
Normally when an Infomap performs success.setValue(false);
the intent is to send back a login page of some form to the browser for the user to complete an authentication challenge. In this case however the page template that gets sent back completes a login because it contains valid EAI response headers.
In the template page, server-side template page scripting is used to populate these headers, and the set of response headers can be extended to include things like am-eai-flags as well (which is what I did for original the max-concurrent-sessions use case).
Hopefully here you can see that that Infomap mechanism can be used for some quite creative use cases, including returning pretty much any server-side dynamically generated content that you wish including (in this case) acting as a generic EAI server.
Happy coding!