Software /
code /
prosody
Comparison
plugins/mod_saslauth.lua @ 290:f9b7afd42b67
Merge new SASL code from Tobias and Waqas
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Sat, 15 Nov 2008 19:44:09 +0000 |
parent | 289:3c8a28c1f331 |
child | 291:5672d2be1bf3 |
comparison
equal
deleted
inserted
replaced
275:7af22e56d625 | 290:f9b7afd42b67 |
---|---|
1 | 1 |
2 local st = require "util.stanza"; | 2 local st = require "util.stanza"; |
3 local send = require "core.sessionmanager".send_to_session; | 3 local send = require "core.sessionmanager".send_to_session; |
4 local sm_bind_resource = require "core.sessionmanager".bind_resource; | 4 local sm_bind_resource = require "core.sessionmanager".bind_resource; |
5 local jid | |
5 | 6 |
6 local usermanager_validate_credentials = require "core.usermanager".validate_credentials; | 7 local usermanager_validate_credentials = require "core.usermanager".validate_credentials; |
7 local t_concat, t_insert = table.concat, table.insert; | 8 local t_concat, t_insert = table.concat, table.insert; |
8 local tostring = tostring; | 9 local tostring = tostring; |
10 local jid_split = require "util.jid".split | |
9 | 11 |
10 local log = require "util.logger".init("mod_saslauth"); | 12 local log = require "util.logger".init("mod_saslauth"); |
11 | 13 |
12 local xmlns_sasl ='urn:ietf:params:xml:ns:xmpp-sasl'; | 14 local xmlns_sasl ='urn:ietf:params:xml:ns:xmpp-sasl'; |
13 local xmlns_bind ='urn:ietf:params:xml:ns:xmpp-bind'; | 15 local xmlns_bind ='urn:ietf:params:xml:ns:xmpp-bind'; |
14 local xmlns_stanzas ='urn:ietf:params:xml:ns:xmpp-stanzas'; | 16 local xmlns_stanzas ='urn:ietf:params:xml:ns:xmpp-stanzas'; |
15 | 17 |
16 local new_sasl = require "util.sasl".new; | 18 local new_sasl = require "util.sasl".new; |
17 | 19 |
20 local function build_reply(status, ret) | |
21 local reply = st.stanza(status, {xmlns = xmlns_sasl}); | |
22 if status == "challenge" then | |
23 reply:text(ret or ""); | |
24 elseif status == "failure" then | |
25 reply:tag(ret):up(); | |
26 elseif status == "success" then | |
27 reply:text(ret or ""); | |
28 else | |
29 error("Unknown sasl status: "..status); | |
30 end | |
31 return reply; | |
32 end | |
33 | |
34 local function handle_status(session, status) | |
35 if status == "failure" then | |
36 session.sasl_handler = nil; | |
37 elseif status == "success" then | |
38 if not session.sasl_handler.username then error("SASL succeeded but we didn't get a username!"); end -- TODO move this to sessionmanager | |
39 sessionmanager.make_authenticated(session, session.sasl_handler.username); | |
40 session.sasl_handler = nil; | |
41 session:reset_stream(); | |
42 end | |
43 end | |
44 | |
45 local function password_callback(jid, mechanism) | |
46 local node, host = jid_split(jid); | |
47 local password = (datamanager.load(node, host, "accounts") or {}).password; -- FIXME handle hashed passwords | |
48 local func = function(x) return x; end; | |
49 if password then | |
50 if mechanism == "PLAIN" then | |
51 return func, password; | |
52 elseif mechanism == "DIGEST-MD5" then | |
53 return func, require "hashes".md5(node.."::"..password); | |
54 end | |
55 end | |
56 return func, nil; | |
57 end | |
58 | |
59 function do_sasl(session, stanza) | |
60 local text = stanza[1]; | |
61 if text then | |
62 text = base64.decode(text); | |
63 if not text then | |
64 session.sasl_handler = nil; | |
65 session.send(build_reply("failure", "incorrect-encoding")); | |
66 return; | |
67 end | |
68 end | |
69 local status, ret = session.sasl_handler:feed(text); | |
70 handle_status(session, status); | |
71 local s = build_reply(status, ret); | |
72 log("debug", "sasl reply: "..tostring(s)); | |
73 session.send(s); | |
74 end | |
75 | |
18 add_handler("c2s_unauthed", "auth", xmlns_sasl, | 76 add_handler("c2s_unauthed", "auth", xmlns_sasl, |
19 function (session, stanza) | 77 function (session, stanza) |
20 if not session.sasl_handler then | 78 if not session.sasl_handler then |
21 session.sasl_handler = new_sasl(stanza.attr.mechanism, | 79 session.sasl_handler = new_sasl(stanza.attr.mechanism, session.host, password_callback); |
22 function (username, password) | 80 do_sasl(session, stanza); |
23 -- onAuth | |
24 require "core.usermanager" | |
25 if usermanager_validate_credentials(session.host, username, password) then | |
26 return true; | |
27 end | |
28 return false; | |
29 end, | |
30 function (username) | |
31 -- onSuccess | |
32 local success, err = sessionmanager.make_authenticated(session, username); | |
33 if not success then | |
34 sessionmanager.destroy_session(session); | |
35 return; | |
36 end | |
37 session.sasl_handler = nil; | |
38 session:reset_stream(); | |
39 end, | |
40 function (reason) | |
41 -- onFail | |
42 log("debug", "SASL failure, reason: %s", reason); | |
43 end, | |
44 function (stanza) | |
45 -- onWrite | |
46 log("debug", "SASL writes: %s", tostring(stanza)); | |
47 send(session, stanza); | |
48 end | |
49 ); | |
50 session.sasl_handler:feed(stanza); | |
51 else | 81 else |
52 error("Client tried to negotiate SASL again", 0); | 82 error("Client tried to negotiate SASL again", 0); |
53 end | 83 end |
54 | |
55 end); | 84 end); |
56 | 85 |
86 add_handler("c2s_unauthed", "abort", xmlns_sasl, | |
87 function(session, stanza) | |
88 if not session.sasl_handler then error("Attempt to abort when sasl has not started"); end | |
89 do_sasl(session, stanza); | |
90 end); | |
91 | |
92 add_handler("c2s_unauthed", "response", xmlns_sasl, | |
93 function(session, stanza) | |
94 if not session.sasl_handler then error("Attempt to respond when sasl has not started"); end | |
95 do_sasl(session, stanza); | |
96 end); | |
97 | |
57 add_event_hook("stream-features", | 98 add_event_hook("stream-features", |
58 function (session, features) | 99 function (session, features) |
59 if not session.username then | 100 if not session.username then |
60 t_insert(features, "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"); | 101 t_insert(features, "<mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>"); |
102 -- TODO: Provide PLAIN only if TLS is active, this is a SHOULD from the introduction of RFC 4616. This behavior could be overridden via configuration but will issuing a warning or so. | |
61 t_insert(features, "<mechanism>PLAIN</mechanism>"); | 103 t_insert(features, "<mechanism>PLAIN</mechanism>"); |
104 t_insert(features, "<mechanism>DIGEST-MD5</mechanism>"); | |
62 t_insert(features, "</mechanisms>"); | 105 t_insert(features, "</mechanisms>"); |
63 else | 106 else |
64 t_insert(features, "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><required/></bind>"); | 107 t_insert(features, "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><required/></bind>"); |
65 t_insert(features, "<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>"); | 108 t_insert(features, "<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>"); |
66 end | 109 end |