liquid_feedback_frontend

annotate app/main/oauth2/authorization.lua @ 1540:b0b557858fd8

Fixed access to non-existing session object in auth filter
author bsw
date Tue Oct 20 17:58:07 2020 +0200 (2020-10-20)
parents 32cc544d5a5b
children 2dc0ea4cdb4a
rev   line source
bsw/jbe@1309 1 local function show_error(text)
bsw/jbe@1309 2 ui.title("Authorization")
bsw/jbe@1309 3 ui.section(function()
bsw/jbe@1309 4 ui.sectionHead(function()
bsw/jbe@1309 5 ui.heading{ content = _"Error during authorization" }
bsw/jbe@1309 6 end)
bsw/jbe@1309 7 ui.sectionRow(function()
bsw/jbe@1309 8 ui.container{ content = text }
bsw/jbe@1309 9 end )
bsw/jbe@1309 10 end )
bsw/jbe@1309 11 end
bsw/jbe@1309 12
bsw/jbe@1309 13 local client_id = param.get("client_id")
bsw/jbe@1309 14 local redirect_uri = param.get("redirect_uri")
bsw/jbe@1309 15 local redirect_uri_explicit = redirect_uri and true or false
bsw/jbe@1309 16 local response_type = param.get("response_type")
bsw/jbe@1309 17 local state = param.get("state")
bsw/jbe@1309 18
bsw/jbe@1309 19 local no_scope_requested = true
bsw/jbe@1309 20
bsw/jbe@1309 21 local scopes = {
bsw/jbe@1309 22 [0] = param.get("scope")
bsw/jbe@1309 23 }
bsw/jbe@1309 24
bsw/jbe@1309 25 for i = 1, math.huge do
bsw/jbe@1309 26 scopes[i] = param.get("scope" .. i)
bsw/jbe@1309 27 if not scopes[i] then
bsw/jbe@1309 28 break
bsw/jbe@1309 29 end
bsw/jbe@1309 30 end
bsw/jbe@1309 31
bsw/jbe@1309 32 if #scopes == 0 and not scopes[0] then
bsw/jbe@1309 33 scopes[0] = "identification"
bsw/jbe@1309 34 end
bsw/jbe@1309 35
bsw/jbe@1309 36 local requested_scopes = {}
bsw/jbe@1309 37
bsw/jbe@1309 38 for i = 0, #scopes do
bsw/jbe@1309 39 if scopes[i] then
bsw/jbe@1309 40 for scope in string.gmatch(scopes[i], "[^ ]+") do
bsw/jbe@1309 41 requested_scopes[scope] = true
bsw/jbe@1309 42 end
bsw/jbe@1309 43 end
bsw/jbe@1309 44 end
bsw/jbe@1309 45
bsw/jbe@1309 46 local system_application
bsw/jbe@1309 47 local member_application
bsw/jbe@1309 48 local client_name
bsw/jbe@1309 49 local scopes_to_accept = table.new(requested_scopes)
bsw/jbe@1309 50 local accepted_scopes = {}
bsw/jbe@1309 51
bsw/jbe@1309 52 local domain
bsw/jbe@1309 53
bsw/jbe@1309 54 if client_id then
bsw/jbe@1309 55 domain = string.match(client_id, "^dynamic:([a-z0-9.-]+)$")
bsw/jbe@1309 56 end
bsw/jbe@1309 57
bsw/jbe@1309 58 local dynamic_application_check
bsw/jbe@1309 59 if domain then
bsw/jbe@1309 60 if #domain > 255 then
bsw/jbe@1309 61 return show_error(_"Domain too long")
bsw/jbe@1309 62 end
bsw/jbe@1309 63 if string.find(domain, "^%.") or string.find(domain, "%.$") or string.find(domain, "%.%.") then
bsw/jbe@1309 64 return show_error(_"Invalid domain format")
bsw/jbe@1309 65 end
bsw/jbe@1309 66 if redirect_uri then
bsw/jbe@1309 67 local redirect_uri_domain, magic = string.match(redirect_uri, "^[Hh][Tt][Tt][Pp][Ss]://([A-Za-z0-9_.-]+)/(.*)$")
bsw/jbe@1309 68 if not redirect_uri_domain or string.lower(redirect_uri_domain) ~= domain or magic ~= config.oauth2.endpoint_magic then
bsw/jbe@1309 69 return show_error(_"Redirect URI forbidden")
bsw/jbe@1309 70 end
bsw/jbe@1309 71 else
bsw/jbe@1309 72 redirect_uri = "https://" .. domain .. "/" .. config.oauth2.endpoint_magic
bsw/jbe@1309 73 end
bsw/jbe@1309 74 dynamic_application_check = DynamicApplicationScope:check_scopes(domain, redirect_uri, response_type, requested_scopes)
bsw/jbe@1309 75 if dynamic_application_check == "not_registered" then
bsw/jbe@1309 76 return show_error(_"Redirect URI or response type not registered")
bsw/jbe@1309 77 end
bsw/jbe@1309 78 client_name = domain
bsw/jbe@1309 79 member_application = MemberApplication:by_member_id_and_domain(app.session.member_id, domain)
bsw/jbe@1309 80 if member_application then
bsw/jbe@1309 81 for scope in string.gmatch(member_application.scope, "[^ ]+") do
bsw/jbe@1309 82 accepted_scopes[scope] = true
bsw/jbe@1309 83 scopes_to_accept[scope] = nil
bsw/jbe@1309 84 end
bsw/jbe@1309 85 end
bsw/jbe@1309 86 else
bsw/jbe@1309 87 system_application = SystemApplication:by_client_id(client_id)
bsw/jbe@1309 88 if system_application then
bsw/jbe@1309 89 if redirect_uri_explicit then
bsw/jbe@1309 90 if
bsw/jbe@1309 91 redirect_uri ~= system_application.default_redirect_uri
bsw/jbe@1309 92 and not SystemApplicationRedirectUri:by_pk(system_application.id, redirect_uri)
bsw/jbe@1309 93 then
bsw/jbe@1309 94 return show_error(_"Redirect URI invalid")
bsw/jbe@1309 95 end
bsw/jbe@1309 96 else
bsw/jbe@1309 97 redirect_uri = system_application.default_redirect_uri
bsw/jbe@1309 98 end
bsw/jbe@1309 99 if system_application.flow ~= response_type then
bsw/jbe@1309 100 return show_error(_"Response type not allowed for given client")
bsw/jbe@1309 101 end
bsw/jbe@1309 102 client_name = system_application.name
bsw/jbe@1309 103 member_application = MemberApplication:by_member_id_and_system_application_id(app.session.member_id, system_application.id)
bsw/jbe@1309 104 end
bsw/jbe@1309 105 end
bsw/jbe@1309 106
bsw/jbe@1309 107 if not client_name then
bsw/jbe@1309 108 return show_error(_"Client ID invalid")
bsw/jbe@1309 109 end
bsw/jbe@1309 110
bsw/jbe@1309 111 local function error_redirect(error_code, description)
bsw/jbe@1309 112 local params = {
bsw/jbe@1309 113 state = state,
bsw/jbe@1309 114 error = error_code,
bsw/jbe@1309 115 error_description = description
bsw/jbe@1309 116 }
bsw/jbe@1309 117 if response_type == "token" then
bsw/jbe@1309 118 local anchor_params_list = {}
bsw/jbe@1309 119 for k, v in pairs(params) do
bsw/jbe@1309 120 anchor_params_list[#anchor_params_list+1] = k .. "=" .. encode.url_part(v)
bsw/jbe@1309 121 end
bsw/jbe@1309 122 local anchor = table.concat(anchor_params_list, "&")
bsw/jbe@1309 123 request.redirect{
bsw/jbe@1309 124 external = redirect_uri .. "#" .. anchor
bsw/jbe@1309 125 }
bsw/jbe@1309 126 else
bsw/jbe@1309 127 request.redirect{
bsw/jbe@1309 128 external = redirect_uri,
bsw/jbe@1309 129 params = params
bsw/jbe@1309 130 }
bsw/jbe@1309 131 end
bsw/jbe@1309 132 end
bsw/jbe@1309 133
bsw/jbe@1309 134 if response_type ~= "code" and response_type ~= "token" then
bsw/jbe@1309 135 return error_redirect("unsupported_response_type", "Invalid response type")
bsw/jbe@1309 136 end
bsw/jbe@1309 137
bsw/jbe@1309 138 for i = 0, #scopes do
bsw/jbe@1309 139 if scopes[i] == "" then
bsw/jbe@1309 140 return error_redirect("invalid_scope", "Empty scope requested")
bsw/jbe@1309 141 end
bsw/jbe@1309 142 end
bsw/jbe@1309 143
bsw/jbe@1309 144 for scope in pairs(requested_scopes) do
bsw/jbe@1309 145 local scope_valid = false
bsw/jbe@1309 146 for i, entry in ipairs(config.oauth2.available_scopes) do
bsw/jbe@1309 147 if scope == entry.scope or scope == entry.scope .. "_detached" then
bsw/jbe@1309 148 scope_valid = true
bsw/jbe@1309 149 break
bsw/jbe@1309 150 end
bsw/jbe@1309 151 end
bsw/jbe@1309 152 if not scope_valid then
bsw/jbe@1309 153 return error_redirect("invalid_scope", "Requested scope not available")
bsw/jbe@1309 154 end
bsw/jbe@1309 155 end
bsw/jbe@1309 156
bsw/jbe@1309 157 if system_application then
bsw/jbe@1309 158 if system_application.permitted_scope then
bsw/jbe@1309 159 local permitted_scopes = {}
bsw/jbe@1309 160 for scope in string.gmatch(system_application.permitted_scope, "[^ ]+") do
bsw/jbe@1309 161 permitted_scopes[scope] = true
bsw/jbe@1309 162 end
bsw/jbe@1309 163 for scope in pairs(requested_scopes) do
bsw/jbe@1309 164 if not permitted_scopes[scope] then
bsw/jbe@1309 165 return error_redirect("invalid_scope", "Scope not permitted")
bsw/jbe@1309 166 end
bsw/jbe@1309 167 end
bsw/jbe@1309 168 end
bsw/jbe@1309 169 if system_application.forbidden_scope then
bsw/jbe@1309 170 for scope in string.gmatch(system_application.forbidden_scope, "[^ ]+") do
bsw/jbe@1309 171 if requested_scopes[scope] then
bsw/jbe@1309 172 return error_redirect("invalid_scope", "Scope forbidden")
bsw/jbe@1309 173 end
bsw/jbe@1309 174 end
bsw/jbe@1309 175 end
bsw/jbe@1309 176 if system_application.automatic_scope then
bsw/jbe@1309 177 for scope in string.gmatch(system_application.automatic_scope, "[^ ]+") do
bsw/jbe@1309 178 scopes_to_accept[scope] = nil
bsw/jbe@1309 179 accepted_scopes[scope] = true
bsw/jbe@1309 180 end
bsw/jbe@1309 181 end
bsw/jbe@1309 182 if member_application then
bsw/jbe@1309 183 for scope in string.gmatch(member_application.scope, "[^ ]+") do
bsw/jbe@1309 184 scopes_to_accept[scope] = nil
bsw/jbe@1309 185 accepted_scopes[scope] = true
bsw/jbe@1309 186 end
bsw/jbe@1309 187 end
bsw/jbe@1309 188 else
bsw/jbe@1309 189 if dynamic_application_check == "missing_scope" then
bsw/jbe@1309 190 return error_redirect("invalid_scope", "Scope not permitted")
bsw/jbe@1309 191 end
bsw/jbe@1309 192 end
bsw/jbe@1309 193
bsw/jbe@1309 194 if next(scopes_to_accept) then
bsw/jbe@1309 195 ui.title("Application authorization")
bsw/jbe@1309 196 ui.section(function()
bsw/jbe@1309 197 ui.sectionHead(function()
bsw/jbe@1309 198 ui.heading{ content = client_name }
bsw/jbe@1309 199 ui.heading{ content = "wants to access your account" }
bsw/jbe@1309 200 end)
bsw/jbe@1309 201 if not system_application and not member_application then
bsw/jbe@1309 202 ui.sectionRow(function()
bsw/jbe@1309 203 ui.container{ content = _"Warning: Untrusted third party application." }
bsw/jbe@1309 204 end)
bsw/jbe@1309 205 end
bsw/jbe@1309 206 ui.sectionRow(function()
bsw/jbe@1309 207 ui.heading{ level = 3, content = _"Requested privileges:" }
bsw/jbe@1309 208 ui.tag{ tag = "ul", attr = { class = "ul" }, content = function()
bsw/jbe@1309 209 for i, entry in ipairs(config.oauth2.available_scopes) do
bsw/jbe@1309 210 local name = entry.name[locale.get("lang")] or entry.scope
bsw/jbe@1309 211 if accepted_scopes[entry.scope] or requested_scopes[entry.scope] or accepted_scopes[entry.scope .. "_detached"] or requested_scopes[entry.scope .. "_detached"] then
bsw/jbe@1309 212 ui.tag{ tag = "li", content = function()
bsw/jbe@1309 213 ui.tag{ content = name }
bsw/jbe@1309 214 if accepted_scopes[entry.scope .. "_detached"] or requested_scopes[entry.scope .. "_detached"] then
bsw/jbe@1309 215 slot.put(" ")
bsw/jbe@1309 216 ui.tag{ content = _"(detached)" }
bsw/jbe@1309 217 end
bsw/jbe@1309 218 if scopes_to_accept[entry.scope] or scopes_to_accept[entry.scope .. "_detached"] then
bsw/jbe@1309 219 slot.put(" ")
bsw/jbe@1309 220 ui.tag{ content = _"(new)" }
bsw/jbe@1309 221 end
bsw/jbe@1309 222 -- TODO display changes
bsw/jbe@1309 223 end }
bsw/jbe@1309 224 end
bsw/jbe@1309 225 end
bsw/jbe@1309 226 end }
bsw/jbe@1309 227 end )
bsw/jbe@1309 228 local params = {
bsw/jbe@1309 229 system_application_id = system_application and system_application.id or nil,
bsw/jbe@1309 230 domain = domain,
bsw/jbe@1309 231 redirect_uri = redirect_uri,
bsw/jbe@1309 232 redirect_uri_explicit = redirect_uri_explicit,
bsw/jbe@1309 233 state = state,
bsw/jbe@1309 234 response_type = response_type
bsw/jbe@1309 235 }
bsw/jbe@1309 236 for i = 0, #scopes do
bsw/jbe@1309 237 params["scope" .. i] = scopes[i]
bsw/jbe@1309 238 end
bsw/jbe@1309 239 ui.form{
bsw/jbe@1309 240 module = "oauth2", action = "accept_scope", params = params,
bsw/jbe@1309 241 routing = { default = { mode = "redirect", module = "oauth2", view = "authorization", params = request.get_param_strings() } },
bsw/jbe@1309 242 content = function()
bsw/jbe@1309 243 ui.sectionRow(function()
bsw/jbe@1309 244 ui.submit{ text = _"Grant authorization", attr = { class = "mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect mdl-button--colored " } }
bsw/jbe@1309 245 slot.put("   ")
bsw/jbe@1309 246 ui.link{ content = _"Decline authorization", attr = { class = "mdl-button mdl-js-button" }, external = redirect_uri, params = { error = "access_denied", error_description = "User declined to authorize client" } }
bsw/jbe@1309 247 end )
bsw/jbe@1309 248 end
bsw/jbe@1309 249 }
bsw/jbe@1309 250 end )
bsw/jbe@1309 251 else
bsw/jbe@1309 252
bsw/jbe@1309 253 execute.chunk{ module = "oauth2", chunk = "_authorization", params = {
bsw/jbe@1309 254 member_id = app.session.member_id,
bsw/jbe@1309 255 system_application_id = system_application and system_application.id or nil,
bsw/jbe@1309 256 domain = domain,
bsw/jbe@1309 257 session_id = app.session.id,
bsw/jbe@1309 258 redirect_uri = redirect_uri,
bsw/jbe@1309 259 redirect_uri_explicit = redirect_uri_explicit,
bsw/jbe@1309 260 scopes = scopes,
bsw/jbe@1309 261 state = state,
bsw/jbe@1309 262 response_type = response_type
bsw/jbe@1309 263 } }
bsw/jbe@1309 264
bsw/jbe@1309 265
bsw/jbe@1309 266 end
bsw/jbe@1309 267

Impressum / About Us