Prev: Next: Up: Lua[Contents][Index]


8.2 Lua conditionals

Lua functions are most commonly used to implement new conditions, that can be used to select the Service section to use. Such conditions are applied using LuaMatch statements in Service sections. The LuaMatch statement takes at least one argument: the name of Lua function to call. It can be followed by any number of string values, which will be passed to the function as its arguments. Before being passed to the function, these values undergo backreference expansion and request accessor interpretation (see Request modifications).

The first argument can be either an unqualified name, as ‘mycond’, or a fully qualified one, as ‘modname.mycond’. Use the latter form to call functions defined in modules.

Information about HTTP request is provided to Lua functions via the built-in variable http.req, described in Lua API.

To illustrate the concept, here’s the definition of a Lua test that returns true if the value of a header named in its first argument matches any of its remaining arguments, treated as anchored Lua patterns:

function isheader(name, ...)
   local args = { ... }
   for _, pat in ipairs(args) do
      if string.find(http.req.headers[name], "^"..pat.."$") then
         return true
      end
   end
   return false
end

Supposing that this function is defined in file isheader.lua, it can be used as follows:

Lua
    Load "isheader.lua"
End
ListenHTTP
    ...
    Service
        LuaMatch "host" "foo[.]bar" "www[.]fo+[.]bar"
        Backend
            ...
        End
    End
End

As a more practical example, the function below implements Bearer authorization scheme.

local bearer = {}
local jwt = require 'jwt'

function bearer.ok(secret)
   -- Read in the Authorization header.
   local bh = http.req.headers['Authorization']
   if bh == nil then
      return false
   end

   -- Check if it starts with "Bearer".
   local n, k = bh:find('%s+')
   if n == nil or bh:sub(1,n-1):lower() ~= 'bearer' then
      return false
   end

   -- Extract the token and parse it.
   local j, err = jwt.parse(bh:sub(k+1))
   if err ~= nil then
      return false
   end

   -- Verify the token.
   if not j:verify(secret) then
      return false
   end

   -- Check expiration time.
   if j.payload.exp ~= nil then
      local exp = tonumber(j.payload.exp)
      if exp == nil then
         return false
      elseif os.time() < j.payload.exp then
         return false
      end
   end

   return true
end

return bearer

See jwt.lua, for the implementation of the jwt module.

The following configuration fragment uses bearer.ok function as a condition, to reject requests without a valid bearer token:

Service
    Not LuaMatch "bearer.ok" "secret"
    Rewrite response
        SetHeader "WWW-Authenticate: Bearer realm=\"Restricted access\""
    End
    Error 401
End

Prev: Next: Up: Lua[Contents][Index]