# HG changeset patch # User JC Brand # Date 1635170296 -7200 # Node ID 0a0334a3a78416c28c7cd3328631837f94fc7f79 # Parent c5b1e9b8ccca7386c870532c9f05930bf7a3506d mod_muc_http_auth: Allow for enabling/disabling per user host IMPORTANT: This is a breaking change. The `muc_http_auth_enabled_for` and `muc_http_auth_disabled_for` options are now maps (with user hosts as keys) and not sets. diff -r c5b1e9b8ccca -r 0a0334a3a784 mod_muc_http_auth/README.md --- a/mod_muc_http_auth/README.md Mon Oct 25 12:40:26 2021 +0200 +++ b/mod_muc_http_auth/README.md Mon Oct 25 15:58:16 2021 +0200 @@ -1,12 +1,12 @@ # Introduction -This module externalizes MUC authorization via HTTP. +This module externalizes MUC authorization via HTTP. Whenever a user wants to join a MUC, an HTTP GET request is made to `authorization_url` -with the user's bare jid (`userJID`), the MUC jid (`mucJID`) and the user's nickname (`nickname`) as GET parameters. -Example: +with the user's bare jid (`userJID`), the MUC jid (`mucJID`) and the user's nickname (`nickname`) as GET parameters. +Example: `https://www.prosody.im/users/can-join/?userJID=romeo@example.com&mucJID=teaparty@chat.example.com&nickname=Romeo` -This allows an external service to decide whether a user is authorized to join a MUC or not. +This allows an external service to decide whether a user is authorized to join a MUC or not. When a user is authorized to join a MUC, this module expects the following JSON payload: ``` @@ -39,26 +39,30 @@ ## Settings -|Name |Description |Default | -|-----|------------|--------| -|muc_http_auth_url| URL of the external HTTP service to which send `userJID`, `mucJID` and `nickname` in a GET request | "" | -|muc_http_auth_enabled_for| List of MUC names (node part) to enable this module for | nil | -|muc_http_auth_disabled_for| List of MUC names (node part) to disable this module for | nil | -|muc_http_auth_insecure| Disable certificate verification for request. Only intended for development of the external service. | false | -|muc_http_auth_authorization_header| Value of the Authorization header if requested by the external HTTP service. Example: `Basic dXNlcm5hbWU6cGFzc3dvcmQ=`| nil | +| Name | Description | Default | +|------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------|---------| +| muc_http_auth_url | URL of the external HTTP service to which send `userJID`, `mucJID` and `nickname` in a GET request | "" | +| muc_http_auth_enabled_for | A map of user hostnames to an array of MUC names (node part) to enable this module for. To enable for all hostnames, use `"all"` as key. | nil | +| muc_http_auth_disabled_for | A map of user hostnames to an array of MUC names (node part) to disable this module for. To disable for all hostnames, use `"all"` as key. | nil | +| muc_http_auth_insecure | Disable certificate verification for request. Only intended for development of the external service. | false | +| muc_http_auth_authorization_header | Value of the Authorization header if requested by the external HTTP service. Example: `Basic dXNlcm5hbWU6cGFzc3dvcmQ=` | nil | This module can be enabled/disabled for specific rooms. Only one of the following settings must be set. ``` --- muc_http_auth_enabled_for = {"teaparty"} --- muc_http_auth_disabled_for = {"teaparty"} +-- muc_http_auth_enabled_for = {["all"] = {"teaparty"}} +-- muc_http_auth_disabled_for = {["all"] = {"teaparty"}} ``` If none is set, all rooms in the MUC component will have this module enabled. -Note: Use the node part of the MUC jid for these lists. Example: +Note: Use the node part of the MUC jid for these lists. Example: Wrong: -`muc_http_auth_enabled_for = {"teaparty@rooms.example.net"}` +`muc_http_auth_enabled_for = {["all"] = {"teaparty@rooms.example.net"}}` Correct: -`muc_http_auth_enabled_for = {"teaparty"}` \ No newline at end of file +`muc_http_auth_enabled_for = {["all"] = {"teaparty"}}` + +It's also possible to disable/enable checking for a particular host, for example: + + `muc_http_auth_enabled_for = {["jabber.org"] = {"teaparty"}, ["prosody.org] = {"orchard"}}` diff -r c5b1e9b8ccca -r 0a0334a3a784 mod_muc_http_auth/mod_muc_http_auth.lua --- a/mod_muc_http_auth/mod_muc_http_auth.lua Mon Oct 25 12:40:26 2021 +0200 +++ b/mod_muc_http_auth/mod_muc_http_auth.lua Mon Oct 25 15:58:16 2021 +0200 @@ -1,15 +1,16 @@ -local wait_for = require "util.async".wait_for; local http = require "net.http"; +local jid_bare = require "util.jid".bare; +local jid_host = require "util.jid".host; +local jid_node = require "util.jid".node; +local jid_resource = require "util.jid".resource; local json = require "util.json"; local st = require "util.stanza"; -local jid_node = require "util.jid".node; -local jid_bare = require "util.jid".bare; -local jid_resource = require "util.jid".resource; local urlencode = require "util.http".urlencode; +local wait_for = require "util.async".wait_for; local authorization_url = module:get_option("muc_http_auth_url", "") -local enabled_for = module:get_option_set("muc_http_auth_enabled_for", nil) -local disabled_for = module:get_option_set("muc_http_auth_disabled_for", nil) +local enabled_for = module:get_option("muc_http_auth_enabled_for", nil) +local disabled_for = module:get_option("muc_http_auth_disabled_for", nil) local insecure = module:get_option("muc_http_auth_insecure", false) --For development purposes local authorize_registration = module:get_option("muc_http_auth_authorize_registration", false) local authorization_header = module:get_option("muc_http_auth_authorization_header", nil) @@ -21,12 +22,21 @@ local verbs = {presence='join', iq='register'}; -local function must_be_authorized(room_node) +local function must_be_authorized(room_node, user_host) -- If none of these is set, all rooms need authorization if not enabled_for and not disabled_for then return true; end - if enabled_for then return enabled_for:contains(room_node); end - if disabled_for then return not disabled_for:contains(room_node); end + if enabled_for then + local enabled_for_host = set.new(enabled_for[user_host] or {}); + local enabled_for_all = set.new(enabled_for['all'] or {}); + return enabled_for_host:contains(room_node) or enabled_for_all:contains(room_node); + + end + if disabled_for then + local disabled_for_host = set.new(disabled_for[user_host] or {}); + local disabled_for_all = set.new(disabled_for['all'] or {}); + return not disabled_for_host:contains(room_node) and not disabled_for_all:contains(room_node); + end end local function handle_success(response) @@ -50,9 +60,12 @@ local room, origin = event.room, event.origin; if (not room) or (not origin) then return; end - if not must_be_authorized(jid_node(room.jid)) then return; end + local user_bare_jid = jid_bare(stanza.attr.from) + if not must_be_authorized(jid_node(room.jid), jid_host(user_bare_jid)) then + module:log("debug", "Authorization not required for "..jid_node(room.jid).." and "..jid_host(user_bare_jid)) + return; + end - local user_bare_jid = jid_bare(stanza.attr.from); local user_nickname = jid_resource(stanza.attr.to); -- Nickname is mandatory to enter a MUC