Merge 0.10->trunk
[prosody.git] / plugins / mod_saslauth.lua
index 9e63b4c7a9421e73a650ed97e6c7aab682a733f9..bb36600b2e066641e59fc975c4a01281b90f23dd 100644 (file)
@@ -16,8 +16,10 @@ local base64 = require "util.encodings".base64;
 local usermanager_get_sasl_handler = require "core.usermanager".get_sasl_handler;
 local tostring = tostring;
 
-local secure_auth_only = module:get_option("c2s_require_encryption") or module:get_option("require_encryption");
-local allow_unencrypted_plain_auth = module:get_option("allow_unencrypted_plain_auth")
+local secure_auth_only = module:get_option_boolean("c2s_require_encryption", module:get_option_boolean("require_encryption", false));
+local allow_unencrypted_plain_auth = module:get_option_boolean("allow_unencrypted_plain_auth", false)
+local insecure_mechanisms = module:get_option_set("insecure_sasl_mechanisms", allow_unencrypted_plain_auth and {} or {"PLAIN", "LOGIN"});
+local disabled_mechanisms = module:get_option_set("disable_sasl_mechanisms", { "DIGEST-MD5" });
 
 local log = module._log;
 
@@ -183,9 +185,12 @@ module:hook("stanza/urn:ietf:params:xml:ns:xmpp-sasl:auth", function(event)
                session.sasl_handler = usermanager_get_sasl_handler(module.host, session);
        end
        local mechanism = stanza.attr.mechanism;
-       if not session.secure and (secure_auth_only or (mechanism == "PLAIN" and not allow_unencrypted_plain_auth)) then
+       if not session.secure and (secure_auth_only or insecure_mechanisms:contains(mechanism)) then
                session.send(build_reply("failure", "encryption-required"));
                return true;
+       elseif disabled_mechanisms:contains(mechanism) then
+               session.send(build_reply("failure", "invalid-mechanism"));
+               return true;
        end
        local valid_mechanism = session.sasl_handler:select(mechanism);
        if not valid_mechanism then
@@ -209,6 +214,10 @@ module:hook("stanza/urn:ietf:params:xml:ns:xmpp-sasl:abort", function(event)
        return true;
 end);
 
+local function tls_unique(self)
+       return self.userdata["tls-unique"]:getpeerfinished();
+end
+
 local mechanisms_attr = { xmlns='urn:ietf:params:xml:ns:xmpp-sasl' };
 local bind_attr = { xmlns='urn:ietf:params:xml:ns:xmpp-bind' };
 local xmpp_session_attr = { xmlns='urn:ietf:params:xml:ns:xmpp-session' };
@@ -218,24 +227,32 @@ module:hook("stream-features", function(event)
                if secure_auth_only and not origin.secure then
                        return;
                end
-               origin.sasl_handler = usermanager_get_sasl_handler(module.host, origin);
+               local sasl_handler = usermanager_get_sasl_handler(module.host, origin)
+               origin.sasl_handler = sasl_handler;
                if origin.encrypted then
                        -- check wether LuaSec has the nifty binding to the function needed for tls-unique
                        -- FIXME: would be nice to have this check only once and not for every socket
-                       if origin.conn:socket().getpeerfinished and origin.sasl_handler.add_cb_handler then
-                               origin.sasl_handler:add_cb_handler("tls-unique", function(self)
-                                       return self.userdata:getpeerfinished();
-                               end);
-                               origin.sasl_handler["userdata"] = origin.conn:socket();
+                       if sasl_handler.add_cb_handler then
+                               local socket = origin.conn:socket();
+                               if socket.getpeerfinished then
+                                       sasl_handler:add_cb_handler("tls-unique", tls_unique);
+                               end
+                               sasl_handler["userdata"] = {
+                                       ["tls-unique"] = socket;
+                               };
                        end
                end
                local mechanisms = st.stanza("mechanisms", mechanisms_attr);
-               for mechanism in pairs(origin.sasl_handler:mechanisms()) do
-                       if mechanism ~= "PLAIN" or origin.secure or allow_unencrypted_plain_auth then
+               for mechanism in pairs(sasl_handler:mechanisms()) do
+                       if (not disabled_mechanisms:contains(mechanism)) and (origin.secure or not insecure_mechanisms:contains(mechanism)) then
                                mechanisms:tag("mechanism"):text(mechanism):up();
                        end
                end
-               if mechanisms[1] then features:add_child(mechanisms); end
+               if mechanisms[1] then
+                       features:add_child(mechanisms);
+               else
+                       (origin.log or log)("warn", "No SASL mechanisms to offer");
+               end
        else
                features:tag("bind", bind_attr):tag("required"):up():up();
                features:tag("session", xmpp_session_attr):tag("optional"):up():up();