Software /
code /
verse
File
plugins/sasl.lua @ 498:50d0bd035bb7
util.sasl.oauthbearer: Don't send authzid
It's not needed and not recommended in XMPP unless we want to act as
someone other than who we authenticate as. We find out the JID during
resource binding.
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Fri, 23 Jun 2023 12:09:49 +0200 |
parent | 490:6b2f31da9610 |
line wrap: on
line source
local verse = require"verse"; local base64, unbase64 = require "mime".b64, require"mime".unb64; local xmlns_sasl = "urn:ietf:params:xml:ns:xmpp-sasl"; function verse.plugins.sasl(stream) local function handle_features(features_stanza) if stream.authenticated then return; end stream:debug("Authenticating with SASL..."); local sasl_mechanisms = features_stanza:get_child("mechanisms", xmlns_sasl); if not sasl_mechanisms then return end local mechanisms = {}; local preference = {}; local offered = {}; for mech in sasl_mechanisms:childtags("mechanism") do mech = mech:get_text(); stream:debug("Server offers %s", mech); offered[mech] = true; if not mechanisms[mech] then local name = mech:match("[^-]+"); local ok, impl = pcall(require, "verse.util.sasl."..name:lower()); if ok then stream:debug("Loaded SASL %s module", name); mechanisms[mech], preference[mech] = impl(stream, mech); elseif not tostring(impl):match("not found") then stream:debug("Loading failed: %s", tostring(impl)); end end end local supported = {}; -- by the server for mech in pairs(mechanisms) do table.insert(supported, mech); end if not supported[1] then stream:event("authentication-failure", { condition = "no-supported-sasl-mechanisms", mechanisms = offered }); stream:close(); return; end table.sort(supported, function (a, b) return preference[a] > preference[b]; end); local mechanism, initial_data = supported[1]; stream:debug("Selecting %s mechanism...", mechanism); stream.sasl_mechanism = coroutine.wrap(mechanisms[mechanism]); initial_data = stream:sasl_mechanism(mechanism); local auth_stanza = verse.stanza("auth", { xmlns = xmlns_sasl, mechanism = mechanism }); if initial_data then auth_stanza:text(base64(initial_data)); end stream:send(auth_stanza); return true; end local function handle_sasl(sasl_stanza) if sasl_stanza.name == "failure" then local err = sasl_stanza.tags[1]; local text = sasl_stanza:get_child_text("text"); stream:event("authentication-failure", { condition = err.name, text = text }); stream:close(); return false; end local ok, err = stream.sasl_mechanism(sasl_stanza.name, unbase64(sasl_stanza:get_text())); if not ok then stream:event("authentication-failure", { condition = err }); stream:close(); return false; elseif ok == true then stream:event("authentication-success"); stream.authenticated = true stream:reopen(); else stream:send(verse.stanza("response", { xmlns = xmlns_sasl }):text(base64(ok))); end return true; end stream:hook("stream-features", handle_features, 300); stream:hook("stream/"..xmlns_sasl, handle_sasl); return true; end