Mercurial > prosody-modules
view mod_compat_roles/mod_compat_roles.lua @ 5401:c8d04ac200fc
mod_http_oauth2: Reject loopback URIs as client_uri
This really should be a proper website with info, https://localhost is
not good enough. Ideally we'd validate that it's got proper DNS and is
actually reachable, but triggering HTTP or even DNS lookups seems like
it would carry abuse potential that would best to avoid.
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Tue, 02 May 2023 16:20:55 +0200 |
parents | f03f4ec859a3 |
children | 825c6fb76c48 |
line wrap: on
line source
-- Export a module:may() that works on Prosody 0.12 and earlier -- (i.e. backed by is_admin). -- This API is safe because Prosody 0.12 and earlier do not support -- per-session roles - all authorization is based on JID alone. It is not -- safe on versions that support per-session authorization. module:set_global(); local moduleapi = require "core.moduleapi"; -- If module.may already exists, abort if moduleapi.may then return; end local jid_split = require "util.jid".split; local um_is_admin = require "core.usermanager".is_admin; local function get_jid_role_name(jid, host) if um_is_admin(jid, "*") then return "prosody:operator"; elseif um_is_admin(jid, host) then return "prosody:admin"; end return nil; end local function get_user_role_name(username, host) return get_jid_role_name(username.."@"..host, host); end -- permissions[host][role_name][permission_name] = is_permitted local permissions = {}; local role_inheritance = { ["prosody:operator"] = "prosody:admin"; ["prosody:admin"] = "prosody:user"; ["prosody:user"] = "prosody:restricted"; }; local function role_may(host, role_name, permission) local host_roles = permissions[host]; if not host_roles then return false; end local role_permissions = host_roles[role_name]; if not role_permissions then return false; end local next_role = role_inheritance[role_name]; return not not permissions[role_name][permission] or (next_role and role_may(host, next_role, permission)); end function moduleapi.may(self, action, context) if action:byte(1) == 58 then -- action begins with ':' action = self.name..action; -- prepend module name end if type(context) == "string" then -- check JID permissions local role; local node, host = jid_split(context); if host == self.host then role = get_user_role_name(node, self.host); else role = get_jid_role_name(context, self.host); end if not role then self:log("debug", "Access denied: JID <%s> may not %s (no role found)", context, action); return false; end local permit = role_may(self.host, role, action); if not permit then self:log("debug", "Access denied: JID <%s> may not %s (not permitted by role %s)", context, action, role.name); end return permit; end local session = context.origin or context.session; if type(session) ~= "table" then error("Unable to identify actor session from context"); end if session.type == "s2sin" or (session.type == "c2s" and session.host ~= self.host) then local actor_jid = context.stanza.attr.from; local role_name = get_jid_role_name(actor_jid); if not role_name then self:log("debug", "Access denied: JID <%s> may not %s (no role found)", actor_jid, action); return false; end local permit = role_may(self.host, role_name, action, context); if not permit then self:log("debug", "Access denied: JID <%s> may not %s (not permitted by role %s)", actor_jid, action, role_name); end return permit; end end function moduleapi.default_permission(self, role_name, permission) local p = permissions[self.host]; if not p then p = {}; permissions[self.host] = p; end local r = p[role_name]; if not r then r = {}; p[role_name] = r; end r[permission] = true; end function moduleapi.default_permissions(self, role_name, permission_list) for _, permission in ipairs(permission_list) do self:default_permission(role_name, permission); end end function module.add_host(host_module) permissions[host_module.host] = {}; function host_module.unload() permissions[host_module.host] = nil; end end