Software /
code /
prosody
Comparison
plugins/mod_saslauth.lua @ 2193:8fbbdb11a520
Merge with sasl branch.
author | Tobias Markmann <tm@ayena.de> |
---|---|
date | Mon, 16 Nov 2009 21:43:57 +0100 |
parent | 2014:913c0845ef9a |
parent | 2179:c985536d5452 |
child | 2204:de3edab7551d |
comparison
equal
deleted
inserted
replaced
2080:ca419b92a8c7 | 2193:8fbbdb11a520 |
---|---|
1 -- Prosody IM | 1 -- Prosody IM |
2 -- Copyright (C) 2008-2009 Matthew Wild | 2 -- Copyright (C) 2008-2009 Matthew Wild |
3 -- Copyright (C) 2008-2009 Waqas Hussain | 3 -- Copyright (C) 2008-2009 Waqas Hussain |
4 -- | 4 -- |
5 -- This project is MIT/X11 licensed. Please see the | 5 -- This project is MIT/X11 licensed. Please see the |
6 -- COPYING file in the source package for more information. | 6 -- COPYING file in the source package for more information. |
7 -- | 7 -- |
8 | 8 |
9 | 9 |
33 local xmlns_bind ='urn:ietf:params:xml:ns:xmpp-bind'; | 33 local xmlns_bind ='urn:ietf:params:xml:ns:xmpp-bind'; |
34 local xmlns_stanzas ='urn:ietf:params:xml:ns:xmpp-stanzas'; | 34 local xmlns_stanzas ='urn:ietf:params:xml:ns:xmpp-stanzas'; |
35 | 35 |
36 local new_sasl = require "util.sasl".new; | 36 local new_sasl = require "util.sasl".new; |
37 | 37 |
38 default_authentication_profile = { | |
39 plain = function(username, realm) | |
40 local prepped_username = nodeprep(username); | |
41 if not prepped_username then | |
42 log("debug", "NODEprep failed on username: %s", username); | |
43 return "", nil; | |
44 end | |
45 local password = usermanager_get_password(prepped_username, realm); | |
46 if not password then | |
47 return "", nil; | |
48 end | |
49 return password, true; | |
50 end | |
51 }; | |
52 | |
53 anonymous_authentication_profile = { | |
54 anonymous = function(username, realm) | |
55 return true; -- for normal usage you should always return true here | |
56 end | |
57 } | |
58 | |
38 local function build_reply(status, ret, err_msg) | 59 local function build_reply(status, ret, err_msg) |
39 local reply = st.stanza(status, {xmlns = xmlns_sasl}); | 60 local reply = st.stanza(status, {xmlns = xmlns_sasl}); |
40 if status == "challenge" then | 61 if status == "challenge" then |
41 log("debug", "%s", ret or ""); | 62 log("debug", "%s", ret or ""); |
42 reply:text(base64.encode(ret or "")); | 63 reply:text(base64.encode(ret or "")); |
55 local function handle_status(session, status) | 76 local function handle_status(session, status) |
56 if status == "failure" then | 77 if status == "failure" then |
57 session.sasl_handler = nil; | 78 session.sasl_handler = nil; |
58 elseif status == "success" then | 79 elseif status == "success" then |
59 local username = nodeprep(session.sasl_handler.username); | 80 local username = nodeprep(session.sasl_handler.username); |
60 session.sasl_handler = nil; | |
61 if not username then -- TODO move this to sessionmanager | 81 if not username then -- TODO move this to sessionmanager |
62 module:log("warn", "SASL succeeded but we didn't get a username!"); | 82 module:log("warn", "SASL succeeded but we didn't get a username!"); |
63 session.sasl_handler = nil; | 83 session.sasl_handler = nil; |
64 session:reset_stream(); | 84 session:reset_stream(); |
65 return; | 85 return; |
66 end | 86 end |
67 sm_make_authenticated(session, username); | 87 sm_make_authenticated(session, session.sasl_handler.username); |
88 session.sasl_handler = nil; | |
68 session:reset_stream(); | 89 session:reset_stream(); |
69 end | |
70 end | |
71 | |
72 local function credentials_callback(mechanism, ...) | |
73 if mechanism == "PLAIN" then | |
74 local username, hostname, password = ...; | |
75 username = nodeprep(username); | |
76 if not username then | |
77 return false; | |
78 end | |
79 local response = usermanager_validate_credentials(hostname, username, password, mechanism); | |
80 if response == nil then | |
81 return false; | |
82 else | |
83 return response; | |
84 end | |
85 elseif mechanism == "DIGEST-MD5" then | |
86 local function func(x) return x; end | |
87 local node, domain, realm, decoder = ...; | |
88 local prepped_node = nodeprep(node); | |
89 if not prepped_node then | |
90 return func, nil; | |
91 end | |
92 local password = usermanager_get_password(prepped_node, domain); | |
93 if password then | |
94 if decoder then | |
95 node, realm, password = decoder(node), decoder(realm), decoder(password); | |
96 end | |
97 return func, md5(node..":"..realm..":"..password); | |
98 else | |
99 return func, nil; | |
100 end | |
101 end | 90 end |
102 end | 91 end |
103 | 92 |
104 local function sasl_handler(session, stanza) | 93 local function sasl_handler(session, stanza) |
105 if stanza.name == "auth" then | 94 if stanza.name == "auth" then |
109 return session.send(build_reply("failure", "invalid-mechanism")); | 98 return session.send(build_reply("failure", "invalid-mechanism")); |
110 end | 99 end |
111 elseif stanza.attr.mechanism == "ANONYMOUS" then | 100 elseif stanza.attr.mechanism == "ANONYMOUS" then |
112 return session.send(build_reply("failure", "mechanism-too-weak")); | 101 return session.send(build_reply("failure", "mechanism-too-weak")); |
113 end | 102 end |
114 session.sasl_handler = new_sasl(stanza.attr.mechanism, session.host, credentials_callback); | 103 local valid_mechanism = session.sasl_handler:select(stanza.attr.mechanism); |
115 if not session.sasl_handler then | 104 if not valid_mechanism then |
116 return session.send(build_reply("failure", "invalid-mechanism")); | 105 return session.send(build_reply("failure", "invalid-mechanism")); |
117 end | 106 end |
118 elseif not session.sasl_handler then | 107 elseif not session.sasl_handler then |
119 return; -- FIXME ignoring out of order stanzas because ejabberd does | 108 return; -- FIXME ignoring out of order stanzas because ejabberd does |
120 end | 109 end |
126 session.sasl_handler = nil; | 115 session.sasl_handler = nil; |
127 session.send(build_reply("failure", "incorrect-encoding")); | 116 session.send(build_reply("failure", "incorrect-encoding")); |
128 return; | 117 return; |
129 end | 118 end |
130 end | 119 end |
131 local status, ret, err_msg = session.sasl_handler:feed(text); | 120 local status, ret, err_msg = session.sasl_handler:process(text); |
132 handle_status(session, status); | 121 handle_status(session, status); |
133 local s = build_reply(status, ret, err_msg); | 122 local s = build_reply(status, ret, err_msg); |
134 log("debug", "sasl reply: %s", tostring(s)); | 123 log("debug", "sasl reply: %s", tostring(s)); |
135 session.send(s); | 124 session.send(s); |
136 end | 125 end |
146 function (session, features) | 135 function (session, features) |
147 if not session.username then | 136 if not session.username then |
148 if secure_auth_only and not session.secure then | 137 if secure_auth_only and not session.secure then |
149 return; | 138 return; |
150 end | 139 end |
140 if config.get(session.host or "*", "core", "anonymous_login") then | |
141 session.sasl_handler = new_sasl(session.host, anonymous_authentication_profile); | |
142 else | |
143 session.sasl_handler = new_sasl(session.host, default_authentication_profile); | |
144 end | |
151 features:tag("mechanisms", mechanisms_attr); | 145 features:tag("mechanisms", mechanisms_attr); |
152 -- 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. | 146 -- 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. |
153 if config.get(session.host or "*", "core", "anonymous_login") then | 147 for k, v in pairs(session.sasl_handler:mechanisms()) do |
154 features:tag("mechanism"):text("ANONYMOUS"):up(); | 148 features:tag("mechanism"):text(v):up(); |
155 else | 149 end |
156 local mechanisms = usermanager_get_supported_methods(session.host or "*"); | |
157 for k, v in pairs(mechanisms) do | |
158 features:tag("mechanism"):text(k):up(); | |
159 end | |
160 end | |
161 features:up(); | 150 features:up(); |
162 else | 151 else |
163 features:tag("bind", bind_attr):tag("required"):up():up(); | 152 features:tag("bind", bind_attr):tag("required"):up():up(); |
164 features:tag("session", xmpp_session_attr):tag("optional"):up():up(); | 153 features:tag("session", xmpp_session_attr):tag("optional"):up():up(); |
165 end | 154 end |