core, plugins: Split prosody:user role into prosody:{guest,registered,member}
authorMatthew Wild <mwild1@gmail.com>
Thu, 29 Jun 2023 15:36:13 +0100
changeset 13174 082c7d856e61
parent 13173 7b6e7290265b
child 13175 e2c3582ab9fa
core, plugins: Split prosody:user role into prosody:{guest,registered,member} This gives us more granular control over different types of user account. Accounts registered by IBR get assigned prosody:registered by default, while accounts provisioned by an admin (e.g. via prosodyctl shell) will receive prosody:member by default.
core/features.lua
plugins/mod_admin_shell.lua
plugins/mod_authz_internal.lua
plugins/mod_invites_adhoc.lua
plugins/mod_register_ibr.lua
plugins/muc/hidden.lib.lua
plugins/muc/mod_muc.lua
plugins/muc/persistent.lib.lua
--- a/core/features.lua	Thu Jun 29 15:31:46 2023 +0100
+++ b/core/features.lua	Thu Jun 29 15:36:13 2023 +0100
@@ -12,5 +12,8 @@
 		"keyval+";
 
 		"s2sout-pre-connect-event";
+
+		-- prosody:guest, prosody:registered, prosody:member
+		"split-user-roles";
 	};
 };
--- a/plugins/mod_admin_shell.lua	Thu Jun 29 15:31:46 2023 +0100
+++ b/plugins/mod_admin_shell.lua	Thu Jun 29 15:36:13 2023 +0100
@@ -282,8 +282,10 @@
 	elseif section == "roles" then
 		print [[Roles may grant access or restrict users from certain operations]]
 		print [[Built-in roles are:]]
-		print [[  prosody:user     - Normal user (default)]]
-		print [[  prosody:admin    - Host administrator]]
+		print [[  prosody:guest      - Guest/anonymous user]]
+		print [[  prosody:registered - Registered user]]
+		print [[  prosody:member     - Provisioned user]]
+		print [[  prosody:admin      - Host administrator]]
 		print [[  prosody:operator - Server administrator]]
 		print [[]]
 		print [[Roles can be assigned using the user management commands (see 'help user').]]
@@ -1582,36 +1584,16 @@
 		return nil, "User exists";
 	end
 
-	if role then
-		local ok, err = um.create_user(username, nil, host);
-		if not ok then
-			return nil, "Could not create user: "..err;
-		end
-
-		local role_ok, rerr = um.set_user_role(jid, host, role);
-		if not role_ok then
-			return nil, "Could not set role: " .. tostring(rerr);
-		end
-
-		if password then
-			local ok, err = um.set_password(username, password, host, nil);
-			if not ok then
-				return nil, "Could not set password for user: "..err;
-			end
-
-			local ok, err = um.enable_user(username, host);
-			if not ok and err ~= "method not implemented" then
-				return nil, "Could not enable user: "..err;
-			end
-		end
-	else
-		local ok, err = um.create_user(username, password, host);
-		if not ok then
-			return nil, "Could not create user: "..err;
-		end
+	if not role then
+		role = module:get_option_string("default_provisioned_role", "prosody:member");
 	end
 
-	return true, "User created";
+	local ok, err = um.create_user_with_role(username, password, host, role);
+	if not ok then
+		return nil, "Could not create user: "..err;
+	end
+
+	return true, ("Created %s with role '%s'"):format(jid, role);
 end
 
 function def_env.user:disable(jid)
--- a/plugins/mod_authz_internal.lua	Thu Jun 29 15:31:46 2023 +0100
+++ b/plugins/mod_authz_internal.lua	Thu Jun 29 15:36:13 2023 +0100
@@ -11,10 +11,13 @@
 local host_suffix = host:gsub("^[^%.]+%.", "");
 
 local hosts = prosody.hosts;
+local is_anon_host = module:get_option_string("authentication") == "anonymous";
+local default_user_role = module:get_option_string("default_user_role", is_anon_host and "prosody:guest" or "prosody:registered");
+
 local is_component = hosts[host].type == "component";
 local host_user_role, server_user_role, public_user_role;
 if is_component then
-	host_user_role = module:get_option_string("host_user_role", "prosody:user");
+	host_user_role = module:get_option_string("host_user_role", "prosody:registered");
 	server_user_role = module:get_option_string("server_user_role");
 	public_user_role = module:get_option_string("public_user_role");
 end
@@ -48,23 +51,36 @@
 end
 
 -- Default roles
+
+-- For untrusted guest/anonymous users
 register_role {
-	name = "prosody:restricted";
+	name = "prosody:guest";
 	priority = 15;
 };
 
+-- For e.g. self-registered accounts
 register_role {
-	name = "prosody:user";
+	name = "prosody:registered";
 	priority = 25;
-	inherits = { "prosody:restricted" };
+	inherits = { "prosody:guest" };
 };
 
+
+-- For trusted/provisioned accounts
+register_role {
+	name = "prosody:member";
+	priority = 35;
+	inherits = { "prosody:registered" };
+};
+
+-- For administrators, e.g. of a host
 register_role {
 	name = "prosody:admin";
 	priority = 50;
-	inherits = { "prosody:user" };
+	inherits = { "prosody:member" };
 };
 
+-- For server operators (full access)
 register_role {
 	name = "prosody:operator";
 	priority = 75;
@@ -128,11 +144,11 @@
 			return nil, err;
 		end
 		-- No role set, use default role
-		return role_registry["prosody:user"];
+		return role_registry[default_user_role];
 	end
 	if stored_roles._default == nil then
 		-- No primary role explicitly set, return default
-		return role_registry["prosody:user"];
+		return role_registry[default_user_role];
 	end
 	local primary_stored_role = role_registry[stored_roles._default];
 	if not primary_stored_role then
@@ -152,7 +168,7 @@
 		-- Primary role cannot be secondary role
 		[role_name] = role_map_store.remove;
 	};
-	if role_name == "prosody:user" then
+	if role_name == default_user_role then
 		-- Don't store default
 		keys_update._default = role_map_store.remove;
 	end
--- a/plugins/mod_invites_adhoc.lua	Thu Jun 29 15:31:46 2023 +0100
+++ b/plugins/mod_invites_adhoc.lua	Thu Jun 29 15:36:13 2023 +0100
@@ -12,7 +12,7 @@
 -- on the server, use the option above instead.
 local allow_contact_invites = module:get_option_boolean("allow_contact_invites", true);
 
-module:default_permission(allow_user_invites and "prosody:user" or "prosody:admin", ":invite-users");
+module:default_permission(allow_user_invites and "prosody:registered" or "prosody:admin", ":invite-users");
 
 local invites;
 if prosody.shutdown then -- COMPAT hack to detect prosodyctl
--- a/plugins/mod_register_ibr.lua	Thu Jun 29 15:31:46 2023 +0100
+++ b/plugins/mod_register_ibr.lua	Thu Jun 29 15:36:13 2023 +0100
@@ -10,7 +10,7 @@
 local st = require "prosody.util.stanza";
 local dataform_new = require "prosody.util.dataforms".new;
 local usermanager_user_exists  = require "prosody.core.usermanager".user_exists;
-local usermanager_create_user  = require "prosody.core.usermanager".create_user;
+local usermanager_create_user_with_role  = require "prosody.core.usermanager".create_user_with_role;
 local usermanager_set_password = require "prosody.core.usermanager".create_user;
 local usermanager_delete_user  = require "prosody.core.usermanager".delete_user;
 local nodeprep = require "prosody.util.encodings".stringprep.nodeprep;
@@ -20,6 +20,8 @@
 local require_encryption = module:get_option_boolean("c2s_require_encryption",
 	module:get_option_boolean("require_encryption", true));
 
+local default_role = module:get_option_string("register_ibr_default_role", "prosody:registered");
+
 pcall(function ()
 	module:depends("register_limits");
 end);
@@ -166,7 +168,12 @@
 		return true;
 	end
 
-	local user = { username = username, password = password, host = host, additional = data, ip = session.ip, session = session, allowed = true }
+	local user = {
+		username = username, password = password, host = host;
+		additional = data, ip = session.ip, session = session;
+		role = default_role;
+		allowed = true;
+	};
 	module:fire_event("user-registering", user);
 	if not user.allowed then
 		local error_type, error_condition, reason;
@@ -200,7 +207,7 @@
 		end
 	end
 
-	local created, err = usermanager_create_user(username, password, host);
+	local created, err = usermanager_create_user_with_role(username, password, host, user.role);
 	if created then
 		data.registered = os.time();
 		if not account_details:set(username, data) then
--- a/plugins/muc/hidden.lib.lua	Thu Jun 29 15:31:46 2023 +0100
+++ b/plugins/muc/hidden.lib.lua	Thu Jun 29 15:36:13 2023 +0100
@@ -8,7 +8,7 @@
 --
 
 local restrict_public = not module:get_option_boolean("muc_room_allow_public", true);
-module:default_permission(restrict_public and "prosody:admin" or "prosody:user", ":create-public-room");
+module:default_permission(restrict_public and "prosody:admin" or "prosody:registered", ":create-public-room");
 
 local function get_hidden(room)
 	return room._data.hidden;
--- a/plugins/muc/mod_muc.lua	Thu Jun 29 15:31:46 2023 +0100
+++ b/plugins/muc/mod_muc.lua	Thu Jun 29 15:36:13 2023 +0100
@@ -414,7 +414,7 @@
 end
 
 local restrict_room_creation = module:get_option("restrict_room_creation");
-module:default_permission(restrict_room_creation == true and "prosody:admin" or "prosody:user", ":create-room");
+module:default_permission(restrict_room_creation == true and "prosody:admin" or "prosody:registered", ":create-room");
 module:hook("muc-room-pre-create", function(event)
 	local origin, stanza = event.origin, event.stanza;
 	if restrict_room_creation ~= false and not module:may(":create-room", event) then
--- a/plugins/muc/persistent.lib.lua	Thu Jun 29 15:31:46 2023 +0100
+++ b/plugins/muc/persistent.lib.lua	Thu Jun 29 15:36:13 2023 +0100
@@ -9,7 +9,7 @@
 
 local restrict_persistent = not module:get_option_boolean("muc_room_allow_persistent", true);
 module:default_permission(
-	restrict_persistent and "prosody:admin" or "prosody:user",
+	restrict_persistent and "prosody:admin" or "prosody:registered",
 	":create-persistent-room"
 );