Annotate

mod_muc_http_auth/mod_muc_http_auth.lua @ 5623:59d5fc50f602

mod_http_oauth2: Implement refresh token rotation Makes refresh tokens one-time-use, handing out a new refresh token with each access token. Thus if a refresh token is stolen and used by an attacker, the next time the legitimate client tries to use the previous refresh token, it will not work and the attack will be noticed. If the attacker does not use the refresh token, it becomes invalid after the legitimate client uses it. This behavior is recommended by draft-ietf-oauth-security-topics
author Kim Alvefur <zash@zash.se>
date Sun, 23 Jul 2023 02:56:08 +0200
parent 4724:b125db92bac6
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
4296
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
1 local http = require "net.http";
4723
0a0334a3a784 mod_muc_http_auth: Allow for enabling/disabling per user host
JC Brand <jc@opkode.com>
parents: 4697
diff changeset
2 local jid_bare = require "util.jid".bare;
0a0334a3a784 mod_muc_http_auth: Allow for enabling/disabling per user host
JC Brand <jc@opkode.com>
parents: 4697
diff changeset
3 local jid_host = require "util.jid".host;
0a0334a3a784 mod_muc_http_auth: Allow for enabling/disabling per user host
JC Brand <jc@opkode.com>
parents: 4697
diff changeset
4 local jid_node = require "util.jid".node;
0a0334a3a784 mod_muc_http_auth: Allow for enabling/disabling per user host
JC Brand <jc@opkode.com>
parents: 4697
diff changeset
5 local jid_resource = require "util.jid".resource;
4296
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
6 local json = require "util.json";
4724
b125db92bac6 mod_muc_http_auth: Add missing import
JC Brand <jc@opkode.com>
parents: 4723
diff changeset
7 local set = require "util.set";
4296
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
8 local st = require "util.stanza";
4696
6a05c9eb964e mod_muc_http_auth: Make sure query parameters are URL encoded
Seve Ferrer <seve@delape.net>
parents: 4695
diff changeset
9 local urlencode = require "util.http".urlencode;
4723
0a0334a3a784 mod_muc_http_auth: Allow for enabling/disabling per user host
JC Brand <jc@opkode.com>
parents: 4697
diff changeset
10 local wait_for = require "util.async".wait_for;
4296
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
11
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
12 local authorization_url = module:get_option("muc_http_auth_url", "")
4723
0a0334a3a784 mod_muc_http_auth: Allow for enabling/disabling per user host
JC Brand <jc@opkode.com>
parents: 4697
diff changeset
13 local enabled_for = module:get_option("muc_http_auth_enabled_for", nil)
0a0334a3a784 mod_muc_http_auth: Allow for enabling/disabling per user host
JC Brand <jc@opkode.com>
parents: 4697
diff changeset
14 local disabled_for = module:get_option("muc_http_auth_disabled_for", nil)
4296
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
15 local insecure = module:get_option("muc_http_auth_insecure", false) --For development purposes
4299
8006da2cf44c For deployments that have https://hg.prosody.im/trunk/file/tip/plugins/muc/register.lib.lua#l7 and use https://modules.prosody.im/mod_muc_http_auth.html users can still register to a MUC even if they are not allowed to join. That means they would receive RAI or RMN, for instance.
Seve Ferrer <seve@delape.net>
parents: 4296
diff changeset
16 local authorize_registration = module:get_option("muc_http_auth_authorize_registration", false)
4322
9606e7a63a69 mod_mucc_http_auth: Provide Authorization header setting for deployments behind a login
Seve Ferrer <seve@delape.net>
parents: 4319
diff changeset
17 local authorization_header = module:get_option("muc_http_auth_authorization_header", nil)
9606e7a63a69 mod_mucc_http_auth: Provide Authorization header setting for deployments behind a login
Seve Ferrer <seve@delape.net>
parents: 4319
diff changeset
18
9606e7a63a69 mod_mucc_http_auth: Provide Authorization header setting for deployments behind a login
Seve Ferrer <seve@delape.net>
parents: 4319
diff changeset
19 local options = {method="GET", insecure=insecure}
9606e7a63a69 mod_mucc_http_auth: Provide Authorization header setting for deployments behind a login
Seve Ferrer <seve@delape.net>
parents: 4319
diff changeset
20 if authorization_header then
9606e7a63a69 mod_mucc_http_auth: Provide Authorization header setting for deployments behind a login
Seve Ferrer <seve@delape.net>
parents: 4319
diff changeset
21 options.headers = {["Authorization"] = authorization_header};
9606e7a63a69 mod_mucc_http_auth: Provide Authorization header setting for deployments behind a login
Seve Ferrer <seve@delape.net>
parents: 4319
diff changeset
22 end
4296
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
23
4304
aec8148df26a mod_muc_http_auth: Bugfix: Not properly listening on register IQs
Seve Ferrer <seve@delape.net>
parents: 4303
diff changeset
24 local verbs = {presence='join', iq='register'};
aec8148df26a mod_muc_http_auth: Bugfix: Not properly listening on register IQs
Seve Ferrer <seve@delape.net>
parents: 4303
diff changeset
25
4723
0a0334a3a784 mod_muc_http_auth: Allow for enabling/disabling per user host
JC Brand <jc@opkode.com>
parents: 4697
diff changeset
26 local function must_be_authorized(room_node, user_host)
4303
d261233f7ced Improve UX by providing defaults users expect
Seve Ferrer <seve@delape.net>
parents: 4301
diff changeset
27 -- If none of these is set, all rooms need authorization
4296
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
28 if not enabled_for and not disabled_for then return true; end
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
29
4723
0a0334a3a784 mod_muc_http_auth: Allow for enabling/disabling per user host
JC Brand <jc@opkode.com>
parents: 4697
diff changeset
30 if enabled_for then
0a0334a3a784 mod_muc_http_auth: Allow for enabling/disabling per user host
JC Brand <jc@opkode.com>
parents: 4697
diff changeset
31 local enabled_for_host = set.new(enabled_for[user_host] or {});
0a0334a3a784 mod_muc_http_auth: Allow for enabling/disabling per user host
JC Brand <jc@opkode.com>
parents: 4697
diff changeset
32 local enabled_for_all = set.new(enabled_for['all'] or {});
0a0334a3a784 mod_muc_http_auth: Allow for enabling/disabling per user host
JC Brand <jc@opkode.com>
parents: 4697
diff changeset
33 return enabled_for_host:contains(room_node) or enabled_for_all:contains(room_node);
0a0334a3a784 mod_muc_http_auth: Allow for enabling/disabling per user host
JC Brand <jc@opkode.com>
parents: 4697
diff changeset
34
0a0334a3a784 mod_muc_http_auth: Allow for enabling/disabling per user host
JC Brand <jc@opkode.com>
parents: 4697
diff changeset
35 end
0a0334a3a784 mod_muc_http_auth: Allow for enabling/disabling per user host
JC Brand <jc@opkode.com>
parents: 4697
diff changeset
36 if disabled_for then
0a0334a3a784 mod_muc_http_auth: Allow for enabling/disabling per user host
JC Brand <jc@opkode.com>
parents: 4697
diff changeset
37 local disabled_for_host = set.new(disabled_for[user_host] or {});
0a0334a3a784 mod_muc_http_auth: Allow for enabling/disabling per user host
JC Brand <jc@opkode.com>
parents: 4697
diff changeset
38 local disabled_for_all = set.new(disabled_for['all'] or {});
0a0334a3a784 mod_muc_http_auth: Allow for enabling/disabling per user host
JC Brand <jc@opkode.com>
parents: 4697
diff changeset
39 return not disabled_for_host:contains(room_node) and not disabled_for_all:contains(room_node);
0a0334a3a784 mod_muc_http_auth: Allow for enabling/disabling per user host
JC Brand <jc@opkode.com>
parents: 4697
diff changeset
40 end
4296
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
41 end
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
42
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
43 local function handle_success(response)
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
44 local body = json.decode(response.body or "") or {}
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
45 response = {
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
46 err = body.error,
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
47 allowed = body.allowed,
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
48 code = response.code
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
49 }
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
50 return {response=response, err=response.err};
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
51 end
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
52
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
53 local function handle_error(err)
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
54 return {err=err};
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
55 end
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
56
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
57 local function handle_presence(event)
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
58 local stanza = event.stanza;
4304
aec8148df26a mod_muc_http_auth: Bugfix: Not properly listening on register IQs
Seve Ferrer <seve@delape.net>
parents: 4303
diff changeset
59 if stanza.name ~= "iq" and stanza.name ~= "presence" or stanza.attr.type == "unavailable" then return; end
4296
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
60
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
61 local room, origin = event.room, event.origin;
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
62 if (not room) or (not origin) then return; end
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
63
4723
0a0334a3a784 mod_muc_http_auth: Allow for enabling/disabling per user host
JC Brand <jc@opkode.com>
parents: 4697
diff changeset
64 local user_bare_jid = jid_bare(stanza.attr.from)
0a0334a3a784 mod_muc_http_auth: Allow for enabling/disabling per user host
JC Brand <jc@opkode.com>
parents: 4697
diff changeset
65 if not must_be_authorized(jid_node(room.jid), jid_host(user_bare_jid)) then
0a0334a3a784 mod_muc_http_auth: Allow for enabling/disabling per user host
JC Brand <jc@opkode.com>
parents: 4697
diff changeset
66 module:log("debug", "Authorization not required for "..jid_node(room.jid).." and "..jid_host(user_bare_jid))
0a0334a3a784 mod_muc_http_auth: Allow for enabling/disabling per user host
JC Brand <jc@opkode.com>
parents: 4697
diff changeset
67 return;
0a0334a3a784 mod_muc_http_auth: Allow for enabling/disabling per user host
JC Brand <jc@opkode.com>
parents: 4697
diff changeset
68 end
4296
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
69
4695
4b3f054666e6 mod_muc_http_auth: External auth services might need to check on the nickname as well
Seve Ferrer <seve@delape.net>
parents: 4322
diff changeset
70 local user_nickname = jid_resource(stanza.attr.to);
4b3f054666e6 mod_muc_http_auth: External auth services might need to check on the nickname as well
Seve Ferrer <seve@delape.net>
parents: 4322
diff changeset
71
4b3f054666e6 mod_muc_http_auth: External auth services might need to check on the nickname as well
Seve Ferrer <seve@delape.net>
parents: 4322
diff changeset
72 -- Nickname is mandatory to enter a MUC
4b3f054666e6 mod_muc_http_auth: External auth services might need to check on the nickname as well
Seve Ferrer <seve@delape.net>
parents: 4322
diff changeset
73 if not user_nickname then return; end
4b3f054666e6 mod_muc_http_auth: External auth services might need to check on the nickname as well
Seve Ferrer <seve@delape.net>
parents: 4322
diff changeset
74
4697
15c335dc196e mod_muc_http_auth: Make sure query parameters are URL encoded
Seve Ferrer <seve@delape.net>
parents: 4696
diff changeset
75 local url = authorization_url .. "?userJID=" .. urlencode(user_bare_jid) .."&mucJID=" .. urlencode(room.jid) .. "&nickname=" .. urlencode(user_nickname);
4296
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
76
4322
9606e7a63a69 mod_mucc_http_auth: Provide Authorization header setting for deployments behind a login
Seve Ferrer <seve@delape.net>
parents: 4319
diff changeset
77 local result = wait_for(http.request(url, options):next(handle_success, handle_error));
4296
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
78 local response, err = result.response, result.err;
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
79
4304
aec8148df26a mod_muc_http_auth: Bugfix: Not properly listening on register IQs
Seve Ferrer <seve@delape.net>
parents: 4303
diff changeset
80 local verb = verbs[stanza.name];
4296
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
81 if not (response and response.allowed) then
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
82 -- User is not authorized to join this room
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
83 err = (response or {}).err or err
4304
aec8148df26a mod_muc_http_auth: Bugfix: Not properly listening on register IQs
Seve Ferrer <seve@delape.net>
parents: 4303
diff changeset
84 module:log("debug", user_bare_jid .. " is not authorized to " ..verb.. ": " .. room.jid .. " Error: " .. tostring(err));
4319
caaa40f072da mod_muc_http_auth: `no-authorized` error must be of type `auth`
JC Brand <jc@opkode.com>
parents: 4304
diff changeset
85 origin.send(st.error_reply(stanza, "auth", "not-authorized", nil, module.host));
4296
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
86 return true;
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
87 end
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
88
4304
aec8148df26a mod_muc_http_auth: Bugfix: Not properly listening on register IQs
Seve Ferrer <seve@delape.net>
parents: 4303
diff changeset
89 module:log("debug", user_bare_jid .. " is authorized to " .. verb .. ": " .. room.jid);
4296
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
90 return;
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
91 end
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
92
4299
8006da2cf44c For deployments that have https://hg.prosody.im/trunk/file/tip/plugins/muc/register.lib.lua#l7 and use https://modules.prosody.im/mod_muc_http_auth.html users can still register to a MUC even if they are not allowed to join. That means they would receive RAI or RMN, for instance.
Seve Ferrer <seve@delape.net>
parents: 4296
diff changeset
93 if authorize_registration then
8006da2cf44c For deployments that have https://hg.prosody.im/trunk/file/tip/plugins/muc/register.lib.lua#l7 and use https://modules.prosody.im/mod_muc_http_auth.html users can still register to a MUC even if they are not allowed to join. That means they would receive RAI or RMN, for instance.
Seve Ferrer <seve@delape.net>
parents: 4296
diff changeset
94 module:hook("muc-register-iq", handle_presence);
8006da2cf44c For deployments that have https://hg.prosody.im/trunk/file/tip/plugins/muc/register.lib.lua#l7 and use https://modules.prosody.im/mod_muc_http_auth.html users can still register to a MUC even if they are not allowed to join. That means they would receive RAI or RMN, for instance.
Seve Ferrer <seve@delape.net>
parents: 4296
diff changeset
95 end
4296
08138de4cb88 Prosodoy module to externalize MUC authorization via HTTP
Seve Ferrer <seve@delape.net>
parents:
diff changeset
96
4319
caaa40f072da mod_muc_http_auth: `no-authorized` error must be of type `auth`
JC Brand <jc@opkode.com>
parents: 4304
diff changeset
97 module:hook("muc-occupant-pre-join", handle_presence);