Mercurial > prosody-hg
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 |
| parents | 913c0845ef9a c985536d5452 |
| children | 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 |
