aboutsummaryrefslogtreecommitdiffstats
path: root/plugins/mod_authz_internal.lua
diff options
context:
space:
mode:
authorMatthew Wild <mwild1@gmail.com>2022-07-19 18:02:02 +0100
committerMatthew Wild <mwild1@gmail.com>2022-07-19 18:02:02 +0100
commitc0b857e5fb2a670d0a7a6ef29977ee58528e842f (patch)
tree50ffd59d689316a0fccf34c38ea9b3fb907a5d79 /plugins/mod_authz_internal.lua
parent77146aa4e7841eb5ca35cca28881d37eb53e5a96 (diff)
downloadprosody-c0b857e5fb2a670d0a7a6ef29977ee58528e842f.tar.gz
prosody-c0b857e5fb2a670d0a7a6ef29977ee58528e842f.zip
mod_authz_internal: Use util.roles, some API changes and config support
This commit was too awkward to split (hg record didn't like it), so: - Switch to the new util.roles lib to provide a consistent representation of a role object. - Change API method from get_role_info() to get_role_by_name() (touches sessionmanager and usermanager) - Change get_roles() to get_user_roles(), take a username instead of a JID This is more consistent with all other usermanager API methods. - Support configuration of custom roles and permissions via the config file (to be documented).
Diffstat (limited to 'plugins/mod_authz_internal.lua')
-rw-r--r--plugins/mod_authz_internal.lua159
1 files changed, 96 insertions, 63 deletions
diff --git a/plugins/mod_authz_internal.lua b/plugins/mod_authz_internal.lua
index 35bc3929..135c7e61 100644
--- a/plugins/mod_authz_internal.lua
+++ b/plugins/mod_authz_internal.lua
@@ -3,62 +3,97 @@ local it = require "util.iterators";
local set = require "util.set";
local jid_split, jid_bare = require "util.jid".split, require "util.jid".bare;
local normalize = require "util.jid".prep;
+local roles = require "util.roles";
+
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 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;
- };
+local role_registry = {};
+
+function register_role(role)
+ if role_registry[role.name] ~= nil then
+ return error("A role '"..role.name.."' is already registered");
+ end
+ if not roles.is_role(role) then
+ -- Convert table syntax to real role object
+ for i, inherited_role in ipairs(role.inherits or {}) do
+ if type(inherited_role) == "string" then
+ role.inherits[i] = assert(role_registry[inherited_role], "The named role '"..inherited_role.."' is not registered");
+ end
+ end
+ if not role.permissions then role.permissions = {}; end
+ for _, allow_permission in ipairs(role.allow or {}) do
+ role.permissions[allow_permission] = true;
+ end
+ for _, deny_permission in ipairs(role.deny or {}) do
+ role.permissions[deny_permission] = false;
+ end
+ role = roles.new(role);
+ end
+ role_registry[role.name] = role;
+end
+
+-- Default roles
+register_role {
+ name = "prosody:restricted";
+ priority = 15;
+};
+
+register_role {
+ name = "prosody:user";
+ priority = 25;
+ inherits = { "prosody:restricted" };
+};
+
+register_role {
+ name = "prosody:admin";
+ priority = 50;
+ inherits = { "prosody:user" };
};
--- 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 = {};
+register_role {
+ name = "prosody:operator";
+ priority = 75;
+ inherits = { "prosody:admin" };
+};
+
+
+-- Process custom roles from config
+
+local custom_roles = module:get_option("custom_roles", {});
+for n, role_config in ipairs(custom_roles) do
+ local ok, err = pcall(register_role, role_config);
+ if not ok then
+ module:log("error", "Error registering custom role %s: %s", role_config.name or tostring(n), err);
end
- setmetatable(role_info, role_mt);
end
-function role_methods:may(action, context)
- local policy = self.permissions[action];
- if policy ~= nil then
- return policy;
+-- Process custom permissions from config
+
+local config_add_perms = module:get_option("add_permissions", {});
+local config_remove_perms = module:get_option("remove_permissions", {});
+
+for role_name, added_permissions in pairs(config_add_perms) do
+ if not role_registry[role_name] then
+ module:log("error", "Cannot add permissions to unknown role '%s'", role_name);
+ else
+ for _, permission in ipairs(added_permissions) do
+ role_registry[role_name]:set_permission(permission, true, true);
+ end
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
+
+for role_name, removed_permissions in pairs(config_remove_perms) do
+ if not role_registry[role_name] then
+ module:log("error", "Cannot remove permissions from unknown role '%s'", role_name);
+ else
+ for _, permission in ipairs(removed_permissions) do
+ role_registry[role_name]:set_permission(permission, false, true);
end
end
- return false;
end
-- Public API
@@ -69,6 +104,9 @@ local config_operator_role_set = {
local config_admin_role_set = {
["prosody:admin"] = role_registry["prosody:admin"];
};
+local default_role_set = {
+ ["prosody:user"] = role_registry["prosody:user"];
+};
function get_user_roles(user)
local bare_jid = user.."@"..host;
@@ -78,25 +116,25 @@ function get_user_roles(user)
return config_admin_role_set;
end
local role_names = role_store:get(user);
- if not role_names then return {}; end
- local roles = {};
+ if not role_names then return default_role_set; end
+ local user_roles = {};
for role_name in pairs(role_names) do
- roles[role_name] = role_registry[role_name];
+ user_roles[role_name] = role_registry[role_name];
end
- return roles;
+ return user_roles;
end
-function set_user_roles(user, roles)
- role_store:set(user, roles)
+function set_user_roles(user, user_roles)
+ role_store:set(user, user_roles)
return true;
end
function get_user_default_role(user)
- local roles = get_user_roles(user);
- if not roles then return nil; end
+ local user_roles = get_user_roles(user);
+ if not user_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
+ for role_name, role_info in pairs(user_roles) do --luacheck: ignore 213/role_name
+ if role_info.default ~= false and (not default_role or role_info.priority > default_role.priority) then
default_role = role_info;
end
end
@@ -134,7 +172,7 @@ function get_jid_role(jid)
return nil;
end
-function set_jid_role(jid) -- luacheck: ignore 212
+function set_jid_role(jid, role_name) -- luacheck: ignore 212
return false;
end
@@ -157,16 +195,11 @@ function add_default_permission(role_name, action, policy)
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;
+ if policy == nil then policy = true; end
+ module:log("debug", "Adding policy %s for permission %s on role %s", policy, action, role_name);
+ return role:set_permission(action, policy);
end
-function get_role_info(role_name)
- return role_registry[role_name];
+function get_role_by_name(role_name)
+ return assert(role_registry[role_name], role_name);
end