This is some additional info on creating LUA transformation rules in WebSEAL, building on this topic: WebSEAL LUA http transformation rules with external data

Lua transformation rule using http.requests gotcha

Cookies !

https://daurnimator.github.io/lua-http/0.4/#http.request

doc.png

So the lua-http module that you can use to make call outs, does something unexpected. It will, by default, use a shared cookie store.

Now in WebSEAL, this means this cookie store is shared between all invocations of the LUA transformation rule. This is something you would want to avoid, generally.

I’ll repeat this message : every time a new user invokes the LUA transformation rule that contains a http callout, he will share the same cookie store with the first invocation.

Solution

Luckily, the solution is pretty simple. You need to include an empty cookie store before you invoke the transformation, to avoid leaking information through cookies. You can do that by setting the cookie_store property of the http.request:

req.cookie_store = cookies.new_store()

The updated example looks like this:

local request = require "http.request"
local cookies = require "http.cookie"
local cjson = require "cjson"
 
local configuri = "https://blogs.gwbasics.be/requestmatch.json"
local req = request.new_from_uri(configuri)

-- cookie store
-- request has a shared cookie store by default.  So create a new store every time.
req.cookie_store = cookies.new_store()
-- cookie store end

local headers, stream = assert(req:go())
 
if (headers == nil) or (not headers) then
    Control.returnErrorPage( "1. Could not load configuration data from: "..configuri )
    return
end
 
local body = assert(stream:get_body_as_string())
 
if headers:get ":status" ~= "200" then
    Control.returnErrorPage( "2. http error during loading of: "..configuri )
    return
end
 
if (body == nil) or (not body) then
    Control.returnErrorPage( "3. http error during loading of: "..configuri )
    return
end
 
Control.trace(5, string.format(body))
 
local thejsonbody = cjson.decode(body)
 
local req = HTTPRequest.getURL()
 
for i,v in ipairs(thejsonbody) do
 
    Control.trace(5, "Access url table element : "..v["url"])
 
    if string.find(req, v["url"]) then
        HTTPRequest.setHeader("X-LUA-Processed", "Tom Bosmans")
        Control.trace(5, "Found match "..req)
    end
end

Test the rule

So there is nothing really new here, and it’s also not visible that we now no longer share cookies from the backend. The test described here, would also not really indicate any issues with cookies: Since for every invocation, the container is restarted, there is no previous cookie store.

However, you will be able to verify that the cookie store is no longer shared if you deploy the http transformation rule on WebSEAL, or on an actual IAG deployed in a container management platform.

Prepare context.yaml

You can generate a context.yaml using dumpContext (in lua script), or by creating one yourself.

You can start from a generated context:

podman run --rm --entrypoint iag_lua_transformation_test icr.io/ibmappgateway/ibm-application-gateway:22.07 -t

This is the output, and you can edit it as you like.

http:
  request:
    method:   <method>
    url:      <url>
    version:  <version>
    protocol: <protocol>
    body:     <body>
    headers:
      - name:  <hdr-name>
        value: <hdr-value>
    cookies:
      - name:  <cookie-name>
        value: <cookie-value>
  response:
    version:  <version>
    body:     <body>
    status:
      code:    <code>
      message: <message>
    headers:
      - name:  <hdr-name>
        value: <hdr-value>
    cookies:
      - name:  <cookie-name>
        value: <cookie-value>
session:
  id:       <id>
  username: <username>
  credential:
    attributes:
      - name:  <attribute-name>
        value: <attribute-value>

This is the context.yaml I’m using for this test :

http:
  request:
    method: "GET"
    url:    "/junction1/index.html"
    headers:
      - name:  "User-Agent"
        value: "curl"
      - name:  "Host"
        value: "www.ibm.com"
credential:
  attribute:
    - name:  "AZN_CRED_PRINCIPAL_NAME"
      value: "testuser"

Save it in the current directory, together with the .lua file.

Run the test

You should now have 2 files in the current directory:

  • load_from_http.lua ( the actual lua script )
  • context.yaml (the webseal context)
podman run --rm -v ${PWD}:/lua_test:z --entrypoint iag_lua_transformation_test \
 icr.io/ibmappgateway/ibm-application-gateway:24.12 -c /lua_test/context.yaml -s /lua_test/load_from_http.lua

Or, using the IVIA WebSEAL container:

podman run --rm -v ${PWD}:/lua_test:z --entrypoint isva_lua_transformation_test \
  icr.io/ivia/ivia-wrp:11.0.0.0 -c /lua_test/context.yaml -s /lua_test/load_from_http.lua

Note: in podman, the :z option in the volume mount seems necessary. The error message is not particularly helpful, but if you get the message below, it’s likely the volume mount files are not accessible by the container. DPWWA3301E A failure occurred while parsing the YAML file: /var/iag/staging/context.yaml (bad file) The reason is that the files actually should have system_u:object_r:container_file_t:s0 as selinux context. If you run the above podman command once with the :z option, the selinux context is updated and :z is no longer necessary.

If all goes well, you get this output:

Lua trace (level: 5): [
{"url": "index.html"},
{"url": "testerdetest"} 
]

Lua trace (level: 5): Access url table element : index.html
Request header: set (X-LUA-Processed,Tom Bosmans)
Lua trace (level: 5): Found match /junction1/index.html
Lua trace (level: 5): Access url table element : testerdetest

Interactive

If you still run into problems, you can also run the iag_lua_transformation_test command interactively:

podman run --rm -it --entrypoint bash icr.io/ibmappgateway/ibm-application-gateway:22.07
[ivmgr@76f3f6ef8a69 /]$ cd /var/iag/staging/
[ivmgr@76f3f6ef8a69 staging]$ ls
[ivmgr@76f3f6ef8a69 staging]$ vi rule.lua
[ivmgr@76f3f6ef8a69 staging]$ vi context.yaml
[ivmgr@76f3f6ef8a69 staging]$ iag_lua_transformation_test -c context.yaml -s rule.lua

WebSeal configuration

webseald.conf

Once you’ve tested the rule, you can deploy it in WebSEAL.

Edit the webseald.conf, and add a request-match entry.

loadfromhttp = load_from_http.lua

[http-transformations:loadfromhttp]
request-match = request:* /isam/*

NOTE: Make sure to limit the scope here (limit when the lua transformation rule is executed). There is going to be a relatively big hit on performance, since the http call is executed every time the transformation rule is called.

Error page

By adding a page named errors/c/38b9a4b2.html to the management root of the instance, you create a custom error page for these transformations. You can use the macro %FAILREASON% to show the error messages you generate in the lua script using Control.returnErrorPage.

<html>
<head>
    <title>ERROR during transformation</title>
</head>
<body>
 
<h1>Error during execution of a transformation rule</h1>
 
%FAILREASON%
</body>
</html>

It’s easy to verify this, for instance by using a non-existing hostname for the configuri variable.