IBM Verify

 View Only

Creative use of Infomap as an EAI

By Shane Weeden posted Wed July 12, 2023 01:39 AM

  

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!

7 comments
74 views

Permalink

Comments

Fri March 15, 2024 05:29 AM

Hi Shane,

a GET directly to a single policy containing your approach worked fine A POST didn't. I finally found out, what kind of problem caused this: For the POST to my policy containing several steps (and finally the terminate all sessions step) i used the /apiauthsvc/ path... so of course i ran into problems returning HTML. So i simply switched the returned file to json and everything worked fine. Thanks again for your creative approach!

Fri January 19, 2024 10:07 AM

I had a closer look at my transformation triggers in the WebSEAL configuration file. It seems to me, that the http transformation triggers are set to use specific XSLT-Rules e.g. if a specific URL is called to change response headers of the WebSEAL. My goal is to use your approach to add a custom attribute to the response header of my AAC (EAI) responding to a call from the WebSEAL. Did i get something wrong? I will now try to implement your approch as a single authPolicy that is used as a last step in an accessPolicy.

Mon January 15, 2024 03:47 AM

Check your http transformation triggers are set correctly. 

Mon January 15, 2024 02:50 AM

Hi Shane,

i digged a bit deeper... the approch works fine for GET-Requests from the PD to the Backend (AAC). The custom response headers work and show up as expected. But if i want to customize them via a POST-Request, the response from the Backend (AAC) contains a 200 OK status (expected behaviour for POSTs), but no custom headers. Is there any possibility to add custom headers also to responses for incoming POST-Requests? Thanks!

Fri January 12, 2024 05:23 AM

Hello Shane,

i'm using an "isolated" InfoMap now and your approach works fine! My problem seemed to be, that the InfoMap calling the template wasn't part of the "last" Policy/Mechanism called, so the headers created by the EAI (here AAC) were finally created by another InfoMap and therefore my custom headers were not part of the response.

Thanks for your support!

FYI: "macro_utils" is just a helper class calling "macros.put(...)"

Thu January 11, 2024 04:33 PM

In the infomap code you used macro_utils, but this needs to be macros.

Did you get the original example I wrote to work first?

Did you add IDMappingExtUtils.traceString("...") debugging to your infomap to ensure it is actually being called?

Are you really using the C locale and not serving back a page from another location?

Sounds like there are a bunch of things you could try to help further isolate the issue.

What you didn't say is what was actually seen to be sent back from the Infomap. 

Thu January 11, 2024 09:18 AM

Hello Shane,

thanks for your interesting post and approach! I tried to add a header this way (after a user changed his password to ensure logout from all sessions afterwards). I use the following code in my infomap:

macro_utils.put("@USERNAME@", username);
page.setValue("/authsvc/authenticator/eailogin.html");
success.setValue(false);

My template (located in C/authsvc/authenticator/eailogin.html) looks like:

<%
templateContext.response.setHeader("am-eai-server-task", "terminate all_sessions " + templateContext.macros["@USERNAME@"]);
%>

Sadly this approch does not work. I tried to add custom headers like "some-header" with "some-value" as well (without using macros). The debug-tracelog does not show any of my custom headers. Is there anything i got wrong? Thanks in advance and best regards!