Browse Source

Solve review issues and add retries for http call

j8
Andrei Bora 5 years ago
parent
commit
b765adca75

+ 18
- 16
resources/prosody-plugins/mod_auth_token.lua View File

74
 	return nil;
74
 	return nil;
75
 end
75
 end
76
 
76
 
77
-local function validate_result(session, res, error, reason)
78
-    if res == false then
79
-        log("warn",
80
-            "Error verifying token err:%s, reason:%s", error, reason);
81
-        session.auth_token = nil;
82
-        return res, error, reason;
83
-    end
84
-end
85
-
86
 function provider.get_sasl_handler(session)
77
 function provider.get_sasl_handler(session)
87
 
78
 
88
 	local function get_username_from_token(self, message)
79
 	local function get_username_from_token(self, message)
89
 
80
 
90
         -- retrieve custom public key from server and save it on the session
81
         -- retrieve custom public key from server and save it on the session
91
-        local event_result = prosody.events.fire_event("pre-jitsi-authentication-fetch-key", session);
92
-        if event_result ~= nil then
93
-            validate_result(session,event_result.res, event_result.error, event_result.reason)
82
+        local pre_event_result = prosody.events.fire_event("pre-jitsi-authentication-fetch-key", session);
83
+        if pre_event_result ~= nil and pre_event_result.res == false then
84
+            log("warn",
85
+                "Error verifying token on pre authentication stage:%s, reason:%s", pre_event_result.error, pre_event_result.reason);
86
+            session.auth_token = nil;
87
+            return pre_event_result.res, pre_event_result.error, pre_event_result.reason;
94
         end
88
         end
95
 
89
 
96
         local res, error, reason = token_util:process_and_verify_token(session);
90
         local res, error, reason = token_util:process_and_verify_token(session);
97
-        validate_result(session, res, error, reason);
91
+        if res == false then
92
+            log("warn",
93
+                "Error verifying token err:%s, reason:%s", error, reason);
94
+            session.auth_token = nil;
95
+            return res, error, reason;
96
+        end
98
 
97
 
99
         local customUsername
98
         local customUsername
100
             = prosody.events.fire_event("pre-jitsi-authentication", session);
99
             = prosody.events.fire_event("pre-jitsi-authentication", session);
112
             self.username = message;
111
             self.username = message;
113
         end
112
         end
114
 
113
 
115
-        local event_result = prosody.events.fire_event("post-jitsi-authentication", session);
116
-        if event_result ~= nil then
117
-            validate_result(session,event_result.res, event_result.error, event_result.reason)
114
+        local post_event_result = prosody.events.fire_event("post-jitsi-authentication", session);
115
+        if post_event_result ~= nil and post_event_result.res == false then
116
+            log("warn",
117
+                "Error verifying token on post authentication stage :%s, reason:%s", post_event_result.error, post_event_result.reason);
118
+            session.auth_token = nil;
119
+            return post_event_result.res, post_event_result.error, post_event_result.reason;
118
         end
120
         end
119
 
121
 
120
         return res;
122
         return res;

+ 6
- 57
resources/prosody-plugins/token/util.lib.lua View File

5
 local have_async, async = pcall(require, "util.async");
5
 local have_async, async = pcall(require, "util.async");
6
 local hex = require "util.hex";
6
 local hex = require "util.hex";
7
 local jwt = require "luajwtjitsi";
7
 local jwt = require "luajwtjitsi";
8
-local http = require "net.http";
9
 local jid = require "util.jid";
8
 local jid = require "util.jid";
10
 local json_safe = require "cjson.safe";
9
 local json_safe = require "cjson.safe";
11
 local path = require "util.paths";
10
 local path = require "util.paths";
12
 local sha256 = require "util.hashes".sha256;
11
 local sha256 = require "util.hashes".sha256;
13
-local timer = require "util.timer";
12
+local http_get_with_retry = module:require "util".http_get_with_retry;
14
 
13
 
15
-local http_timeout = 30;
16
-local http_headers = {
17
-    ["User-Agent"] = "Prosody ("..prosody.version.."; "..prosody.platform..")"
18
-};
14
+local nr_retries = 3;
19
 
15
 
20
 -- TODO: Figure out a less arbitrary default cache size.
16
 -- TODO: Figure out a less arbitrary default cache size.
21
 local cacheSize = module:get_option_number("jwt_pubkey_cache_size", 128);
17
 local cacheSize = module:get_option_number("jwt_pubkey_cache_size", 128);
131
     if content == nil then
127
     if content == nil then
132
         -- If the key is not found in the cache.
128
         -- If the key is not found in the cache.
133
         module:log("debug", "Cache miss for key: "..keyId);
129
         module:log("debug", "Cache miss for key: "..keyId);
134
-        local code;
135
-        local timeout_occurred;
136
-        local wait, done = async.waiter();
137
-
138
         local keyurl = path.join(self.asapKeyServer, hex.to(sha256(keyId))..'.pem');
130
         local keyurl = path.join(self.asapKeyServer, hex.to(sha256(keyId))..'.pem');
139
-
140
-        local function cb(content_, code_, response_, request_)
141
-            if timeout_occurred == nil then
142
-                content, code = content_, code_;
143
-                if code == 200 or code == 204 then
144
-                    self.cache:set(keyId, content);
145
-                else
146
-                    module:log("warn", "Error on public key request: Code %s, Content %s",
147
-                    code_, content_);
148
-                end
149
-                done();
150
-            else
151
-                module:log("warn", "public key reply delivered after timeout from: %s",keyurl);
152
-            end
153
-        end
154
-
155
-        -- TODO: Is the done() call racey? Can we cancel this if the request
156
-        --       succeedes?
157
-        local function cancel()
158
-            -- TODO: This check is racey. Not likely to be a problem, but we should
159
-            --       still stick a mutex on content / code at some point.
160
-            if code == nil then
161
-                timeout_occurred = true;
162
-                module:log("warn", "Timeout %s seconds fetching public key from: %s",http_timeout,keyurl);
163
-                if http.destroy_request ~= nil then
164
-                    http.destroy_request(request);
165
-                end
166
-                done();
167
-            end
168
-        end
169
-
170
         module:log("debug", "Fetching public key from: "..keyurl);
131
         module:log("debug", "Fetching public key from: "..keyurl);
171
-
172
-        -- We hash the key ID to work around some legacy behavior and make
173
-        -- deployment easier. It also helps prevent directory
174
-        -- traversal attacks (although path cleaning could have done this too).
175
-        local request = http.request(keyurl, {
176
-            headers = http_headers or {},
177
-            method = "GET"
178
-        }, cb);
179
-
180
-        timer.add_task(http_timeout, cancel);
181
-        wait();
182
-
183
-        if code == 200 or code == 204 then
184
-            return content;
132
+        content = http_get_with_retry(keyurl, nr_retries);
133
+        if content ~= nil then
134
+            self.cache:set(keyId, content);
185
         end
135
         end
136
+        return content;
186
     else
137
     else
187
         -- If the key is in the cache, use it.
138
         -- If the key is in the cache, use it.
188
         module:log("debug", "Cache hit for key: "..keyId);
139
         module:log("debug", "Cache hit for key: "..keyId);
189
         return content;
140
         return content;
190
     end
141
     end
191
-
192
-    return nil;
193
 end
142
 end
194
 
143
 
195
 --- Verifies issuer part of token
144
 --- Verifies issuer part of token

+ 71
- 0
resources/prosody-plugins/util.lib.lua View File

1
 local jid = require "util.jid";
1
 local jid = require "util.jid";
2
+local timer = require "util.timer";
3
+local http = require "net.http";
4
+
5
+local http_timeout = 30;
2
 local have_async, async = pcall(require, "util.async");
6
 local have_async, async = pcall(require, "util.async");
7
+local http_headers = {
8
+    ["User-Agent"] = "Prosody ("..prosody.version.."; "..prosody.platform..")"
9
+};
10
+
3
 local muc_domain_prefix
11
 local muc_domain_prefix
4
     = module:get_option_string("muc_mapper_domain_prefix", "conference");
12
     = module:get_option_string("muc_mapper_domain_prefix", "conference");
5
 
13
 
208
     return false;
216
     return false;
209
 end
217
 end
210
 
218
 
219
+-- Utility function to make an http get request and
220
+-- retry @param retry number of times
221
+-- @param url endpoint to be called
222
+-- @param retry nr of retries, if retry is
223
+-- nil there will be no retries
224
+-- @returns result of the http call or nil if
225
+-- the external call failed after the last retry
226
+function http_get_with_retry(url, retry)
227
+    local content, code;
228
+    local wait, done = async.waiter();
229
+    local function cb(content_, code_, response_, request_)
230
+        code = code_;
231
+        if code == 200 or code == 204 then
232
+            module:log("debug", "External call was successful, content %s", content_);
233
+            content = content_
234
+        else
235
+            module:log("warn", "Error on public key request: Code %s, Content %s",
236
+                code_, content_);
237
+        end
238
+        done();
239
+    end
240
+
241
+    local function call_http()
242
+        return http.request(url, {
243
+            headers = http_headers or {},
244
+            method = "GET"
245
+        }, cb);
246
+    end
247
+
248
+    local request = call_http();
249
+
250
+    local function cancel()
251
+        -- TODO: This check is racey. Not likely to be a problem, but we should
252
+        --       still stick a mutex on content / code at some point.
253
+        if code == nil then
254
+            -- no longer present in prosody 0.11, so check before calling
255
+            if http.destroy_request ~= nil then
256
+                http.destroy_request(request);
257
+            end
258
+            if retry == nil then
259
+                module:log("debug", "External call failed and retry policy is not set");
260
+                done();
261
+            elseif retry ~= nil and retry < 1 then
262
+                module:log("debug", "External call failed after retry")
263
+                done();
264
+            else
265
+                module:log("debug", "External call failed, retry nr %s", retry)
266
+                retry = retry - 1;
267
+                request = call_http()
268
+                return http_timeout;
269
+            end
270
+        end
271
+    end
272
+    timer.add_task(http_timeout, cancel);
273
+    wait();
274
+
275
+    if code == 200 or code == 204 then
276
+        return content;
277
+    end
278
+    return nil;
279
+end
280
+
211
 return {
281
 return {
212
     is_feature_allowed = is_feature_allowed;
282
     is_feature_allowed = is_feature_allowed;
213
     is_healthcheck_room = is_healthcheck_room;
283
     is_healthcheck_room = is_healthcheck_room;
217
     room_jid_split_subdomain = room_jid_split_subdomain;
287
     room_jid_split_subdomain = room_jid_split_subdomain;
218
     internal_room_jid_match_rewrite = internal_room_jid_match_rewrite;
288
     internal_room_jid_match_rewrite = internal_room_jid_match_rewrite;
219
     update_presence_identity = update_presence_identity;
289
     update_presence_identity = update_presence_identity;
290
+    http_get_with_retry = http_get_with_retry;
220
 };
291
 };

Loading…
Cancel
Save