From 00763f3c6118279b3713999ff75a59c079815970 Mon Sep 17 00:00:00 2001 From: Nicolas Temciuc Date: Thu, 30 Oct 2025 15:40:06 -0300 Subject: [PATCH 1/2] feat: allow any top origin via :allow_all --- README.md | 4 + lib/webauthn/authenticator_response.rb | 5 +- .../authenticator_assertion_response_spec.rb | 112 +++++++++++++++++- ...authenticator_attestation_response_spec.rb | 112 +++++++++++++++++- 4 files changed, 223 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 7b5f2132..c7fe5a34 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 = :allow_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..2ef6322d 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 == :allow_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..37e85808 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 :allow_all" do + let(:allowed_top_origins) { :allow_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 :allow_all" do + let(:allowed_top_origins) { :allow_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..cb2014ea 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 :allow_all" do + let(:allowed_top_origins) { :allow_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 :allow_all" do + let(:allowed_top_origins) { :allow_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 From ce56271560d98a2a2b1d94d3bed77d54aeb09f07 Mon Sep 17 00:00:00 2001 From: Nicolas Temciuc Date: Fri, 31 Oct 2025 13:06:46 -0300 Subject: [PATCH 2/2] chore: use `:all` instead of `:allow_all` --- README.md | 2 +- lib/webauthn/authenticator_response.rb | 2 +- spec/webauthn/authenticator_assertion_response_spec.rb | 8 ++++---- spec/webauthn/authenticator_attestation_response_spec.rb | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index c7fe5a34..13dde688 100644 --- a/README.md +++ b/README.md @@ -128,7 +128,7 @@ WebAuthn.configure do |config| # # (C) Allow all top-level origins: # - # config.allowed_top_origins = :allow_all + # 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 2ef6322d..b4454628 100644 --- a/lib/webauthn/authenticator_response.rb +++ b/lib/webauthn/authenticator_response.rb @@ -89,7 +89,7 @@ def valid_token_binding? def valid_top_origin? return false unless client_data.cross_origin && client_data.top_origin - relying_party.allowed_top_origins == :allow_all || + relying_party.allowed_top_origins == :all || relying_party.allowed_top_origins&.include?(client_data.top_origin) end diff --git a/spec/webauthn/authenticator_assertion_response_spec.rb b/spec/webauthn/authenticator_assertion_response_spec.rb index 37e85808..a026a118 100644 --- a/spec/webauthn/authenticator_assertion_response_spec.rb +++ b/spec/webauthn/authenticator_assertion_response_spec.rb @@ -449,8 +449,8 @@ end end - context "when allowed_top_origins is :allow_all" do - let(:allowed_top_origins) { :allow_all } + context "when allowed_top_origins is :all" do + let(:allowed_top_origins) { :all } context "when cross_origin is true" do let(:cross_origin) { true } @@ -633,8 +633,8 @@ end end - context "when allowed_top_origins is :allow_all" do - let(:allowed_top_origins) { :allow_all } + context "when allowed_top_origins is :all" do + let(:allowed_top_origins) { :all } context "when cross_origin is true" do let(:cross_origin) { true } diff --git a/spec/webauthn/authenticator_attestation_response_spec.rb b/spec/webauthn/authenticator_attestation_response_spec.rb index cb2014ea..3ee95beb 100644 --- a/spec/webauthn/authenticator_attestation_response_spec.rb +++ b/spec/webauthn/authenticator_attestation_response_spec.rb @@ -778,8 +778,8 @@ end end - context "when allowed_top_origins is :allow_all" do - let(:allowed_top_origins) { :allow_all } + context "when allowed_top_origins is :all" do + let(:allowed_top_origins) { :all } context "when cross_origin is true" do let(:cross_origin) { true } @@ -962,8 +962,8 @@ end end - context "when allowed_top_origins is :allow_all" do - let(:allowed_top_origins) { :allow_all } + context "when allowed_top_origins is :all" do + let(:allowed_top_origins) { :all } context "when cross_origin is true" do let(:cross_origin) { true }