
kind: ConfigMap
apiVersion: v1
metadata:
  name: kong-plugin-auth-client
data:
  schema.lua: |
    local typedefs = require "kong.db.schema.typedefs"

    return {
      name = "auth-client",
      fields = {
        { consumer = typedefs.no_consumer },
        { protocols = typedefs.protocols_http },
        {
          config = {
            type = "record",
            fields = {
              {
                authorization_endpoint = {
                  type = "string",
                  default = "http://regional-server.regional-server-system/api/premium/v1/k8s/authTokens/",
                  description = "regional-server auth endpoint URL. The `k8sName` will be appended to this URL.",
                }
              },
              {
                k8s_name_tag_prefix = {
                  type = "string",
                  default = "k8sName=",
                  description = "the prefix for the k8s name tag in the Ingress annotations. This will be used to extract the k8s name from the Ingress annotations.",
                }
              },
              {
                token_json_path = {
                  type = "string",
                  default = "token",
                  description = "the JSON path to extract the token from the response. This is used to retrieve the token from the authorization service response.",
                }
              },
              {
                connect_timeout = {
                  type = "number",
                  default = 2000,
                  description = "the timeout (in milliseconds) for connecting to the authorization service.",
                }
              },
              {
                read_timeout = {
                  type = "number",
                  default = 5000,
                  description = "the timeout (in milliseconds) for reading responses from the authorization service.",
                }
              },
            },
          },
        },
      },
    }

  handler.lua: |
    local http = require "resty.http"
    local cjson = require "cjson"
    local string_gmatch = string.gmatch

    local AuthClientHandler = {
      PRIORITY = 1000,
      VERSION = "0.1.0",
    }

    -- Helper function to extract value from JSON based on a simple path
    local function get_value_from_json(data, path)
      if not path or path == "" then
        return nil
      end
      local keys = {}
      for key in string_gmatch(path, "([^.]+)") do
        table.insert(keys, key)
      end

      local current = data
      for _, key in ipairs(keys) do
        if type(current) ~= "table" or current[key] == nil then
          return nil
        end
        current = current[key]
      end
      return current
    end


    function AuthClientHandler:access(conf)
      -- Step 1: Get 'k8sName' from route.tags (assumed to be set in Ingress annotations)
      local route = kong.router.get_route()
      if not route or not route.tags then
        return kong.response.exit(400, { message = "Route configuration error: missing tags" })
      end

      local k8s_name
      local k8s_name_tag_prefix = conf.k8s_name_tag_prefix

      for _, tag in ipairs(route.tags) do
        if tag:sub(1, #k8s_name_tag_prefix) == k8s_name_tag_prefix then
          k8s_name = tag:sub(#k8s_name_tag_prefix + 1)
          break
        end
      end

      if not k8s_name or k8s_name == "" then
        return kong.response.exit(400, { message = "k8sName tag not found or value is empty" })
      end

      -- Step 2: Append k8sName to authorization_endpoint
      local base_auth_url = conf.authorization_endpoint
      local auth_url = base_auth_url .. k8s_name
      kong.log.notice("AuthClientHandler:access - Constructed authorization URL: ", auth_url)

      -- Step 3: Request auth_url to get token
      local httpc = http.new()
      httpc:set_timeout(conf.connect_timeout)

      local res, err = httpc:request_uri(auth_url, {
        method = "GET",
        ssl_verify = false,
        headers = {
          ["Accept"] = "application/json",
        },
        keepalive_timeout = conf.read_timeout,
        keepalive_pool = 10,
      })

      if not res then
        return kong.response.exit(503, { message = "Failed to get authorization token: " .. (err or "unknown error") })
      end

      if res.status ~= 200 then
        return kong.response.exit(502, { message = "Authorization service returned error: " .. res.status .. " - " .. (res.body or "no response body") })
      end

      if not res.body or res.body == "" then
        return kong.response.exit(500, { message = "Empty response body from authorization service" })
      end
      local body_str = res.body

      local decoded_body, decode_err = cjson.decode(body_str)
      if decode_err then
        return kong.response.exit(500, { message = "Invalid JSON response from authorization service" .. decode_err })
      end

      -- Extract token from JSON response, e.g. {"token": "$TOKEN"}
      local token = get_value_from_json(decoded_body, conf.token_json_path)
      if not token or token == "" then
        return kong.response.exit(500, { message = "Token not found in authorization response" })
      end

      -- Step 4: Attach token as Bearer token to original request header
      kong.service.request.set_header("Authorization", "Bearer " .. token)
      kong.log.notice("AuthClientHandler:access - Plugin executed successfully")
    end

    return AuthClientHandler
