From 13975e0df8afd7a12786c472f222c3231fe191bc Mon Sep 17 00:00:00 2001 From: titusfortner Date: Thu, 4 Aug 2022 15:23:03 -0500 Subject: [PATCH] [rb] update virtual auth implementation to match conventions --- rb/lib/selenium/webdriver/common/driver.rb | 7 +- .../virtual_authenticator.rb | 30 +- .../virtual_authenticator_options.rb | 35 +- rb/lib/selenium/webdriver/remote/bridge.rb | 16 +- rb/lib/selenium/webdriver/remote/commands.rb | 3 +- .../webdriver/virtual_authenticator_spec.rb | 452 +++++++----------- .../virtual_authenticator_options_spec.rb | 88 ++-- 7 files changed, 241 insertions(+), 390 deletions(-) diff --git a/rb/lib/selenium/webdriver/common/driver.rb b/rb/lib/selenium/webdriver/common/driver.rb index 02b02947a9224..5f7e2e806826c 100644 --- a/rb/lib/selenium/webdriver/common/driver.rb +++ b/rb/lib/selenium/webdriver/common/driver.rb @@ -249,17 +249,14 @@ def execute_async_script(script, *args) end # - # virtual-authenticator + # @return [VirtualAuthenticator] + # @see VirtualAuthenticator # def add_virtual_authenticator(options) bridge.add_virtual_authenticator(options) end - def remove_virtual_authenticator(authenticator) - bridge.remove_virtual_authenticator(authenticator) - end - #-------------------------------- sugar -------------------------------- # diff --git a/rb/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator.rb b/rb/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator.rb index 2730922105dfb..1584200ea701d 100644 --- a/rb/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator.rb +++ b/rb/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator.rb @@ -20,41 +20,53 @@ module Selenium module WebDriver class VirtualAuthenticator - attr_reader :id, :bridge + + attr_reader :options # # api private + # Use `Driver#add_virtual_authenticator` # - def initialize(bridge, authenticator_id) + def initialize(bridge, authenticator_id, options) @id = authenticator_id @bridge = bridge + @options = options + @valid = true end def add_credential(credential) credential = credential.as_json - credential[:authenticatorId] = @id - bridge.add_credential credential + @bridge.add_credential credential, @id end def credentials - credential_data = bridge.credentials @id + credential_data = @bridge.credentials @id credential_data.map do |cred| Credential.from_json(cred) end end def remove_credential(credential_id) - credential_id = Base64.urlsafe_encode64(credential_id.pack('C*')) if credential_id.instance_of?(Array) - bridge.remove_credential credential_id, @id + credential_id = Credential.encode(credential_id) if credential_id.instance_of?(Array) + @bridge.remove_credential credential_id, @id end def remove_all_credentials - bridge.remove_all_credentials @id + @bridge.remove_all_credentials @id end def user_verified=(verified) - bridge.user_verified verified, @id + @bridge.user_verified verified, @id + end + + def remove! + @bridge.remove_virtual_authenticator(@id) + @valid = false + end + + def valid? + @valid end end # VirtualAuthenticator end # WebDriver diff --git a/rb/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator_options.rb b/rb/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator_options.rb index 4556fd55771d7..9f1e4bb2abbf8 100644 --- a/rb/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator_options.rb +++ b/rb/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator_options.rb @@ -29,17 +29,20 @@ class VirtualAuthenticatorOptions PROTOCOL = {ctap2: "ctap2", u2f: "ctap1/u2f"}.freeze TRANSPORT = {ble: "ble", usb: "usb", nfc: "nfc", internal: "internal"}.freeze - attr_accessor :protocol, :transport, :has_resident_key, :has_user_verification, :is_user_consenting, - :is_user_verified - - def initialize(protocol: PROTOCOL[:ctap2], transport: TRANSPORT[:usb], has_resident_key: false, - has_user_verification: false, is_user_consenting: true, is_user_verified: false) + attr_accessor :protocol, :transport, :resident_key, :user_verification, :user_consenting, :user_verified + alias_method :resident_key?, :resident_key + alias_method :user_verification?, :user_verification + alias_method :user_consenting?, :user_consenting + alias_method :user_verified?, :user_verified + + def initialize(protocol: :ctap2, transport: :usb, resident_key: false, + user_verification: false, user_consenting: true, user_verified: false) @protocol = protocol @transport = transport - @has_resident_key = has_resident_key - @has_user_verification = has_user_verification - @is_user_consenting = is_user_consenting - @is_user_verified = is_user_verified + @resident_key = resident_key + @user_verification = user_verification + @user_consenting = user_consenting + @user_verified = user_verified end # @@ -47,14 +50,12 @@ def initialize(protocol: PROTOCOL[:ctap2], transport: TRANSPORT[:usb], has_resid # def as_json(*) - { - protocol: @protocol, - transport: @transport, - hasResidentKey: @has_resident_key, - hasUserVerification: @has_user_verification, - isUserConsenting: @is_user_consenting, - isUserVerified: @is_user_verified - } + {'protocol' => PROTOCOL[protocol], + 'transport' => TRANSPORT[transport], + 'hasResidentKey' => resident_key?, + 'hasUserVerification' => user_verification?, + 'isUserConsenting' => user_consenting?, + 'isUserVerified' => user_verified?} end end # VirtualAuthenticatorOptions end # WebDriver diff --git a/rb/lib/selenium/webdriver/remote/bridge.rb b/rb/lib/selenium/webdriver/remote/bridge.rb index 047d70763e6d6..de2f15194387e 100644 --- a/rb/lib/selenium/webdriver/remote/bridge.rb +++ b/rb/lib/selenium/webdriver/remote/bridge.rb @@ -574,15 +574,15 @@ def shadow_root(element) def add_virtual_authenticator(options) authenticator_id = execute :add_virtual_authenticator, {}, options.as_json - VirtualAuthenticator.new(self, authenticator_id) + VirtualAuthenticator.new(self, authenticator_id, options) end - def remove_virtual_authenticator(authenticator) - execute :remove_virtual_authenticator, {}, {authenticatorId: authenticator.id} + def remove_virtual_authenticator(id) + execute :remove_virtual_authenticator, {authenticatorId: id} end - def add_credential(credential) - execute :add_credential, {}, credential + def add_credential(credential, id) + execute :add_credential, {authenticatorId: id}, credential end def credentials(authenticator_id) @@ -590,15 +590,15 @@ def credentials(authenticator_id) end def remove_credential(credential_id, authenticator_id) - execute :remove_credential, {}, {credentialId: credential_id, authenticatorId: authenticator_id} + execute :remove_credential, {credentialId: credential_id, authenticatorId: authenticator_id} end def remove_all_credentials(authenticator_id) - execute :remove_all_credentials, {}, {authenticatorId: authenticator_id} + execute :remove_all_credentials, {authenticatorId: authenticator_id} end def user_verified(verified, authenticator_id) - execute :set_user_verified, {}, {authenticatorId: authenticator_id, isUserVerified: verified} + execute :set_user_verified, {authenticatorId: authenticator_id}, {isUserVerified: verified} end private diff --git a/rb/lib/selenium/webdriver/remote/commands.rb b/rb/lib/selenium/webdriver/remote/commands.rb index 1885b860c4a26..483992f9685c9 100644 --- a/rb/lib/selenium/webdriver/remote/commands.rb +++ b/rb/lib/selenium/webdriver/remote/commands.rb @@ -159,7 +159,8 @@ class Bridge remove_virtual_authenticator: [:delete, 'session/:session_id/webauthn/authenticator/:authenticatorId'], add_credential: [:post, 'session/:session_id/webauthn/authenticator/:authenticatorId/credential'], get_credentials: [:get, 'session/:session_id/webauthn/authenticator/:authenticatorId/credentials'], - remove_credential: [:delete, 'session/:session_id/webauthn/authenticator/:authenticatorId/credentials/:credentialId'], + remove_credential: [:delete, + 'session/:session_id/webauthn/authenticator/:authenticatorId/credentials/:credentialId'], remove_all_credentials: [:delete, 'session/:session_id/webauthn/authenticator/:authenticatorId/credentials'], set_user_verified: [:post, 'session/:session_id/webauthn/authenticator/:authenticatorId/uv'] diff --git a/rb/spec/integration/selenium/webdriver/virtual_authenticator_spec.rb b/rb/spec/integration/selenium/webdriver/virtual_authenticator_spec.rb index d0ba96dcf9b5d..8de6af39decce 100644 --- a/rb/spec/integration/selenium/webdriver/virtual_authenticator_spec.rb +++ b/rb/spec/integration/selenium/webdriver/virtual_authenticator_spec.rb @@ -21,56 +21,14 @@ module Selenium module WebDriver - describe VirtualAuthenticator, exclusive: {browser: %i[chrome]} do - def create_rk_disabled_u2f_authenticator - options = VirtualAuthenticatorOptions.new - options.protocol = VirtualAuthenticatorOptions::PROTOCOL[:u2f] - options.has_resident_key = false - driver.add_virtual_authenticator(options) - end - - def create_rk_enabled_u2f_authenticator - options = VirtualAuthenticatorOptions.new - options.protocol = VirtualAuthenticatorOptions::PROTOCOL[:u2f] - options.has_resident_key = true - driver.add_virtual_authenticator(options) - end - - def create_rk_disabled_ctap2_authenticator - options = VirtualAuthenticatorOptions.new - options.protocol = VirtualAuthenticatorOptions::PROTOCOL[:ctap2] - options.has_resident_key = false - options.has_user_verification = true - options.is_user_verified = true - driver.add_virtual_authenticator(options) - end - - def create_rk_enabled_ctap2_authenticator - options = VirtualAuthenticatorOptions.new - options.protocol = VirtualAuthenticatorOptions::PROTOCOL[:ctap2] - options.has_resident_key = true - options.has_user_verification = true - options.is_user_verified = true - driver.add_virtual_authenticator(options) - end - - def get_assertion_for(credential_id) - driver.execute_async_script(get_credential, credential_id) - end - - def extract_raw_id_from(response) - response['credential']['rawId'] - end - - def extract_id_from(response) - response['credential']['id'] + describe VirtualAuthenticator, exclusive: {browser: %i[chrome edge]} do + # A pkcs#8 encoded unencrypted EC256 private key as a base64url string. + let(:pkcs8_private_key) do + "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg8_zMDQDYAxlU-Q" \ + "hk1Dwkf0v18GZca1DMF3SaJ9HPdmShRANCAASNYX5lyVCOZLzFZzrIKmeZ2jwU" \ + "RmgsJYxGP__fWN_S-j5sN4tT15XEpN_7QZnt14YvI6uvAgO0uJEboFaZlOEB" end - - # - # A private key as a base64url string. - # - - let(:base64_encoded_pk) do + let(:encoded_private_key) do "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDbBOu5Lhs4vpowbCnmCyLUpIE7JM9sm9QXzye2G+jr+Kr" \ "MsinWohEce47BFPJlTaDzHSvOW2eeunBO89ZcvvVc8RLz4qyQ8rO98xS1jtgqi1NcBPETDrtzthODu/gd0sjB2Tk3TLuBGV" \ "oPXt54a+Oo4JbBJ6h3s0+5eAfGplCbSNq6hN3Jh9YOTw5ZA6GCEy5l8zBaOgjXytd2v2OdSVoEDNiNQRkjJd2rmS2oi9AyQ" \ @@ -90,302 +48,214 @@ def extract_id_from(response) "zJOGpf9x2RSWzQJ+dq8+6fACgfFZOVpN644+sAHfNPAI/gnNKU5OfUv+eav8fBnzlf1A3y3GIkyMyzFN3DE7e0n/lyqxE4H" \ "BYGpI8g==" end - - let(:register_credential) do - "registerCredential().then(arguments[arguments.length - 1]);" + let(:u2f) { VirtualAuthenticatorOptions.new(protocol: :u2f) } + let(:ctap2) { VirtualAuthenticatorOptions.new(user_verification: true, user_verified: true) } + + before { driver.navigate.to url_for('virtual-authenticator.html') } + + after { @authenticator&.remove! if @authenticator&.valid? } + + def register_credential(require_resident: false, user_verification: false) + params = if require_resident + '{authenticatorSelection: {requireResidentKey: true}}' + elsif user_verification + "{userVerification: 'required'}" + else + '' + end + driver.execute_async_script "registerCredential(#{params}).then(arguments[arguments.length - 1]);" end - let(:get_credential) do - "getCredential([{\n" \ - "\"type\": \"public-key\",\n" \ - "\"id\": Int8Array.from(arguments[0]),\n" \ - "}]).then(arguments[arguments.length - 1]);\n" + def credential(id) + script = <<~CREDENTIAL + getCredential([{ + "type": "public-key", + "id": Int8Array.from(arguments[0]), + }]).then(arguments[arguments.length - 1]); + CREDENTIAL + driver.execute_async_script(script, id) end - before do - driver.navigate.to url_for('virtual-authenticator.html') - end + describe '#intialize' do + it 'creates resident key disabled u2f' do + @authenticator = driver.add_virtual_authenticator(u2f) - after do - driver.remove_virtual_authenticator(@authenticator) unless @authenticator.nil? - end + expect(@authenticator.options.protocol).to eq :u2f + expect(@authenticator.options.resident_key?).to eq false + end - it 'should test create authenticator' do - # - # Register a credential on the Virtual Authenticator. - # + it 'creates resident key enabled u2f' do + u2f.resident_key = true + @authenticator = driver.add_virtual_authenticator(u2f) - @authenticator = create_rk_disabled_u2f_authenticator - expect(@authenticator).not_to eq(nil) + expect(@authenticator.options.protocol).to eq :u2f + expect(@authenticator.options.resident_key?).to eq true + end - response = driver.execute_async_script(register_credential) - expect(response['status']).to eq('OK') + it 'creates resident key disabled ctap2' do + @authenticator = driver.add_virtual_authenticator(ctap2) - # - # Attempt to use the credential to get an assertion. - # - response = get_assertion_for(extract_raw_id_from(response)) - expect(response['status']).to eq('OK') - end + expect(@authenticator.options.protocol).to eq :ctap2 + expect(@authenticator.options.resident_key?).to eq false + expect(@authenticator.options.user_verified?).to eq true + expect(@authenticator.options.user_verification?).to eq true + end - it 'should test remove authenticator' do - options = VirtualAuthenticatorOptions.new - @authenticator = driver.add_virtual_authenticator(options) - expect(@authenticator).not_to eq(nil) + it 'creates resident key enabled ctap2' do + ctap2.resident_key = true + @authenticator = driver.add_virtual_authenticator(ctap2) - driver.remove_virtual_authenticator(@authenticator) - @authenticator = nil + expect(@authenticator.options.protocol).to eq :ctap2 + expect(@authenticator.options.resident_key?).to eq true + expect(@authenticator.options.user_verified?).to eq true + expect(@authenticator.options.user_verification?).to eq true + end end - it 'should test add non-resident credential' do - # - # Add a non-resident credential using the testing API. - # - @authenticator = create_rk_disabled_ctap2_authenticator - credential = Credential.non_resident( - id: [1, 2, 3, 4], - rp_id: 'localhost', - private_key: Credential.decode(base64_encoded_pk), - sign_count: 0 - ) - - @authenticator.add_credential(credential) - # - # Attempt to use the credential to generate an assertion. - # - response = get_assertion_for([1, 2, 3, 4]) - expect(response['status']).to eq('OK') - end + describe '#remove!' do + it 'removes authenticator' do + @authenticator = driver.add_virtual_authenticator(u2f) - it 'should test add non-resident credential when authenticator uses U2F protocol' do - @authenticator = create_rk_disabled_u2f_authenticator - base64_enc_pk = - "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg8_zMDQDYAxlU-Q" \ - "hk1Dwkf0v18GZca1DMF3SaJ9HPdmShRANCAASNYX5lyVCOZLzFZzrIKmeZ2jwU" \ - "RmgsJYxGP__fWN_S-j5sN4tT15XEpN_7QZnt14YvI6uvAgO0uJEboFaZlOEB" - - credential = Credential.non_resident( - id: [1, 2, 3, 4], - rp_id: 'localhost', - private_key: Credential.decode(base64_enc_pk), - sign_count: 0 - ) - @authenticator.add_credential(credential) - response = get_assertion_for([1, 2, 3, 4]) - expect(response['status']).to eq('OK') - end + @authenticator.remove! - it 'should test add resident credential' do - @authenticator = create_rk_enabled_ctap2_authenticator - credential = Credential.resident( - id: [1, 2, 3, 4], - rp_id: 'localhost', - user_handle: [1], - private_key: Credential.decode(base64_encoded_pk), - sign_count: 0 - ) - @authenticator.add_credential(credential) - # - # Attempt to use the credential to generate an assertion. Notice we use an - # empty allowCredentials array. - # - - response = driver.execute_async_script("getCredential([]).then(arguments[arguments.length - 1]);") - expect(response['status']).to eq("OK") - expect(response['attestation']['userHandle'].include?(1)).to eq(true) + expect(@authenticator.valid?).to eq false + end end - it 'should test add resident credential not supported when authenticator uses U2F protocol' do - @authenticator = create_rk_enabled_u2f_authenticator - base64_enc_pk = - "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg8_zMDQDYAxlU-Q" \ - "hk1Dwkf0v18GZca1DMF3SaJ9HPdmShRANCAASNYX5lyVCOZLzFZzrIKmeZ2jwU" \ - "RmgsJYxGP__fWN_S-j5sN4tT15XEpN_7QZnt14YvI6uvAgO0uJEboFaZlOEB" - - credential = Credential.resident( - id: [1, 2, 3, 4], - rp_id: 'localhost', - user_handle: [1], - private_key: Credential.decode(base64_enc_pk), - sign_count: 0 - ) + describe '#add_credential' do + it 'to non-resident ctap' do + @authenticator = driver.add_virtual_authenticator(ctap2) - # - # Throws InvalidArgumentError - # + byte_array_id = [1, 2, 3, 4] + credential = Credential.non_resident(id: byte_array_id, + rp_id: 'localhost', + private_key: Credential.decode(encoded_private_key)) - begin @authenticator.add_credential(credential) - rescue StandardError => e - expect(e.class).to eq(WebDriver::Error::InvalidArgumentError) + + expect(credential(byte_array_id)['status']).to eq('OK') end - end - it 'should test get credentials' do - @authenticator = create_rk_enabled_ctap2_authenticator - # - # Register a resident credential. - # + it 'to non-resident u2f' do + @authenticator = driver.add_virtual_authenticator(u2f) - response1 = driver.execute_async_script( - "registerCredential({authenticatorSelection: {requireResidentKey: true}})" \ - " .then(arguments[arguments.length - 1]);" - ) - expect(response1['status']).to eq('OK') + byte_array_id = [1, 2, 3, 4] + credential = Credential.non_resident(id: byte_array_id, + rp_id: 'localhost', + private_key: Credential.decode(pkcs8_private_key)) - # - # Register a non resident credential. - # + @authenticator.add_credential(credential) - response2 = driver.execute_async_script(register_credential) - expect(response2['status']).to eq('OK') + expect(credential(byte_array_id)['status']).to eq('OK') + end - credential_1_id = extract_raw_id_from(response1) - credential_2_id = extract_raw_id_from(response2) + it 'to resident ctap' do + ctap2.resident_key = true + @authenticator = driver.add_virtual_authenticator(ctap2) - expect(credential_1_id.sort).not_to eq(credential_2_id.sort) + byte_array_id = [1, 2, 3, 4] + credential = Credential.resident(id: byte_array_id, + rp_id: 'localhost', + user_handle: [1], + private_key: Credential.decode(encoded_private_key)) - # - # Retrieve the two credentials. - # + @authenticator.add_credential(credential) - credentials = @authenticator.credentials + expect(credential(byte_array_id)['status']).to eq('OK') + expect(@authenticator.credentials.first.user_handle).to eq [1] + end - expect(credentials.length).to eq(2) + it 'to resident u2f' do + u2f.resident_key = true + @authenticator = driver.add_virtual_authenticator(u2f) - credential1 = nil - credential2 = nil + byte_array_id = [1, 2, 3, 4] + credential = Credential.resident(id: byte_array_id, + rp_id: 'localhost', + user_handle: [1], + private_key: Credential.decode(encoded_private_key)) - credentials.each do |credential| - if credential.id == credential_1_id - credential1 = credential - elsif credential.id == credential_2_id - credential2 = credential - else - raise "Unrecognized credential id" - end + msg = /The Authenticator does not support Resident Credentials/ + expect { @authenticator.add_credential(credential) }.to raise_error(Error::InvalidArgumentError, msg) end - - expect(credential1.resident_credential?).to eq(true) - expect(credential1.private_key).not_to eq(nil) - expect(credential1.rp_id).to eq('localhost') - expect(credential1.user_handle).to eq([1]) - expect(credential1.sign_count).to eq(1) - - expect(credential2.resident_credential?).to eq(false) - expect(credential2.private_key).not_to eq(nil) - # - # Non resident keys do not store raw RP IDs or user handles. - # - expect(credential2.rp_id).to eq(nil) - expect(credential2.user_handle).to eq(nil) - expect(credential2.sign_count).to eq(1) end - it 'should test remove credential by rawID' do - @authenticator = create_rk_disabled_u2f_authenticator + describe '#credentials' do + it 'gets multiple' do + ctap2.resident_key = true + @authenticator = driver.add_virtual_authenticator(ctap2) - response = driver.execute_async_script(register_credential) - expect(response['status']).to eq('OK') + # Add multiple credentials with JS + res_cred_resp = register_credential(require_resident: true)['credential'] + non_res_cred_resp = register_credential['credential'] + expect(res_cred_resp['id']).not_to eq(non_res_cred_resp['id']) - # - # Remove a credential by its ID as an array of bytes. - # + credentials = @authenticator.credentials + expect(credentials.length).to eq(2) - raw_id = extract_raw_id_from(response) - @authenticator.remove_credential(raw_id) + res_cred_output = credentials.find { |cred| Credential.encode(cred.id).match res_cred_resp['id'] } + non_res_cred_output = credentials.tap { |cred| cred.delete(res_cred_output) }.first - # - # Trying to get an assertion should fail. - # + expect(res_cred_output.resident_credential?).to eq true + expect(res_cred_output.rp_id).to eq 'localhost' + expect(res_cred_output.sign_count).to eq 1 + expect(res_cred_output.user_handle).to eq [1] - response = get_assertion_for(raw_id) - expect(response['status']).to start_with("NotAllowedError") + expect(non_res_cred_output.resident_credential?).to eq false + expect(non_res_cred_output.rp_id).to eq nil + expect(non_res_cred_output.sign_count).to eq 1 + expect(non_res_cred_output.user_handle).to be_nil + end end - it 'should test remove credential by base64url Id' do - @authenticator = create_rk_disabled_u2f_authenticator - response = driver.execute_async_script(register_credential) - raw_id = extract_raw_id_from(response) - credential_id = extract_id_from(response) + describe '#remove_credential' do + it 'by raw ID' do + @authenticator = driver.add_virtual_authenticator(u2f) - # - # Remove a credential by its base64url ID. - # + credential = register_credential['credential'] + raw_id = credential['rawId'] + id = credential['id'] + 2.times { register_credential } - @authenticator.remove_credential(credential_id) + @authenticator.remove_credential(raw_id) - response = get_assertion_for(raw_id) - expect(response['status']).to start_with("NotAllowedError") - end + expect(@authenticator.credentials.map(&:id)).not_to include(id) + end - it 'should test remove all credentials' do - @authenticator = create_rk_disabled_u2f_authenticator - - response1 = driver.execute_async_script(register_credential) - expect(response1['status']).to eq('OK') - raw_id1 = extract_raw_id_from(response1) - - response2 = driver.execute_async_script(register_credential) - expect(response2['status']).to eq('OK') - raw_id2 = extract_raw_id_from(response2) - - # - # Remove all credentials. - # - - @authenticator.remove_all_credentials - - # - # Trying to get an assertion allowing for any of both should fail. - # - - response = driver.execute_async_script( - "getCredential([{" \ - " \"type\": \"public-key\"," \ - " \"id\": Int8Array.from(arguments[0])," \ - "}, {" \ - " \"type\": \"public-key\"," \ - " \"id\": Int8Array.from(arguments[1])," \ - "}]).then(arguments[arguments.length - 1]);", - raw_id1, - raw_id2 - ) - expect(response['status']).to start_with("NotAllowedError") - end + it 'by encoded ID' do + @authenticator = driver.add_virtual_authenticator(u2f) + + id = register_credential.dig('credential', 'id') + 2.times { register_credential } - it 'should test set user verified' do - @authenticator = create_rk_enabled_ctap2_authenticator + @authenticator.remove_credential(id) - # - # Register a credential requiring User Verification - # + expect(@authenticator.credentials.map(&:id)).not_to include(id) + end + end + + describe '#remove_all_credentials' do + it 'removes multiple' do + @authenticator = driver.add_virtual_authenticator(u2f) + 3.times { register_credential } - response = driver.execute_async_script( - "registerCredential({authenticatorSelection: {userVerification: 'required'}})" \ - " .then(arguments[arguments.length - 1]);" - ) - expect(response['status']).to eq('OK') + @authenticator.remove_all_credentials - raw_id = extract_raw_id_from(response) + expect(@authenticator.credentials).to be_empty + end + end - # - # Getting an assertion requiring user verification should succeed. - # + describe '#user_verified=' do + it 'can not obtain credential requiring verification when set to false' do + ctap2.resident_key = true + @authenticator = driver.add_virtual_authenticator(ctap2) - response = driver.execute_async_script(get_credential, raw_id) - expect(response['status']).to eq('OK') + raw_id = register_credential(user_verification: true).dig('credential', 'rawId') - # - # Disable user verification. - # - @authenticator.user_verified = false + @authenticator.user_verified = false - # - # Getting an assertion requiring user verification should fail. - # - response = driver.execute_async_script(get_credential, raw_id) - expect(response['status']).to start_with("NotAllowedError") + expect(credential(raw_id)['status']).to include "NotAllowedError" + end end end # VirtualAuthenticator end # WebDriver diff --git a/rb/spec/unit/selenium/webdriver/common/virtual_authenticator_options_spec.rb b/rb/spec/unit/selenium/webdriver/common/virtual_authenticator_options_spec.rb index b99ae80bcda66..730e67ddad3ee 100644 --- a/rb/spec/unit/selenium/webdriver/common/virtual_authenticator_options_spec.rb +++ b/rb/spec/unit/selenium/webdriver/common/virtual_authenticator_options_spec.rb @@ -23,65 +23,35 @@ module Selenium module WebDriver describe VirtualAuthenticatorOptions do let(:options) do - VirtualAuthenticatorOptions.new - end - - it 'can test_transport' do - options.transport = VirtualAuthenticatorOptions::TRANSPORT[:usb] - expect(options.transport).to eq(VirtualAuthenticatorOptions::TRANSPORT[:usb]) - - options.transport = VirtualAuthenticatorOptions::TRANSPORT[:nfc] - expect(options.transport).to eq(VirtualAuthenticatorOptions::TRANSPORT[:nfc]) - end - - it 'can test_protocol' do - options.protocol = VirtualAuthenticatorOptions::PROTOCOL[:u2f] - expect(options.protocol).to eq(VirtualAuthenticatorOptions::PROTOCOL[:u2f]) - - options.protocol = VirtualAuthenticatorOptions::PROTOCOL[:ctap2] - expect(options.protocol).to eq(VirtualAuthenticatorOptions::PROTOCOL[:ctap2]) - end - - it 'can test_has_resident_key' do - options.has_resident_key = true - expect(options.has_resident_key).to eq(true) - - options.has_resident_key = false - expect(options.has_resident_key).to eq(false) - end - - it 'can test_has_user_verification' do - options.has_user_verification = true - expect(options.has_user_verification).to eq(true) - - options.has_user_verification = false - expect(options.has_user_verification).to eq(false) - end - - it 'can test_is_user_consenting' do - options.is_user_consenting = true - expect(options.is_user_consenting).to eq(true) - - options.is_user_consenting = false - expect(options.is_user_consenting).to eq(false) - end - - it 'can test_is_user_verified' do - options.is_user_verified = true - expect(options.is_user_verified).to eq(true) - - options.is_user_verified = false - expect(options.is_user_verified).to eq(false) - end - - it 'can test_to_dict_with_defaults' do - default_options = options.as_json - expect(default_options[:transport]).to eq(VirtualAuthenticatorOptions::TRANSPORT[:usb]) - expect(default_options[:protocol]).to eq(VirtualAuthenticatorOptions::PROTOCOL[:ctap2]) - expect(default_options[:hasResidentKey]).to eq(false) - expect(default_options[:hasUserVerification]).to eq(false) - expect(default_options[:isUserConsenting]).to eq(true) - expect(default_options[:isUserVerified]).to eq(false) + VirtualAuthenticatorOptions.new(transport: :nfc, + protocol: :u2f, + resident_key: true, + user_verification: true, + user_consenting: false, + user_verified: true) + end + + describe '#initialize' do + it 'sets parameters' do + expect(options.transport).to eq(:nfc) + expect(options.protocol).to eq(:u2f) + expect(options.resident_key?).to eq(true) + expect(options.user_verification?).to eq(true) + expect(options.user_consenting?).to eq(false) + expect(options.user_verified?).to eq(true) + end + end + + describe '#as_json' do + it 'converts default options to JSON' do + json = options.as_json + expect(json['transport']).to eq('nfc') + expect(json['protocol']).to eq('ctap1/u2f') + expect(json['hasResidentKey']).to eq(true) + expect(json['hasUserVerification']).to eq(true) + expect(json['isUserConsenting']).to eq(false) + expect(json['isUserVerified']).to eq(true) + end end end # VirtualAuthenticatorOptions end # WebDriver