| // Copyright 2019 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/autofill/core/browser/payments/credit_card_fido_authenticator.h" |
| |
| #include <stddef.h> |
| |
| #include <algorithm> |
| #include <memory> |
| #include <string> |
| #include <tuple> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/base64.h" |
| #include "base/command_line.h" |
| #include "base/feature_list.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/metrics/field_trial.h" |
| #include "base/metrics/metrics_hashes.h" |
| #include "base/stl_util.h" |
| #include "base/strings/string16.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "base/test/task_environment.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "base/time/time.h" |
| #include "base/values.h" |
| #include "build/build_config.h" |
| #include "components/autofill/core/browser/autocomplete_history_manager.h" |
| #include "components/autofill/core/browser/autofill_download_manager.h" |
| #include "components/autofill/core/browser/autofill_test_utils.h" |
| #include "components/autofill/core/browser/data_model/autofill_profile.h" |
| #include "components/autofill/core/browser/data_model/credit_card.h" |
| #include "components/autofill/core/browser/metrics/form_events.h" |
| #include "components/autofill/core/browser/payments/test_authentication_requester.h" |
| #include "components/autofill/core/browser/payments/test_credit_card_fido_authenticator.h" |
| #include "components/autofill/core/browser/payments/test_payments_client.h" |
| #include "components/autofill/core/browser/personal_data_manager.h" |
| #include "components/autofill/core/browser/test_autofill_client.h" |
| #include "components/autofill/core/browser/test_autofill_clock.h" |
| #include "components/autofill/core/browser/test_autofill_driver.h" |
| #include "components/autofill/core/browser/test_personal_data_manager.h" |
| #include "components/autofill/core/browser/validation.h" |
| #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" |
| #include "components/autofill/core/common/autofill_clock.h" |
| #include "components/autofill/core/common/autofill_features.h" |
| #include "components/autofill/core/common/autofill_payments_features.h" |
| #include "components/autofill/core/common/autofill_prefs.h" |
| #include "components/autofill/core/common/autofill_switches.h" |
| #include "components/autofill/core/common/autofill_util.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/security_state/core/security_state.h" |
| #include "components/strings/grit/components_strings.h" |
| #include "components/sync/driver/test_sync_service.h" |
| #include "components/variations/variations_associated_data.h" |
| #include "components/variations/variations_params_manager.h" |
| #include "components/version_info/channel.h" |
| #include "net/base/url_util.h" |
| #include "services/metrics/public/cpp/ukm_builders.h" |
| #include "services/network/public/cpp/shared_url_loader_factory.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/gfx/geometry/rect.h" |
| #include "url/gurl.h" |
| |
| #include "components/autofill/core/browser/payments/payments_service_url.h" |
| |
| using base::ASCIIToUTF16; |
| |
| namespace autofill { |
| namespace { |
| |
| const char kTestGUID[] = "00000000-0000-0000-0000-000000000001"; |
| const char kTestNumber[] = "4234567890123456"; // Visa |
| const char kTestRelyingPartyId[] = "google.com"; |
| // Base64 encoding of "This is a test challenge". |
| constexpr char kTestChallenge[] = "VGhpcyBpcyBhIHRlc3QgY2hhbGxlbmdl"; |
| // Base64 encoding of "This is a test Credential ID". |
| const char kTestCredentialId[] = "VGhpcyBpcyBhIHRlc3QgQ3JlZGVudGlhbCBJRC4="; |
| // Base64 encoding of "This is a test signature". |
| const char kTestSignature[] = "VGhpcyBpcyBhIHRlc3Qgc2lnbmF0dXJl"; |
| const char kTestAuthToken[] = "dummy_card_authorization_token"; |
| |
| std::string NextMonth() { |
| base::Time::Exploded now; |
| base::Time::Now().LocalExplode(&now); |
| return base::NumberToString(now.month % 12 + 1); |
| } |
| |
| std::vector<uint8_t> Base64ToBytes(std::string base64) { |
| std::string bytes; |
| bool did_succeed = base::Base64Decode(base::StringPiece(base64), &bytes); |
| if (did_succeed) { |
| return std::vector<uint8_t>(bytes.begin(), bytes.end()); |
| } |
| return std::vector<uint8_t>{}; |
| } |
| |
| std::string BytesToBase64(const std::vector<uint8_t> bytes) { |
| std::string base64; |
| base::Base64Encode(std::string(bytes.begin(), bytes.end()), &base64); |
| return base64; |
| } |
| } // namespace |
| |
| class CreditCardFIDOAuthenticatorTest : public testing::Test { |
| public: |
| CreditCardFIDOAuthenticatorTest() {} |
| |
| void SetUp() override { |
| autofill_client_.SetPrefs(test::PrefServiceForTesting()); |
| personal_data_manager_.Init(/*profile_database=*/database_, |
| /*account_database=*/nullptr, |
| /*pref_service=*/autofill_client_.GetPrefs(), |
| /*identity_manager=*/nullptr, |
| /*client_profile_validator=*/nullptr, |
| /*history_service=*/nullptr, |
| /*is_off_the_record=*/false); |
| personal_data_manager_.SetPrefService(autofill_client_.GetPrefs()); |
| |
| requester_.reset(new TestAuthenticationRequester()); |
| autofill_driver_ = |
| std::make_unique<testing::NiceMock<TestAutofillDriver>>(); |
| |
| payments::TestPaymentsClient* payments_client = |
| new payments::TestPaymentsClient( |
| autofill_driver_->GetURLLoaderFactory(), |
| autofill_client_.GetIdentityManager(), &personal_data_manager_); |
| autofill_client_.set_test_payments_client( |
| std::unique_ptr<payments::TestPaymentsClient>(payments_client)); |
| autofill_client_.set_test_strike_database( |
| std::make_unique<TestStrikeDatabase>()); |
| fido_authenticator_ = std::make_unique<CreditCardFIDOAuthenticator>( |
| autofill_driver_.get(), &autofill_client_); |
| } |
| |
| void TearDown() override { |
| // Order of destruction is important as AutofillDriver relies on |
| // PersonalDataManager to be around when it gets destroyed. |
| autofill_driver_.reset(); |
| } |
| |
| CreditCard CreateServerCard(std::string guid, std::string number) { |
| CreditCard masked_server_card = CreditCard(); |
| test::SetCreditCardInfo(&masked_server_card, "Elvis Presley", |
| number.c_str(), NextMonth().c_str(), |
| test::NextYear().c_str(), "1"); |
| masked_server_card.set_guid(guid); |
| masked_server_card.set_record_type(CreditCard::MASKED_SERVER_CARD); |
| |
| personal_data_manager_.ClearCreditCards(); |
| personal_data_manager_.AddServerCreditCard(masked_server_card); |
| |
| return masked_server_card; |
| } |
| |
| base::Value GetTestRequestOptions(std::string challenge, |
| std::string relying_party_id, |
| std::string credential_id) { |
| base::Value request_options = base::Value(base::Value::Type::DICTIONARY); |
| |
| // Building the following JSON structure-- |
| // request_options = { |
| // "challenge": challenge, |
| // "timeout_millis": kTestTimeoutSeconds, |
| // "relying_party_id": relying_party_id, |
| // "key_info": [{ |
| // "credential_id": credential_id, |
| // "authenticator_transport_support": ["INTERNAL"] |
| // }]} |
| request_options.SetKey("challenge", base::Value(challenge)); |
| request_options.SetKey("relying_party_id", base::Value(relying_party_id)); |
| |
| base::Value key_info(base::Value::Type::DICTIONARY); |
| key_info.SetKey("credential_id", base::Value(credential_id)); |
| key_info.SetKey("authenticator_transport_support", |
| base::Value(base::Value::Type::LIST)); |
| key_info |
| .FindKeyOfType("authenticator_transport_support", |
| base::Value::Type::LIST) |
| ->GetList() |
| .push_back(base::Value("INTERNAL")); |
| |
| request_options.SetKey("key_info", base::Value(base::Value::Type::LIST)); |
| request_options.FindKeyOfType("key_info", base::Value::Type::LIST) |
| ->GetList() |
| .push_back(std::move(key_info)); |
| return request_options; |
| } |
| |
| base::Value GetTestCreationOptions(std::string challenge, |
| std::string relying_party_id) { |
| base::Value creation_options = base::Value(base::Value::Type::DICTIONARY); |
| |
| // Building the following JSON structure-- |
| // request_options = { |
| // "challenge": challenge, |
| // "relying_party_id": relying_party_id, |
| // }]} |
| if (!challenge.empty()) |
| creation_options.SetKey("challenge", base::Value(challenge)); |
| creation_options.SetKey("relying_party_id", base::Value(relying_party_id)); |
| return creation_options; |
| } |
| |
| // Invokes GetRealPan callback. |
| void GetRealPan(AutofillClient::PaymentsRpcResult result, |
| const std::string& real_pan) { |
| DCHECK(fido_authenticator_->full_card_request_); |
| payments::PaymentsClient::UnmaskResponseDetails response; |
| fido_authenticator_->full_card_request_->OnDidGetRealPan( |
| result, response.with_real_pan(real_pan)); |
| } |
| |
| // Mocks an OptChange response from Payments Client. |
| void OptChange(AutofillClient::PaymentsRpcResult result, |
| bool user_is_opted_in, |
| bool include_creation_options = false, |
| bool include_request_options = false) { |
| payments::PaymentsClient::OptChangeResponseDetails response; |
| response.user_is_opted_in = user_is_opted_in; |
| if (include_creation_options) { |
| response.fido_creation_options = |
| GetTestCreationOptions(kTestChallenge, kTestRelyingPartyId); |
| } |
| if (include_request_options) { |
| response.fido_request_options = GetTestRequestOptions( |
| kTestChallenge, kTestRelyingPartyId, kTestCredentialId); |
| } |
| fido_authenticator_->OnDidGetOptChangeResult(result, response); |
| } |
| |
| protected: |
| std::unique_ptr<TestAuthenticationRequester> requester_; |
| base::test::TaskEnvironment task_environment_; |
| TestAutofillClient autofill_client_; |
| std::unique_ptr<TestAutofillDriver> autofill_driver_; |
| scoped_refptr<AutofillWebDataService> database_; |
| TestPersonalDataManager personal_data_manager_; |
| base::test::ScopedFeatureList scoped_feature_list_; |
| std::unique_ptr<CreditCardFIDOAuthenticator> fido_authenticator_; |
| }; |
| |
| TEST_F(CreditCardFIDOAuthenticatorTest, IsUserOptedIn_FlagDisabled) { |
| scoped_feature_list_.InitAndDisableFeature( |
| features::kAutofillCreditCardAuthentication); |
| EXPECT_FALSE(fido_authenticator_->IsUserOptedIn()); |
| } |
| |
| TEST_F(CreditCardFIDOAuthenticatorTest, IsUserOptedIn_False) { |
| scoped_feature_list_.InitAndEnableFeature( |
| features::kAutofillCreditCardAuthentication); |
| ::autofill::prefs::SetCreditCardFIDOAuthEnabled(autofill_client_.GetPrefs(), |
| false); |
| EXPECT_FALSE(fido_authenticator_->IsUserOptedIn()); |
| } |
| |
| TEST_F(CreditCardFIDOAuthenticatorTest, IsUserOptedIn_True) { |
| scoped_feature_list_.InitAndEnableFeature( |
| features::kAutofillCreditCardAuthentication); |
| ::autofill::prefs::SetCreditCardFIDOAuthEnabled(autofill_client_.GetPrefs(), |
| true); |
| EXPECT_TRUE(fido_authenticator_->IsUserOptedIn()); |
| } |
| |
| TEST_F(CreditCardFIDOAuthenticatorTest, SyncUserOptIn_OnOfferedOptIn) { |
| scoped_feature_list_.InitAndEnableFeature( |
| features::kAutofillCreditCardAuthentication); |
| ::autofill::prefs::SetCreditCardFIDOAuthEnabled(autofill_client_.GetPrefs(), |
| true); |
| EXPECT_TRUE(fido_authenticator_->IsUserOptedIn()); |
| |
| // If payments is offering to opt-in, then that means user is not opted in. |
| AutofillClient::UnmaskDetails unmask_details; |
| unmask_details.offer_fido_opt_in = true; |
| fido_authenticator_->SyncUserOptIn(unmask_details); |
| EXPECT_FALSE(fido_authenticator_->IsUserOptedIn()); |
| } |
| |
| TEST_F(CreditCardFIDOAuthenticatorTest, SyncUserOptIn_OnFIDOAuthRequest) { |
| scoped_feature_list_.InitAndEnableFeature( |
| features::kAutofillCreditCardAuthentication); |
| ::autofill::prefs::SetCreditCardFIDOAuthEnabled(autofill_client_.GetPrefs(), |
| false); |
| EXPECT_FALSE(fido_authenticator_->IsUserOptedIn()); |
| |
| // If payments is requesting a FIDO auth, then that means user is opted in. |
| AutofillClient::UnmaskDetails unmask_details; |
| unmask_details.unmask_auth_method = AutofillClient::UnmaskAuthMethod::FIDO; |
| fido_authenticator_->SyncUserOptIn(unmask_details); |
| EXPECT_TRUE(fido_authenticator_->IsUserOptedIn()); |
| } |
| |
| TEST_F(CreditCardFIDOAuthenticatorTest, IsUserVerifiable_False) { |
| fido_authenticator_->IsUserVerifiable( |
| base::BindOnce(&TestAuthenticationRequester::IsUserVerifiableCallback, |
| requester_->GetWeakPtr())); |
| EXPECT_FALSE(requester_->is_user_verifiable().value()); |
| } |
| |
| TEST_F(CreditCardFIDOAuthenticatorTest, ParseRequestOptions) { |
| base::Value request_options_json = GetTestRequestOptions( |
| kTestChallenge, kTestRelyingPartyId, kTestCredentialId); |
| |
| PublicKeyCredentialRequestOptionsPtr request_options_ptr = |
| fido_authenticator_->ParseRequestOptions(std::move(request_options_json)); |
| EXPECT_EQ(kTestChallenge, BytesToBase64(request_options_ptr->challenge)); |
| EXPECT_EQ(kTestRelyingPartyId, request_options_ptr->relying_party_id); |
| EXPECT_EQ(kTestCredentialId, |
| BytesToBase64(request_options_ptr->allow_credentials.front().id())); |
| } |
| |
| TEST_F(CreditCardFIDOAuthenticatorTest, ParseAssertionResponse) { |
| GetAssertionAuthenticatorResponsePtr assertion_response_ptr = |
| GetAssertionAuthenticatorResponse::New(); |
| assertion_response_ptr->info = blink::mojom::CommonCredentialInfo::New(); |
| assertion_response_ptr->info->id = kTestCredentialId; |
| assertion_response_ptr->signature = Base64ToBytes(kTestSignature); |
| |
| base::Value assertion_response_json = |
| fido_authenticator_->ParseAssertionResponse( |
| std::move(assertion_response_ptr)); |
| EXPECT_EQ(kTestCredentialId, |
| *assertion_response_json.FindStringKey("credential_id")); |
| EXPECT_EQ(kTestSignature, |
| *assertion_response_json.FindStringKey("signature")); |
| } |
| |
| TEST_F(CreditCardFIDOAuthenticatorTest, ParseCreationOptions) { |
| base::Value creation_options_json = |
| GetTestCreationOptions(kTestChallenge, kTestRelyingPartyId); |
| |
| PublicKeyCredentialCreationOptionsPtr creation_options_ptr = |
| fido_authenticator_->ParseCreationOptions( |
| std::move(creation_options_json)); |
| EXPECT_EQ(kTestChallenge, BytesToBase64(creation_options_ptr->challenge)); |
| EXPECT_EQ(kTestRelyingPartyId, creation_options_ptr->relying_party.id); |
| |
| // Ensure only platform authenticators are allowed. |
| EXPECT_EQ(AuthenticatorAttachment::kPlatform, |
| creation_options_ptr->authenticator_selection |
| ->authenticator_attachment()); |
| EXPECT_EQ(UserVerificationRequirement::kRequired, |
| creation_options_ptr->authenticator_selection |
| ->user_verification_requirement()); |
| } |
| |
| TEST_F(CreditCardFIDOAuthenticatorTest, ParseAttestationResponse) { |
| MakeCredentialAuthenticatorResponsePtr attestation_response_ptr = |
| MakeCredentialAuthenticatorResponse::New(); |
| attestation_response_ptr->info = blink::mojom::CommonCredentialInfo::New(); |
| attestation_response_ptr->attestation_object = Base64ToBytes(kTestSignature); |
| |
| base::Value attestation_response_json = |
| fido_authenticator_->ParseAttestationResponse( |
| std::move(attestation_response_ptr)); |
| EXPECT_EQ(kTestSignature, *attestation_response_json.FindStringPath( |
| "fido_attestation_info.attestation_object")); |
| } |
| |
| TEST_F(CreditCardFIDOAuthenticatorTest, AuthenticateCard_BadRequestOptions) { |
| CreditCard card = CreateServerCard(kTestGUID, kTestNumber); |
| |
| fido_authenticator_->Authenticate(&card, requester_->GetWeakPtr(), |
| base::TimeTicks::Now(), |
| base::Value(base::Value::Type::DICTIONARY)); |
| EXPECT_FALSE(requester_->did_succeed()); |
| } |
| |
| TEST_F(CreditCardFIDOAuthenticatorTest, |
| AuthenticateCard_UserVerificationFailed) { |
| CreditCard card = CreateServerCard(kTestGUID, kTestNumber); |
| |
| fido_authenticator_->Authenticate(&card, requester_->GetWeakPtr(), |
| base::TimeTicks::Now(), |
| base::Value(base::Value::Type::DICTIONARY)); |
| |
| TestCreditCardFIDOAuthenticator::GetAssertion(fido_authenticator_.get(), |
| /*did_succeed=*/false); |
| EXPECT_FALSE(requester_->did_succeed()); |
| } |
| |
| TEST_F(CreditCardFIDOAuthenticatorTest, |
| AuthenticateCard_PaymentsResponseError) { |
| CreditCard card = CreateServerCard(kTestGUID, kTestNumber); |
| |
| fido_authenticator_->Authenticate( |
| &card, requester_->GetWeakPtr(), base::TimeTicks::Now(), |
| GetTestRequestOptions(kTestChallenge, kTestRelyingPartyId, |
| kTestCredentialId)); |
| EXPECT_EQ(CreditCardFIDOAuthenticator::Flow::AUTHENTICATION_FLOW, |
| fido_authenticator_->current_flow()); |
| |
| // Mock user verification. |
| TestCreditCardFIDOAuthenticator::GetAssertion(fido_authenticator_.get(), |
| /*did_succeed=*/true); |
| GetRealPan(AutofillClient::PaymentsRpcResult::NETWORK_ERROR, ""); |
| |
| EXPECT_FALSE(requester_->did_succeed()); |
| } |
| |
| TEST_F(CreditCardFIDOAuthenticatorTest, AuthenticateCard_Success) { |
| CreditCard card = CreateServerCard(kTestGUID, kTestNumber); |
| |
| fido_authenticator_->Authenticate( |
| &card, requester_->GetWeakPtr(), base::TimeTicks::Now(), |
| GetTestRequestOptions(kTestChallenge, kTestRelyingPartyId, |
| kTestCredentialId)); |
| EXPECT_EQ(CreditCardFIDOAuthenticator::Flow::AUTHENTICATION_FLOW, |
| fido_authenticator_->current_flow()); |
| |
| // Mock user verification and payments response. |
| TestCreditCardFIDOAuthenticator::GetAssertion(fido_authenticator_.get(), |
| /*did_succeed=*/true); |
| GetRealPan(AutofillClient::PaymentsRpcResult::SUCCESS, kTestNumber); |
| |
| EXPECT_TRUE(requester_->did_succeed()); |
| EXPECT_EQ(ASCIIToUTF16(kTestNumber), requester_->number()); |
| } |
| |
| TEST_F(CreditCardFIDOAuthenticatorTest, OptIn_PaymentsResponseError) { |
| scoped_feature_list_.InitAndEnableFeature( |
| features::kAutofillCreditCardAuthentication); |
| EXPECT_FALSE(fido_authenticator_->IsUserOptedIn()); |
| |
| fido_authenticator_->Register(kTestAuthToken); |
| EXPECT_EQ(CreditCardFIDOAuthenticator::Flow::OPT_IN_FETCH_CHALLENGE_FLOW, |
| fido_authenticator_->current_flow()); |
| |
| // Mock payments response. |
| OptChange(AutofillClient::PaymentsRpcResult::NETWORK_ERROR, |
| /*user_is_opted_in=*/false); |
| EXPECT_FALSE(fido_authenticator_->IsUserOptedIn()); |
| } |
| |
| TEST_F(CreditCardFIDOAuthenticatorTest, OptIn_Success) { |
| scoped_feature_list_.InitAndEnableFeature( |
| features::kAutofillCreditCardAuthentication); |
| EXPECT_FALSE(fido_authenticator_->IsUserOptedIn()); |
| |
| fido_authenticator_->Register(kTestAuthToken); |
| EXPECT_EQ(CreditCardFIDOAuthenticator::Flow::OPT_IN_FETCH_CHALLENGE_FLOW, |
| fido_authenticator_->current_flow()); |
| |
| // Mock payments response. |
| OptChange(AutofillClient::PaymentsRpcResult::SUCCESS, |
| /*user_is_opted_in=*/true); |
| EXPECT_TRUE(fido_authenticator_->IsUserOptedIn()); |
| } |
| |
| TEST_F(CreditCardFIDOAuthenticatorTest, Register_BadCreationOptions) { |
| scoped_feature_list_.InitAndEnableFeature( |
| features::kAutofillCreditCardAuthentication); |
| EXPECT_FALSE(fido_authenticator_->IsUserOptedIn()); |
| |
| fido_authenticator_->Register( |
| kTestAuthToken, |
| GetTestCreationOptions(/*challenge=*/"", kTestRelyingPartyId)); |
| |
| EXPECT_FALSE(fido_authenticator_->IsUserOptedIn()); |
| } |
| |
| TEST_F(CreditCardFIDOAuthenticatorTest, Register_UserResponseFailure) { |
| scoped_feature_list_.InitAndEnableFeature( |
| features::kAutofillCreditCardAuthentication); |
| EXPECT_FALSE(fido_authenticator_->IsUserOptedIn()); |
| |
| fido_authenticator_->Register( |
| kTestAuthToken, |
| GetTestCreationOptions(kTestChallenge, kTestRelyingPartyId)); |
| EXPECT_EQ(CreditCardFIDOAuthenticator::Flow::OPT_IN_WITH_CHALLENGE_FLOW, |
| fido_authenticator_->current_flow()); |
| |
| // Mock user response and payments response. |
| TestCreditCardFIDOAuthenticator::MakeCredential(fido_authenticator_.get(), |
| /*did_succeed=*/false); |
| EXPECT_FALSE(fido_authenticator_->IsUserOptedIn()); |
| } |
| |
| TEST_F(CreditCardFIDOAuthenticatorTest, Register_Success) { |
| scoped_feature_list_.InitAndEnableFeature( |
| features::kAutofillCreditCardAuthentication); |
| EXPECT_FALSE(fido_authenticator_->IsUserOptedIn()); |
| |
| fido_authenticator_->Register( |
| kTestAuthToken, |
| GetTestCreationOptions(kTestChallenge, kTestRelyingPartyId)); |
| EXPECT_EQ(CreditCardFIDOAuthenticator::Flow::OPT_IN_WITH_CHALLENGE_FLOW, |
| fido_authenticator_->current_flow()); |
| |
| // Mock user response and payments response. |
| TestCreditCardFIDOAuthenticator::MakeCredential(fido_authenticator_.get(), |
| /*did_succeed=*/true); |
| OptChange(AutofillClient::PaymentsRpcResult::SUCCESS, |
| /*user_is_opted_in=*/true); |
| EXPECT_TRUE(fido_authenticator_->IsUserOptedIn()); |
| } |
| |
| TEST_F(CreditCardFIDOAuthenticatorTest, |
| Register_EnrollAttemptReturnsCreationOptions) { |
| scoped_feature_list_.InitAndEnableFeature( |
| features::kAutofillCreditCardAuthentication); |
| EXPECT_FALSE(fido_authenticator_->IsUserOptedIn()); |
| |
| fido_authenticator_->Register(kTestAuthToken); |
| EXPECT_EQ(CreditCardFIDOAuthenticator::Flow::OPT_IN_FETCH_CHALLENGE_FLOW, |
| fido_authenticator_->current_flow()); |
| |
| // Mock payments response with challenge to invoke enrollment flow. |
| OptChange(AutofillClient::PaymentsRpcResult::SUCCESS, |
| /*user_is_opted_in=*/false, /*include_creation_options=*/true); |
| EXPECT_EQ(CreditCardFIDOAuthenticator::Flow::OPT_IN_WITH_CHALLENGE_FLOW, |
| fido_authenticator_->current_flow()); |
| EXPECT_FALSE(fido_authenticator_->IsUserOptedIn()); |
| |
| // Mock user response and second payments response. |
| TestCreditCardFIDOAuthenticator::MakeCredential(fido_authenticator_.get(), |
| /*did_succeed=*/true); |
| OptChange(AutofillClient::PaymentsRpcResult::SUCCESS, |
| /*user_is_opted_in=*/true); |
| EXPECT_TRUE(fido_authenticator_->IsUserOptedIn()); |
| } |
| |
| TEST_F(CreditCardFIDOAuthenticatorTest, |
| Register_OptInAttemptReturnsRequestOptions) { |
| scoped_feature_list_.InitAndEnableFeature( |
| features::kAutofillCreditCardAuthentication); |
| EXPECT_FALSE(fido_authenticator_->IsUserOptedIn()); |
| |
| fido_authenticator_->Register(kTestAuthToken); |
| EXPECT_EQ(CreditCardFIDOAuthenticator::Flow::OPT_IN_FETCH_CHALLENGE_FLOW, |
| fido_authenticator_->current_flow()); |
| |
| // Mock payments response with challenge to invoke opt-in flow. |
| OptChange(AutofillClient::PaymentsRpcResult::SUCCESS, |
| /*user_is_opted_in=*/false, /*include_creation_options=*/false, |
| /*include_request_options=*/true); |
| EXPECT_EQ(CreditCardFIDOAuthenticator::Flow::OPT_IN_WITH_CHALLENGE_FLOW, |
| fido_authenticator_->current_flow()); |
| EXPECT_FALSE(fido_authenticator_->IsUserOptedIn()); |
| |
| // Mock user response and second payments response. |
| TestCreditCardFIDOAuthenticator::GetAssertion(fido_authenticator_.get(), |
| /*did_succeed=*/true); |
| OptChange(AutofillClient::PaymentsRpcResult::SUCCESS, |
| /*user_is_opted_in=*/true); |
| EXPECT_TRUE(fido_authenticator_->IsUserOptedIn()); |
| } |
| |
| TEST_F(CreditCardFIDOAuthenticatorTest, Register_NewCardAuthorization) { |
| scoped_feature_list_.InitAndEnableFeature( |
| features::kAutofillCreditCardAuthentication); |
| ::autofill::prefs::SetCreditCardFIDOAuthEnabled(autofill_client_.GetPrefs(), |
| true); |
| EXPECT_TRUE(fido_authenticator_->IsUserOptedIn()); |
| |
| fido_authenticator_->Authorize( |
| kTestAuthToken, GetTestRequestOptions(kTestChallenge, kTestRelyingPartyId, |
| kTestCredentialId)); |
| EXPECT_EQ(CreditCardFIDOAuthenticator::Flow::FOLLOWUP_AFTER_CVC_AUTH_FLOW, |
| fido_authenticator_->current_flow()); |
| |
| // Mock user response and second payments response. |
| TestCreditCardFIDOAuthenticator::GetAssertion(fido_authenticator_.get(), |
| /*did_succeed=*/true); |
| OptChange(AutofillClient::PaymentsRpcResult::SUCCESS, |
| /*user_is_opted_in=*/true); |
| EXPECT_TRUE(fido_authenticator_->IsUserOptedIn()); |
| } |
| |
| TEST_F(CreditCardFIDOAuthenticatorTest, OptOut_Success) { |
| scoped_feature_list_.InitAndEnableFeature( |
| features::kAutofillCreditCardAuthentication); |
| ::autofill::prefs::SetCreditCardFIDOAuthEnabled(autofill_client_.GetPrefs(), |
| true); |
| |
| EXPECT_TRUE(fido_authenticator_->IsUserOptedIn()); |
| |
| fido_authenticator_->OptOut(); |
| EXPECT_EQ(CreditCardFIDOAuthenticator::Flow::OPT_OUT_FLOW, |
| fido_authenticator_->current_flow()); |
| |
| // Mock payments response. |
| OptChange(AutofillClient::PaymentsRpcResult::SUCCESS, |
| /*user_is_opted_in=*/false); |
| EXPECT_FALSE(fido_authenticator_->IsUserOptedIn()); |
| } |
| |
| } // namespace autofill |