comparison mod_sasl2_fast/mod_sasl2_fast.lua @ 5650:0eb2d5ea2428

merge
author Stephen Paul Weber <singpolyma@singpolyma.net>
date Sat, 06 May 2023 19:40:23 -0500
parents b10a7082b3c3
children 563c2c70cb9f
comparison
equal deleted inserted replaced
5649:2c69577b28c2 5650:0eb2d5ea2428
1 local usermanager = require "core.usermanager";
2
1 local sasl = require "util.sasl"; 3 local sasl = require "util.sasl";
2 local dt = require "util.datetime"; 4 local dt = require "util.datetime";
3 local id = require "util.id"; 5 local id = require "util.id";
4 local jid = require "util.jid"; 6 local jid = require "util.jid";
5 local st = require "util.stanza"; 7 local st = require "util.stanza";
36 return token_info; 38 return token_info;
37 end 39 end
38 40
39 local function new_token_tester(hmac_f) 41 local function new_token_tester(hmac_f)
40 return function (mechanism, username, client_id, token_hash, cb_data, invalidate) 42 return function (mechanism, username, client_id, token_hash, cb_data, invalidate)
43 local account_info = usermanager.get_account_info(username, module.host);
44 local last_password_change = account_info and account_info.password_updated;
41 local tried_current_token = false; 45 local tried_current_token = false;
42 local key = hash.sha256(client_id, true).."-new"; 46 local key = hash.sha256(client_id, true).."-new";
43 local token; 47 local token;
44 repeat 48 repeat
45 log("debug", "Looking for %s token %s/%s", mechanism, username, key); 49 log("debug", "Looking for %s token %s/%s", mechanism, username, key);
50 local current_time = now(); 54 local current_time = now();
51 if token.expires_at < current_time then 55 if token.expires_at < current_time then
52 log("debug", "Token found, but it has expired (%ds ago). Cleaning up...", current_time - token.expires_at); 56 log("debug", "Token found, but it has expired (%ds ago). Cleaning up...", current_time - token.expires_at);
53 token_store:set(username, key, nil); 57 token_store:set(username, key, nil);
54 return nil, "credentials-expired"; 58 return nil, "credentials-expired";
59 elseif last_password_change and token.issued_at < last_password_change then
60 log("debug", "Token found, but issued prior to password change (%ds ago). Cleaning up...",
61 current_time - last_password_change
62 );
63 token_store:set(username, key, nil);
64 return nil, "credentials-expired";
55 end 65 end
56 if not tried_current_token and not invalidate then 66 if not tried_current_token and not invalidate then
57 -- The new token is becoming the current token 67 -- The new token is becoming the current token
58 token_store:set_keys(username, { 68 token_store:set_keys(username, {
59 [key] = token_store.remove; 69 [key] = token_store.remove;
60 [key:sub(1, -4).."-cur"] = token; 70 [key:sub(1, -5).."-cur"] = token;
61 }); 71 });
62 end 72 end
63 local rotation_needed; 73 local rotation_needed;
64 if invalidate then 74 if invalidate then
65 token_store:set(username, key, nil); 75 token_store:set(username, key, nil);
72 end 82 end
73 if not tried_current_token then 83 if not tried_current_token then
74 log("debug", "Trying next token..."); 84 log("debug", "Trying next token...");
75 -- Try again with the current token instead 85 -- Try again with the current token instead
76 tried_current_token = true; 86 tried_current_token = true;
77 key = key:sub(1, -4).."-cur"; 87 key = key:sub(1, -5).."-cur";
78 else 88 else
79 log("debug", "No matching %s token found for %s/%s", mechanism, username, key); 89 log("debug", "No matching %s token found for %s/%s", mechanism, username, key);
80 return nil; 90 return nil;
81 end 91 end
82 until false; 92 until false;
100 username = jid.node(event.stream.from); 110 username = jid.node(event.stream.from);
101 if not username then return; end 111 if not username then return; end
102 end 112 end
103 local sasl_handler = get_sasl_handler(username); 113 local sasl_handler = get_sasl_handler(username);
104 if not sasl_handler then return; end 114 if not sasl_handler then return; end
115 sasl_handler.fast_auth = true; -- For informational purposes
105 -- Copy channel binding info from primary SASL handler 116 -- Copy channel binding info from primary SASL handler
106 sasl_handler.profile.cb = session.sasl_handler.profile.cb; 117 sasl_handler.profile.cb = session.sasl_handler.profile.cb;
107 sasl_handler.userdata = session.sasl_handler.userdata; 118 sasl_handler.userdata = session.sasl_handler.userdata;
108 -- Store this handler, in case we later want to use it for authenticating 119 -- Store this handler, in case we later want to use it for authenticating
109 session.fast_sasl_handler = sasl_handler; 120 session.fast_sasl_handler = sasl_handler;
215 226
216 register_ht_mechanism("HT-SHA-256-NONE", "ht_sha_256", nil); 227 register_ht_mechanism("HT-SHA-256-NONE", "ht_sha_256", nil);
217 register_ht_mechanism("HT-SHA-256-UNIQ", "ht_sha_256", "tls-unique"); 228 register_ht_mechanism("HT-SHA-256-UNIQ", "ht_sha_256", "tls-unique");
218 register_ht_mechanism("HT-SHA-256-ENDP", "ht_sha_256", "tls-server-end-point"); 229 register_ht_mechanism("HT-SHA-256-ENDP", "ht_sha_256", "tls-server-end-point");
219 register_ht_mechanism("HT-SHA-256-EXPR", "ht_sha_256", "tls-exporter"); 230 register_ht_mechanism("HT-SHA-256-EXPR", "ht_sha_256", "tls-exporter");
231
232 -- Public API
233
234 --luacheck: ignore 131
235 function is_client_fast(username, client_id, last_password_change)
236 local client_id_hash = hash.sha256(client_id, true);
237 local curr_time = now();
238 local cur = token_store:get(username, client_id_hash.."-cur");
239 if cur and cur.expires_at >= curr_time and (not last_password_change or last_password_change < cur.issued_at) then
240 return true;
241 end
242 local new = token_store:get(username, client_id_hash.."-new");
243 if new and new.expires_at >= curr_time and (not last_password_change or last_password_change < new.issued_at) then
244 return true;
245 end
246 return false;
247 end
248
249 function revoke_fast_tokens(username, client_id)
250 local client_id_hash = hash.sha256(client_id, true);
251 local cur_ok = token_store:set(username, client_id_hash.."-cur", nil);
252 local new_ok = token_store:set(username, client_id_hash.."-new", nil);
253 return cur_ok and new_ok;
254 end