diff --git a/README.md b/README.md index 7b5f2132..13dde688 100644 --- a/README.md +++ b/README.md @@ -126,6 +126,10 @@ WebAuthn.configure do |config| # # config.allowed_top_origins = [] # + # (C) Allow all top-level origins: + # + # config.allowed_top_origins = :all + # # Note: if `verify_cross_origin` is not enabled, any values set in `allowed_top_origins` # will be ignored. diff --git a/lib/webauthn/authenticator_response.rb b/lib/webauthn/authenticator_response.rb index c31f45d4..b4454628 100644 --- a/lib/webauthn/authenticator_response.rb +++ b/lib/webauthn/authenticator_response.rb @@ -87,9 +87,10 @@ def valid_token_binding? end def valid_top_origin? - return false unless client_data.cross_origin + return false unless client_data.cross_origin && client_data.top_origin - relying_party.allowed_top_origins&.include?(client_data.top_origin) + relying_party.allowed_top_origins == :all || + relying_party.allowed_top_origins&.include?(client_data.top_origin) end def valid_challenge?(expected_challenge) diff --git a/spec/webauthn/authenticator_assertion_response_spec.rb b/spec/webauthn/authenticator_assertion_response_spec.rb index ce828fe6..a026a118 100644 --- a/spec/webauthn/authenticator_assertion_response_spec.rb +++ b/spec/webauthn/authenticator_assertion_response_spec.rb @@ -373,8 +373,8 @@ end end - context "when allowed_top_origins is set" do - let(:allowed_top_origins) { [top_origin] } + context "when allowed_top_origins is a collection of origins" do + let(:allowed_top_origins) { [top_origin, "http://another.example.com"] } context "when cross_origin is true" do let(:cross_origin) { true } @@ -448,6 +448,58 @@ end end end + + context "when allowed_top_origins is :all" do + let(:allowed_top_origins) { :all } + + context "when cross_origin is true" do + let(:cross_origin) { true } + + context "when top_origin is set" do + let(:client_top_origin) { top_origin } + + it_behaves_like "a valid assertion response" + end + + context "when top_origin is not set" do + let(:client_top_origin) { nil } + + it_behaves_like "a valid assertion response" + end + end + + context "when cross_origin is false" do + let(:cross_origin) { false } + + context "when top_origin is set" do + let(:client_top_origin) { top_origin } + + it_behaves_like "a valid assertion response" + end + + context "when top_origin is not set" do + let(:client_top_origin) { nil } + + it_behaves_like "a valid assertion response" + end + end + + context "when cross_origin is not set" do + let(:cross_origin) { nil } + + context "when top_origin is set" do + let(:client_top_origin) { top_origin } + + it_behaves_like "a valid assertion response" + end + + context "when top_origin is not set" do + let(:client_top_origin) { nil } + + it_behaves_like "a valid assertion response" + end + end + end end context "when verify_cross_origin is true" do @@ -505,8 +557,8 @@ end end - context "when allowed_top_origins is set" do - let(:allowed_top_origins) { [top_origin] } + context "when allowed_top_origins is a collection of origins" do + let(:allowed_top_origins) { [top_origin, "http://another.example.com"] } context "when cross_origin is true" do let(:cross_origin) { true } @@ -580,6 +632,58 @@ end end end + + context "when allowed_top_origins is :all" do + let(:allowed_top_origins) { :all } + + context "when cross_origin is true" do + let(:cross_origin) { true } + + context "when top_origin is set" do + let(:client_top_origin) { top_origin } + + it_behaves_like "a valid assertion response" + end + + context "when top_origin is not set" do + let(:client_top_origin) { nil } + + it_behaves_like "an invalid assertion response that raises", WebAuthn::TopOriginVerificationError + end + end + + context "when cross_origin is false" do + let(:cross_origin) { false } + + context "when top_origin is set" do + let(:client_top_origin) { top_origin } + + it_behaves_like "an invalid assertion response that raises", WebAuthn::TopOriginVerificationError + end + + context "when top_origin is not set" do + let(:client_top_origin) { nil } + + it_behaves_like "a valid assertion response" + end + end + + context "when cross_origin is not set" do + let(:cross_origin) { nil } + + context "when top_origin is set" do + let(:client_top_origin) { top_origin } + + it_behaves_like "an invalid assertion response that raises", WebAuthn::TopOriginVerificationError + end + + context "when top_origin is not set" do + let(:client_top_origin) { nil } + + it_behaves_like "a valid assertion response" + end + end + end end end diff --git a/spec/webauthn/authenticator_attestation_response_spec.rb b/spec/webauthn/authenticator_attestation_response_spec.rb index 91ce28a3..3ee95beb 100644 --- a/spec/webauthn/authenticator_attestation_response_spec.rb +++ b/spec/webauthn/authenticator_attestation_response_spec.rb @@ -702,8 +702,8 @@ end end - context "when allowed_top_origins is set" do - let(:allowed_top_origins) { [top_origin] } + context "when allowed_top_origins is a collection of origins" do + let(:allowed_top_origins) { [top_origin, "https://another.example.com"] } context "when cross_origin is true" do let(:cross_origin) { true } @@ -777,6 +777,58 @@ end end end + + context "when allowed_top_origins is :all" do + let(:allowed_top_origins) { :all } + + context "when cross_origin is true" do + let(:cross_origin) { true } + + context "when top_origin is set" do + let(:client_top_origin) { top_origin } + + it_behaves_like "a valid attestation response" + end + + context "when top_origin is not set" do + let(:client_top_origin) { nil } + + it_behaves_like "a valid attestation response" + end + end + + context "when cross_origin is false" do + let(:cross_origin) { false } + + context "when top_origin is set" do + let(:client_top_origin) { top_origin } + + it_behaves_like "a valid attestation response" + end + + context "when top_origin is not set" do + let(:client_top_origin) { nil } + + it_behaves_like "a valid attestation response" + end + end + + context "when cross_origin is not set" do + let(:cross_origin) { nil } + + context "when top_origin is set" do + let(:client_top_origin) { top_origin } + + it_behaves_like "a valid attestation response" + end + + context "when top_origin is not set" do + let(:client_top_origin) { nil } + + it_behaves_like "a valid attestation response" + end + end + end end context "when verify_cross_origin is true" do @@ -834,8 +886,8 @@ end end - context "when allowed_top_origins is set" do - let(:allowed_top_origins) { [top_origin] } + context "when allowed_top_origins is a collection of origins" do + let(:allowed_top_origins) { [top_origin, "https://another.example.com"] } context "when cross_origin is true" do let(:cross_origin) { true } @@ -909,6 +961,58 @@ end end end + + context "when allowed_top_origins is :all" do + let(:allowed_top_origins) { :all } + + context "when cross_origin is true" do + let(:cross_origin) { true } + + context "when top_origin is set" do + let(:client_top_origin) { top_origin } + + it_behaves_like "a valid attestation response" + end + + context "when top_origin is not set" do + let(:client_top_origin) { nil } + + it_behaves_like "an invalid attestation response that raises", WebAuthn::TopOriginVerificationError + end + end + + context "when cross_origin is false" do + let(:cross_origin) { false } + + context "when top_origin is set" do + let(:client_top_origin) { top_origin } + + it_behaves_like "an invalid attestation response that raises", WebAuthn::TopOriginVerificationError + end + + context "when top_origin is not set" do + let(:client_top_origin) { nil } + + it_behaves_like "a valid attestation response" + end + end + + context "when cross_origin is not set" do + let(:cross_origin) { nil } + + context "when top_origin is set" do + let(:client_top_origin) { top_origin } + + it_behaves_like "an invalid attestation response that raises", WebAuthn::TopOriginVerificationError + end + + context "when top_origin is not set" do + let(:client_top_origin) { nil } + + it_behaves_like "a valid attestation response" + end + end + end end end