zmartzone / lua-resty-openidc

OpenID Connect Relying Party and OAuth 2.0 Resource Server implementation in Lua for NGINX / OpenResty
Apache License 2.0
976 stars 249 forks source link

Bug: authentication fails for some users #500

Closed strgalt-t closed 11 months ago

strgalt-t commented 12 months ago

Hello,

we're using the lua-resty-openidc plugin together with Keycloak. Nearly all of our users have no issue with authentication, yet we have a handful of users from whom it fails. It's an issue that's different to replicate, as it happens randomly. The users for whom authentication fails for site B, can still access site A that's also protected by the plugin. The configurations itself between site A and B are near identical, only the groups that are matched upon differ.

Environment
Expected behaviour

I expect all users to be successfully authenticated.

Actual behaviour

Some users get a 500 internal server while it works fine for others.

The logs show the following:

2023/12/05 12:20:01 [error] 7#7: *3301 lua entry thread aborted: runtime error: /etc/nginx/lua/access.lua
stack traceback:
 coroutine 0:
  [C]: in function 'pairs'
   /etc/nginx/lua/access.lua:17: in function 'table_to_string'
   /etc/nginx/lua/access.lua:46: in main chunk, client: 172.18.0.2, server: <SERVER_URL>, request: "GET /PATH) HTTP/1.1", host: "<SERVER_URL>", <USER-AGENT>"

The access.lua contains the following:

-- this script is used to configure authentication against the running keycloak instance
local opts = {
...
  }
  -- Convert a lua table into a lua syntactically correct string
  function table_to_string(tbl)
      local result = "{"
      for k, v in pairs(tbl) do
          -- Check the key type (ignore any numerical keys - assume its an array)
          if type(k) == "string" then
              result = result.."[\""..k.."\"]".."="
          end

          -- Check the value type
          if type(v) == "table" then
              result = result..table_to_string(v)
          elseif type(v) == "boolean" then
              result = result..tostring(v)
          else
              result = result.."\""..v.."\""
          end
          result = result..","
      end
      -- Remove leading commas from the result
      if result ~= "{" then
          result = result:sub(1, result:len()-1)
      end
      return result.."}"
  end
  -- call introspect for OAuth 2.0 Bearer Access Token validation
  local res, err = require("resty.openidc").authenticate(opts)
  if err then
    ngx.status = 403
    ngx.say(err)
    ngx.exit(ngx.HTTP_FORBIDDEN)
  end
  if string.find(table_to_string(res.id_token.groups), "<GROUP>") then
    ngx.status = 200
  elseif string.find(res.id_token.email, "<COMPANY>.com") then
    ngx.status = 200
  else
    ngx.exit(ngx.HTTP_FORBIDDEN)
  end

Any help would be much appreciated.