diff options
-rw-r--r-- | plugins/mod_dialback.lua | 8 | ||||
-rw-r--r-- | plugins/mod_s2s/mod_s2s.lua | 4 | ||||
-rw-r--r-- | plugins/mod_saslauth.lua | 101 |
3 files changed, 43 insertions, 70 deletions
diff --git a/plugins/mod_dialback.lua b/plugins/mod_dialback.lua index 4c5e3e44..5dfd9839 100644 --- a/plugins/mod_dialback.lua +++ b/plugins/mod_dialback.lua @@ -176,14 +176,6 @@ module:hook("stanza/jabber:server:dialback:result", function(event) end end); -module:hook_stanza("urn:ietf:params:xml:ns:xmpp-sasl", "failure", function (origin, stanza) - if origin.external_auth == "failed" then - module:log("debug", "SASL EXTERNAL failed, falling back to dialback"); - initiate_dialback(origin); - return true; - end -end, 100); - module:hook_stanza(xmlns_stream, "features", function (origin, stanza) if not origin.external_auth or origin.external_auth == "failed" then module:log("debug", "Initiating dialback..."); diff --git a/plugins/mod_s2s/mod_s2s.lua b/plugins/mod_s2s/mod_s2s.lua index 7ff921d9..a50387fb 100644 --- a/plugins/mod_s2s/mod_s2s.lua +++ b/plugins/mod_s2s/mod_s2s.lua @@ -154,6 +154,10 @@ function module.add_host(module) -- so the stream is ready for stanzas. RFC 6120 Section 4.3 mark_connected(session); return true; + elseif not session.dialback_verifying then + session.log("warn", "No SASL EXTERNAL offer and Dialback doesn't seem to be enabled, giving up"); + session:close(); + return false; end end, -1); end diff --git a/plugins/mod_saslauth.lua b/plugins/mod_saslauth.lua index a07c5fd2..9e63b4c7 100644 --- a/plugins/mod_saslauth.lua +++ b/plugins/mod_saslauth.lua @@ -13,8 +13,6 @@ local sm_bind_resource = require "core.sessionmanager".bind_resource; local sm_make_authenticated = require "core.sessionmanager".make_authenticated; local base64 = require "util.encodings".base64; -local cert_verify_identity = require "util.x509".verify_identity; - local usermanager_get_sasl_handler = require "core.usermanager".get_sasl_handler; local tostring = tostring; @@ -28,15 +26,15 @@ local xmlns_bind ='urn:ietf:params:xml:ns:xmpp-bind'; local function build_reply(status, ret, err_msg) local reply = st.stanza(status, {xmlns = xmlns_sasl}); - if status == "challenge" then - --log("debug", "CHALLENGE: %s", ret or ""); - reply:text(base64.encode(ret or "")); - elseif status == "failure" then + if status == "failure" then reply:tag(ret):up(); if err_msg then reply:tag("text"):text(err_msg); end - elseif status == "success" then - --log("debug", "SUCCESS: %s", ret or ""); - reply:text(base64.encode(ret or "")); + elseif status == "challenge" or status == "success" then + if ret == "" then + reply:text("=") + elseif ret then + reply:text(base64.encode(ret)); + end else module:log("error", "Unknown sasl status: %s", status); end @@ -99,12 +97,10 @@ module:hook_stanza(xmlns_sasl, "failure", function (session, stanza) module:log("info", "SASL EXTERNAL with %s failed", session.to_host) -- TODO: Log the failure reason session.external_auth = "failed" + session:close(); + return true; end, 500) -module:hook_stanza(xmlns_sasl, "failure", function (session, stanza) - -- TODO: Dialback wasn't loaded. Do something useful. -end, 90) - module:hook_stanza("http://etherx.jabber.org/streams", "features", function (session, stanza) if session.type ~= "s2sout_unauthed" or not session.secure then return; end @@ -124,71 +120,52 @@ module:hook_stanza("http://etherx.jabber.org/streams", "features", function (ses end, 150); local function s2s_external_auth(session, stanza) + if session.external_auth ~= "offered" then return end -- Unexpected request + local mechanism = stanza.attr.mechanism; - if not session.secure then - if mechanism == "EXTERNAL" then - session.sends2s(build_reply("failure", "encryption-required")) - else - session.sends2s(build_reply("failure", "invalid-mechanism")) - end + if mechanism ~= "EXTERNAL" then + session.sends2s(build_reply("failure", "invalid-mechanism")); return true; end - if mechanism ~= "EXTERNAL" or session.cert_chain_status ~= "valid" then - session.sends2s(build_reply("failure", "invalid-mechanism")) + if not session.secure then + session.sends2s(build_reply("failure", "encryption-required")); return true; end - local text = stanza[1] + local text = stanza[1]; if not text then - session.sends2s(build_reply("failure", "malformed-request")) - return true + session.sends2s(build_reply("failure", "malformed-request")); + return true; end - -- Either the value is "=" and we've already verified the external - -- cert identity, or the value is a string and either matches the - -- from_host ( - - text = base64.decode(text) + text = base64.decode(text); if not text then - session.sends2s(build_reply("failure", "incorrect-encoding")) + session.sends2s(build_reply("failure", "incorrect-encoding")); return true; end - if session.cert_identity_status == "valid" then - if text ~= "" and text ~= session.from_host then - session.sends2s(build_reply("failure", "invalid-authzid")) - return true - end - else - if text == "" then - session.sends2s(build_reply("failure", "invalid-authzid")) - return true - end - - local cert = session.conn:socket():getpeercertificate() - if (cert_verify_identity(text, "xmpp-server", cert)) then - session.cert_identity_status = "valid" - else - session.cert_identity_status = "invalid" - session.sends2s(build_reply("failure", "invalid-authzid")) - return true - end + -- The text value is either "" or equals session.from_host + if not ( text == "" or text == session.from_host ) then + session.sends2s(build_reply("failure", "invalid-authzid")); + return true; end - session.external_auth = "succeeded" - - if not session.from_host then - session.from_host = text; + -- We've already verified the external cert identity before offering EXTERNAL + if session.cert_chain_status ~= "valid" or session.cert_identity_status ~= "valid" then + session.sends2s(build_reply("failure", "not-authorized")); + session:close(); + return true; end - session.sends2s(build_reply("success")) - local domain = text ~= "" and text or session.from_host; - module:log("info", "Accepting SASL EXTERNAL identity from %s", domain); - module:fire_event("s2s-authenticated", { session = session, host = domain }); + -- Success! + session.external_auth = "succeeded"; + session.sends2s(build_reply("success")); + module:log("info", "Accepting SASL EXTERNAL identity from %s", session.from_host); + module:fire_event("s2s-authenticated", { session = session, host = session.from_host }); session:reset_stream(); - return true + return true; end module:hook("stanza/urn:ietf:params:xml:ns:xmpp-sasl:auth", function(event) @@ -268,10 +245,10 @@ end); module:hook("s2s-stream-features", function(event) local origin, features = event.origin, event.features; if origin.secure and origin.type == "s2sin_unauthed" then - -- Offer EXTERNAL if chain is valid and either we didn't validate - -- the identity or it passed. - if origin.cert_chain_status == "valid" and origin.cert_identity_status ~= "invalid" then --TODO: Configurable - module:log("debug", "Offering SASL EXTERNAL") + -- Offer EXTERNAL only if both chain and identity is valid. + if origin.cert_chain_status == "valid" and origin.cert_identity_status == "valid" then + module:log("debug", "Offering SASL EXTERNAL"); + origin.external_auth = "offered" features:tag("mechanisms", { xmlns = xmlns_sasl }) :tag("mechanism"):text("EXTERNAL") :up():up(); |