plugins/sasl.lua

changeset 354
58cd27b74ba5
parent 315
3742107e2505
child 358
a8f6fd6a70ed
equal deleted inserted replaced
353:8cd05c3d0f1f 354:58cd27b74ba5
1 local base64 = require "mime".b64; 1 -- local verse = require"verse";
2 local base64, unbase64 = require "mime".b64, require"mime".unb64;
2 local xmlns_sasl = "urn:ietf:params:xml:ns:xmpp-sasl"; 3 local xmlns_sasl = "urn:ietf:params:xml:ns:xmpp-sasl";
3 4
4 function verse.plugins.sasl(stream) 5 function verse.plugins.sasl(stream)
5 local function handle_features(features_stanza) 6 local function handle_features(features_stanza)
6 if stream.authenticated then return; end 7 if stream.authenticated then return; end
7 stream:debug("Authenticating with SASL..."); 8 stream:debug("Authenticating with SASL...");
8 --stream.sasl_state, initial_data = sasl_new({"PLAIN"}, stream.username, stream.password, stream.jid); 9 local sasl_mechanisms = features_stanza:get_child("mechanisms", xmlns_sasl);
9 local mechanism , initial_data 10 if not sasl_mechanisms then return end
10 if stream.username then 11
11 mechanism = "PLAIN" 12 local mechanisms = {};
12 initial_data = base64("\0"..stream.username.."\0"..stream.password); 13 local preference = {};
13 else 14
14 mechanism = "ANONYMOUS" 15 for mech in sasl_mechanisms:childtags("mechanism") do
16 mech = mech:get_text();
17 stream:debug("Server offers %s", mech);
18 if not mechanisms[mech] then
19 local name = mech:match("[^-]+");
20 local ok, impl = pcall(require, "util.sasl."..name:lower());
21 if ok then
22 stream:debug("Loaded SASL %s module", name);
23 impl(stream, mechanisms, preference);
24 elseif not tostring(impl):match("not found") then
25 stream:debug("Loading failed: %s", tostring(impl));
26 end
27 end
15 end 28 end
16 stream:debug("Selecting %s mechanism...",mechanism); 29
30 local supported = {}; -- by the server
31 for mech in pairs(mechanisms) do
32 table.insert(supported, mech);
33 end
34 if not supported[1] then
35 stream:event("authentication-failure", { condition = "no-supported-sasl-mechanisms" });
36 stream:close();
37 return;
38 end
39 table.sort(supported, function (a, b) return preference[a] > preference[b]; end);
40 local mechanism, initial_data = supported[1];
41 stream:debug("Selecting %s mechanism...", mechanism);
42 stream.sasl_mechanism = coroutine.wrap(mechanisms[mechanism]);
43 initial_data = stream:sasl_mechanism(mechanism);
17 local auth_stanza = verse.stanza("auth", { xmlns = xmlns_sasl, mechanism = mechanism }); 44 local auth_stanza = verse.stanza("auth", { xmlns = xmlns_sasl, mechanism = mechanism });
18 if initial_data then 45 if initial_data then
19 auth_stanza:text(initial_data); 46 auth_stanza:text(base64(initial_data));
20 end 47 end
21 stream:send(auth_stanza); 48 stream:send(auth_stanza);
22 return true; 49 return true;
23 end 50 end
24 51
25 local function handle_sasl(sasl_stanza) 52 local function handle_sasl(sasl_stanza)
26 if sasl_stanza.name == "success" then 53 if sasl_stanza.name == "failure" then
27 stream.authenticated = true;
28 stream:event("authentication-success");
29 elseif sasl_stanza.name == "failure" then
30 local err = sasl_stanza.tags[1]; 54 local err = sasl_stanza.tags[1];
31 local text = sasl_stanza:get_child_text("text"); 55 local text = sasl_stanza:get_child_text("text");
32 stream:event("authentication-failure", { condition = err.name, text = text }); 56 stream:event("authentication-failure", { condition = err.name, text = text });
57 stream:close();
58 return false;
33 end 59 end
34 stream:reopen(); 60 local ok, err = stream.sasl_mechanism(sasl_stanza.name, unbase64(sasl_stanza:get_text()));
61 if not ok then
62 stream:event("authentication-failure", { condition = err });
63 stream:close();
64 return false;
65 elseif ok == true then
66 stream:event("authentication-success");
67 stream.authenticated = true
68 stream:reopen();
69 else
70 stream:send(verse.stanza("response", { xmlns = xmlns_sasl }):text(base64(ok)));
71 end
35 return true; 72 return true;
36 end 73 end
37 74
38 stream:hook("stream-features", handle_features, 300); 75 stream:hook("stream-features", handle_features, 300);
39 stream:hook("stream/"..xmlns_sasl, handle_sasl); 76 stream:hook("stream/"..xmlns_sasl, handle_sasl);

mercurial