aboutsummaryrefslogtreecommitdiffstats
path: root/core/usermanager.lua
diff options
context:
space:
mode:
Diffstat (limited to 'core/usermanager.lua')
-rw-r--r--core/usermanager.lua120
1 files changed, 90 insertions, 30 deletions
diff --git a/core/usermanager.lua b/core/usermanager.lua
index bb5669cf..45f104fa 100644
--- a/core/usermanager.lua
+++ b/core/usermanager.lua
@@ -9,19 +9,21 @@
local modulemanager = require "core.modulemanager";
local log = require "util.logger".init("usermanager");
local type = type;
-local ipairs = ipairs;
+local it = require "util.iterators";
local jid_bare = require "util.jid".bare;
+local jid_split = require "util.jid".split;
local jid_prep = require "util.jid".prep;
local config = require "core.configmanager";
local sasl_new = require "util.sasl".new;
local storagemanager = require "core.storagemanager";
+local set = require "util.set";
local prosody = _G.prosody;
local hosts = prosody.hosts;
local setmetatable = setmetatable;
-local default_provider = "internal_plain";
+local default_provider = "internal_hashed";
local _ENV = nil;
-- luacheck: std none
@@ -34,10 +36,38 @@ local function new_null_provider()
});
end
+local global_admins_config = config.get("*", "admins");
+if type(global_admins_config) ~= "table" then
+ global_admins_config = nil; -- TODO: factor out moduleapi magic config handling and use it here
+end
+local global_admins = set.new(global_admins_config) / jid_prep;
+
+local admin_role = { ["prosody:admin"] = true };
+local global_authz_provider = {
+ get_user_roles = function (user) end; --luacheck: ignore 212/user
+ get_jid_roles = function (jid)
+ if global_admins:contains(jid) then
+ return admin_role;
+ end
+ end;
+ get_jids_with_role = function (role)
+ if role ~= "prosody:admin" then return {}; end
+ return it.to_array(global_admins);
+ end;
+ set_user_roles = function (user, roles) end; -- luacheck: ignore 212
+ set_jid_roles = function (jid, roles) end; -- luacheck: ignore 212
+};
+
local provider_mt = { __index = new_null_provider() };
local function initialize_host(host)
local host_session = hosts[host];
+
+ local authz_provider_name = config.get(host, "authorization") or "internal";
+
+ local authz_mod = modulemanager.load(host, "authz_"..authz_provider_name);
+ host_session.authz = authz_mod or global_authz_provider;
+
if host_session.type ~= "local" then return; end
host_session.events.add_handler("item-added/auth-provider", function (event)
@@ -66,6 +96,7 @@ local function initialize_host(host)
if auth_provider ~= "null" then
modulemanager.load(host, "auth_"..auth_provider);
end
+
end;
prosody.events.add_handler("host-activated", initialize_host, 100);
@@ -113,45 +144,70 @@ local function get_provider(host)
return hosts[host].users;
end
-local function is_admin(jid, host)
+local function get_roles(jid, host)
if host and not hosts[host] then return false; end
if type(jid) ~= "string" then return false; end
jid = jid_bare(jid);
host = host or "*";
- local host_admins = config.get(host, "admins");
- local global_admins = config.get("*", "admins");
-
- if host_admins and host_admins ~= global_admins then
- if type(host_admins) == "table" then
- for _,admin in ipairs(host_admins) do
- if jid_prep(admin) == jid then
- return true;
- end
- end
- elseif host_admins then
- log("error", "Option 'admins' for host '%s' is not a list", host);
- end
+ local actor_user, actor_host = jid_split(jid);
+ local roles;
+
+ local authz_provider = (host ~= "*" and hosts[host].authz) or global_authz_provider;
+
+ if actor_user and actor_host == host then -- Local user
+ roles = authz_provider.get_user_roles(actor_user);
+ else -- Remote user/JID
+ roles = authz_provider.get_jid_roles(jid);
end
- if global_admins then
- if type(global_admins) == "table" then
- for _,admin in ipairs(global_admins) do
- if jid_prep(admin) == jid then
- return true;
- end
- end
- elseif global_admins then
- log("error", "Global option 'admins' is not a list");
+ return roles;
+end
+
+local function set_roles(jid, host, roles)
+ if host and not hosts[host] then return false; end
+ if type(jid) ~= "string" then return false; end
+
+ jid = jid_bare(jid);
+ host = host or "*";
+
+ local actor_user, actor_host = jid_split(jid);
+
+ local authz_provider = (host ~= "*" and hosts[host].authz) or global_authz_provider;
+ if actor_user and actor_host == host then -- Local user
+ local ok, err = authz_provider.set_user_roles(actor_user, roles);
+ if ok then
+ prosody.events.fire_event("user-roles-changed", {
+ username = actor_user, host = actor_host
+ });
end
+ return ok, err;
+ else -- Remote entity
+ return authz_provider.set_jid_roles(jid, roles)
end
+end
- -- Still not an admin, check with auth provider
- if host ~= "*" and hosts[host].users and hosts[host].users.is_admin then
- return hosts[host].users.is_admin(jid);
- end
- return false;
+local function is_admin(jid, host)
+ local roles = get_roles(jid, host);
+ return roles and roles["prosody:admin"];
+end
+
+local function get_users_with_role(role, host)
+ if not hosts[host] then return false; end
+ if type(role) ~= "string" then return false; end
+
+ return hosts[host].authz.get_users_with_role(role);
+end
+
+local function get_jids_with_role(role, host)
+ if host and not hosts[host] then return false; end
+ if type(role) ~= "string" then return false; end
+
+ host = host or "*";
+
+ local authz_provider = (host ~= "*" and hosts[host].authz) or global_authz_provider;
+ return authz_provider.get_jids_with_role(role);
end
return {
@@ -166,5 +222,9 @@ return {
users = users;
get_sasl_handler = get_sasl_handler;
get_provider = get_provider;
+ get_roles = get_roles;
+ set_roles = set_roles;
is_admin = is_admin;
+ get_users_with_role = get_users_with_role;
+ get_jids_with_role = get_jids_with_role;
};