aboutsummaryrefslogtreecommitdiffstats
path: root/plugins/mod_authz_internal.lua
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/mod_authz_internal.lua')
-rw-r--r--plugins/mod_authz_internal.lua145
1 files changed, 129 insertions, 16 deletions
diff --git a/plugins/mod_authz_internal.lua b/plugins/mod_authz_internal.lua
index 17687959..35bc3929 100644
--- a/plugins/mod_authz_internal.lua
+++ b/plugins/mod_authz_internal.lua
@@ -1,20 +1,89 @@
local array = require "util.array";
local it = require "util.iterators";
local set = require "util.set";
-local jid_split = require "util.jid".split;
+local jid_split, jid_bare = require "util.jid".split, require "util.jid".bare;
local normalize = require "util.jid".prep;
+local config_global_admin_jids = module:context("*"):get_option_set("admins", {}) / normalize;
local config_admin_jids = module:get_option_inherited_set("admins", {}) / normalize;
local host = module.host;
local role_store = module:open_store("roles");
local role_map_store = module:open_store("roles", "map");
-local admin_role = { ["prosody:admin"] = true };
+local role_methods = {};
+local role_mt = { __index = role_methods };
+
+local role_registry = {
+ ["prosody:operator"] = {
+ default = true;
+ priority = 75;
+ includes = { "prosody:admin" };
+ };
+ ["prosody:admin"] = {
+ default = true;
+ priority = 50;
+ includes = { "prosody:user" };
+ };
+ ["prosody:user"] = {
+ default = true;
+ priority = 25;
+ includes = { "prosody:restricted" };
+ };
+ ["prosody:restricted"] = {
+ default = true;
+ priority = 15;
+ };
+};
+
+-- Some processing on the role registry
+for role_name, role_info in pairs(role_registry) do
+ role_info.name = role_name;
+ role_info.includes = set.new(role_info.includes) / function (included_role_name)
+ return role_registry[included_role_name];
+ end;
+ if not role_info.permissions then
+ role_info.permissions = {};
+ end
+ setmetatable(role_info, role_mt);
+end
+
+function role_methods:may(action, context)
+ local policy = self.permissions[action];
+ if policy ~= nil then
+ return policy;
+ end
+ for inherited_role in self.includes do
+ module:log("debug", "Checking included role '%s' for %s", inherited_role.name, action);
+ policy = inherited_role:may(action, context);
+ if policy ~= nil then
+ return policy;
+ end
+ end
+ return false;
+end
+
+-- Public API
+
+local config_operator_role_set = {
+ ["prosody:operator"] = role_registry["prosody:operator"];
+};
+local config_admin_role_set = {
+ ["prosody:admin"] = role_registry["prosody:admin"];
+};
function get_user_roles(user)
- if config_admin_jids:contains(user.."@"..host) then
- return admin_role;
+ local bare_jid = user.."@"..host;
+ if config_global_admin_jids:contains(bare_jid) then
+ return config_operator_role_set;
+ elseif config_admin_jids:contains(bare_jid) then
+ return config_admin_role_set;
+ end
+ local role_names = role_store:get(user);
+ if not role_names then return {}; end
+ local roles = {};
+ for role_name in pairs(role_names) do
+ roles[role_name] = role_registry[role_name];
end
- return role_store:get(user);
+ return roles;
end
function set_user_roles(user, roles)
@@ -22,10 +91,29 @@ function set_user_roles(user, roles)
return true;
end
-function get_users_with_role(role)
- local storage_role_users = it.to_array(it.keys(role_map_store:get_all(role) or {}));
- if role == "prosody:admin" then
- local config_admin_users = config_admin_jids / function (admin_jid)
+function get_user_default_role(user)
+ local roles = get_user_roles(user);
+ if not roles then return nil; end
+ local default_role;
+ for role_name, role_info in pairs(roles) do --luacheck: ignore 213/role_name
+ if role_info.default and (not default_role or role_info.priority > default_role.priority) then
+ default_role = role_info;
+ end
+ end
+ if not default_role then return nil; end
+ return default_role;
+end
+
+function get_users_with_role(role_name)
+ local storage_role_users = it.to_array(it.keys(role_map_store:get_all(role_name) or {}));
+ local config_set;
+ if role_name == "prosody:admin" then
+ config_set = config_admin_jids;
+ elseif role_name == "prosody:operator" then
+ config_set = config_global_admin_jids;
+ end
+ if config_set then
+ local config_admin_users = config_set / function (admin_jid)
local j_node, j_host = jid_split(admin_jid);
if j_host == host then
return j_node;
@@ -36,24 +124,49 @@ function get_users_with_role(role)
return storage_role_users;
end
-function get_jid_roles(jid)
- if config_admin_jids:contains(jid) then
- return admin_role;
+function get_jid_role(jid)
+ local bare_jid = jid_bare(jid);
+ if config_global_admin_jids:contains(bare_jid) then
+ return role_registry["prosody:operator"];
+ elseif config_admin_jids:contains(bare_jid) then
+ return role_registry["prosody:admin"];
end
return nil;
end
-function set_jid_roles(jid) -- luacheck: ignore 212
+function set_jid_role(jid) -- luacheck: ignore 212
return false;
end
-function get_jids_with_role(role)
+function get_jids_with_role(role_name)
-- Fetch role users from storage
- local storage_role_jids = array.map(get_users_with_role(role), function (username)
+ local storage_role_jids = array.map(get_users_with_role(role_name), function (username)
return username.."@"..host;
end);
- if role == "prosody:admin" then
+ if role_name == "prosody:admin" then
return it.to_array(config_admin_jids + set.new(storage_role_jids));
+ elseif role_name == "prosody:operator" then
+ return it.to_array(config_global_admin_jids + set.new(storage_role_jids));
end
return storage_role_jids;
end
+
+function add_default_permission(role_name, action, policy)
+ local role = role_registry[role_name];
+ if not role then
+ module:log("warn", "Attempt to add default permission for unknown role: %s", role_name);
+ return nil, "no-such-role";
+ end
+ if role.permissions[action] == nil then
+ if policy == nil then
+ policy = true;
+ end
+ module:log("debug", "Adding permission, role '%s' may '%s': %s", role_name, action, policy and "allow" or "deny");
+ role.permissions[action] = policy;
+ end
+ return true;
+end
+
+function get_role_info(role_name)
+ return role_registry[role_name];
+end