Add option for RFC 7033 WebFinger http fallback

This commit is contained in:
Benjamin Neff 2017-09-07 23:45:13 +02:00
parent 80e4844654
commit f24dd528ee
No known key found for this signature in database
GPG key ID: 971464C3F1A90194
4 changed files with 98 additions and 38 deletions

View file

@ -14,8 +14,6 @@ GET /.well-known/webfinger
Let's assume we are searching for `alice@example.org`, then we need to make a request to `example.org`.
The request should first be tried with https, if this doesn't work, the requesting server should fallback to http.
#### Parameters
| Name | Description |

View file

@ -39,6 +39,7 @@ module DiasporaFederation
]
# defaults
@webfinger_http_fallback = false
@http_concurrency = 20
@http_timeout = 30
@http_verbose = false
@ -74,6 +75,21 @@ module DiasporaFederation
# @param [String] value path to certificate authorities
attr_accessor :certificate_authorities
# Configure if WebFinger discovery should fallback to http if https fails (default: +false+)
#
# This is useful for example for development environments where https isn't available.
#
# This setting only applies to the WebFinger route from RFC 7033 +/.well-known/webfinger+.
# Legacy WebFinger flow unconditionally falls back to http.
#
# @overload webfinger_http_fallback
# @return [Boolean] webfinger http fallback enabled
# @overload webfinger_http_fallback=
# @example
# config.webfinger_http_fallback = AppConfig.server.rails_environment == "development"
# @param [Boolean] value webfinger http fallback enabled
attr_accessor :webfinger_http_fallback
# Maximum number of parallel HTTP requests made to other pods (default: +20+)
#
# @overload http_concurrency

View file

@ -76,8 +76,8 @@ module DiasporaFederation
return @webfinger if @webfinger
webfinger_url = "https://#{domain}/.well-known/webfinger?resource=#{acct_parameter}"
# This tries the WebFinger URL with https first, then falls back to http.
@webfinger = WebFinger.from_json(get(webfinger_url, true))
# This tries the WebFinger URL with https first, then falls back to http if webfinger_http_fallback is enabled.
@webfinger = WebFinger.from_json(get(webfinger_url, DiasporaFederation.webfinger_http_fallback))
rescue => e
logger.warn "WebFinger failed, retrying with legacy WebFinger for #{diaspora_id}: #{e.class}: #{e.message}"
@webfinger = WebFinger.from_xml(get(legacy_webfinger_url_from_host_meta))

View file

@ -94,36 +94,6 @@ module DiasporaFederation
expect(subject.fetch_and_save).to be(callback_person)
end
it "falls back to http if https fails with 404" do
stub_request(:get, "https://localhost:3000/.well-known/webfinger?resource=acct:#{account}")
.to_return(status: 404)
stub_request(:get, "http://localhost:3000/.well-known/webfinger?resource=acct:#{account}")
.to_return(status: 200, body: webfinger_jrd)
stub_request(:get, "http://localhost:3000/hcard/users/#{alice.guid}")
.to_return(status: 200, body: hcard_html)
expect_callback(:save_person_after_webfinger, kind_of(Entities::Person))
person = subject.fetch_and_save
expect(person.guid).to eq(alice.guid)
expect(person.diaspora_id).to eq(account)
end
it "falls back to http if https fails with ssl error" do
stub_request(:get, "https://localhost:3000/.well-known/webfinger?resource=acct:#{account}")
.to_raise(OpenSSL::SSL::SSLError)
stub_request(:get, "http://localhost:3000/.well-known/webfinger?resource=acct:#{account}")
.to_return(status: 200, body: webfinger_jrd)
stub_request(:get, "http://localhost:3000/hcard/users/#{alice.guid}")
.to_return(status: 200, body: hcard_html)
expect_callback(:save_person_after_webfinger, kind_of(Entities::Person))
person = subject.fetch_and_save
expect(person.guid).to eq(alice.guid)
expect(person.diaspora_id).to eq(account)
end
it "fails if the diaspora* ID does not match" do
modified_webfinger = webfinger_jrd.gsub(account, "anonther_user@example.com")
@ -146,6 +116,86 @@ module DiasporaFederation
expect { subject.fetch_and_save }.to raise_error Discovery::DiscoveryError
end
context "http fallback" do
context "http fallback disabled (default)" do
it "falls back to legacy WebFinger if https fails with 404" do
stub_request(:get, "https://localhost:3000/.well-known/webfinger?resource=acct:#{account}")
.to_return(status: 404)
stub_request(:get, "https://localhost:3000/.well-known/host-meta")
.to_return(status: 200, body: host_meta_xrd)
stub_request(:get, "http://localhost:3000/.well-known/webfinger.xml?resource=acct:#{account}")
.to_return(status: 200, body: webfinger_xrd)
stub_request(:get, "http://localhost:3000/hcard/users/#{alice.guid}")
.to_return(status: 200, body: hcard_html)
expect_callback(:save_person_after_webfinger, kind_of(Entities::Person))
person = subject.fetch_and_save
expect(person.guid).to eq(alice.guid)
expect(person.diaspora_id).to eq(account)
end
it "falls back to legacy WebFinger if https fails with ssl error" do
stub_request(:get, "https://localhost:3000/.well-known/webfinger?resource=acct:#{account}")
.to_raise(OpenSSL::SSL::SSLError)
stub_request(:get, "https://localhost:3000/.well-known/host-meta")
.to_raise(OpenSSL::SSL::SSLError)
stub_request(:get, "http://localhost:3000/.well-known/host-meta")
.to_return(status: 200, body: host_meta_xrd)
stub_request(:get, "http://localhost:3000/.well-known/webfinger.xml?resource=acct:#{account}")
.to_return(status: 200, body: webfinger_xrd)
stub_request(:get, "http://localhost:3000/hcard/users/#{alice.guid}")
.to_return(status: 200, body: hcard_html)
expect_callback(:save_person_after_webfinger, kind_of(Entities::Person))
person = subject.fetch_and_save
expect(person.guid).to eq(alice.guid)
expect(person.diaspora_id).to eq(account)
end
end
context "http fallback enabled" do
before :all do
DiasporaFederation.webfinger_http_fallback = true
end
after :all do
DiasporaFederation.webfinger_http_fallback = false
end
it "falls back to http if https fails with 404" do
stub_request(:get, "https://localhost:3000/.well-known/webfinger?resource=acct:#{account}")
.to_return(status: 404)
stub_request(:get, "http://localhost:3000/.well-known/webfinger?resource=acct:#{account}")
.to_return(status: 200, body: webfinger_jrd)
stub_request(:get, "http://localhost:3000/hcard/users/#{alice.guid}")
.to_return(status: 200, body: hcard_html)
expect_callback(:save_person_after_webfinger, kind_of(Entities::Person))
person = subject.fetch_and_save
expect(person.guid).to eq(alice.guid)
expect(person.diaspora_id).to eq(account)
end
it "falls back to http if https fails with ssl error" do
stub_request(:get, "https://localhost:3000/.well-known/webfinger?resource=acct:#{account}")
.to_raise(OpenSSL::SSL::SSLError)
stub_request(:get, "http://localhost:3000/.well-known/webfinger?resource=acct:#{account}")
.to_return(status: 200, body: webfinger_jrd)
stub_request(:get, "http://localhost:3000/hcard/users/#{alice.guid}")
.to_return(status: 200, body: hcard_html)
expect_callback(:save_person_after_webfinger, kind_of(Entities::Person))
person = subject.fetch_and_save
expect(person.guid).to eq(alice.guid)
expect(person.diaspora_id).to eq(account)
end
end
end
context "legacy WebFinger" do
it "falls back to legacy WebFinger" do
incomplete_webfinger_json = "{\"links\":[{\"rel\":\"http://openid.net/specs/connect/1.0/issuer\"," \
@ -181,8 +231,6 @@ module DiasporaFederation
it "falls back to http if https fails with 404" do
stub_request(:get, "https://localhost:3000/.well-known/webfinger?resource=acct:#{account}")
.to_return(status: 404)
stub_request(:get, "http://localhost:3000/.well-known/webfinger?resource=acct:#{account}")
.to_return(status: 404)
stub_request(:get, "https://localhost:3000/.well-known/host-meta")
.to_return(status: 404)
stub_request(:get, "http://localhost:3000/.well-known/host-meta")
@ -202,8 +250,6 @@ module DiasporaFederation
it "falls back to http if https fails with ssl error" do
stub_request(:get, "https://localhost:3000/.well-known/webfinger?resource=acct:#{account}")
.to_raise(OpenSSL::SSL::SSLError)
stub_request(:get, "http://localhost:3000/.well-known/webfinger?resource=acct:#{account}")
.to_return(status: 200, body: "foobar")
stub_request(:get, "https://localhost:3000/.well-known/host-meta")
.to_raise(OpenSSL::SSL::SSLError)
stub_request(:get, "http://localhost:3000/.well-known/host-meta")