webfinger/finger: allow WebFinger endpoint delegation with FEP-2c59
The ban on redirects was based on a misreading of FEP-2c59’s requirements. It is only meant to forbid addresses other than the canonical ActivityPub ID being advertised as such in the returned WebFinger data. This does not meaningfully lessen security and verification still remains stricter than without FEP-2c59. Notably this allows Mastodon with its backwards WebFinger redirect (redirecting from the canonical WebFinger domain to the AP domain) to adopt FEP-2c59 without causing issues or extra effort to existing deplyoments which already adopted the Mastodon-recommended setup.
This commit is contained in:
parent
4f03a3b709
commit
9d1e169472
2 changed files with 12 additions and 10 deletions
|
|
@ -107,9 +107,9 @@ defmodule Pleroma.Web.WebFinger.Finger do
|
|||
e -> {:error, "Cachex error: #{inspect(e)}"}
|
||||
end
|
||||
|
||||
defp make_finger_uri(domain, resource, allow_delegation) do
|
||||
defp make_finger_uri(domain, resource) do
|
||||
encoded_resource = URI.encode(resource)
|
||||
discovered_template = allow_delegation && find_lrdd_template(domain)
|
||||
discovered_template = find_lrdd_template(domain)
|
||||
|
||||
case discovered_template do
|
||||
{:ok, template} ->
|
||||
|
|
@ -150,19 +150,17 @@ defmodule Pleroma.Web.WebFinger.Finger do
|
|||
|
||||
defp map_fetch_error_reason(%Tesla.Env{} = env), do: {:http_error, :connect, env}
|
||||
|
||||
defp finger_unverified_data(domain, resource, allow_delegation \\ true) do
|
||||
query_uri = make_finger_uri(domain, resource, allow_delegation)
|
||||
defp finger_unverified_data(domain, resource) do
|
||||
query_uri = make_finger_uri(domain, resource)
|
||||
resp = HTTP.Backoff.get(query_uri, [{"accept", "application/xrd+xml,application/jrd+json"}])
|
||||
|
||||
with {:ok, %{url: resolved_uri, status: status} = resp_data} when status in 200..299 <- resp,
|
||||
{_, true} <- {:redirect, allow_delegation || query_uri == resolved_uri},
|
||||
{_, {:ok, parsed_data}} <- {:parse, parse_finger_response(resp_data)} do
|
||||
resolved_domain = URI.parse(resolved_uri).host
|
||||
|
||||
{:ok, resolved_domain, parsed_data}
|
||||
else
|
||||
{:ok, %Tesla.Env{} = env} -> {:error, map_fetch_error_reason(env)}
|
||||
{:redirect, _} -> {:error, :redirect}
|
||||
{:parse, {:error, _} = error} -> error
|
||||
{:error, _reason} = e -> e
|
||||
end
|
||||
|
|
@ -201,9 +199,13 @@ defmodule Pleroma.Web.WebFinger.Finger do
|
|||
|
||||
with {_, false} <- {:no_domain, domain == nil || ap_domain == nil},
|
||||
{_, false} <- {:matching_domain, domain == ap_domain},
|
||||
# Per FEP-2c59 no form of redirects are allowed when fingering the handle
|
||||
# We check for an exact match to the preferred handle which will ALWAYS
|
||||
# belong to the initial query domain, thus we do not need to consider the final domain here.
|
||||
# If the query domain delegates to another domain via host-meta or HTTP redirects on
|
||||
# ./well-known/ paths (which ought to be directly controlled by the operator),
|
||||
# this clearly indicates consent of the query domain to allow the final domain to manage this data
|
||||
{_, {:ok, _, %{"ap_id" => fingered_ap_id, "subject" => finger_subject}}} <-
|
||||
{:query, finger_unverified_data(domain, ap_id, false)},
|
||||
{:query, finger_unverified_data(domain, ap_id)},
|
||||
{_, false} <- {:fingered_data_mismatch, ap_id != fingered_ap_id},
|
||||
finger_handle <- normalise_webfinger_handle(finger_subject),
|
||||
{_, false} <- {:fingered_data_mismatch, preferred_handle != finger_handle} do
|
||||
|
|
|
|||
|
|
@ -529,7 +529,7 @@ defmodule Pleroma.Web.WebFinger.FingerTest do
|
|||
end
|
||||
end
|
||||
|
||||
test "should not permit a redirect on the webfinger" do
|
||||
test "permits a redirect on the webfinger endpoint if all data matches" do
|
||||
Tesla.Mock.mock(fn
|
||||
# we should finger the webfinger property
|
||||
%{
|
||||
|
|
@ -559,7 +559,7 @@ defmodule Pleroma.Web.WebFinger.FingerTest do
|
|||
}}
|
||||
end)
|
||||
|
||||
assert {:error, :redirect} =
|
||||
assert {:ok, "user@example.com"} =
|
||||
Finger.finger_actor(%{
|
||||
"id" => "https://social.example.com/users/user",
|
||||
"webfinger" => "user@example.com"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue