blob: 557ee8091e9b6c82322b2ad58e33c81f8ecfe632 [file] [log] [blame]
// 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