Home | History | Annotate | Download | only in browser
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "components/password_manager/core/browser/password_store.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/debug/dump_without_crashing.h"
      9 #include "base/memory/scoped_ptr.h"
     10 #include "base/message_loop/message_loop.h"
     11 #include "base/message_loop/message_loop_proxy.h"
     12 #include "base/metrics/histogram.h"
     13 #include "base/stl_util.h"
     14 #include "components/autofill/core/common/password_form.h"
     15 #include "components/password_manager/core/browser/password_store_consumer.h"
     16 #include "components/password_manager/core/browser/password_syncable_service.h"
     17 
     18 #if defined(PASSWORD_MANAGER_ENABLE_SYNC)
     19 #include "components/password_manager/core/browser/password_syncable_service.h"
     20 #endif
     21 
     22 using autofill::PasswordForm;
     23 
     24 namespace password_manager {
     25 
     26 namespace {
     27 
     28 // Calls |consumer| back with the request result, if |consumer| is still alive.
     29 // Takes ownership of the elements in |result|, passing ownership to |consumer|
     30 // if it is still alive.
     31 void MaybeCallConsumerCallback(base::WeakPtr<PasswordStoreConsumer> consumer,
     32                                scoped_ptr<std::vector<PasswordForm*> > result) {
     33   if (consumer.get())
     34     consumer->OnGetPasswordStoreResults(*result);
     35   else
     36     STLDeleteElements(result.get());
     37 }
     38 
     39 // http://crbug.com/404012. Let's see where the empty fields come from.
     40 void CheckForEmptyUsernameAndPassword(const PasswordForm& form) {
     41   if (form.username_value.empty() &&
     42       form.password_value.empty() &&
     43       !form.blacklisted_by_user)
     44     base::debug::DumpWithoutCrashing();
     45 }
     46 
     47 }  // namespace
     48 
     49 PasswordStore::GetLoginsRequest::GetLoginsRequest(
     50     PasswordStoreConsumer* consumer)
     51     : consumer_weak_(consumer->GetWeakPtr()),
     52       result_(new std::vector<PasswordForm*>()) {
     53   DCHECK(thread_checker_.CalledOnValidThread());
     54   origin_loop_ = base::MessageLoopProxy::current();
     55 }
     56 
     57 PasswordStore::GetLoginsRequest::~GetLoginsRequest() {
     58 }
     59 
     60 void PasswordStore::GetLoginsRequest::ApplyIgnoreLoginsCutoff() {
     61   if (!ignore_logins_cutoff_.is_null()) {
     62     // Count down rather than up since we may be deleting elements.
     63     // Note that in principle it could be more efficient to copy the whole array
     64     // since that's worst-case linear time, but we expect that elements will be
     65     // deleted rarely and lists will be small, so this avoids the copies.
     66     for (size_t i = result_->size(); i > 0; --i) {
     67       if ((*result_)[i - 1]->date_created < ignore_logins_cutoff_) {
     68         delete (*result_)[i - 1];
     69         result_->erase(result_->begin() + (i - 1));
     70       }
     71     }
     72   }
     73 }
     74 
     75 void PasswordStore::GetLoginsRequest::ForwardResult() {
     76   origin_loop_->PostTask(FROM_HERE,
     77                          base::Bind(&MaybeCallConsumerCallback,
     78                                     consumer_weak_,
     79                                     base::Passed(result_.Pass())));
     80 }
     81 
     82 PasswordStore::PasswordStore(
     83     scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
     84     scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner)
     85     : main_thread_runner_(main_thread_runner),
     86       db_thread_runner_(db_thread_runner),
     87       observers_(new ObserverListThreadSafe<Observer>()),
     88       shutdown_called_(false) {}
     89 
     90 bool PasswordStore::Init(const syncer::SyncableService::StartSyncFlare& flare,
     91                          const std::string& sync_username) {
     92   ReportMetrics(sync_username);
     93 #if defined(PASSWORD_MANAGER_ENABLE_SYNC)
     94   ScheduleTask(base::Bind(&PasswordStore::InitSyncableService, this, flare));
     95 #endif
     96   return true;
     97 }
     98 
     99 void PasswordStore::AddLogin(const PasswordForm& form) {
    100   CheckForEmptyUsernameAndPassword(form);
    101   ScheduleTask(
    102       base::Bind(&PasswordStore::WrapModificationTask, this,
    103                  base::Bind(&PasswordStore::AddLoginImpl, this, form)));
    104 }
    105 
    106 void PasswordStore::UpdateLogin(const PasswordForm& form) {
    107   CheckForEmptyUsernameAndPassword(form);
    108   ScheduleTask(
    109       base::Bind(&PasswordStore::WrapModificationTask, this,
    110                  base::Bind(&PasswordStore::UpdateLoginImpl, this, form)));
    111 }
    112 
    113 void PasswordStore::RemoveLogin(const PasswordForm& form) {
    114   ScheduleTask(
    115       base::Bind(&PasswordStore::WrapModificationTask, this,
    116                  base::Bind(&PasswordStore::RemoveLoginImpl, this, form)));
    117 }
    118 
    119 void PasswordStore::RemoveLoginsCreatedBetween(base::Time delete_begin,
    120                                                base::Time delete_end) {
    121   ScheduleTask(
    122       base::Bind(&PasswordStore::WrapModificationTask, this,
    123                  base::Bind(&PasswordStore::RemoveLoginsCreatedBetweenImpl,
    124                             this, delete_begin, delete_end)));
    125 }
    126 
    127 void PasswordStore::RemoveLoginsSyncedBetween(base::Time delete_begin,
    128                                               base::Time delete_end) {
    129   ScheduleTask(
    130       base::Bind(&PasswordStore::WrapModificationTask,
    131                  this,
    132                  base::Bind(&PasswordStore::RemoveLoginsSyncedBetweenImpl,
    133                             this,
    134                             delete_begin,
    135                             delete_end)));
    136 }
    137 
    138 void PasswordStore::GetLogins(
    139     const PasswordForm& form,
    140     AuthorizationPromptPolicy prompt_policy,
    141     PasswordStoreConsumer* consumer) {
    142   // Per http://crbug.com/121738, we deliberately ignore saved logins for
    143   // http*://www.google.com/ that were stored prior to 2012. (Google now uses
    144   // https://accounts.google.com/ for all login forms, so these should be
    145   // unused.) We don't delete them just yet, and they'll still be visible in the
    146   // password manager, but we won't use them to autofill any forms. This is a
    147   // security feature to help minimize damage that can be done by XSS attacks.
    148   // TODO(mdm): actually delete them at some point, say M24 or so.
    149   base::Time ignore_logins_cutoff;  // the null time
    150   if (form.scheme == PasswordForm::SCHEME_HTML &&
    151       (form.signon_realm == "http://www.google.com" ||
    152        form.signon_realm == "http://www.google.com/" ||
    153        form.signon_realm == "https://www.google.com" ||
    154        form.signon_realm == "https://www.google.com/")) {
    155     static const base::Time::Exploded exploded_cutoff =
    156         { 2012, 1, 0, 1, 0, 0, 0, 0 };  // 00:00 Jan 1 2012
    157     ignore_logins_cutoff = base::Time::FromUTCExploded(exploded_cutoff);
    158   }
    159   GetLoginsRequest* request = new GetLoginsRequest(consumer);
    160   request->set_ignore_logins_cutoff(ignore_logins_cutoff);
    161 
    162   ConsumerCallbackRunner callback_runner =
    163       base::Bind(&PasswordStore::CopyAndForwardLoginsResult,
    164                  this, base::Owned(request));
    165   ScheduleTask(base::Bind(&PasswordStore::GetLoginsImpl,
    166                           this, form, prompt_policy, callback_runner));
    167 }
    168 
    169 void PasswordStore::GetAutofillableLogins(PasswordStoreConsumer* consumer) {
    170   Schedule(&PasswordStore::GetAutofillableLoginsImpl, consumer);
    171 }
    172 
    173 void PasswordStore::GetBlacklistLogins(PasswordStoreConsumer* consumer) {
    174   Schedule(&PasswordStore::GetBlacklistLoginsImpl, consumer);
    175 }
    176 
    177 void PasswordStore::ReportMetrics(const std::string& sync_username) {
    178   ScheduleTask(base::Bind(&PasswordStore::ReportMetricsImpl, this,
    179                           sync_username));
    180 }
    181 
    182 void PasswordStore::AddObserver(Observer* observer) {
    183   observers_->AddObserver(observer);
    184 }
    185 
    186 void PasswordStore::RemoveObserver(Observer* observer) {
    187   observers_->RemoveObserver(observer);
    188 }
    189 
    190 bool PasswordStore::ScheduleTask(const base::Closure& task) {
    191   scoped_refptr<base::SingleThreadTaskRunner> task_runner(
    192       GetBackgroundTaskRunner());
    193   if (task_runner.get())
    194     return task_runner->PostTask(FROM_HERE, task);
    195   return false;
    196 }
    197 
    198 void PasswordStore::Shutdown() {
    199 #if defined(PASSWORD_MANAGER_ENABLE_SYNC)
    200   ScheduleTask(base::Bind(&PasswordStore::DestroySyncableService, this));
    201 #endif
    202   shutdown_called_ = true;
    203 }
    204 
    205 #if defined(PASSWORD_MANAGER_ENABLE_SYNC)
    206 base::WeakPtr<syncer::SyncableService>
    207     PasswordStore::GetPasswordSyncableService() {
    208   DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
    209   DCHECK(syncable_service_);
    210   return syncable_service_->AsWeakPtr();
    211 }
    212 #endif
    213 
    214 PasswordStore::~PasswordStore() { DCHECK(shutdown_called_); }
    215 
    216 scoped_refptr<base::SingleThreadTaskRunner>
    217 PasswordStore::GetBackgroundTaskRunner() {
    218   return db_thread_runner_;
    219 }
    220 
    221 void PasswordStore::ForwardLoginsResult(GetLoginsRequest* request) {
    222   request->ApplyIgnoreLoginsCutoff();
    223   request->ForwardResult();
    224 }
    225 
    226 void PasswordStore::CopyAndForwardLoginsResult(
    227     PasswordStore::GetLoginsRequest* request,
    228     const std::vector<PasswordForm*>& matched_forms) {
    229   // Copy the contents of |matched_forms| into the request. The request takes
    230   // ownership of the PasswordForm elements.
    231   *(request->result()) = matched_forms;
    232   ForwardLoginsResult(request);
    233 }
    234 
    235 void PasswordStore::LogStatsForBulkDeletion(int num_deletions) {
    236   UMA_HISTOGRAM_COUNTS("PasswordManager.NumPasswordsDeletedByBulkDelete",
    237                        num_deletions);
    238 }
    239 
    240 void PasswordStore::NotifyLoginsChanged(
    241     const PasswordStoreChangeList& changes) {
    242   DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
    243   if (!changes.empty()) {
    244     observers_->Notify(&Observer::OnLoginsChanged, changes);
    245 #if defined(PASSWORD_MANAGER_ENABLE_SYNC)
    246     if (syncable_service_)
    247       syncable_service_->ActOnPasswordStoreChanges(changes);
    248 #endif
    249   }
    250 }
    251 
    252 template<typename BackendFunc>
    253 void PasswordStore::Schedule(
    254     BackendFunc func,
    255     PasswordStoreConsumer* consumer) {
    256   GetLoginsRequest* request = new GetLoginsRequest(consumer);
    257   consumer->cancelable_task_tracker()->PostTask(
    258       GetBackgroundTaskRunner().get(),
    259       FROM_HERE,
    260       base::Bind(func, this, base::Owned(request)));
    261 }
    262 
    263 void PasswordStore::WrapModificationTask(ModificationTask task) {
    264   PasswordStoreChangeList changes = task.Run();
    265   NotifyLoginsChanged(changes);
    266 }
    267 
    268 #if defined(PASSWORD_MANAGER_ENABLE_SYNC)
    269 void PasswordStore::InitSyncableService(
    270     const syncer::SyncableService::StartSyncFlare& flare) {
    271   DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
    272   DCHECK(!syncable_service_);
    273   syncable_service_.reset(new PasswordSyncableService(this));
    274   syncable_service_->InjectStartSyncFlare(flare);
    275 }
    276 
    277 void PasswordStore::DestroySyncableService() {
    278   DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
    279   syncable_service_.reset();
    280 }
    281 #endif
    282 
    283 }  // namespace password_manager
    284