File

plugins/mod_tokenauth.lua @ 12731:a314f5bff9f0

mod_muc: Better map restrict_room_creation to role permissions (behaviour change) With this change and 427dd01f0864, room creation is now effectively restricted to parent-host users by default. This is a better default than previous Prosody versions (where room creation was not restricted). The "local" option for restrict_room_creation is no longer used (any value other than true/false won't change the default behaviour). restrict_room_creation = true will grant prosody:admin the ability to create rooms. restrict_room_creation = false disables all permission checks. Anything between these two can be achieved using custom roles and permissions.
author Matthew Wild <mwild1@gmail.com>
date Thu, 29 Sep 2022 12:30:52 +0100
parent 12662:07424992d7fc
child 12742:126aefd2c4c6
line wrap: on
line source

local id = require "util.id";
local jid = require "util.jid";
local base64 = require "util.encodings".base64;
local usermanager = require "core.usermanager";
local generate_identifier = require "util.id".short;

local token_store = module:open_store("auth_tokens", "map");

local function select_role(username, host, role)
	if role then
		return prosody.hosts[host].authz.get_role_by_name(role);
	end
	return usermanager.get_user_role(username, host);
end

function create_jid_token(actor_jid, token_jid, token_role, token_ttl)
	token_jid = jid.prep(token_jid);
	if not actor_jid or token_jid ~= actor_jid and not jid.compare(token_jid, actor_jid) then
		return nil, "not-authorized";
	end

	local token_username, token_host, token_resource = jid.split(token_jid);

	if token_host ~= module.host then
		return nil, "invalid-host";
	end

	local token_info = {
		owner = actor_jid;
		created = os.time();
		expires = token_ttl and (os.time() + token_ttl) or nil;
		jid = token_jid;

		resource = token_resource;
		role = token_role;
	};

	local token_id = id.long();
	local token = base64.encode("1;"..jid.join(token_username, token_host)..";"..token_id);
	token_store:set(token_username, token_id, token_info);

	return token, token_info;
end

local function parse_token(encoded_token)
	local token = base64.decode(encoded_token);
	if not token then return nil; end
	local token_jid, token_id = token:match("^1;([^;]+);(.+)$");
	if not token_jid then return nil; end
	local token_user, token_host = jid.split(token_jid);
	return token_id, token_user, token_host;
end

local function _get_parsed_token_info(token_id, token_user, token_host)
	if token_host ~= module.host then
		return nil, "invalid-host";
	end

	local token_info, err = token_store:get(token_user, token_id);
	if not token_info then
		if err then
			return nil, "internal-error";
		end
		return nil, "not-authorized";
	end

	if token_info.expires and token_info.expires < os.time() then
		return nil, "not-authorized";
	end

	return token_info
end

function get_token_info(token)
	local token_id, token_user, token_host = parse_token(token);
	if not token_id then
		return nil, "invalid-token-format";
	end
	return _get_parsed_token_info(token_id, token_user, token_host);
end

function get_token_session(token, resource)
	local token_id, token_user, token_host = parse_token(token);
	if not token_id then
		return nil, "invalid-token-format";
	end

	local token_info, err = _get_parsed_token_info(token_id, token_user, token_host);
	if not token_info then return nil, err; end

	return {
		username = token_user;
		host = token_host;
		resource = token_info.resource or resource or generate_identifier();

		role = select_role(token_user, token_host, token_info.role);
	};
end


function revoke_token(token)
	local token_id, token_user, token_host = parse_token(token);
	if not token_id then
		return nil, "invalid-token-format";
	end
	if token_host ~= module.host then
		return nil, "invalid-host";
	end
	return token_store:set(token_user, token_id, nil);
end