Commit 50480d41 authored by Marc Treib's avatar Marc Treib Committed by Commit Bot

MultiStorePasswordSaveManager: Track action for each store

This CL adds profile_store_action_ and account_store_action_ to
MultiStorePasswordSaveManager (in addition to pending_credentials_state_
from the base class). Explicitly tracking the two states, instead of
just a single "canonical" one, allows us to be more explicit in how
conflicts are resolved, and in particular it allows us to handle some
edge cases that we couldn't handle correctly before.
It also adds an integration test for one such edge case.

Bug: 1012203, 1060524
Change-Id: I9602c3641da761a76b2dc9a1f62b630ef2fbcb2e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2139654
Commit-Queue: Mohamed Amir Yosef <mamir@chromium.org>
Auto-Submit: Marc Treib <treib@chromium.org>
Reviewed-by: default avatarMohamed Amir Yosef <mamir@chromium.org>
Cr-Commit-Position: refs/heads/master@{#758777}
parent 40f67347
...@@ -541,6 +541,36 @@ IN_PROC_BROWSER_TEST_F(PasswordManagerSyncTest, ...@@ -541,6 +541,36 @@ IN_PROC_BROWSER_TEST_F(PasswordManagerSyncTest,
ASSERT_THAT(GetAllLoginsFromAccountPasswordStore(), ASSERT_THAT(GetAllLoginsFromAccountPasswordStore(),
ElementsAre(MatchesLogin("user", "pass"))); ElementsAre(MatchesLogin("user", "pass")));
} }
IN_PROC_BROWSER_TEST_F(PasswordManagerSyncTest,
AutoUpdatePSLMatchInBothStoresOnSuccessfulUse) {
ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
// Add the same PSL-matched credential to both stores (i.e. it's stored for
// psl.example.com instead of www.example.com).
AddCredentialToFakeServer(CreateTestPSLPasswordForm("user", "pass"));
AddLocalCredential(CreateTestPSLPasswordForm("user", "pass"));
SetupSyncTransportWithPasswordAccountStorage();
content::WebContents* web_contents = nullptr;
GetNewTab(GetBrowser(0), &web_contents);
// Go to a form (on www.) and submit it with the saved credentials.
NavigateToFile(web_contents, "/password/simple_password.html");
FillAndSubmitPasswordForm(web_contents, "user", "pass");
// Now the PSL-matched credential should have been automatically saved for
// www. as well, in both stores.
EXPECT_THAT(GetAllLoginsFromAccountPasswordStore(),
UnorderedElementsAre(
MatchesLoginAndRealm("user", "pass", GetWWWOrigin()),
MatchesLoginAndRealm("user", "pass", GetPSLOrigin())));
EXPECT_THAT(GetAllLoginsFromProfilePasswordStore(),
UnorderedElementsAre(
MatchesLoginAndRealm("user", "pass", GetWWWOrigin()),
MatchesLoginAndRealm("user", "pass", GetPSLOrigin())));
}
#endif // !defined(OS_CHROMEOS) #endif // !defined(OS_CHROMEOS)
} // namespace } // namespace
...@@ -54,27 +54,23 @@ bool AccountStoreMatchesContainForm( ...@@ -54,27 +54,23 @@ bool AccountStoreMatchesContainForm(
PendingCredentialsState ResolvePendingCredentialsStates( PendingCredentialsState ResolvePendingCredentialsStates(
PendingCredentialsState profile_state, PendingCredentialsState profile_state,
PendingCredentialsState account_state) { PendingCredentialsState account_state) {
// Resolve the two states to a single canonical one, according to the // The result of this resolution will be used to decide whether to show a
// following hierarchy: // save or update prompt to the user. Resolve the two states to a single
// "canonical" one according to the following hierarchy:
// AUTOMATIC_SAVE > EQUAL_TO_SAVED_MATCH > UPDATE > NEW_LOGIN // AUTOMATIC_SAVE > EQUAL_TO_SAVED_MATCH > UPDATE > NEW_LOGIN
// Note that UPDATE and NEW_LOGIN will result in an Update or Save bubble to // Note that UPDATE or NEW_LOGIN will result in an Update or Save bubble to
// be shown, while AUTOMATIC_SAVE and EQUAL_TO_SAVED_MATCH will result in a // be shown, while AUTOMATIC_SAVE and EQUAL_TO_SAVED_MATCH will result in a
// silent save/update. // silent save/update.
// Some interesting cases: // Some interesting cases:
// NEW_LOGIN means that store doesn't know about the credential yet. If the // NEW_LOGIN means that store doesn't know about the credential yet. If the
// other store knows anything at all, then that always wins. // other store knows anything at all, then that always wins.
// EQUAL_TO_SAVED_MATCH vs UPDATE: This means one store had a match, the other // EQUAL_TO_SAVED_MATCH vs UPDATE: This means one store had a match, the other
// had a mismatch (same username but different password). We want to silently // had a mismatch (same username but different password). The mismatch should
// update the mismatch, which EQUAL achieves (since it'll still result in an // be updated silently, so resolve to EQUAL so that there's no visible prompt.
// update to date_last_used, and updates always go to both stores). // AUTOMATIC_SAVE vs EQUAL_TO_SAVED_MATCH: These are both silent, so it
// TODO(crbug.com/1012203): AUTOMATIC_SAVE vs EQUAL: We should still perform // doesn't really matter to which one we resolve.
// the silent update for EQUAL (so last_use_date gets updated). // AUTOMATIC_SAVE vs UPDATE: Similar to EQUAL_TO_SAVED_MATCH vs UPDATE, the
// TODO(crbug.com/1012203): AUTOMATIC_SAVE vs UPDATE: What's the expected // mismatch should be silently updated.
// outcome? Currently we'll auto-save the PSL match and ignore the update
// (which isn't too bad, since on the next submission the update will become
// a silent update through EQUAL_TO_SAVED_MATCH).
// TODO(crbug.com/1012203): AUTOMATIC_SAVE vs AUTOMATIC_SAVE: Somehow make
// sure that the save goes to both stores.
if (profile_state == PendingCredentialsState::AUTOMATIC_SAVE || if (profile_state == PendingCredentialsState::AUTOMATIC_SAVE ||
account_state == PendingCredentialsState::AUTOMATIC_SAVE) { account_state == PendingCredentialsState::AUTOMATIC_SAVE) {
return PendingCredentialsState::AUTOMATIC_SAVE; return PendingCredentialsState::AUTOMATIC_SAVE;
...@@ -101,60 +97,91 @@ MultiStorePasswordSaveManager::MultiStorePasswordSaveManager( ...@@ -101,60 +97,91 @@ MultiStorePasswordSaveManager::MultiStorePasswordSaveManager(
std::unique_ptr<FormSaver> profile_form_saver, std::unique_ptr<FormSaver> profile_form_saver,
std::unique_ptr<FormSaver> account_form_saver) std::unique_ptr<FormSaver> account_form_saver)
: PasswordSaveManagerImpl(std::move(profile_form_saver)), : PasswordSaveManagerImpl(std::move(profile_form_saver)),
account_store_form_saver_(std::move(account_form_saver)) {} account_store_form_saver_(std::move(account_form_saver)) {
DCHECK(account_store_form_saver_);
}
MultiStorePasswordSaveManager::~MultiStorePasswordSaveManager() = default; MultiStorePasswordSaveManager::~MultiStorePasswordSaveManager() = default;
void MultiStorePasswordSaveManager::SaveInternal( void MultiStorePasswordSaveManager::SavePendingToStoreImpl(
const std::vector<const PasswordForm*>& matches, const PasswordForm& parsed_submitted_form) {
const base::string16& old_password) { auto matches = form_fetcher_->GetAllRelevantMatches();
// For New Credentials, we should respect the default password store selected PendingCredentialsStates states =
// by user. In other cases such PSL matching, we respect the store in the ComputePendingCredentialsStates(parsed_submitted_form, matches);
// retrieved credentials.
if (pending_credentials_state_ == PendingCredentialsState::NEW_LOGIN) { auto account_matches = AccountStoreMatches(matches);
pending_credentials_.in_store = auto profile_matches = ProfileStoreMatches(matches);
client_->GetPasswordFeatureManager()->GetDefaultPasswordStore();
base::string16 old_account_password =
states.similar_saved_form_from_account_store
? states.similar_saved_form_from_account_store->password_value
: base::string16();
base::string16 old_profile_password =
states.similar_saved_form_from_profile_store
? states.similar_saved_form_from_profile_store->password_value
: base::string16();
if (states.profile_store_state == PendingCredentialsState::NEW_LOGIN &&
states.account_store_state == PendingCredentialsState::NEW_LOGIN) {
// If the credential is new to both stores, store it only in the default
// store.
if (AccountStoreIsDefault()) {
// TODO(crbug.com/1012203): Record UMA for how many passwords get dropped
// here. In rare cases it could happen that the user *was* opted in when
// the save dialog was shown, but now isn't anymore.
if (IsOptedInForAccountStorage()) {
account_store_form_saver_->Save(pending_credentials_, account_matches,
old_account_password);
}
} else {
form_saver_->Save(pending_credentials_, profile_matches,
old_profile_password);
}
return;
} }
switch (pending_credentials_.in_store) { switch (states.profile_store_state) {
case PasswordForm::Store::kAccountStore: case PendingCredentialsState::AUTOMATIC_SAVE:
if (account_store_form_saver_ && IsOptedInForAccountStorage()) { form_saver_->Save(pending_credentials_, profile_matches,
account_store_form_saver_->Save( old_profile_password);
pending_credentials_, AccountStoreMatches(matches), old_password); break;
case PendingCredentialsState::UPDATE:
case PendingCredentialsState::EQUAL_TO_SAVED_MATCH:
form_saver_->Update(pending_credentials_, profile_matches,
old_profile_password);
break;
// The NEW_LOGIN case was already handled separately above.
case PendingCredentialsState::NEW_LOGIN:
case PendingCredentialsState::NONE:
break;
} }
// TODO(crbug.com/1012203): Record UMA for how many passwords get dropped // TODO(crbug.com/1012203): Record UMA for how many passwords get dropped
// here. In rare cases it could happen that the user *was* opted in when // here. In rare cases it could happen that the user *was* opted in when
// the save dialog was shown, but now isn't anymore. // the save dialog was shown, but now isn't anymore.
if (IsOptedInForAccountStorage()) {
switch (states.account_store_state) {
case PendingCredentialsState::AUTOMATIC_SAVE:
account_store_form_saver_->Save(pending_credentials_, account_matches,
old_account_password);
break; break;
case PasswordForm::Store::kProfileStore: case PendingCredentialsState::UPDATE:
form_saver_->Save(pending_credentials_, ProfileStoreMatches(matches), case PendingCredentialsState::EQUAL_TO_SAVED_MATCH:
old_password); account_store_form_saver_->Update(pending_credentials_, account_matches,
old_account_password);
break; break;
case PasswordForm::Store::kNotSet: // The NEW_LOGIN case was already handled separately above.
NOTREACHED(); case PendingCredentialsState::NEW_LOGIN:
case PendingCredentialsState::NONE:
break; break;
} }
}
void MultiStorePasswordSaveManager::UpdateInternal(
const std::vector<const PasswordForm*>& matches,
const base::string16& old_password) {
// Try to update both stores anyway because if credentials don't exist, the
// update operation is no-op.
form_saver_->Update(pending_credentials_, ProfileStoreMatches(matches),
old_password);
if (account_store_form_saver_ && IsOptedInForAccountStorage()) {
account_store_form_saver_->Update(
pending_credentials_, AccountStoreMatches(matches), old_password);
} }
} }
void MultiStorePasswordSaveManager::PermanentlyBlacklist( void MultiStorePasswordSaveManager::PermanentlyBlacklist(
const PasswordStore::FormDigest& form_digest) { const PasswordStore::FormDigest& form_digest) {
DCHECK(!client_->IsIncognito()); DCHECK(!client_->IsIncognito());
if (account_store_form_saver_ && IsOptedInForAccountStorage() && if (IsOptedInForAccountStorage() && AccountStoreIsDefault()) {
client_->GetPasswordFeatureManager()->GetDefaultPasswordStore() ==
PasswordForm::Store::kAccountStore) {
account_store_form_saver_->PermanentlyBlacklist(form_digest); account_store_form_saver_->PermanentlyBlacklist(form_digest);
} else { } else {
// For users who aren't yet opted-in to the account storage, we store their // For users who aren't yet opted-in to the account storage, we store their
...@@ -168,9 +195,8 @@ void MultiStorePasswordSaveManager::Unblacklist( ...@@ -168,9 +195,8 @@ void MultiStorePasswordSaveManager::Unblacklist(
// Try to unblacklist in both stores anyway because if credentials don't // Try to unblacklist in both stores anyway because if credentials don't
// exist, the unblacklist operation is no-op. // exist, the unblacklist operation is no-op.
form_saver_->Unblacklist(form_digest); form_saver_->Unblacklist(form_digest);
if (account_store_form_saver_ && IsOptedInForAccountStorage()) { if (IsOptedInForAccountStorage())
account_store_form_saver_->Unblacklist(form_digest); account_store_form_saver_->Unblacklist(form_digest);
}
} }
std::unique_ptr<PasswordSaveManager> MultiStorePasswordSaveManager::Clone() { std::unique_ptr<PasswordSaveManager> MultiStorePasswordSaveManager::Clone() {
...@@ -218,61 +244,78 @@ void MultiStorePasswordSaveManager::MoveCredentialsToAccountStore() { ...@@ -218,61 +244,78 @@ void MultiStorePasswordSaveManager::MoveCredentialsToAccountStore() {
} }
} }
std::pair<const autofill::PasswordForm*, PendingCredentialsState> std::pair<const PasswordForm*, PendingCredentialsState>
MultiStorePasswordSaveManager::FindSimilarSavedFormAndComputeState( MultiStorePasswordSaveManager::FindSimilarSavedFormAndComputeState(
const PasswordForm& parsed_submitted_form) const { const PasswordForm& parsed_submitted_form) const {
const std::vector<const PasswordForm*> matches = PendingCredentialsStates states = ComputePendingCredentialsStates(
form_fetcher_->GetBestMatches(); parsed_submitted_form, form_fetcher_->GetBestMatches());
const PasswordForm* similar_saved_form_from_profile_store =
password_manager_util::GetMatchForUpdating(parsed_submitted_form,
ProfileStoreMatches(matches));
const PasswordForm* similar_saved_form_from_account_store =
password_manager_util::GetMatchForUpdating(parsed_submitted_form,
AccountStoreMatches(matches));
// Compute the PendingCredentialsState (i.e. what to do - save, update, silent // Resolve the two states to a single canonical one. This will be used to
// update) separately for the two stores. // decide what UI bubble (if any) to show to the user.
PendingCredentialsState profile_state = ComputePendingCredentialsState( PendingCredentialsState resolved_state = ResolvePendingCredentialsStates(
parsed_submitted_form, similar_saved_form_from_profile_store); states.profile_store_state, states.account_store_state);
PendingCredentialsState account_state = ComputePendingCredentialsState(
parsed_submitted_form, similar_saved_form_from_account_store);
// Resolve the two states to a single canonical one.
PendingCredentialsState state =
ResolvePendingCredentialsStates(profile_state, account_state);
// Choose which of the saved forms (if any) to use as the base for updating, // Choose which of the saved forms (if any) to use as the base for updating,
// based on which of the two states won the resolution. // based on which of the two states won the resolution.
// Note that if we got the same state for both stores, then it doesn't really // Note that if we got the same state for both stores, then it doesn't really
// matter which one we pick for updating, since the result will be the same // matter which one we pick for updating, since the result will be the same
// anyway. // anyway.
const PasswordForm* similar_saved_form = nullptr; const PasswordForm* resolved_similar_saved_form = nullptr;
if (state == profile_state) if (resolved_state == states.profile_store_state)
similar_saved_form = similar_saved_form_from_profile_store; resolved_similar_saved_form = states.similar_saved_form_from_profile_store;
else if (state == account_state) else if (resolved_state == states.account_store_state)
similar_saved_form = similar_saved_form_from_account_store; resolved_similar_saved_form = states.similar_saved_form_from_account_store;
return std::make_pair(similar_saved_form, state); return std::make_pair(resolved_similar_saved_form, resolved_state);
} }
FormSaver* MultiStorePasswordSaveManager::GetFormSaverForGeneration() { FormSaver* MultiStorePasswordSaveManager::GetFormSaverForGeneration() {
return IsOptedInForAccountStorage() && account_store_form_saver_ return IsOptedInForAccountStorage() ? account_store_form_saver_.get()
? account_store_form_saver_.get()
: form_saver_.get(); : form_saver_.get();
} }
std::vector<const autofill::PasswordForm*> std::vector<const PasswordForm*>
MultiStorePasswordSaveManager::GetRelevantMatchesForGeneration( MultiStorePasswordSaveManager::GetRelevantMatchesForGeneration(
const std::vector<const autofill::PasswordForm*>& matches) { const std::vector<const PasswordForm*>& matches) {
// For account store users, only matches in the account store should be // For account store users, only matches in the account store should be
// considered for conflict resolution during generation. // considered for conflict resolution during generation.
return IsOptedInForAccountStorage() && account_store_form_saver_ return IsOptedInForAccountStorage()
? MatchesInStore(matches, PasswordForm::Store::kAccountStore) ? MatchesInStore(matches, PasswordForm::Store::kAccountStore)
: matches; : matches;
} }
bool MultiStorePasswordSaveManager::IsOptedInForAccountStorage() { // static
MultiStorePasswordSaveManager::PendingCredentialsStates
MultiStorePasswordSaveManager::ComputePendingCredentialsStates(
const PasswordForm& parsed_submitted_form,
const std::vector<const PasswordForm*>& matches) {
PendingCredentialsStates result;
// Try to find a similar existing saved form from each of the stores.
result.similar_saved_form_from_profile_store =
password_manager_util::GetMatchForUpdating(parsed_submitted_form,
ProfileStoreMatches(matches));
result.similar_saved_form_from_account_store =
password_manager_util::GetMatchForUpdating(parsed_submitted_form,
AccountStoreMatches(matches));
// Compute the PendingCredentialsState (i.e. what to do - save, update, silent
// update) separately for the two stores.
result.profile_store_state = ComputePendingCredentialsState(
parsed_submitted_form, result.similar_saved_form_from_profile_store);
result.account_store_state = ComputePendingCredentialsState(
parsed_submitted_form, result.similar_saved_form_from_account_store);
return result;
}
bool MultiStorePasswordSaveManager::IsOptedInForAccountStorage() const {
return client_->GetPasswordFeatureManager()->IsOptedInForAccountStorage(); return client_->GetPasswordFeatureManager()->IsOptedInForAccountStorage();
} }
bool MultiStorePasswordSaveManager::AccountStoreIsDefault() const {
return client_->GetPasswordFeatureManager()->GetDefaultPasswordStore() ==
PasswordForm::Store::kAccountStore;
}
} // namespace password_manager } // namespace password_manager
...@@ -27,12 +27,6 @@ class MultiStorePasswordSaveManager : public PasswordSaveManagerImpl { ...@@ -27,12 +27,6 @@ class MultiStorePasswordSaveManager : public PasswordSaveManagerImpl {
std::unique_ptr<FormSaver> account_form_saver); std::unique_ptr<FormSaver> account_form_saver);
~MultiStorePasswordSaveManager() override; ~MultiStorePasswordSaveManager() override;
void SaveInternal(const std::vector<const autofill::PasswordForm*>& matches,
const base::string16& old_password) override;
void UpdateInternal(const std::vector<const autofill::PasswordForm*>& matches,
const base::string16& old_password) override;
void PermanentlyBlacklist( void PermanentlyBlacklist(
const PasswordStore::FormDigest& form_digest) override; const PasswordStore::FormDigest& form_digest) override;
void Unblacklist(const PasswordStore::FormDigest& form_digest) override; void Unblacklist(const PasswordStore::FormDigest& form_digest) override;
...@@ -42,6 +36,8 @@ class MultiStorePasswordSaveManager : public PasswordSaveManagerImpl { ...@@ -42,6 +36,8 @@ class MultiStorePasswordSaveManager : public PasswordSaveManagerImpl {
void MoveCredentialsToAccountStore() override; void MoveCredentialsToAccountStore() override;
protected: protected:
void SavePendingToStoreImpl(
const autofill::PasswordForm& parsed_submitted_form) override;
std::pair<const autofill::PasswordForm*, PendingCredentialsState> std::pair<const autofill::PasswordForm*, PendingCredentialsState>
FindSimilarSavedFormAndComputeState( FindSimilarSavedFormAndComputeState(
const autofill::PasswordForm& parsed_submitted_form) const override; const autofill::PasswordForm& parsed_submitted_form) const override;
...@@ -50,9 +46,24 @@ class MultiStorePasswordSaveManager : public PasswordSaveManagerImpl { ...@@ -50,9 +46,24 @@ class MultiStorePasswordSaveManager : public PasswordSaveManagerImpl {
const std::vector<const autofill::PasswordForm*>& matches) override; const std::vector<const autofill::PasswordForm*>& matches) override;
private: private:
bool IsOptedInForAccountStorage(); struct PendingCredentialsStates {
PendingCredentialsState profile_store_state = PendingCredentialsState::NONE;
PendingCredentialsState account_store_state = PendingCredentialsState::NONE;
const autofill::PasswordForm* similar_saved_form_from_profile_store =
nullptr;
const autofill::PasswordForm* similar_saved_form_from_account_store =
nullptr;
};
static PendingCredentialsStates ComputePendingCredentialsStates(
const autofill::PasswordForm& parsed_submitted_form,
const std::vector<const autofill::PasswordForm*>& matches);
bool IsOptedInForAccountStorage() const;
bool AccountStoreIsDefault() const;
const std::unique_ptr<FormSaver> account_store_form_saver_; const std::unique_ptr<FormSaver> account_store_form_saver_;
DISALLOW_COPY_AND_ASSIGN(MultiStorePasswordSaveManager); DISALLOW_COPY_AND_ASSIGN(MultiStorePasswordSaveManager);
}; };
......
...@@ -298,8 +298,7 @@ TEST_F(MultiStorePasswordSaveManagerTest, SaveInProfileStore) { ...@@ -298,8 +298,7 @@ TEST_F(MultiStorePasswordSaveManagerTest, SaveInProfileStore) {
password_save_manager()->Save(observed_form_, parsed_submitted_form); password_save_manager()->Save(observed_form_, parsed_submitted_form);
} }
TEST_F(MultiStorePasswordSaveManagerTest, TEST_F(MultiStorePasswordSaveManagerTest, UpdateInAccountStoreOnly) {
UpdateBothStoresIfCredentialsExistInAccountStoreOnly) {
SetAccountStoreEnabled(/*is_enabled=*/true); SetAccountStoreEnabled(/*is_enabled=*/true);
PasswordForm saved_match_in_account_store(saved_match_); PasswordForm saved_match_in_account_store(saved_match_);
...@@ -317,14 +316,13 @@ TEST_F(MultiStorePasswordSaveManagerTest, ...@@ -317,14 +316,13 @@ TEST_F(MultiStorePasswordSaveManagerTest,
// An update prompt should be shown. // An update prompt should be shown.
EXPECT_TRUE(password_save_manager()->IsPasswordUpdate()); EXPECT_TRUE(password_save_manager()->IsPasswordUpdate());
EXPECT_CALL(*mock_profile_form_saver(), Update(_, _, _)); EXPECT_CALL(*mock_profile_form_saver(), Update(_, _, _)).Times(0);
EXPECT_CALL(*mock_account_form_saver(), Update(_, _, _)); EXPECT_CALL(*mock_account_form_saver(), Update(_, _, _));
password_save_manager()->Save(observed_form_, parsed_submitted_form_); password_save_manager()->Save(observed_form_, parsed_submitted_form_);
} }
TEST_F(MultiStorePasswordSaveManagerTest, TEST_F(MultiStorePasswordSaveManagerTest, UpdateInProfileStoreOnly) {
UpdateBothStoresIfCredentialsExistInProfileStoreOnly) {
SetAccountStoreEnabled(/*is_enabled=*/true); SetAccountStoreEnabled(/*is_enabled=*/true);
PasswordForm saved_match_in_profile_store(saved_match_); PasswordForm saved_match_in_profile_store(saved_match_);
...@@ -343,13 +341,12 @@ TEST_F(MultiStorePasswordSaveManagerTest, ...@@ -343,13 +341,12 @@ TEST_F(MultiStorePasswordSaveManagerTest,
EXPECT_TRUE(password_save_manager()->IsPasswordUpdate()); EXPECT_TRUE(password_save_manager()->IsPasswordUpdate());
EXPECT_CALL(*mock_profile_form_saver(), Update(_, _, _)); EXPECT_CALL(*mock_profile_form_saver(), Update(_, _, _));
EXPECT_CALL(*mock_account_form_saver(), Update(_, _, _)); EXPECT_CALL(*mock_account_form_saver(), Update(_, _, _)).Times(0);
password_save_manager()->Save(observed_form_, parsed_submitted_form_); password_save_manager()->Save(observed_form_, parsed_submitted_form_);
} }
TEST_F(MultiStorePasswordSaveManagerTest, TEST_F(MultiStorePasswordSaveManagerTest, UpdateInBothStores) {
UpdateBothStoresIfCredentialsExistInBothStores) {
SetAccountStoreEnabled(/*is_enabled=*/true); SetAccountStoreEnabled(/*is_enabled=*/true);
PasswordForm saved_match_in_profile_store(saved_match_); PasswordForm saved_match_in_profile_store(saved_match_);
......
...@@ -157,7 +157,7 @@ void PasswordSaveManagerImpl::CreatePendingCredentials( ...@@ -157,7 +157,7 @@ void PasswordSaveManagerImpl::CreatePendingCredentials(
const FormData& submitted_form, const FormData& submitted_form,
bool is_http_auth, bool is_http_auth,
bool is_credential_api_save) { bool is_credential_api_save) {
const PasswordForm* similar_saved_form; const PasswordForm* similar_saved_form = nullptr;
std::tie(similar_saved_form, pending_credentials_state_) = std::tie(similar_saved_form, pending_credentials_state_) =
FindSimilarSavedFormAndComputeState(parsed_submitted_form); FindSimilarSavedFormAndComputeState(parsed_submitted_form);
...@@ -451,29 +451,37 @@ void PasswordSaveManagerImpl::SavePendingToStore( ...@@ -451,29 +451,37 @@ void PasswordSaveManagerImpl::SavePendingToStore(
const PasswordForm& parsed_submitted_form) { const PasswordForm& parsed_submitted_form) {
UploadVotesAndMetrics(observed_form, parsed_submitted_form); UploadVotesAndMetrics(observed_form, parsed_submitted_form);
bool update = !IsNewLogin();
const PasswordForm* similar_saved_form =
FindSimilarSavedFormAndComputeState(parsed_submitted_form).first;
if (update && !pending_credentials_.IsFederatedCredential())
DCHECK(similar_saved_form);
base::string16 old_password = similar_saved_form
? similar_saved_form->password_value
: base::string16();
if (HasGeneratedPassword()) { if (HasGeneratedPassword()) {
generation_manager_->CommitGeneratedPassword( generation_manager_->CommitGeneratedPassword(
pending_credentials_, form_fetcher_->GetAllRelevantMatches(), pending_credentials_, form_fetcher_->GetAllRelevantMatches(),
old_password, GetFormSaverForGeneration()); GetOldPassword(parsed_submitted_form), GetFormSaverForGeneration());
} else if (update) { } else {
SavePendingToStoreImpl(parsed_submitted_form);
}
}
void PasswordSaveManagerImpl::SavePendingToStoreImpl(
const PasswordForm& parsed_submitted_form) {
auto matches = form_fetcher_->GetAllRelevantMatches();
base::string16 old_password = GetOldPassword(parsed_submitted_form);
if (IsNewLogin()) {
form_saver_->Save(pending_credentials_, matches, old_password);
} else {
// It sounds wrong that we still update even if the state is NONE. We // It sounds wrong that we still update even if the state is NONE. We
// should double check if this actually necessary. Currently some tests // should double check if this actually necessary. Currently some tests
// depend on this behavior. // depend on this behavior.
UpdateInternal(form_fetcher_->GetAllRelevantMatches(), old_password); form_saver_->Update(pending_credentials_, matches, old_password);
} else {
SaveInternal(form_fetcher_->GetAllRelevantMatches(), old_password);
} }
} }
base::string16 PasswordSaveManagerImpl::GetOldPassword(
const PasswordForm& parsed_submitted_form) const {
const PasswordForm* similar_saved_form =
FindSimilarSavedFormAndComputeState(parsed_submitted_form).first;
return similar_saved_form ? similar_saved_form->password_value
: base::string16();
}
void PasswordSaveManagerImpl::UploadVotesAndMetrics( void PasswordSaveManagerImpl::UploadVotesAndMetrics(
const FormData& observed_form, const FormData& observed_form,
const PasswordForm& parsed_submitted_form) { const PasswordForm& parsed_submitted_form) {
...@@ -530,18 +538,6 @@ PasswordSaveManagerImpl::GetRelevantMatchesForGeneration( ...@@ -530,18 +538,6 @@ PasswordSaveManagerImpl::GetRelevantMatchesForGeneration(
return matches; return matches;
} }
void PasswordSaveManagerImpl::SaveInternal(
const std::vector<const PasswordForm*>& matches,
const base::string16& old_password) {
form_saver_->Save(pending_credentials_, matches, old_password);
}
void PasswordSaveManagerImpl::UpdateInternal(
const std::vector<const PasswordForm*>& matches,
const base::string16& old_password) {
form_saver_->Update(pending_credentials_, matches, old_password);
}
void PasswordSaveManagerImpl::CloneInto(PasswordSaveManagerImpl* clone) { void PasswordSaveManagerImpl::CloneInto(PasswordSaveManagerImpl* clone) {
DCHECK(clone); DCHECK(clone);
if (generation_manager_) if (generation_manager_)
......
...@@ -111,13 +111,8 @@ class PasswordSaveManagerImpl : public PasswordSaveManager { ...@@ -111,13 +111,8 @@ class PasswordSaveManagerImpl : public PasswordSaveManager {
GetRelevantMatchesForGeneration( GetRelevantMatchesForGeneration(
const std::vector<const autofill::PasswordForm*>& matches); const std::vector<const autofill::PasswordForm*>& matches);
virtual void SaveInternal( virtual void SavePendingToStoreImpl(
const std::vector<const autofill::PasswordForm*>& matches, const autofill::PasswordForm& parsed_submitted_form);
const base::string16& old_password);
virtual void UpdateInternal(
const std::vector<const autofill::PasswordForm*>& matches,
const base::string16& old_password);
// Clones the current object into |clone|. |clone| must not be null. // Clones the current object into |clone|. |clone| must not be null.
void CloneInto(PasswordSaveManagerImpl* clone); void CloneInto(PasswordSaveManagerImpl* clone);
...@@ -142,6 +137,9 @@ class PasswordSaveManagerImpl : public PasswordSaveManager { ...@@ -142,6 +137,9 @@ class PasswordSaveManagerImpl : public PasswordSaveManager {
const FormFetcher* form_fetcher_; const FormFetcher* form_fetcher_;
private: private:
base::string16 GetOldPassword(
const autofill::PasswordForm& parsed_submitted_form) const;
void SetVotesAndRecordMetricsForPendingCredentials( void SetVotesAndRecordMetricsForPendingCredentials(
const autofill::PasswordForm& parsed_submitted_form); const autofill::PasswordForm& parsed_submitted_form);
......
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