File

mod_sasl2_bind2/mod_sasl2_bind2.lua @ 5549:01a0b67a9afd

mod_http_oauth2: Add TODO about disabling password grant Per recommendation in draft-ietf-oauth-security-topics-23 it should at the very least be disabled by default. However since this is used by the Snikket web portal some care needs to be taken not to break this, unless it's already broken by other changes to this module.
author Kim Alvefur <zash@zash.se>
date Fri, 16 Jun 2023 00:06:53 +0200
parent 5180:6361afcda1a3
line wrap: on
line source

local base64 = require "util.encodings".base64;
local id = require "util.id";
local sha1 = require "util.hashes".sha1;
local st = require "util.stanza";

local sm_bind_resource = require "core.sessionmanager".bind_resource;

local xmlns_bind2 = "urn:xmpp:bind:0";
local xmlns_sasl2 = "urn:xmpp:sasl:2";

module:depends("sasl2");

-- Advertise what we can do

module:hook("advertise-sasl-features", function(event)
	local bind = st.stanza("bind", { xmlns = xmlns_bind2 });
	local inline = st.stanza("inline");
	module:fire_event("advertise-bind-features", { origin = event.origin, features = inline });
	bind:add_direct_child(inline);

	event.features:add_direct_child(bind);
end, 1);

-- Helper to actually bind a resource to a session

local function do_bind(session, bind_request)
	local resource = session.sasl_handler.resource;

	if not resource then
		local client_name_tag = bind_request:get_child_text("tag");
		if client_name_tag then
			local client_id = session.client_id;
			local tag_suffix = client_id and base64.encode(sha1(client_id):sub(1, 9)) or id.medium();
			resource = ("%s~%s"):format(client_name_tag, tag_suffix);
		end
	end

	local success, err_type, err, err_msg = sm_bind_resource(session, resource);
	if not success then
		session.log("debug", "Resource bind failed: %s", err_msg or err);
		return nil, { type = err_type, condition = err, text = err_msg };
	end

	session.log("debug", "Resource bound: %s", session.full_jid);
	return st.stanza("bound", { xmlns = xmlns_bind2 });
end

-- Enable inline features requested by the client

local function enable_features(session, bind_request, bind_result)
	module:fire_event("enable-bind-features", {
		session = session;
		request = bind_request;
		result = bind_result;
	});
end

-- SASL 2 integration

module:hook_tag(xmlns_sasl2, "authenticate", function (session, auth)
	-- Cache action for future processing (after auth success)
	session.sasl2_bind_request = auth:child_with_ns(xmlns_bind2);
end, 100);

module:hook("sasl2/c2s/success", function (event)
	local session = event.session;

	local bind_request = session.sasl2_bind_request;
	if not bind_request then return; end -- No bind requested
	session.sasl2_bind_request = nil;

	local sm_success = session.sasl2_sm_success;
	if sm_success and sm_success.type == "resumed" then
		return; -- No need to bind a resource
	end

	local bind_result, err = do_bind(session, bind_request);
	if not bind_result then
		bind_result = st.stanza("failed", { xmlns = xmlns_bind2 })
			:add_error(err);
	else
		enable_features(session, bind_request, bind_result);
	end

	event.success:add_child(bind_result);
end, 100);

-- Inline features

module:hook("advertise-bind-features", function (event)
	local features = event.features;
	features:tag("feature", { var = "urn:xmpp:carbons:2" }):up();
	features:tag("feature", { var = "urn:xmpp:csi:0" }):up();
end);

module:hook("enable-bind-features", function (event)
	local session, request = event.session, event.request;

	-- Carbons
	if request:get_child("enable", "urn:xmpp:carbons:2") then
		session.want_carbons = true;
		event.result:tag("enabled", { xmlns = "urn:xmpp:carbons:2" }):up();
	end

	-- CSI
	local csi_state_tag = request:child_with_ns("urn:xmpp:csi:0");
	if csi_state_tag then
		session.state = csi_state_tag.name;
	end
end, 10);