Commit 356b5659 authored by Manas Verma's avatar Manas Verma Committed by Commit Bot

[Payments Autofill] Adding GetAuthenticationDetails to Payments Client

The GetDetailsForGetRealPan request will return the type of authentication required and potentially a dynamic nonce for the authenticator to sign.

Bug: 949269
Change-Id: I35b53f59415d8cc353ea501af6ad8b73eda47f1a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1589695Reviewed-by: default avatarJared Saul <jsaul@google.com>
Commit-Queue: Manas Verma <manasverma@google.com>
Cr-Commit-Position: refs/heads/master@{#664891}
parent 7f9c7bba
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#include "components/autofill/core/browser/payments/payments_client.h" #include "components/autofill/core/browser/payments/payments_client.h"
#include <memory> #include <memory>
#include <set>
#include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
...@@ -45,6 +47,9 @@ namespace payments { ...@@ -45,6 +47,9 @@ namespace payments {
namespace { namespace {
const char kGetUnmaskDetailsRequestPath[] =
"payments/apis/chromepaymentsservice/getdetailsforgetrealpan";
const char kUnmaskCardRequestPath[] = const char kUnmaskCardRequestPath[] =
"payments/apis-secure/creditcardservice/getrealpan?s7e_suffix=chromewallet"; "payments/apis-secure/creditcardservice/getrealpan?s7e_suffix=chromewallet";
const char kUnmaskCardRequestFormat[] = const char kUnmaskCardRequestFormat[] =
...@@ -225,6 +230,93 @@ void SetActiveExperiments(const std::vector<const char*>& active_experiments, ...@@ -225,6 +230,93 @@ void SetActiveExperiments(const std::vector<const char*>& active_experiments,
std::move(active_chrome_experiments)); std::move(active_chrome_experiments));
} }
class GetUnmaskDetailsRequest : public PaymentsRequest {
public:
GetUnmaskDetailsRequest(GetUnmaskDetailsCallback callback,
const std::string& app_locale,
const bool full_sync_enabled)
: callback_(std::move(callback)),
app_locale_(app_locale),
full_sync_enabled_(full_sync_enabled) {}
~GetUnmaskDetailsRequest() override {}
std::string GetRequestUrlPath() override {
return kGetUnmaskDetailsRequestPath;
}
std::string GetRequestContentType() override { return "application/json"; }
std::string GetRequestContent() override {
base::Value request_dict(base::Value::Type::DICTIONARY);
base::Value context(base::Value::Type::DICTIONARY);
context.SetKey("language_code", base::Value(app_locale_));
context.SetKey("billable_service",
base::Value(kUnmaskCardBillableServiceNumber));
request_dict.SetKey("context", std::move(context));
if (ShouldUseActiveSignedInAccount()) {
base::Value chrome_user_context(base::Value::Type::DICTIONARY);
chrome_user_context.SetKey("full_sync_enabled",
base::Value(full_sync_enabled_));
request_dict.SetKey("chrome_user_context",
std::move(chrome_user_context));
}
std::string request_content;
base::JSONWriter::Write(request_dict, &request_content);
VLOG(3) << "getdetailsforgetrealpan request body: " << request_content;
return request_content;
}
void ParseResponse(const base::Value& response) override {
const auto* method = response.FindStringKey("authentication_method");
auth_method_ = method ? *method : std::string();
const auto* offer_opt_in =
response.FindKeyOfType("offer_opt_in", base::Value::Type::BOOLEAN);
offer_opt_in_ = offer_opt_in && offer_opt_in->GetBool();
const auto* dictionary_value = response.FindKeyOfType(
"request_options", base::Value::Type::DICTIONARY);
if (dictionary_value)
request_options_ =
std::make_unique<base::Value>(dictionary_value->Clone());
const auto* fido_eligible_card_ids = response.FindKeyOfType(
"fido_eligible_credit_card_id", base::Value::Type::LIST);
if (fido_eligible_card_ids) {
for (const base::Value& result : fido_eligible_card_ids->GetList()) {
fido_eligible_card_ids_.insert(result.GetString());
}
}
}
bool IsResponseComplete() override { return !auth_method_.empty(); }
void RespondToDelegate(AutofillClient::PaymentsRpcResult result) override {
std::move(callback_).Run(result, auth_method_, offer_opt_in_,
std::move(request_options_),
fido_eligible_card_ids_);
}
private:
GetUnmaskDetailsCallback callback_;
std::string app_locale_;
const bool full_sync_enabled_;
// The type of authentication method suggested for card unmask.
std::string auth_method_;
// Set to true if the user should be offered opt-in for FIDO Authentication.
bool offer_opt_in_;
// Public Key Credential Request Options required for authentication.
// https://www.w3.org/TR/webauthn/#dictdef-publickeycredentialrequestoptions
std::unique_ptr<base::Value> request_options_;
// Set of credit cards ids that are eligible for FIDO Authentication.
std::set<std::string> fido_eligible_card_ids_;
DISALLOW_COPY_AND_ASSIGN(GetUnmaskDetailsRequest);
};
class UnmaskCardRequest : public PaymentsRequest { class UnmaskCardRequest : public PaymentsRequest {
public: public:
UnmaskCardRequest(const PaymentsClient::UnmaskRequestDetails& request_details, UnmaskCardRequest(const PaymentsClient::UnmaskRequestDetails& request_details,
...@@ -773,6 +865,14 @@ void PaymentsClient::Prepare() { ...@@ -773,6 +865,14 @@ void PaymentsClient::Prepare() {
StartTokenFetch(false); StartTokenFetch(false);
} }
void PaymentsClient::GetUnmaskDetails(GetUnmaskDetailsCallback callback,
const std::string& app_locale) {
IssueRequest(std::make_unique<GetUnmaskDetailsRequest>(
std::move(callback), app_locale,
account_info_getter_->IsSyncFeatureEnabled()),
/*authenticate=*/true);
}
void PaymentsClient::UnmaskCard( void PaymentsClient::UnmaskCard(
const PaymentsClient::UnmaskRequestDetails& request_details, const PaymentsClient::UnmaskRequestDetails& request_details,
base::OnceCallback<void(AutofillClient::PaymentsRpcResult, base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_CLIENT_H_ #ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_CLIENT_H_
#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_CLIENT_H_ #define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_PAYMENTS_CLIENT_H_
#include <set>
#include <string>
#include <utility> #include <utility>
#include "base/macros.h" #include "base/macros.h"
...@@ -46,6 +48,14 @@ typedef base::OnceCallback<void( ...@@ -46,6 +48,14 @@ typedef base::OnceCallback<void(
const std::string& display_text)> const std::string& display_text)>
MigrateCardsCallback; MigrateCardsCallback;
// Callback type for GetUnmaskDetails callback.
typedef base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
std::string,
bool,
std::unique_ptr<base::Value>,
std::set<std::string>)>
GetUnmaskDetailsCallback;
// Billable service number is defined in Payments server to distinguish // Billable service number is defined in Payments server to distinguish
// different requests. // different requests.
const int kUnmaskCardBillableServiceNumber = 70154; const int kUnmaskCardBillableServiceNumber = 70154;
...@@ -151,6 +161,12 @@ class PaymentsClient { ...@@ -151,6 +161,12 @@ class PaymentsClient {
// accepted an upload prompt. // accepted an upload prompt.
void Prepare(); void Prepare();
// The user has interacted with a credit card form and may attempt to unmask a
// card. This request returns what method of authentication is required, along
// with any information to facilitate the authentication.
virtual void GetUnmaskDetails(GetUnmaskDetailsCallback callback,
const std::string& app_locale);
// The user has attempted to unmask a card with the given cvc. // The user has attempted to unmask a card with the given cvc.
void UnmaskCard(const UnmaskRequestDetails& request_details, void UnmaskCard(const UnmaskRequestDetails& request_details,
base::OnceCallback<void(AutofillClient::PaymentsRpcResult, base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include <set>
#include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
...@@ -111,6 +113,18 @@ class PaymentsClientTest : public testing::Test { ...@@ -111,6 +113,18 @@ class PaymentsClientTest : public testing::Test {
base::FieldTrialList::CreateFieldTrial(trial_name, group_name)->group(); base::FieldTrialList::CreateFieldTrial(trial_name, group_name)->group();
} }
void OnDidGetUnmaskDetails(AutofillClient::PaymentsRpcResult result,
std::string auth_method,
bool offer_opt_in,
std::unique_ptr<base::Value> request_options,
std::set<std::string> fido_eligible_card_ids) {
result_ = result;
auth_method_ = auth_method;
offer_opt_in_ = offer_opt_in;
request_options_ = std::move(request_options);
fido_eligible_card_ids_ = fido_eligible_card_ids;
}
void OnDidGetRealPan(AutofillClient::PaymentsRpcResult result, void OnDidGetRealPan(AutofillClient::PaymentsRpcResult result,
const std::string& real_pan) { const std::string& real_pan) {
result_ = result; result_ = result;
...@@ -145,6 +159,15 @@ class PaymentsClientTest : public testing::Test { ...@@ -145,6 +159,15 @@ class PaymentsClientTest : public testing::Test {
protected: protected:
base::test::ScopedFeatureList scoped_feature_list_; base::test::ScopedFeatureList scoped_feature_list_;
// Issue a GetUnmaskDetails request. This requires an OAuth token before
// starting the request.
void StartGettingUnmaskDetails() {
client_->GetUnmaskDetails(
base::BindOnce(&PaymentsClientTest::OnDidGetUnmaskDetails,
weak_ptr_factory_.GetWeakPtr()),
"language-LOCALE");
}
// Issue an UnmaskCard request. This requires an OAuth token before starting // Issue an UnmaskCard request. This requires an OAuth token before starting
// the request. // the request.
void StartUnmasking() { void StartUnmasking() {
...@@ -235,6 +258,11 @@ class PaymentsClientTest : public testing::Test { ...@@ -235,6 +258,11 @@ class PaymentsClientTest : public testing::Test {
} }
AutofillClient::PaymentsRpcResult result_; AutofillClient::PaymentsRpcResult result_;
std::string auth_method_;
bool offer_opt_in_;
std::unique_ptr<base::Value> request_options_;
std::set<std::string> fido_eligible_card_ids_;
std::string server_id_; std::string server_id_;
std::string real_pan_; std::string real_pan_;
std::unique_ptr<base::Value> legal_message_; std::unique_ptr<base::Value> legal_message_;
...@@ -289,6 +317,31 @@ class PaymentsClientTest : public testing::Test { ...@@ -289,6 +317,31 @@ class PaymentsClientTest : public testing::Test {
} }
}; };
TEST_F(PaymentsClientTest, GetUnmaskDetailsSuccess) {
StartGettingUnmaskDetails();
IssueOAuthToken();
ReturnResponse(
net::HTTP_OK,
"{ \"offer_opt_in\": \"false\", \"authentication_method\": \"CVC\" }");
EXPECT_EQ(AutofillClient::SUCCESS, result_);
EXPECT_EQ(false, offer_opt_in_);
EXPECT_EQ("CVC", auth_method_);
}
TEST_F(PaymentsClientTest, GetUnmaskDetailsIncludesChromeUserContext) {
scoped_feature_list_.InitWithFeatures(
{features::kAutofillGetPaymentsIdentityFromSync}, // Enabled
{features::kAutofillEnableAccountWalletStorage}); // Disabled
StartGettingUnmaskDetails();
IssueOAuthToken();
ReturnResponse(net::HTTP_OK, "{}");
// ChromeUserContext was set.
EXPECT_TRUE(GetUploadData().find("chrome_user_context") != std::string::npos);
EXPECT_TRUE(GetUploadData().find("full_sync_enabled") != std::string::npos);
}
TEST_F(PaymentsClientTest, OAuthError) { TEST_F(PaymentsClientTest, OAuthError) {
StartUnmasking(); StartUnmasking();
identity_test_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithError( identity_test_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithError(
......
...@@ -21,6 +21,12 @@ TestPaymentsClient::TestPaymentsClient( ...@@ -21,6 +21,12 @@ TestPaymentsClient::TestPaymentsClient(
TestPaymentsClient::~TestPaymentsClient() {} TestPaymentsClient::~TestPaymentsClient() {}
void TestPaymentsClient::GetUnmaskDetails(GetUnmaskDetailsCallback callback,
const std::string& app_locale) {
std::move(callback).Run(AutofillClient::SUCCESS, auth_method_, offer_opt_in_,
std::move(request_options_), fido_eligible_card_ids_);
}
void TestPaymentsClient::GetUploadDetails( void TestPaymentsClient::GetUploadDetails(
const std::vector<AutofillProfile>& addresses, const std::vector<AutofillProfile>& addresses,
const int detected_values, const int detected_values,
...@@ -61,6 +67,24 @@ void TestPaymentsClient::MigrateCards( ...@@ -61,6 +67,24 @@ void TestPaymentsClient::MigrateCards(
"this is display text"); "this is display text");
} }
void TestPaymentsClient::SetAuthenticationMethod(std::string auth_method) {
auth_method_ = auth_method;
}
void TestPaymentsClient::AllowFidoRegistration(bool offer_opt_in) {
offer_opt_in_ = offer_opt_in;
}
void TestPaymentsClient::SetFidoRequestOptions(
std::unique_ptr<base::Value> request_options) {
request_options_ = std::move(request_options);
}
void TestPaymentsClient::SetFidoEligibleCardIds(
std::set<std::string> fido_eligible_card_ids) {
fido_eligible_card_ids_ = fido_eligible_card_ids;
}
void TestPaymentsClient::SetServerIdForCardUpload(std::string server_id) { void TestPaymentsClient::SetServerIdForCardUpload(std::string server_id) {
server_id_ = server_id; server_id_ = server_id;
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_TEST_PAYMENTS_CLIENT_H_ #ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_TEST_PAYMENTS_CLIENT_H_
#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_TEST_PAYMENTS_CLIENT_H_ #define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_TEST_PAYMENTS_CLIENT_H_
#include <set>
#include <string> #include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
...@@ -27,6 +28,9 @@ class TestPaymentsClient : public payments::PaymentsClient { ...@@ -27,6 +28,9 @@ class TestPaymentsClient : public payments::PaymentsClient {
~TestPaymentsClient() override; ~TestPaymentsClient() override;
void GetUnmaskDetails(GetUnmaskDetailsCallback callback,
const std::string& app_locale) override;
void GetUploadDetails( void GetUploadDetails(
const std::vector<AutofillProfile>& addresses, const std::vector<AutofillProfile>& addresses,
const int detected_values, const int detected_values,
...@@ -50,6 +54,14 @@ class TestPaymentsClient : public payments::PaymentsClient { ...@@ -50,6 +54,14 @@ class TestPaymentsClient : public payments::PaymentsClient {
const std::vector<MigratableCreditCard>& migratable_credit_cards, const std::vector<MigratableCreditCard>& migratable_credit_cards,
MigrateCardsCallback callback) override; MigrateCardsCallback callback) override;
void SetAuthenticationMethod(std::string auth_method);
void AllowFidoRegistration(bool offer_opt_in = true);
void SetFidoRequestOptions(std::unique_ptr<base::Value> request_options);
void SetFidoEligibleCardIds(std::set<std::string> fido_eligible_card_ids);
void SetServerIdForCardUpload(std::string); void SetServerIdForCardUpload(std::string);
void SetSaveResultForCardsMigration( void SetSaveResultForCardsMigration(
...@@ -77,6 +89,10 @@ class TestPaymentsClient : public payments::PaymentsClient { ...@@ -77,6 +89,10 @@ class TestPaymentsClient : public payments::PaymentsClient {
private: private:
std::string server_id_; std::string server_id_;
std::string auth_method_;
bool offer_opt_in_ = false;
std::unique_ptr<base::Value> request_options_ = nullptr;
std::set<std::string> fido_eligible_card_ids_;
std::vector<std::pair<int, int>> supported_card_bin_ranges_; std::vector<std::pair<int, int>> supported_card_bin_ranges_;
std::vector<AutofillProfile> upload_details_addresses_; std::vector<AutofillProfile> upload_details_addresses_;
std::vector<AutofillProfile> upload_card_addresses_; std::vector<AutofillProfile> upload_card_addresses_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment