Diff

mod_http_oauth2/mod_http_oauth2.lua @ 5663:f6e8165a2ec2

Merge upstream
author Trần H. Trung <xmpp:trần.h.trung@trung.fun>
date Tue, 29 Aug 2023 22:46:27 +0700
parent 5651:dd2079b3dec6
child 5665:7c105277a9ca
line wrap: on
line diff
--- a/mod_http_oauth2/mod_http_oauth2.lua	Tue Aug 01 01:27:45 2023 +0700
+++ b/mod_http_oauth2/mod_http_oauth2.lua	Tue Aug 29 22:46:27 2023 +0700
@@ -394,15 +394,19 @@
 		return oauth_error("invalid_request", "PKCE required");
 	end
 
+	local prefix = "authorization_code:";
 	local code = id.medium();
 	if params.redirect_uri == device_uri then
 		local is_device, device_state = verify_device_token(params.state);
 		if is_device then
 			-- reconstruct the device_code
+			prefix = "device_code:";
 			code = b64url(hashes.hmac_sha256(verification_key, device_state.user_code));
+		else
+			return oauth_error("invalid_request");
 		end
 	end
-	local ok = codes:set("authorization_code:" .. params.client_id .. "#" .. code, {
+	local ok = codes:set(prefix.. params.client_id .. "#" .. code, {
 		expires = os.time() + 600;
 		granted_jid = granted_jid;
 		granted_scopes = granted_scopes;
@@ -578,7 +582,7 @@
 		return oauth_error("invalid_client", "incorrect credentials");
 	end
 
-	local code = codes:get("device_code:" .. params.device_code);
+	local code = codes:get("device_code:" .. params.client_id .. "#" .. params.device_code);
 	if type(code) ~= "table" or code_expired(code) then
 		return oauth_error("expired_token");
 	elseif code.error then
@@ -586,7 +590,7 @@
 	elseif not code.granted_jid then
 		return oauth_error("authorization_pending");
 	end
-	codes:set("device_code:" .. params.device_code, nil);
+	codes:set("device_code:" .. params.client_id .. "#" .. params.device_code, nil);
 
 	return json.encode(new_access_token(code.granted_jid, code.granted_role, code.granted_scopes, client, code.id_token));
 end
@@ -991,9 +995,10 @@
 	local verification_uri = module:http_url() .. "/device";
 	local verification_uri_complete = verification_uri .. "?" .. http.formencode({ user_code = user_code });
 
-	local dc_ok = codes:set("device_code:" .. params.client_id .. "#" .. device_code, { expires = os.time() + 1200 });
+	local expires = os.time() + 600;
+	local dc_ok = codes:set("device_code:" .. params.client_id .. "#" .. device_code, { expires = expires });
 	local uc_ok = codes:set("user_code:" .. user_code,
-		{ user_code = user_code; expires = os.time() + 600; client_id = params.client_id;
+		{ user_code = user_code; expires = expires; client_id = params.client_id;
     scope = requested_scopes:concat(" ") });
 	if not dc_ok or not uc_ok then
 		return oauth_error("temporarily_unavailable");
@@ -1041,6 +1046,8 @@
 	}
 end
 
+local strict_auth_revoke = module:get_option_boolean("oauth2_require_auth_revoke", false);
+
 local function handle_revocation_request(event)
 	local request, response = event.request, event.response;
 	response.headers.cache_control = "no-store";
@@ -1055,6 +1062,11 @@
 		if not verify_client_secret(credentials.username, credentials.password) then
 			return 401;
 		end
+		-- TODO check that it's their token I guess?
+	elseif strict_auth_revoke then
+		-- Why require auth to revoke a leaked token?
+		response.headers.www_authenticate = string.format("Basic realm=%q", module.host.."/"..module.name);
+		return 401;
 	end
 
 	local form_data = strict_formdecode(event.request.body);
@@ -1224,6 +1236,16 @@
 		return nil, oauth_error("invalid_request", "Failed schema validation.");
 	end
 
+	local client_uri = url.parse(client_metadata.client_uri);
+	if not client_uri or client_uri.scheme ~= "https" or loopbacks:contains(client_uri.host) then
+		return nil, oauth_error("invalid_client_metadata", "Missing, invalid or insecure client_uri");
+	end
+
+	if not client_metadata.application_type and redirect_uri_allowed(client_metadata.redirect_uris[1], client_uri, "native") then
+		client_metadata.application_type = "native";
+		-- else defaults to "web"
+	end
+
 	-- Fill in default values
 	for propname, propspec in pairs(registration_schema.properties) do
 		if client_metadata[propname] == nil and type(propspec) == "table" and propspec.default ~= nil then
@@ -1238,11 +1260,6 @@
 		end
 	end
 
-	local client_uri = url.parse(client_metadata.client_uri);
-	if not client_uri or client_uri.scheme ~= "https" or loopbacks:contains(client_uri.host) then
-		return nil, oauth_error("invalid_client_metadata", "Missing, invalid or insecure client_uri");
-	end
-
 	for _, redirect_uri in ipairs(client_metadata.redirect_uris) do
 		if not redirect_uri_allowed(redirect_uri, client_uri, client_metadata.application_type) then
 			return nil, oauth_error("invalid_redirect_uri", "Invalid, insecure or inappropriate redirect URI.");