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@1593
|
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@1593
|
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
|