WebSEAL LUA http transformation rules with external data warning
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
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.