basic_auth_access_check.lua 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. local resty_cookie = require("resty.cookie") -- https://github.com/cloudflare/lua-resty-cookie
  2. local util = require("util")
  3. local json = require("json")
  4. local agent_pub = require("agent_pub")
  5. local config = require("config")
  6. local no_permission = "/wolf/rbac/no_permission"
  7. local no_permission_html = "/wolf/rbac/no_permission.html"
  8. local basic_auth_access_check_url = "/wolf/rbac/access_check"
  9. function get_authorization()
  10. local headers = ngx.req.get_headers()
  11. local authorization = headers["Authorization"]
  12. return authorization
  13. end
  14. local function get_host_port()
  15. local host = ngx.var.host
  16. local port = ""
  17. if ngx.var.server_port and ngx.var.server_port ~= 80 then
  18. port = ":" .. tostring(ngx.var.server_port)
  19. end
  20. local host_port = (ngx.var.scheme or "http") .. "://" .. host .. port
  21. return host_port
  22. end
  23. local function url_args_as_args(ext_args)
  24. local args = ngx.req.get_uri_args()
  25. local host_port = get_host_port()
  26. local full_url = host_port .. ngx.var.uri
  27. args["return_to"] = full_url
  28. if ext_args and type(ext_args) == 'table' then
  29. for k, v in pairs(ext_args) do
  30. args[k] = v
  31. end
  32. end
  33. return args
  34. end
  35. local function check_url_permission(appID, action, resName, clientIP)
  36. local retry_max = 3
  37. local reason = nil;
  38. local userInfo = nil
  39. local res = nil
  40. for i = 1, retry_max do
  41. local args = { appID = appID, resName = resName, action = action, agentName=config.agentName, clientIP=clientIP}
  42. local url = basic_auth_access_check_url .. "?" .. ngx.encode_args(args)
  43. res = ngx.location.capture(url)
  44. if res then
  45. ngx.log(ngx.INFO, "check permission request:", url, ", status:", res.status, ",body:", tostring(res.body))
  46. if res.status < 500 then
  47. break
  48. else
  49. ngx.log(ngx.ERR, string.format("request [curl -v %s] failed! status:%d", url, res.status))
  50. end
  51. else
  52. reason = 'check permission failed, check request failed!'
  53. ngx.log(ngx.ERR, "fail request: ", url)
  54. end
  55. end
  56. if not res then
  57. return false, 500, reason
  58. end
  59. if res.status ~= 200 then
  60. local strBody = util.trim(res.body or "")
  61. local body, err = json.loads(strBody)
  62. if err then
  63. userInfo = res.body
  64. reason = 'check permission failed! parse response json failed!'
  65. else
  66. reason = body.reason
  67. end
  68. return false, res.status, reason, userInfo, res.headers
  69. else
  70. local body, err = json.loads(res.body)
  71. if err then
  72. userInfo = res.body
  73. reason = 'check permission failed! parse response json failed!'
  74. ngx.log(ngx.ERR, "json.loads(", res.body, ") failed! err:", err)
  75. else
  76. userInfo = body.data.userInfo
  77. reason = body.reason
  78. end
  79. return true, res.status, reason, userInfo, res.headers
  80. end
  81. end
  82. local function url_redirect(url, args)
  83. local appID = ngx.var.appID or "appIDUnset"
  84. args.appid = appID
  85. args = ngx.encode_args(args)
  86. util.redirect(url, args)
  87. end
  88. local function access_check()
  89. local url = ngx.var.uri
  90. local action = ngx.req.get_method()
  91. if util.url_in_ignore_list(url) then
  92. ngx.log(ngx.INFO, "check permission, ignore current request!")
  93. return
  94. end
  95. local appID = ngx.var.appID or "appIDUnset"
  96. local loginPrompt = ngx.var.loginPrompt or "input you username and password"
  97. local clientIP = util.clientIP()
  98. local permItem = "{appID: " .. appID .. ", action: " .. action .. ", url: " .. url .. ", clientIP: " .. clientIP .. "}"
  99. ngx.log(ngx.INFO, "Cookie: ", ngx.var.http_cookie, ", permItem=", permItem)
  100. local authorization = get_authorization()
  101. if authorization == nil then
  102. ngx.log(ngx.WARN, "no permission to access ", permItem, ", need login!")
  103. ngx.status = ngx.HTTP_UNAUTHORIZED
  104. ngx.header["WWW-Authenticate"] = "Basic realm=\"" .. loginPrompt .. "\""
  105. ngx.send_headers()
  106. ngx.flush(true)
  107. end
  108. local ok, status, reason, userInfo, headers = check_url_permission(appID, action, url, clientIP)
  109. ngx.log(ngx.INFO, " check_url_permission(", permItem, ",token=", tostring(token), ")=",
  110. ok, ", status:", tostring(status), ", userInfo:", tostring(json.dumps(userInfo)))
  111. local userID = -1
  112. local username = nil
  113. local nickname = nil
  114. if type(userInfo) == 'table' then
  115. ngx.req.set_header("X-UserId", userInfo.id)
  116. ngx.req.set_header("X-Username", userInfo.username)
  117. ngx.req.set_header("X-nickname", ngx.escape_uri(userInfo.nickname) or userInfo.username)
  118. -- local args = ngx.req.get_uri_args()
  119. ngx.ctx.userInfo = userInfo
  120. userID = userInfo.id
  121. username = userInfo.username
  122. nickname = userInfo.nickname
  123. end
  124. if headers and headers["Set-Cookie"] then
  125. local cookie_value = headers["Set-Cookie"]
  126. ngx.header['Set-Cookie'] = cookie_value
  127. ngx.log(ngx.INFO, "******* Re Set-Cookie:", cookie_value, " *******")
  128. end
  129. if ok then
  130. ---
  131. else
  132. -- no permission.
  133. if status == ngx.HTTP_UNAUTHORIZED or status == ngx.HTTP_FORBIDDEN then
  134. if reason == "ERR_TOKEN_INVALID" then
  135. ngx.status = ngx.HTTP_UNAUTHORIZED
  136. ngx.header["WWW-Authenticate"] = "Basic realm=\"" .. loginPrompt .. "\""
  137. ngx.send_headers()
  138. ngx.flush(true)
  139. else
  140. local redirect_url = no_permission_html
  141. if url == '/' then
  142. redirect_url = no_permission_html
  143. end
  144. url_redirect(redirect_url, { username = username, reason=reason })
  145. end
  146. elseif status == ngx.HTTP_BAD_REQUEST then
  147. ngx.status = ngx.HTTP_INTERNAL_SERVER_ERROR
  148. ngx.header["Content-Type"] = "text/plain"
  149. ngx.send_headers()
  150. ngx.flush(true)
  151. ngx.say("rbac check permission failed! status:" .. tostring(status))
  152. ngx.flush(true)
  153. else
  154. ngx.status = status
  155. ngx.header["Content-Type"] = "text/plain"
  156. ngx.send_headers()
  157. ngx.flush(true)
  158. ngx.say("rbac check permission failed! status:" .. tostring(status))
  159. ngx.flush(true)
  160. end
  161. end
  162. end
  163. access_check()