Commit bde4f91e authored by Tonko Sabolčec's avatar Tonko Sabolčec Committed by Commit Bot

[Password Manager] Determine status of PasswordStore::Init

Chrome doesn't handle failures when initializing PasswordStore.
This causes a bug that user is asked to save passwords when Chrome is
not able to save them.

This CL includes:
- Check if encryption is available on Mac.
- Check if login database was successfully initialized.

Bug: 479725
Change-Id: Ic491e2b04c98270b984a6f08a431b99863419116
Reviewed-on: https://chromium-review.googlesource.com/1243069
Commit-Queue: Tonko Sabolčec <tsabolcec@google.com>
Reviewed-by: default avatarDominic Battré <battre@chromium.org>
Reviewed-by: default avatarVasilii Sukhanov <vasilii@chromium.org>
Cr-Commit-Position: refs/heads/master@{#595068}
parent d93f7ed7
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "chrome/browser/password_manager/password_store_mac.h" #include "chrome/browser/password_manager/password_store_mac.h"
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "components/os_crypt/os_crypt.h"
#include "components/password_manager/core/common/password_manager_pref_names.h" #include "components/password_manager/core/common/password_manager_pref_names.h"
using password_manager::MigrationStatus; using password_manager::MigrationStatus;
...@@ -33,9 +34,13 @@ void PasswordStoreMac::ShutdownOnUIThread() { ...@@ -33,9 +34,13 @@ void PasswordStoreMac::ShutdownOnUIThread() {
PasswordStoreMac::~PasswordStoreMac() = default; PasswordStoreMac::~PasswordStoreMac() = default;
void PasswordStoreMac::InitOnBackgroundSequence( bool PasswordStoreMac::InitOnBackgroundSequence(
const syncer::SyncableService::StartSyncFlare& flare) { const syncer::SyncableService::StartSyncFlare& flare) {
PasswordStoreDefault::InitOnBackgroundSequence(flare); if (!PasswordStoreDefault::InitOnBackgroundSequence(flare))
return false;
if (!OSCrypt::IsEncryptionAvailable())
return false;
if (login_db() && (initial_status_ == MigrationStatus::NOT_STARTED || if (login_db() && (initial_status_ == MigrationStatus::NOT_STARTED ||
initial_status_ == MigrationStatus::FAILED_ONCE || initial_status_ == MigrationStatus::FAILED_ONCE ||
...@@ -53,6 +58,8 @@ void PasswordStoreMac::InitOnBackgroundSequence( ...@@ -53,6 +58,8 @@ void PasswordStoreMac::InitOnBackgroundSequence(
"PasswordManager.KeychainMigration.Status", "PasswordManager.KeychainMigration.Status",
static_cast<int>(initial_status_), static_cast<int>(initial_status_),
static_cast<int>(MigrationStatus::MIGRATION_STATUS_COUNT)); static_cast<int>(MigrationStatus::MIGRATION_STATUS_COUNT));
return true;
} }
void PasswordStoreMac::UpdateStatusPref(MigrationStatus status) { void PasswordStoreMac::UpdateStatusPref(MigrationStatus status) {
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "components/password_manager/core/browser/keychain_migration_status_mac.h" #include "components/password_manager/core/browser/keychain_migration_status_mac.h"
#include "components/password_manager/core/browser/password_store.h"
#include "components/password_manager/core/browser/password_store_default.h" #include "components/password_manager/core/browser/password_store_default.h"
#include "components/prefs/pref_member.h" #include "components/prefs/pref_member.h"
...@@ -35,7 +36,7 @@ class PasswordStoreMac : public password_manager::PasswordStoreDefault { ...@@ -35,7 +36,7 @@ class PasswordStoreMac : public password_manager::PasswordStoreDefault {
~PasswordStoreMac() override; ~PasswordStoreMac() override;
// PasswordStore: // PasswordStore:
void InitOnBackgroundSequence( bool InitOnBackgroundSequence(
const syncer::SyncableService::StartSyncFlare& flare) override; const syncer::SyncableService::StartSyncFlare& flare) override;
// Writes status to the prefs. // Writes status to the prefs.
......
...@@ -18,7 +18,9 @@ MockPasswordStore::CreateBackgroundTaskRunner() const { ...@@ -18,7 +18,9 @@ MockPasswordStore::CreateBackgroundTaskRunner() const {
return base::SequencedTaskRunnerHandle::Get(); return base::SequencedTaskRunnerHandle::Get();
} }
void MockPasswordStore::InitOnBackgroundSequence( bool MockPasswordStore::InitOnBackgroundSequence(
const syncer::SyncableService::StartSyncFlare& flare) {} const syncer::SyncableService::StartSyncFlare& flare) {
return true;
}
} // namespace password_manager } // namespace password_manager
...@@ -97,7 +97,7 @@ class MockPasswordStore : public PasswordStore { ...@@ -97,7 +97,7 @@ class MockPasswordStore : public PasswordStore {
// PasswordStore: // PasswordStore:
scoped_refptr<base::SequencedTaskRunner> CreateBackgroundTaskRunner() scoped_refptr<base::SequencedTaskRunner> CreateBackgroundTaskRunner()
const override; const override;
void InitOnBackgroundSequence( bool InitOnBackgroundSequence(
const syncer::SyncableService::StartSyncFlare& flare) override; const syncer::SyncableService::StartSyncFlare& flare) override;
}; };
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "base/stl_util.h" #include "base/stl_util.h"
#include "base/task/post_task.h" #include "base/task/post_task.h"
#include "base/task_runner_util.h"
#include "base/threading/sequenced_task_runner_handle.h" #include "base/threading/sequenced_task_runner_handle.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "components/autofill/core/common/form_data.h" #include "components/autofill/core/common/form_data.h"
...@@ -122,7 +123,8 @@ bool PasswordStore::FormDigest::operator==(const FormDigest& other) const { ...@@ -122,7 +123,8 @@ bool PasswordStore::FormDigest::operator==(const FormDigest& other) const {
PasswordStore::PasswordStore() PasswordStore::PasswordStore()
: observers_(new base::ObserverListThreadSafe<Observer>()), : observers_(new base::ObserverListThreadSafe<Observer>()),
is_propagating_password_changes_to_web_credentials_enabled_(false), is_propagating_password_changes_to_web_credentials_enabled_(false),
shutdown_called_(false) {} shutdown_called_(false),
init_status_(InitStatus::kUnknown) {}
bool PasswordStore::Init(const syncer::SyncableService::StartSyncFlare& flare, bool PasswordStore::Init(const syncer::SyncableService::StartSyncFlare& flare,
PrefService* prefs) { PrefService* prefs) {
...@@ -134,8 +136,12 @@ bool PasswordStore::Init(const syncer::SyncableService::StartSyncFlare& flare, ...@@ -134,8 +136,12 @@ bool PasswordStore::Init(const syncer::SyncableService::StartSyncFlare& flare,
prefs_ = prefs; prefs_ = prefs;
hash_password_manager_.set_prefs(prefs); hash_password_manager_.set_prefs(prefs);
#endif #endif
ScheduleTask(base::BindRepeating(&PasswordStore::InitOnBackgroundSequence, if (background_task_runner_) {
this, flare)); base::PostTaskAndReplyWithResult(
background_task_runner_.get(), FROM_HERE,
base::BindOnce(&PasswordStore::InitOnBackgroundSequence, this, flare),
base::BindOnce(&PasswordStore::OnInitCompleted, this));
}
return true; return true;
} }
...@@ -331,6 +337,10 @@ bool PasswordStore::ScheduleTask(const base::Closure& task) { ...@@ -331,6 +337,10 @@ bool PasswordStore::ScheduleTask(const base::Closure& task) {
return false; return false;
} }
bool PasswordStore::IsAbleToSavePasswords() const {
return init_status_ == InitStatus::kSuccess;
}
void PasswordStore::ShutdownOnUIThread() { void PasswordStore::ShutdownOnUIThread() {
ScheduleTask(base::Bind(&PasswordStore::DestroyOnBackgroundSequence, this)); ScheduleTask(base::Bind(&PasswordStore::DestroyOnBackgroundSequence, this));
// The AffiliationService must be destroyed from the main sequence. // The AffiliationService must be destroyed from the main sequence.
...@@ -468,7 +478,7 @@ PasswordStore::CreateBackgroundTaskRunner() const { ...@@ -468,7 +478,7 @@ PasswordStore::CreateBackgroundTaskRunner() const {
{base::MayBlock(), base::TaskPriority::USER_VISIBLE}); {base::MayBlock(), base::TaskPriority::USER_VISIBLE});
} }
void PasswordStore::InitOnBackgroundSequence( bool PasswordStore::InitOnBackgroundSequence(
const syncer::SyncableService::StartSyncFlare& flare) { const syncer::SyncableService::StartSyncFlare& flare) {
DCHECK(background_task_runner_->RunsTasksInCurrentSequence()); DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
DCHECK(!syncable_service_); DCHECK(!syncable_service_);
...@@ -480,6 +490,7 @@ void PasswordStore::InitOnBackgroundSequence( ...@@ -480,6 +490,7 @@ void PasswordStore::InitOnBackgroundSequence(
GetAutofillableLoginsImpl( GetAutofillableLoginsImpl(
std::make_unique<GetLoginsRequest>(reuse_detector_)); std::make_unique<GetLoginsRequest>(reuse_detector_));
#endif #endif
return true;
} }
void PasswordStore::GetLoginsImpl(const FormDigest& form, void PasswordStore::GetLoginsImpl(const FormDigest& form,
...@@ -604,6 +615,12 @@ void PasswordStore::ClearAllEnterprisePasswordHashImpl() { ...@@ -604,6 +615,12 @@ void PasswordStore::ClearAllEnterprisePasswordHashImpl() {
} }
#endif #endif
void PasswordStore::OnInitCompleted(bool success) {
DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
init_status_ = success ? InitStatus::kSuccess : InitStatus::kFailure;
// TODO(tsabolcec): Add UMA histogram to record the success rate.
}
void PasswordStore::Schedule( void PasswordStore::Schedule(
void (PasswordStore::*func)(std::unique_ptr<GetLoginsRequest>), void (PasswordStore::*func)(std::unique_ptr<GetLoginsRequest>),
PasswordStoreConsumer* consumer) { PasswordStoreConsumer* consumer) {
......
...@@ -252,6 +252,9 @@ class PasswordStore : protected PasswordStoreSync, ...@@ -252,6 +252,9 @@ class PasswordStore : protected PasswordStoreSync,
// Schedules the given |task| to be run on the PasswordStore's TaskRunner. // Schedules the given |task| to be run on the PasswordStore's TaskRunner.
bool ScheduleTask(const base::Closure& task); bool ScheduleTask(const base::Closure& task);
// Returns true iff initialization was successful.
bool IsAbleToSavePasswords() const;
base::WeakPtr<syncer::SyncableService> GetPasswordSyncableService(); base::WeakPtr<syncer::SyncableService> GetPasswordSyncableService();
// TODO(crbug.com/706392): Fix password reuse detection for Android. // TODO(crbug.com/706392): Fix password reuse detection for Android.
...@@ -369,6 +372,19 @@ class PasswordStore : protected PasswordStoreSync, ...@@ -369,6 +372,19 @@ class PasswordStore : protected PasswordStoreSync,
}; };
#endif #endif
// Status of PasswordStore::Init().
enum class InitStatus {
// Initialization status is still not determined (init hasn't started or
// finished yet).
kUnknown,
// Initialization is successfully finished.
kSuccess,
// There was an error during initialization and PasswordStore is not ready
// to save or get passwords.
// Removing passwords may still work.
kFailure,
};
~PasswordStore() override; ~PasswordStore() override;
// Create a TaskRunner to be saved in |background_task_runner_|. // Create a TaskRunner to be saved in |background_task_runner_|.
...@@ -376,8 +392,9 @@ class PasswordStore : protected PasswordStoreSync, ...@@ -376,8 +392,9 @@ class PasswordStore : protected PasswordStoreSync,
const; const;
// Creates PasswordSyncableService and PasswordReuseDetector instances on the // Creates PasswordSyncableService and PasswordReuseDetector instances on the
// background sequence. Subclasses can add more logic. // background sequence. Subclasses can add more logic. Returns true on
virtual void InitOnBackgroundSequence( // success.
virtual bool InitOnBackgroundSequence(
const syncer::SyncableService::StartSyncFlare& flare); const syncer::SyncableService::StartSyncFlare& flare);
// Methods below will be run in PasswordStore's own sequence. // Methods below will be run in PasswordStore's own sequence.
...@@ -521,6 +538,11 @@ class PasswordStore : protected PasswordStoreSync, ...@@ -521,6 +538,11 @@ class PasswordStore : protected PasswordStoreSync,
FRIEND_TEST_ALL_PREFIXES(PasswordStoreTest, FRIEND_TEST_ALL_PREFIXES(PasswordStoreTest,
UpdatePasswordsStoredForAffiliatedWebsites); UpdatePasswordsStoredForAffiliatedWebsites);
// Called on the main thread after initialization is completed.
// |success| is true if initialization was successful. Sets the
// |init_status_|.
void OnInitCompleted(bool success);
// Schedule the given |func| to be run in the PasswordStore's own sequence // Schedule the given |func| to be run in the PasswordStore's own sequence
// with responses delivered to |consumer| on the current sequence. // with responses delivered to |consumer| on the current sequence.
void Schedule(void (PasswordStore::*func)(std::unique_ptr<GetLoginsRequest>), void Schedule(void (PasswordStore::*func)(std::unique_ptr<GetLoginsRequest>),
...@@ -676,6 +698,8 @@ class PasswordStore : protected PasswordStoreSync, ...@@ -676,6 +698,8 @@ class PasswordStore : protected PasswordStoreSync,
bool shutdown_called_; bool shutdown_called_;
InitStatus init_status_;
DISALLOW_COPY_AND_ASSIGN(PasswordStore); DISALLOW_COPY_AND_ASSIGN(PasswordStore);
}; };
......
...@@ -28,15 +28,19 @@ void PasswordStoreDefault::ShutdownOnUIThread() { ...@@ -28,15 +28,19 @@ void PasswordStoreDefault::ShutdownOnUIThread() {
ScheduleTask(base::Bind(&PasswordStoreDefault::ResetLoginDB, this)); ScheduleTask(base::Bind(&PasswordStoreDefault::ResetLoginDB, this));
} }
void PasswordStoreDefault::InitOnBackgroundSequence( bool PasswordStoreDefault::InitOnBackgroundSequence(
const syncer::SyncableService::StartSyncFlare& flare) { const syncer::SyncableService::StartSyncFlare& flare) {
DCHECK(background_task_runner()->RunsTasksInCurrentSequence()); DCHECK(background_task_runner()->RunsTasksInCurrentSequence());
DCHECK(login_db_); DCHECK(login_db_);
bool success = true;
if (!login_db_->Init()) { if (!login_db_->Init()) {
login_db_.reset(); login_db_.reset();
// The initialization should be continued, because PasswordSyncableService
// has to be initialized even if database initialization failed.
success = false;
LOG(ERROR) << "Could not create/open login database."; LOG(ERROR) << "Could not create/open login database.";
} }
PasswordStore::InitOnBackgroundSequence(flare); return PasswordStore::InitOnBackgroundSequence(flare) && success;
} }
void PasswordStoreDefault::ReportMetricsImpl( void PasswordStoreDefault::ReportMetricsImpl(
......
...@@ -41,7 +41,7 @@ class PasswordStoreDefault : public PasswordStore { ...@@ -41,7 +41,7 @@ class PasswordStoreDefault : public PasswordStore {
~PasswordStoreDefault() override; ~PasswordStoreDefault() override;
// Opens |login_db_| on the background sequence. // Opens |login_db_| on the background sequence.
void InitOnBackgroundSequence( bool InitOnBackgroundSequence(
const syncer::SyncableService::StartSyncFlare& flare) override; const syncer::SyncableService::StartSyncFlare& flare) override;
// Implements PasswordStore interface. // Implements PasswordStore interface.
......
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