Skip to content

Commit 781f100

Browse files
authored
feat: Allow specifying allow_credentials for FakeClient#get (#335)
* feat: Allow specifying allow_credentials for FakeClient#get * Improve error message, simplify parameter for allow_credentials * Fix too long string
1 parent dbff817 commit 781f100

3 files changed

Lines changed: 48 additions & 4 deletions

File tree

lib/webauthn/fake_authenticator.rb

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,20 @@ def get_assertion(
5050
user_verified: false,
5151
aaguid: AuthenticatorData::AAGUID,
5252
sign_count: nil,
53-
extensions: nil
53+
extensions: nil,
54+
allow_credentials: nil
5455
)
5556
credential_options = credentials[rp_id]
5657

5758
if credential_options
58-
credential_id, credential = credential_options.first
59+
allow_credentials ||= credential_options.keys
60+
credential_id = (credential_options.keys & allow_credentials).first
61+
unless credential_id
62+
raise "No matching credentials (allowed=#{allow_credentials}) " \
63+
"found for RP #{rp_id} among credentials=#{credential_options}"
64+
end
65+
66+
credential = credential_options[credential_id]
5967
credential_key = credential[:credential_key]
6068
credential_sign_count = credential[:sign_count]
6169

lib/webauthn/fake_client.rb

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,19 +74,25 @@ def get(challenge: fake_challenge,
7474
user_verified: false,
7575
sign_count: nil,
7676
extensions: nil,
77-
user_handle: nil)
77+
user_handle: nil,
78+
allow_credentials: nil)
7879
rp_id ||= URI.parse(origin).host
7980

8081
client_data_json = data_json_for(:get, encoder.decode(challenge))
8182
client_data_hash = hashed(client_data_json)
8283

84+
if allow_credentials
85+
allow_credentials = allow_credentials.map { |credential| encoder.decode(credential) }
86+
end
87+
8388
assertion = authenticator.get_assertion(
8489
rp_id: rp_id,
8590
client_data_hash: client_data_hash,
8691
user_present: user_present,
8792
user_verified: user_verified,
8893
sign_count: sign_count,
89-
extensions: extensions
94+
extensions: extensions,
95+
allow_credentials: allow_credentials
9096
)
9197

9298
{

spec/webauthn/fake_client_spec.rb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# frozen_string_literal: true
2+
3+
require "spec_helper"
4+
5+
RSpec.describe "FakeClient" do
6+
let(:client) { WebAuthn::FakeClient.new }
7+
8+
context "#get" do
9+
let!(:credential_1) { client.create }
10+
let!(:credential_2) { client.create }
11+
12+
it "returns the first matching credential when allow_credentials is nil" do
13+
assertion = client.get
14+
expect(assertion["id"]).to eq(credential_1["id"])
15+
end
16+
17+
it "returns the matching credential when allow_credentials is passed" do
18+
allow_credentials = [credential_2["id"]]
19+
assertion = client.get(allow_credentials: allow_credentials)
20+
expect(assertion["id"]).to eq(credential_2["id"])
21+
end
22+
23+
it "raises an error when no matching allow_credential can be found" do
24+
# base64(abc) is surely not a valid credential id (too short)
25+
allow_credentials = ["YWJj"]
26+
expect { client.get(allow_credentials: allow_credentials) }.to \
27+
raise_error(RuntimeError, /No matching credentials \(allowed=\["abc"\]\) found for RP/)
28+
end
29+
end
30+
end

0 commit comments

Comments
 (0)