changeset 5467:1c78a97a1091

mod_http_oauth2: Add a special "xmpp" scope that grants the users' default role This will be the first step towards defining a standard set of XMPP scopes. "xmpp" behaves as an alias for the user's default role, so that the client does not need to know about the various prosody:* roles.
author Kim Alvefur <zash@zash.se>
date Wed, 17 May 2023 19:40:27 +0200
parents 398d936e77fb
children 14b5446e22e1
files mod_http_oauth2/README.markdown mod_http_oauth2/mod_http_oauth2.lua
diffstat 2 files changed, 27 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/mod_http_oauth2/README.markdown	Wed May 17 18:49:22 2023 +0200
+++ b/mod_http_oauth2/README.markdown	Wed May 17 19:40:27 2023 +0200
@@ -165,12 +165,22 @@
 
 OAuth supports "scopes" as a way to grant clients limited access.
 
-There are currently no standard scopes defined for XMPP. This is something
-that we intend to change, e.g. by definitions provided in a future XEP. This
-means that clients you authorize currently have unrestricted access to your
-account (including the ability to change your password and lock you out!). So,
-for now, while using OAuth clients can prevent leaking your password to them,
-it is not currently suitable for connecting untrusted clients to your account.
+There are currently no standard scopes defined for XMPP. This is
+something that we intend to change, e.g. by definitions provided in a
+future XEP. This means that clients you authorize currently have to
+choose between unrestricted access to your account (including the
+ability to change your password and lock you out!) and zero access. So,
+for now, while using OAuth clients can prevent leaking your password to
+them, it is not currently suitable for connecting untrusted clients to
+your account.
+
+As a first step, the `xmpp` scope is supported, and corresponds to
+whatever permissions the user would have when logged in over XMPP.
+
+Further, known Prosody roles can be used as scopes.
+
+OpenID scopes such as `openid` and `profile` can be used for "Login
+with XMPP" without granting access to more than limited profile details.
 
 ## Compatibility
 
--- a/mod_http_oauth2/mod_http_oauth2.lua	Wed May 17 18:49:22 2023 +0200
+++ b/mod_http_oauth2/mod_http_oauth2.lua	Wed May 17 19:40:27 2023 +0200
@@ -102,7 +102,7 @@
 	return array(scope_string:gmatch("%S+"));
 end
 
-local openid_claims = set.new({ "openid", "profile"; "email"; "address"; "phone" });
+local openid_claims = set.new({ "openid"; "profile"; "email"; "address"; "phone" });
 
 -- array -> array, array, array
 local function split_scopes(scope_list)
@@ -111,7 +111,7 @@
 	for _, scope in ipairs(scope_list) do
 		if openid_claims:contains(scope) then
 			claims:push(scope);
-		elseif all_roles[scope] then
+		elseif scope == "xmpp" or all_roles[scope] then
 			roles:push(scope);
 		else
 			unknown:push(scope);
@@ -121,7 +121,7 @@
 end
 
 local function can_assume_role(username, requested_role)
-	return usermanager.user_can_assume_role(username, module.host, requested_role);
+	return requested_role == "xmpp" or usermanager.user_can_assume_role(username, module.host, requested_role);
 end
 
 -- function (string) : function(string) : boolean
@@ -223,6 +223,12 @@
 		refresh_token = refresh_token_info.token;
 	end
 
+	if role == "xmpp" then
+		-- Special scope meaning the users default role.
+		local user_default_role = usermanager.get_user_role(jid.node(token_jid), module.host);
+		role = user_default_role and user_default_role.name;
+	end
+
 	local access_token, access_token_info = tokens.create_token(token_jid, grant.id, role, default_access_ttl, "oauth2");
 
 	local expires_at = access_token_info.expires;
@@ -1080,7 +1086,8 @@
 				authorization_endpoint = handle_authorization_request and module:http_url() .. "/authorize" or nil;
 				token_endpoint = handle_token_grant and module:http_url() .. "/token" or nil;
 				registration_endpoint = handle_register_request and module:http_url() .. "/register" or nil;
-				scopes_supported = usermanager.get_all_roles and array(it.keys(usermanager.get_all_roles(module.host))):append(array(openid_claims:items()));
+				scopes_supported = usermanager.get_all_roles
+					and array(it.keys(usermanager.get_all_roles(module.host))):push("xmpp"):append(array(openid_claims:items()));
 				response_types_supported = array(it.keys(response_type_handlers));
 				token_endpoint_auth_methods_supported = array({ "client_secret_post"; "client_secret_basic" });
 				op_policy_uri = module:get_option_string("oauth2_policy_url", nil);