changeset 4340:7cd3b7ec59e9

mod_http_oauth2: Rudimentary support for scopes (but not really) We don't support limiting access, but this change will inform the client what permissions the created token has (e.g. is the user an admin or not). There is some work in progress on real scope support.
author Matthew Wild <mwild1@gmail.com>
date Sat, 16 Jan 2021 19:47:22 +0000 (2021-01-16)
parents 3b7847c9bd26
children a104440c20a4
files mod_http_oauth2/mod_http_oauth2.lua
diffstat 1 files changed, 25 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/mod_http_oauth2/mod_http_oauth2.lua	Fri Jan 15 18:57:12 2021 +0000
+++ b/mod_http_oauth2/mod_http_oauth2.lua	Sat Jan 16 19:47:22 2021 +0000
@@ -14,6 +14,15 @@
 
 local clients = module:open_store("oauth2_clients", "map");
 
+local function filter_scopes(request_jid, requested_scope_string) --luacheck: ignore 212/requested_scope_string
+	-- We currently don't really support scopes, so override
+	-- to whatever real permissions the user has
+	if usermanager.is_admin(request_jid, module.host) then
+		return "prosody:scope:admin";
+	end
+	return "prosody:scope:default";
+end
+
 local function code_expired(code)
 	return os.difftime(os.time(), code.issued) > 120;
 end
@@ -47,6 +56,7 @@
 		token_type = "bearer";
 		access_token = token;
 		expires_in = ttl;
+		scope = scope;
 		-- TODO: include refresh_token when implemented
 	};
 end
@@ -58,25 +68,22 @@
 	local request_jid = assert(params.username, oauth_error("invalid_request", "missing 'username' (JID)"));
 	local request_password = assert(params.password, oauth_error("invalid_request", "missing 'password'"));
 	local request_username, request_host, request_resource = jid.prepped_split(request_jid);
-	if params.scope and params.scope ~= "" then
-		return oauth_error("invalid_scope", "unknown scope requested");
-	end
+
 	if not (request_username and request_host) or request_host ~= module.host then
 		return oauth_error("invalid_request", "invalid JID");
 	end
-	if usermanager.test_password(request_username, request_host, request_password) then
-		local granted_jid = jid.join(request_username, request_host, request_resource);
-		return json.encode(new_access_token(granted_jid, nil, nil));
+	if not usermanager.test_password(request_username, request_host, request_password) then
+		return oauth_error("invalid_grant", "incorrect credentials");
 	end
-	return oauth_error("invalid_grant", "incorrect credentials");
+
+	local granted_jid = jid.join(request_username, request_host, request_resource);
+	local granted_scopes = filter_scopes(granted_jid, params.scope);
+	return json.encode(new_access_token(granted_jid, granted_scopes, nil));
 end
 
 function response_type_handlers.code(params, granted_jid)
 	if not params.client_id then return oauth_error("invalid_request", "missing 'client_id'"); end
 	if not params.redirect_uri then return oauth_error("invalid_request", "missing 'redirect_uri'"); end
-	if params.scope and params.scope ~= "" then
-		return oauth_error("invalid_scope", "unknown scope requested");
-	end
 
 	local client_owner, client_host, client_id = jid.prepped_split(params.client_id);
 	if client_host ~= module.host then
@@ -88,8 +95,14 @@
 		return oauth_error("invalid_client", "incorrect credentials");
 	end
 
+	local granted_scopes = filter_scopes(granted_jid, params.scope);
+
 	local code = uuid.generate();
-	assert(codes:set(params.client_id .. "#" .. code, {issued = os.time(); granted_jid = granted_jid}));
+	assert(codes:set(params.client_id .. "#" .. code, {
+		issued = os.time();
+		granted_jid = granted_jid;
+		granted_scopes = granted_scopes;
+	}));
 
 	local redirect = url.parse(params.redirect_uri);
 	local query = http.formdecode(redirect.query or "");
@@ -141,7 +154,7 @@
 	end
 	assert(codes:set(client_owner, client_id .. "#" .. params.code, nil));
 
-	return json.encode(new_access_token(code.granted_jid, nil, nil));
+	return json.encode(new_access_token(code.granted_jid, code.granted_scopes, nil));
 end
 
 local function check_credentials(request)