From 513b966c996ea1c526569a11b336d02fb529eb22 Mon Sep 17 00:00:00 2001 From: Nicolas Temciuc Date: Tue, 28 Oct 2025 15:38:47 -0300 Subject: [PATCH 1/5] test: a valid assertion response using shared examples --- .../authenticator_assertion_response_spec.rb | 423 +++--------------- 1 file changed, 70 insertions(+), 353 deletions(-) diff --git a/spec/webauthn/authenticator_assertion_response_spec.rb b/spec/webauthn/authenticator_assertion_response_spec.rb index 686668cd..bbe4ba43 100644 --- a/spec/webauthn/authenticator_assertion_response_spec.rb +++ b/spec/webauthn/authenticator_assertion_response_spec.rb @@ -26,24 +26,49 @@ ) end + let(:challenge) { original_challenge } + let(:public_key) { credential_public_key } + let(:sign_count) { 0 } + let(:user_presence) { nil } + let(:user_verification) { nil } + let(:rp_id) { nil } + before do WebAuthn.configuration.allowed_origins = [origin] end - context "when everything's in place" do + shared_examples "a valid assertion response" do it "verifies" do - expect( - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy + expect { + assertion_response.verify( + challenge, + public_key: public_key, + sign_count: sign_count, + user_presence: user_presence, + user_verification: user_verification, + rp_id: rp_id + ) + }.not_to raise_error end it "is valid" do expect( - assertion_response.valid?(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy + assertion_response.valid?( + challenge, + public_key: public_key, + sign_count: sign_count, + user_presence: user_presence, + user_verification: user_verification, + rp_id: rp_id + ) + ).to be(true) end end + context "when everything's in place" do + it_behaves_like "a valid assertion response" + end + # Gem version v1.11.0 and lower, used to behave so that Credential#public_key # returned an EC P-256 uncompressed point. # @@ -55,14 +80,13 @@ # user and later be passed as the public_key argument in the # AuthenticatorAssertionResponse.verify call, we then need to support the two formats. context "when everything's in place with the old public key format" do - it "verifies" do - old_format_key = - WebAuthn::AttestationStatement::FidoU2f::PublicKey + let(:public_key) { + WebAuthn::AttestationStatement::FidoU2f::PublicKey .new(credential_public_key) .to_uncompressed_point + } - expect(assertion_response.verify(original_challenge, public_key: old_format_key, sign_count: 0)).to be_truthy - end + it_behaves_like "a valid assertion response" end context "if signature was signed with a different key" do @@ -122,27 +146,9 @@ end context 'when user presence is not required' do - it "verifies if user presence is not required" do - expect( - assertion_response.verify( - original_challenge, - public_key: credential_public_key, - sign_count: 0, - user_presence: false - ) - ).to be_truthy - end + let(:user_presence) { false } - it "is valid" do - expect( - assertion_response.valid?( - original_challenge, - public_key: credential_public_key, - sign_count: 0, - user_presence: false - ) - ).to be_truthy - end + it_behaves_like "a valid assertion response" end context 'when user presence is required' do @@ -195,27 +201,9 @@ end context 'when user presence is not required' do - it "verifies if user presence is not required" do - expect( - assertion_response.verify( - original_challenge, - public_key: credential_public_key, - sign_count: 0, - user_presence: false - ) - ).to be_truthy - end + let(:user_presence) { false } - it "is valid" do - expect( - assertion_response.valid?( - original_challenge, - public_key: credential_public_key, - sign_count: 0, - user_presence: false - ) - ).to be_truthy - end + it_behaves_like "a valid assertion response" end context 'when user presence is required' do @@ -254,41 +242,13 @@ end context 'when user presence is not set' do - it "verifies if user presence is not required" do - expect( - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end - - it "is valid" do - expect( - assertion_response.valid?(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end + it_behaves_like "a valid assertion response" end context 'when user presence is not required' do - it "verifies if user presence is not required" do - expect( - assertion_response.verify( - original_challenge, - public_key: credential_public_key, - sign_count: 0, - user_presence: false - ) - ).to be_truthy - end + let(:user_presence) { false } - it "is valid" do - expect( - assertion_response.valid?( - original_challenge, - public_key: credential_public_key, - sign_count: 0, - user_presence: false - ) - ).to be_truthy - end + it_behaves_like "a valid assertion response" end context 'when user presence is required' do @@ -373,17 +333,7 @@ context "it has stuff" do let(:token_binding) { { status: "supported" } } - it "verifies" do - expect( - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end - - it "is valid" do - expect( - assertion_response.valid?(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end + it_behaves_like "a valid assertion response" end context "has an invalid format" do @@ -423,27 +373,9 @@ end context "when correct rp_id is explicitly given" do - it "verifies" do - expect( - assertion_response.verify( - original_challenge, - public_key: credential_public_key, - sign_count: 0, - rp_id: URI.parse(origin).host - ) - ).to be_truthy - end + let(:rp_id) { URI.parse(origin).host } - it "is valid" do - expect( - assertion_response.valid?( - original_challenge, - public_key: credential_public_key, - sign_count: 0, - rp_id: URI.parse(origin).host - ) - ).to be_truthy - end + it_behaves_like "a valid assertion response" end end @@ -451,22 +383,15 @@ context "if authenticator does not support counter" do let(:assertion) { client.get(challenge: original_challenge, sign_count: 0) } - it "verifies" do - expect( - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end + it_behaves_like "a valid assertion response" end context "when the authenticator supports counter" do context "and it's greater than the stored counter" do let(:assertion) { client.get(challenge: original_challenge, sign_count: 6) } + let(:sign_count) { 5 } - it "verifies" do - expect( - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 5) - ).to be_truthy - end + it_behaves_like "a valid assertion response" end context "and it's equal to the stored counter" do @@ -522,33 +447,13 @@ context "when top_origin is set" do let(:client_top_origin) { top_origin } - it "verifies" do - expect( - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end - - it "is valid" do - expect( - assertion_response.valid?(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end + it_behaves_like "a valid assertion response" end context "when top_origin is not set" do let(:client_top_origin) { nil } - it "verifies" do - expect( - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end - - it "is valid" do - expect( - assertion_response.valid?(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end + it_behaves_like "a valid assertion response" end end @@ -558,33 +463,13 @@ context "when top_origin is set" do let(:client_top_origin) { top_origin } - it "verifies" do - expect( - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end - - it "is valid" do - expect( - assertion_response.valid?(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end + it_behaves_like "a valid assertion response" end context "when top_origin is not set" do let(:client_top_origin) { nil } - it "verifies" do - expect( - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end - - it "is valid" do - expect( - assertion_response.valid?(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end + it_behaves_like "a valid assertion response" end end @@ -594,33 +479,13 @@ context "when top_origin is set" do let(:client_top_origin) { top_origin } - it "verifies" do - expect( - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end - - it "is valid" do - expect( - assertion_response.valid?(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end + it_behaves_like "a valid assertion response" end context "when top_origin is not set" do let(:client_top_origin) { nil } - it "verifies" do - expect( - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end - - it "is valid" do - expect( - assertion_response.valid?(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end + it_behaves_like "a valid assertion response" end end end @@ -635,50 +500,20 @@ context "when top_origin matches client top_origin" do let(:client_top_origin) { top_origin } - it "verifies" do - expect( - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end - - it "is valid" do - expect( - assertion_response.valid?(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end + it_behaves_like "a valid assertion response" end context "when top_origin does not match client top_origin" do let(:client_top_origin) { "https://malicious.example.com" } - it "verifies" do - expect( - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end - - it "is valid" do - expect( - assertion_response.valid?(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end + it_behaves_like "a valid assertion response" end end context "when top_origin is not set" do let(:client_top_origin) { nil } - it "verifies" do - expect( - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end - - it "is valid" do - expect( - assertion_response.valid?(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end + it_behaves_like "a valid assertion response" end end @@ -689,49 +524,19 @@ context "when top_origin matches client top_origin" do let(:client_top_origin) { top_origin } - it "verifies" do - expect( - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end - - it "is valid" do - expect( - assertion_response.valid?(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end + it_behaves_like "a valid assertion response" end context "when top_origin does not match client top_origin" do let(:client_top_origin) { "https://malicious.example.com" } - it "verifies" do - expect( - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end - - it "is valid" do - expect( - assertion_response.valid?(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end + it_behaves_like "a valid assertion response" end context "when top_origin is not set" do let(:client_top_origin) { nil } - it "verifies" do - expect( - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end - - it "is valid" do - expect( - assertion_response.valid?(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end + it_behaves_like "a valid assertion response" end end end @@ -743,49 +548,19 @@ context "when top_origin matches client top_origin" do let(:client_top_origin) { top_origin } - it "verifies" do - expect( - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end - - it "is valid" do - expect( - assertion_response.valid?(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end + it_behaves_like "a valid assertion response" end context "when top_origin does not match client top_origin" do let(:client_top_origin) { "https://malicious.example.com" } - it "verifies" do - expect( - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end - - it "is valid" do - expect( - assertion_response.valid?(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end + it_behaves_like "a valid assertion response" end context "when top_origin is not set" do let(:client_top_origin) { nil } - it "verifies" do - expect( - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end - - it "is valid" do - expect( - assertion_response.valid?(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end + it_behaves_like "a valid assertion response" end end end @@ -868,17 +643,7 @@ context "when top_origin is not set" do let(:client_top_origin) { nil } - it "verifies" do - expect( - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end - - it "is valid" do - expect( - assertion_response.valid?(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end + it_behaves_like "a valid assertion response" end end @@ -908,17 +673,7 @@ context "when top_origin is not set" do let(:client_top_origin) { nil } - it "verifies" do - expect( - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end - - it "is valid" do - expect( - assertion_response.valid?(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end + it_behaves_like "a valid assertion response" end end end @@ -933,17 +688,7 @@ context "when top_origin matches client top_origin" do let(:client_top_origin) { top_origin } - it "verifies" do - expect( - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end - - it "is valid" do - expect( - assertion_response.valid?(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end + it_behaves_like "a valid assertion response" end context "when top_origin does not match client top_origin" do @@ -1035,17 +780,7 @@ context "when top_origin is not set" do let(:client_top_origin) { nil } - it "verifies" do - expect( - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end - - it "is valid" do - expect( - assertion_response.valid?(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end + it_behaves_like "a valid assertion response" end end end @@ -1097,17 +832,7 @@ context "when top_origin is not set" do let(:client_top_origin) { nil } - it "verifies" do - expect( - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end - - it "is valid" do - expect( - assertion_response.valid?(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_truthy - end + it_behaves_like "a valid assertion response" end end end @@ -1140,17 +865,9 @@ let(:original_challenge) { WebAuthn::Encoders::Base64Encoder.decode(assertion_data[:challenge]) } context "when correct FIDO AppID is given as rp_id" do - it "verifies" do - expect( - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0, rp_id: app_id) - ).to be_truthy - end + let(:rp_id) { app_id } - it "is valid" do - expect( - assertion_response.valid?(original_challenge, public_key: credential_public_key, sign_count: 0, rp_id: app_id) - ).to be_truthy - end + it_behaves_like "a valid assertion response" end end From de74b311c398f6d538e1d2b17f9289674b9f1d15 Mon Sep 17 00:00:00 2001 From: Nicolas Temciuc Date: Tue, 28 Oct 2025 15:51:52 -0300 Subject: [PATCH 2/5] test: an invalid assertion response using shared examples --- .../authenticator_assertion_response_spec.rb | 393 +++--------------- 1 file changed, 63 insertions(+), 330 deletions(-) diff --git a/spec/webauthn/authenticator_assertion_response_spec.rb b/spec/webauthn/authenticator_assertion_response_spec.rb index bbe4ba43..7a33321d 100644 --- a/spec/webauthn/authenticator_assertion_response_spec.rb +++ b/spec/webauthn/authenticator_assertion_response_spec.rb @@ -65,6 +65,34 @@ end end + shared_examples "an invalid assertion response that raises" do |expected_error| + it "doesn't verify" do + expect { + assertion_response.verify( + challenge, + public_key: public_key, + sign_count: sign_count, + user_presence: user_presence, + user_verification: user_verification, + rp_id: rp_id + ) + }.to raise_error(expected_error) + end + + it "is invalid" do + expect( + assertion_response.valid?( + challenge, + public_key: public_key, + sign_count: sign_count, + user_presence: user_presence, + user_verification: user_verification, + rp_id: rp_id + ) + ).to be(false) + end + end + context "when everything's in place" do it_behaves_like "a valid assertion response" end @@ -90,20 +118,12 @@ end context "if signature was signed with a different key" do - let(:different_public_key) do + let(:public_key) do _different_id, different_public_key = create_credential(client: client) different_public_key end - it "is invalid" do - expect(assertion_response.valid?(original_challenge, public_key: different_public_key, sign_count: 0)).to be_falsy - end - - it "doesn't verify" do - expect { - assertion_response.verify(original_challenge, public_key: different_public_key, sign_count: 0) - }.to raise_exception(WebAuthn::SignatureVerificationError) - end + it_behaves_like "an invalid assertion response that raises", WebAuthn::SignatureVerificationError end describe "type validation" do @@ -112,17 +132,7 @@ allow(client).to receive(:type_for).and_return("webauthn.create") end - it "doesn't verify" do - expect { - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - }.to raise_exception(WebAuthn::TypeVerificationError) - end - - it "is invalid" do - expect( - assertion_response.valid?(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_falsy - end + it_behaves_like "an invalid assertion response that raises", WebAuthn::TypeVerificationError end end @@ -132,17 +142,7 @@ context "when silent_authentication is not set" do context 'when user presence is not set' do - it "doesn't verify" do - expect { - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - }.to raise_exception(WebAuthn::UserPresenceVerificationError) - end - - it "is invalid" do - expect( - assertion_response.valid?(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_falsy - end + it_behaves_like "an invalid assertion response that raises", WebAuthn::UserPresenceVerificationError end context 'when user presence is not required' do @@ -152,27 +152,9 @@ end context 'when user presence is required' do - it "doesn't verify" do - expect { - assertion_response.verify( - original_challenge, - public_key: credential_public_key, - sign_count: 0, - user_presence: true - ) - }.to raise_exception(WebAuthn::UserPresenceVerificationError) - end + let(:user_presence) { true } - it "is invalid" do - expect( - assertion_response.valid?( - original_challenge, - public_key: credential_public_key, - sign_count: 0, - user_presence: true - ) - ).to be_falsy - end + it_behaves_like "an invalid assertion response that raises", WebAuthn::UserPresenceVerificationError end end @@ -187,17 +169,7 @@ end context 'when user presence is not set' do - it "doesn't verify" do - expect { - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - }.to raise_exception(WebAuthn::UserPresenceVerificationError) - end - - it "is invalid" do - expect( - assertion_response.valid?(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_falsy - end + it_behaves_like "an invalid assertion response that raises", WebAuthn::UserPresenceVerificationError end context 'when user presence is not required' do @@ -207,27 +179,9 @@ end context 'when user presence is required' do - it "doesn't verify" do - expect { - assertion_response.verify( - original_challenge, - public_key: credential_public_key, - sign_count: 0, - user_presence: true - ) - }.to raise_exception(WebAuthn::UserPresenceVerificationError) - end + let(:user_presence) { true } - it "is invalid" do - expect( - assertion_response.valid?( - original_challenge, - public_key: credential_public_key, - sign_count: 0, - user_presence: true - ) - ).to be_falsy - end + it_behaves_like "an invalid assertion response that raises", WebAuthn::UserPresenceVerificationError end end @@ -252,27 +206,9 @@ end context 'when user presence is required' do - it "doesn't verify" do - expect { - assertion_response.verify( - original_challenge, - public_key: credential_public_key, - sign_count: 0, - user_presence: true - ) - }.to raise_exception(WebAuthn::UserPresenceVerificationError) - end + let(:user_presence) { true } - it "is invalid" do - expect( - assertion_response.valid?( - original_challenge, - public_key: credential_public_key, - sign_count: 0, - user_presence: true - ) - ).to be_falsy - end + it_behaves_like "an invalid assertion response that raises", WebAuthn::UserPresenceVerificationError end end end @@ -281,31 +217,17 @@ describe "user verified validation" do context "if user flags are off" do let(:assertion) { client.get(challenge: original_challenge, user_present: true, user_verified: false) } + let(:user_verification) { true } - it "doesn't verify" do - expect { - assertion_response.verify( - original_challenge, - public_key: credential_public_key, - sign_count: 0, - user_verification: true - ) - }.to raise_exception(WebAuthn::UserVerifiedVerificationError) - end + it_behaves_like "an invalid assertion response that raises", WebAuthn::UserVerifiedVerificationError end end describe "challenge validation" do context "if challenge doesn't match" do - it "doesn't verify" do - expect { - assertion_response.verify(fake_challenge, public_key: credential_public_key, sign_count: 0) - }.to raise_exception(WebAuthn::ChallengeVerificationError) - end + let(:challenge) { fake_challenge } - it "is invalid" do - expect(assertion_response.valid?(fake_challenge, public_key: credential_public_key, sign_count: 0)).to be_falsy - end + it_behaves_like "an invalid assertion response that raises", WebAuthn::ChallengeVerificationError end end @@ -313,17 +235,7 @@ context "if origin doesn't match" do let(:actual_origin) { "http://different-origin" } - it "doesn't verify" do - expect { - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - }.to raise_exception(WebAuthn::OriginVerificationError) - end - - it "is invalid" do - expect( - assertion_response.valid?(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_falsy - end + it_behaves_like "an invalid assertion response that raises", WebAuthn::OriginVerificationError end end @@ -339,17 +251,7 @@ context "has an invalid format" do let(:token_binding) { "invalid token binding format" } - it "doesn't verify" do - expect { - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - }.to raise_exception(WebAuthn::TokenBindingVerificationError) - end - - it "isn't valid" do - expect( - assertion_response.valid?(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_falsy - end + it_behaves_like "an invalid assertion response that raises", WebAuthn::TokenBindingVerificationError end end @@ -359,17 +261,7 @@ end context "if rp_id_hash doesn't match" do - it "doesn't verify" do - expect { - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - }.to raise_exception(WebAuthn::RpIdVerificationError) - end - - it "is invalid" do - expect( - assertion_response.valid?(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_falsy - end + it_behaves_like "an invalid assertion response that raises", WebAuthn::RpIdVerificationError end context "when correct rp_id is explicitly given" do @@ -396,32 +288,23 @@ context "and it's equal to the stored counter" do let(:assertion) { client.get(challenge: original_challenge, sign_count: 5) } + let(:sign_count) { 5 } - it "doesn't verify" do - expect { - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 5) - }.to raise_exception(WebAuthn::SignCountVerificationError) - end + it_behaves_like "an invalid assertion response that raises", WebAuthn::SignCountVerificationError end context "and it's less than the stored counter" do let(:assertion) { client.get(challenge: original_challenge, sign_count: 4) } + let(:sign_count) { 5 } - it "doesn't verify" do - expect { - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 5) - }.to raise_exception(WebAuthn::SignCountVerificationError) - end + it_behaves_like "an invalid assertion response that raises", WebAuthn::SignCountVerificationError end context "when the RP opts out of verifying the signature counter" do let(:assertion) { client.get(challenge: original_challenge, sign_count: false) } + let(:sign_count) { 5 } - it "verifies" do - expect { - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 5) - }.to raise_exception(WebAuthn::SignCountVerificationError) - end + it_behaves_like "an invalid assertion response that raises", WebAuthn::SignCountVerificationError end end end @@ -579,41 +462,13 @@ context "when top_origin is set" do let(:client_top_origin) { top_origin } - it "is invalid" do - expect( - assertion_response.valid?( - original_challenge, - public_key: credential_public_key, - sign_count: 0 - ) - ).to be_falsy - end - - it "doesn't verify" do - expect { - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - }.to raise_exception(WebAuthn::TopOriginVerificationError) - end + 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 "is invalid" do - expect( - assertion_response.valid?( - original_challenge, - public_key: credential_public_key, - sign_count: 0 - ) - ).to be_falsy - end - - it "doesn't verify" do - expect { - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - }.to raise_exception(WebAuthn::TopOriginVerificationError) - end + it_behaves_like "an invalid assertion response that raises", WebAuthn::TopOriginVerificationError end end @@ -623,21 +478,7 @@ context "when top_origin is set" do let(:client_top_origin) { top_origin } - it "is invalid" do - expect( - assertion_response.valid?( - original_challenge, - public_key: credential_public_key, - sign_count: 0 - ) - ).to be_falsy - end - - it "doesn't verify" do - expect { - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - }.to raise_exception(WebAuthn::TopOriginVerificationError) - end + it_behaves_like "an invalid assertion response that raises", WebAuthn::TopOriginVerificationError end context "when top_origin is not set" do @@ -653,21 +494,7 @@ context "when top_origin is set" do let(:client_top_origin) { top_origin } - it "is invalid" do - expect( - assertion_response.valid?( - original_challenge, - public_key: credential_public_key, - sign_count: 0 - ) - ).to be_falsy - end - - it "doesn't verify" do - expect { - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - }.to raise_exception(WebAuthn::TopOriginVerificationError) - end + it_behaves_like "an invalid assertion response that raises", WebAuthn::TopOriginVerificationError end context "when top_origin is not set" do @@ -694,42 +521,14 @@ context "when top_origin does not match client top_origin" do let(:client_top_origin) { "https://malicious.example.com" } - it "is invalid" do - expect( - assertion_response.valid?( - original_challenge, - public_key: credential_public_key, - sign_count: 0 - ) - ).to be_falsy - end - - it "doesn't verify" do - expect { - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - }.to raise_exception(WebAuthn::TopOriginVerificationError) - end + it_behaves_like "an invalid assertion response that raises", WebAuthn::TopOriginVerificationError end end context "when top_origin is not set" do let(:client_top_origin) { nil } - it "is invalid" do - expect( - assertion_response.valid?( - original_challenge, - public_key: credential_public_key, - sign_count: 0 - ) - ).to be_falsy - end - - it "doesn't verify" do - expect { - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - }.to raise_exception(WebAuthn::TopOriginVerificationError) - end + it_behaves_like "an invalid assertion response that raises", WebAuthn::TopOriginVerificationError end end @@ -740,41 +539,13 @@ context "when top_origin matches client top_origin" do let(:client_top_origin) { top_origin } - it "is invalid" do - expect( - assertion_response.valid?( - original_challenge, - public_key: credential_public_key, - sign_count: 0 - ) - ).to be_falsy - end - - it "doesn't verify" do - expect { - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - }.to raise_exception(WebAuthn::TopOriginVerificationError) - end + it_behaves_like "an invalid assertion response that raises", WebAuthn::TopOriginVerificationError end context "when top_origin does not match client top_origin" do let(:client_top_origin) { "https://malicious.example.com" } - it "is invalid" do - expect( - assertion_response.valid?( - original_challenge, - public_key: credential_public_key, - sign_count: 0 - ) - ).to be_falsy - end - - it "doesn't verify" do - expect { - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - }.to raise_exception(WebAuthn::TopOriginVerificationError) - end + it_behaves_like "an invalid assertion response that raises", WebAuthn::TopOriginVerificationError end context "when top_origin is not set" do @@ -792,41 +563,13 @@ context "when top_origin matches client top_origin" do let(:client_top_origin) { top_origin } - it "is invalid" do - expect( - assertion_response.valid?( - original_challenge, - public_key: credential_public_key, - sign_count: 0 - ) - ).to be_falsy - end - - it "doesn't verify" do - expect { - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - }.to raise_exception(WebAuthn::TopOriginVerificationError) - end + it_behaves_like "an invalid assertion response that raises", WebAuthn::TopOriginVerificationError end context "when top_origin does not match client top_origin" do let(:client_top_origin) { "https://malicious.example.com" } - it "is invalid" do - expect( - assertion_response.valid?( - original_challenge, - public_key: credential_public_key, - sign_count: 0 - ) - ).to be_falsy - end - - it "doesn't verify" do - expect { - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - }.to raise_exception(WebAuthn::TopOriginVerificationError) - end + it_behaves_like "an invalid assertion response that raises", WebAuthn::TopOriginVerificationError end context "when top_origin is not set" do @@ -874,16 +617,6 @@ context "when Authenticator Data is invalid" do let(:authenticator_data) { assertion["response"]["authenticatorData"][0..31] } - it "doesn't verify" do - expect { - assertion_response.verify(original_challenge, public_key: credential_public_key, sign_count: 0) - }.to raise_exception(WebAuthn::AuthenticatorDataVerificationError) - end - - it "is invalid" do - expect( - assertion_response.valid?(original_challenge, public_key: credential_public_key, sign_count: 0) - ).to be_falsy - end + it_behaves_like "an invalid assertion response that raises", WebAuthn::AuthenticatorDataVerificationError end end From 552dc69d5391cd5f83127bfbd89a4912fbe3d616 Mon Sep 17 00:00:00 2001 From: Nicolas Temciuc Date: Tue, 28 Oct 2025 17:02:48 -0300 Subject: [PATCH 3/5] test: a valid attestation response using shared examples --- ...authenticator_attestation_response_spec.rb | 310 ++++-------------- 1 file changed, 63 insertions(+), 247 deletions(-) diff --git a/spec/webauthn/authenticator_attestation_response_spec.rb b/spec/webauthn/authenticator_attestation_response_spec.rb index 0d382ab4..6c3d2266 100644 --- a/spec/webauthn/authenticator_attestation_response_spec.rb +++ b/spec/webauthn/authenticator_attestation_response_spec.rb @@ -23,13 +23,35 @@ let(:public_key_credential) { client.create(challenge: original_challenge) } + let(:challenge) { original_challenge } + let(:expected_origin) { nil } + let(:user_presence) { nil } + let(:user_verification) { nil } + let(:rp_id) { nil } + shared_examples "a valid attestation response" do it "verifies" do - expect(attestation_response.verify(original_challenge)).to be_truthy + expect { + attestation_response.verify( + challenge, + expected_origin, + user_presence: user_presence, + user_verification: user_verification, + rp_id: rp_id + ) + }.not_to raise_error end it "is valid" do - expect(attestation_response.valid?(original_challenge)).to be_truthy + expect( + attestation_response.valid?( + challenge, + expected_origin, + user_presence: user_presence, + user_verification: user_verification, + rp_id: rp_id + ) + ).to be(true) end end @@ -305,13 +327,7 @@ # end end - it "verifies" do - expect(attestation_response.verify(challenge, WebAuthn.configuration.allowed_origins)).to be_truthy - end - - it "is valid" do - expect(attestation_response.valid?(challenge, WebAuthn.configuration.allowed_origins)).to eq(true) - end + it_behaves_like "a valid attestation response" it "returns attestation info" do attestation_response.valid?(challenge, WebAuthn.configuration.allowed_origins) @@ -619,13 +635,7 @@ context "it has stuff" do let(:token_binding) { { status: "supported" } } - it "verifies" do - expect(attestation_response.verify(original_challenge, WebAuthn.configuration.allowed_origins)).to be_truthy - end - - it "is valid" do - expect(attestation_response.valid?(original_challenge, WebAuthn.configuration.allowed_origins)).to be_truthy - end + it_behaves_like "a valid attestation response" end context "has an invalid format" do @@ -665,33 +675,13 @@ context "when top_origin is set" do let(:client_top_origin) { top_origin } - it "verifies" do - expect( - attestation_response.verify(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end - - it "is valid" do - expect( - attestation_response.valid?(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end + it_behaves_like "a valid attestation response" end context "when top_origin is not set" do let(:client_top_origin) { nil } - it "verifies" do - expect( - attestation_response.verify(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end - - it "is valid" do - expect( - attestation_response.valid?(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end + it_behaves_like "a valid attestation response" end end @@ -701,33 +691,13 @@ context "when top_origin is set" do let(:client_top_origin) { top_origin } - it "verifies" do - expect( - attestation_response.verify(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end - - it "is valid" do - expect( - attestation_response.valid?(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end + it_behaves_like "a valid attestation response" end context "when top_origin is not set" do let(:client_top_origin) { nil } - it "verifies" do - expect( - attestation_response.verify(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end - - it "is valid" do - expect( - attestation_response.valid?(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end + it_behaves_like "a valid attestation response" end end @@ -737,33 +707,13 @@ context "when top_origin is set" do let(:client_top_origin) { top_origin } - it "verifies" do - expect( - attestation_response.verify(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end - - it "is valid" do - expect( - attestation_response.valid?(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end + it_behaves_like "a valid attestation response" end context "when top_origin is not set" do let(:client_top_origin) { nil } - it "verifies" do - expect( - attestation_response.verify(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end - - it "is valid" do - expect( - attestation_response.valid?(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end + it_behaves_like "a valid attestation response" end end end @@ -778,50 +728,20 @@ context "when top_origin matches client top_origin" do let(:client_top_origin) { top_origin } - it "verifies" do - expect( - attestation_response.verify(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end - - it "is valid" do - expect( - attestation_response.valid?(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end + it_behaves_like "a valid attestation response" end context "when top_origin does not match client top_origin" do let(:client_top_origin) { "https://malicious.example.com" } - it "verifies" do - expect( - attestation_response.verify(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end - - it "is valid" do - expect( - attestation_response.valid?(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end + it_behaves_like "a valid attestation response" end end context "when top_origin is not set" do let(:client_top_origin) { nil } - it "verifies" do - expect( - attestation_response.verify(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end - - it "is valid" do - expect( - attestation_response.valid?(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end + it_behaves_like "a valid attestation response" end end @@ -832,49 +752,19 @@ context "when top_origin matches client top_origin" do let(:client_top_origin) { top_origin } - it "verifies" do - expect( - attestation_response.verify(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end - - it "is valid" do - expect( - attestation_response.valid?(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end + it_behaves_like "a valid attestation response" end context "when top_origin does not match client top_origin" do let(:client_top_origin) { "https://malicious.example.com" } - it "verifies" do - expect( - attestation_response.verify(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end - - it "is valid" do - expect( - attestation_response.valid?(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end + it_behaves_like "a valid attestation response" end context "when top_origin is not set" do let(:client_top_origin) { nil } - it "verifies" do - expect( - attestation_response.verify(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end - - it "is valid" do - expect( - attestation_response.valid?(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end + it_behaves_like "a valid attestation response" end end end @@ -886,49 +776,19 @@ context "when top_origin matches client top_origin" do let(:client_top_origin) { top_origin } - it "verifies" do - expect( - attestation_response.verify(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end - - it "is valid" do - expect( - attestation_response.valid?(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end + it_behaves_like "a valid attestation response" end context "when top_origin does not match client top_origin" do let(:client_top_origin) { "https://malicious.example.com" } - it "verifies" do - expect( - attestation_response.verify(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end - - it "is valid" do - expect( - attestation_response.valid?(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end + it_behaves_like "a valid attestation response" end context "when top_origin is not set" do let(:client_top_origin) { nil } - it "verifies" do - expect( - attestation_response.verify(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end - - it "is valid" do - expect( - attestation_response.valid?(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end + it_behaves_like "a valid attestation response" end end end @@ -1008,17 +868,7 @@ context "when top_origin is not set" do let(:client_top_origin) { nil } - it "verifies" do - expect( - attestation_response.verify(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end - - it "is valid" do - expect( - attestation_response.valid?(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end + it_behaves_like "a valid attestation response" end end @@ -1047,17 +897,7 @@ context "when top_origin is not set" do let(:client_top_origin) { nil } - it "verifies" do - expect( - attestation_response.verify(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end - - it "is valid" do - expect( - attestation_response.valid?(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end + it_behaves_like "a valid attestation response" end end end @@ -1072,17 +912,7 @@ context "when top_origin matches client top_origin" do let(:client_top_origin) { top_origin } - it "verifies" do - expect( - attestation_response.verify(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end - - it "is valid" do - expect( - attestation_response.valid?(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end + it_behaves_like "a valid attestation response" end context "when top_origin does not match client top_origin" do @@ -1170,17 +1000,7 @@ context "when top_origin is not set" do let(:client_top_origin) { nil } - it "verifies" do - expect( - attestation_response.verify(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end - - it "is valid" do - expect( - attestation_response.valid?(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end + it_behaves_like "a valid attestation response" end end end @@ -1230,17 +1050,7 @@ context "when top_origin is not set" do let(:client_top_origin) { nil } - it "verifies" do - expect( - attestation_response.verify(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end - - it "is valid" do - expect( - attestation_response.valid?(original_challenge, WebAuthn.configuration.allowed_origins) - ).to be_truthy - end + it_behaves_like "a valid attestation response" end end end @@ -1249,6 +1059,8 @@ end describe "user presence" do + let(:expected_origin) { [origin] } + context "when UP is not set" do let(:public_key_credential) { client.create(challenge: original_challenge, user_present: false) } @@ -1259,8 +1071,10 @@ }.to raise_exception(WebAuthn::UserPresenceVerificationError) end - it "verifies if user presence is not required" do - expect(attestation_response.verify(original_challenge, [origin], user_presence: false)).to be_truthy + context "when user presence is not required" do + let(:user_presence) { false } + + it_behaves_like "a valid attestation response" end it "doesn't verify if user presence is required" do @@ -1286,8 +1100,10 @@ }.to raise_exception(WebAuthn::UserPresenceVerificationError) end - it "verifies if user presence is not required" do - expect(attestation_response.verify(original_challenge, [origin], user_presence: false)).to be_truthy + context "when user presence is not required" do + let(:user_presence) { false } + + it_behaves_like "a valid attestation response" end it "doesn't verify if user presence is required" do @@ -1307,12 +1123,14 @@ WebAuthn.configuration.silent_authentication = old_value end - it "verifies if user presence is not set" do - expect(attestation_response.verify(original_challenge, [origin])).to be_truthy + context "when user presence is not set" do + it_behaves_like "a valid attestation response" end - it "verifies if user presence is not required" do - expect(attestation_response.verify(original_challenge, [origin], user_presence: false)).to be_truthy + context "when user presence is not required" do + let(:user_presence) { false } + + it_behaves_like "a valid attestation response" end it "doesn't verify if user presence is required" do @@ -1409,9 +1227,7 @@ WebAuthn.configuration.verify_attestation_statement = false end - it "does not verify the attestation statement" do - expect(attestation_response.verify(original_challenge)).to be_truthy - end + it_behaves_like "a valid attestation response" end end end From 1c3613bd351aa437c3f348d23b32c11305a308b4 Mon Sep 17 00:00:00 2001 From: Nicolas Temciuc Date: Wed, 29 Oct 2025 14:37:25 -0300 Subject: [PATCH 4/5] test: an invalid attestation response using shared examples --- ...authenticator_attestation_response_spec.rb | 290 ++++-------------- 1 file changed, 64 insertions(+), 226 deletions(-) diff --git a/spec/webauthn/authenticator_attestation_response_spec.rb b/spec/webauthn/authenticator_attestation_response_spec.rb index 6c3d2266..434ea1ec 100644 --- a/spec/webauthn/authenticator_attestation_response_spec.rb +++ b/spec/webauthn/authenticator_attestation_response_spec.rb @@ -55,6 +55,32 @@ end end + shared_examples "an invalid attestation response that raises" do |expected_error| + it "doesn't verify" do + expect { + attestation_response.verify( + challenge, + expected_origin, + user_presence: user_presence, + user_verification: user_verification, + rp_id: nil + ) + }.to raise_error(expected_error) + end + + it "is invalid" do + expect( + attestation_response.valid?( + challenge, + expected_origin, + user_presence: user_presence, + user_verification: user_verification, + rp_id: nil + ) + ).to be(false) + end + end + context "when everything's in place" do context "when there is a single origin" do before do @@ -111,13 +137,7 @@ WebAuthn.configuration.rp_id = nil end - it "raises error" do - expect { attestation_response.verify(original_challenge) }.to raise_error(WebAuthn::RpIdVerificationError) - end - - it "is not valid" do - expect(attestation_response.valid?(original_challenge)).to be_falsey - end + it_behaves_like "an invalid attestation response that raises", WebAuthn::RpIdVerificationError # TODO: let FakeClient#create recieve a fixed credential # https://github.com/cedarcode/webauthn-ruby/pull/302#discussion_r365338434 @@ -200,13 +220,7 @@ WebAuthn.configuration.rp_id = nil end - it "raises error" do - expect { attestation_response.verify(original_challenge) }.to raise_error(WebAuthn::RpIdVerificationError) - end - - it "is not valid" do - expect(attestation_response.valid?(original_challenge)).to be_falsey - end + it_behaves_like "an invalid attestation response that raises", WebAuthn::RpIdVerificationError end end end @@ -472,13 +486,7 @@ WebAuthn.configuration.rp_id = nil end - it "raises error" do - expect { attestation_response.verify(original_challenge) }.to raise_error(WebAuthn::RpIdVerificationError) - end - - it "is not valid" do - expect(attestation_response.valid?(original_challenge)).to be_falsey - end + it_behaves_like "an invalid attestation response that raises", WebAuthn::RpIdVerificationError end end end @@ -565,15 +573,7 @@ context "doesn't match the default one" do let(:actual_origin) { "http://invalid" } - it "doesn't verify" do - expect { - attestation_response.verify(original_challenge) - }.to raise_exception(WebAuthn::OriginVerificationError) - end - - it "isn't valid" do - expect(attestation_response.valid?(original_challenge)).to be_falsy - end + it_behaves_like "an invalid attestation response that raises", WebAuthn::OriginVerificationError end end @@ -603,15 +603,7 @@ context "doesn't match the default one" do let(:rp_id) { "invalid" } - it "doesn't verify" do - expect { - attestation_response.verify(original_challenge) - }.to raise_exception(WebAuthn::RpIdVerificationError) - end - - it "is invalid" do - expect(attestation_response.valid?(original_challenge)).to be_falsy - end + it_behaves_like "an invalid attestation response that raises", WebAuthn::RpIdVerificationError end context "matches the one explicitly given" do @@ -641,15 +633,7 @@ context "has an invalid format" do let(:token_binding) { "invalid token binding format" } - it "doesn't verify" do - expect { - attestation_response.verify(original_challenge, WebAuthn.configuration.allowed_origins) - }.to raise_exception(WebAuthn::TokenBindingVerificationError) - end - - it "isn't valid" do - expect(attestation_response.valid?(original_challenge, WebAuthn.configuration.allowed_origins)).to be_falsy - end + it_behaves_like "an invalid attestation response that raises", WebAuthn::TokenBindingVerificationError end end @@ -807,39 +791,13 @@ context "when top_origin is set" do let(:client_top_origin) { top_origin } - it "is invalid" do - expect( - attestation_response.valid?( - original_challenge, - WebAuthn.configuration.allowed_origins - ) - ).to be_falsy - end - - it "doesn't verify" do - expect { - attestation_response.verify(original_challenge, WebAuthn.configuration.allowed_origins) - }.to raise_exception(WebAuthn::TopOriginVerificationError) - end + 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 "is invalid" do - expect( - attestation_response.valid?( - original_challenge, - WebAuthn.configuration.allowed_origins - ) - ).to be_falsy - end - - it "doesn't verify" do - expect { - attestation_response.verify(original_challenge, WebAuthn.configuration.allowed_origins) - }.to raise_exception(WebAuthn::TopOriginVerificationError) - end + it_behaves_like "an invalid attestation response that raises", WebAuthn::TopOriginVerificationError end end @@ -849,20 +807,7 @@ context "when top_origin is set" do let(:client_top_origin) { top_origin } - it "is invalid" do - expect( - attestation_response.valid?( - original_challenge, - WebAuthn.configuration.allowed_origins - ) - ).to be_falsy - end - - it "doesn't verify" do - expect { - attestation_response.verify(original_challenge, WebAuthn.configuration.allowed_origins) - }.to raise_exception(WebAuthn::TopOriginVerificationError) - end + it_behaves_like "an invalid attestation response that raises", WebAuthn::TopOriginVerificationError end context "when top_origin is not set" do @@ -878,20 +823,7 @@ context "when top_origin is set" do let(:client_top_origin) { top_origin } - it "is invalid" do - expect( - attestation_response.valid?( - original_challenge, - WebAuthn.configuration.allowed_origins - ) - ).to be_falsy - end - - it "doesn't verify" do - expect { - attestation_response.verify(original_challenge, WebAuthn.configuration.allowed_origins) - }.to raise_exception(WebAuthn::TopOriginVerificationError) - end + it_behaves_like "an invalid attestation response that raises", WebAuthn::TopOriginVerificationError end context "when top_origin is not set" do @@ -918,40 +850,14 @@ context "when top_origin does not match client top_origin" do let(:client_top_origin) { "https://malicious.example.com" } - it "is invalid" do - expect( - attestation_response.valid?( - original_challenge, - WebAuthn.configuration.allowed_origins - ) - ).to be_falsy - end - - it "doesn't verify" do - expect { - attestation_response.verify(original_challenge, WebAuthn.configuration.allowed_origins) - }.to raise_exception(WebAuthn::TopOriginVerificationError) - end + it_behaves_like "an invalid attestation response that raises", WebAuthn::TopOriginVerificationError end end context "when top_origin is not set" do let(:client_top_origin) { nil } - it "is invalid" do - expect( - attestation_response.valid?( - original_challenge, - WebAuthn.configuration.allowed_origins - ) - ).to be_falsy - end - - it "doesn't verify" do - expect { - attestation_response.verify(original_challenge, WebAuthn.configuration.allowed_origins) - }.to raise_exception(WebAuthn::TopOriginVerificationError) - end + it_behaves_like "an invalid attestation response that raises", WebAuthn::TopOriginVerificationError end end @@ -962,39 +868,13 @@ context "when top_origin matches client top_origin" do let(:client_top_origin) { top_origin } - it "is invalid" do - expect( - attestation_response.valid?( - original_challenge, - WebAuthn.configuration.allowed_origins - ) - ).to be_falsy - end - - it "doesn't verify" do - expect { - attestation_response.verify(original_challenge, WebAuthn.configuration.allowed_origins) - }.to raise_exception(WebAuthn::TopOriginVerificationError) - end + it_behaves_like "an invalid attestation response that raises", WebAuthn::TopOriginVerificationError end context "when top_origin does not match client top_origin" do let(:client_top_origin) { "https://malicious.example.com" } - it "is invalid" do - expect( - attestation_response.valid?( - original_challenge, - WebAuthn.configuration.allowed_origins - ) - ).to be_falsy - end - - it "doesn't verify" do - expect { - attestation_response.verify(original_challenge, WebAuthn.configuration.allowed_origins) - }.to raise_exception(WebAuthn::TopOriginVerificationError) - end + it_behaves_like "an invalid attestation response that raises", WebAuthn::TopOriginVerificationError end context "when top_origin is not set" do @@ -1012,39 +892,13 @@ context "when top_origin matches client top_origin" do let(:client_top_origin) { top_origin } - it "is invalid" do - expect( - attestation_response.valid?( - original_challenge, - WebAuthn.configuration.allowed_origins - ) - ).to be_falsy - end - - it "doesn't verify" do - expect { - attestation_response.verify(original_challenge, WebAuthn.configuration.allowed_origins) - }.to raise_exception(WebAuthn::TopOriginVerificationError) - end + it_behaves_like "an invalid attestation response that raises", WebAuthn::TopOriginVerificationError end context "when top_origin does not match client top_origin" do let(:client_top_origin) { "https://malicious.example.com" } - it "is invalid" do - expect( - attestation_response.valid?( - original_challenge, - WebAuthn.configuration.allowed_origins - ) - ).to be_falsy - end - - it "doesn't verify" do - expect { - attestation_response.verify(original_challenge, WebAuthn.configuration.allowed_origins) - }.to raise_exception(WebAuthn::TopOriginVerificationError) - end + it_behaves_like "an invalid attestation response that raises", WebAuthn::TopOriginVerificationError end context "when top_origin is not set" do @@ -1065,10 +919,8 @@ let(:public_key_credential) { client.create(challenge: original_challenge, user_present: false) } context "when silent_authentication is not set" do - it "doesn't verify if user presence is not set" do - expect { - attestation_response.verify(original_challenge, [origin]) - }.to raise_exception(WebAuthn::UserPresenceVerificationError) + context "when user presence is not set" do + it_behaves_like "an invalid attestation response that raises", WebAuthn::UserPresenceVerificationError end context "when user presence is not required" do @@ -1077,10 +929,10 @@ it_behaves_like "a valid attestation response" end - it "doesn't verify if user presence is required" do - expect { - attestation_response.verify(original_challenge, [origin], user_presence: true) - }.to raise_exception(WebAuthn::UserPresenceVerificationError) + context "when user presence is required" do + let(:user_presence) { true } + + it_behaves_like "an invalid attestation response that raises", WebAuthn::UserPresenceVerificationError end end @@ -1094,10 +946,8 @@ WebAuthn.configuration.silent_authentication = old_value end - it "doesn't verify if user presence is not set" do - expect { - attestation_response.verify(original_challenge, [origin]) - }.to raise_exception(WebAuthn::UserPresenceVerificationError) + context "when user presence is not set" do + it_behaves_like "an invalid attestation response that raises", WebAuthn::UserPresenceVerificationError end context "when user presence is not required" do @@ -1106,10 +956,10 @@ it_behaves_like "a valid attestation response" end - it "doesn't verify if user presence is required" do - expect { - attestation_response.verify(original_challenge, [origin], user_presence: true) - }.to raise_exception(WebAuthn::UserPresenceVerificationError) + context "when user presence is required" do + let(:user_presence) { true } + + it_behaves_like "an invalid attestation response that raises", WebAuthn::UserPresenceVerificationError end end @@ -1133,10 +983,10 @@ it_behaves_like "a valid attestation response" end - it "doesn't verify if user presence is required" do - expect { - attestation_response.verify(original_challenge, [origin], user_presence: true) - }.to raise_exception(WebAuthn::UserPresenceVerificationError) + context "when user presence is required" do + let(:user_presence) { true } + + it_behaves_like "an invalid attestation response that raises", WebAuthn::UserPresenceVerificationError end end end @@ -1150,14 +1000,10 @@ context "when UV is not set" do let(:public_key_credential) { client.create(challenge: original_challenge, user_verified: false) } - it "doesn't verify if user verification is required" do - expect { - attestation_response.verify( - original_challenge, - WebAuthn.configuration.allowed_origins, - user_verification: true - ) - }.to raise_exception(WebAuthn::UserVerifiedVerificationError) + context "when user verification is required" do + let(:user_verification) { true } + + it_behaves_like "an invalid attestation response that raises", WebAuthn::UserVerifiedVerificationError end end end @@ -1170,11 +1016,7 @@ context "when AT is not set" do let(:public_key_credential) { client.create(challenge: original_challenge, attested_credential_data: false) } - it "doesn't verify" do - expect { - attestation_response.verify(original_challenge, WebAuthn.configuration.allowed_origins) - }.to raise_exception(WebAuthn::AttestedCredentialVerificationError) - end + it_behaves_like "an invalid attestation response that raises", WebAuthn::AttestedCredentialVerificationError end context "when credential algorithm is not what expected" do @@ -1182,11 +1024,7 @@ WebAuthn.configuration.algorithms = ["RS256"] end - it "doesn't verify" do - expect { - attestation_response.verify(original_challenge, WebAuthn.configuration.allowed_origins) - }.to raise_exception(WebAuthn::AttestedCredentialVerificationError) - end + it_behaves_like "an invalid attestation response that raises", WebAuthn::AttestedCredentialVerificationError end end From a4bb0ba529b287daf6def706d9d9b3d672c5ded5 Mon Sep 17 00:00:00 2001 From: Nicolas Temciuc Date: Thu, 30 Oct 2025 11:35:44 -0300 Subject: [PATCH 5/5] test: use `be_truthy` and `be_falsy` --- spec/webauthn/authenticator_assertion_response_spec.rb | 8 ++++---- spec/webauthn/authenticator_attestation_response_spec.rb | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/spec/webauthn/authenticator_assertion_response_spec.rb b/spec/webauthn/authenticator_assertion_response_spec.rb index 7a33321d..ce828fe6 100644 --- a/spec/webauthn/authenticator_assertion_response_spec.rb +++ b/spec/webauthn/authenticator_assertion_response_spec.rb @@ -39,7 +39,7 @@ shared_examples "a valid assertion response" do it "verifies" do - expect { + expect( assertion_response.verify( challenge, public_key: public_key, @@ -48,7 +48,7 @@ user_verification: user_verification, rp_id: rp_id ) - }.not_to raise_error + ).to be_truthy end it "is valid" do @@ -61,7 +61,7 @@ user_verification: user_verification, rp_id: rp_id ) - ).to be(true) + ).to be_truthy end end @@ -89,7 +89,7 @@ user_verification: user_verification, rp_id: rp_id ) - ).to be(false) + ).to be_falsy end end diff --git a/spec/webauthn/authenticator_attestation_response_spec.rb b/spec/webauthn/authenticator_attestation_response_spec.rb index 434ea1ec..91ce28a3 100644 --- a/spec/webauthn/authenticator_attestation_response_spec.rb +++ b/spec/webauthn/authenticator_attestation_response_spec.rb @@ -31,7 +31,7 @@ shared_examples "a valid attestation response" do it "verifies" do - expect { + expect( attestation_response.verify( challenge, expected_origin, @@ -39,7 +39,7 @@ user_verification: user_verification, rp_id: rp_id ) - }.not_to raise_error + ).to be_truthy end it "is valid" do @@ -51,7 +51,7 @@ user_verification: user_verification, rp_id: rp_id ) - ).to be(true) + ).to be_truthy end end @@ -77,7 +77,7 @@ user_verification: user_verification, rp_id: nil ) - ).to be(false) + ).to be_falsy end end