Home | History | Annotate | Download | only in password_manager
      1 // Copyright (c) 2012 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 "chrome/browser/password_manager/password_store.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/memory/scoped_ptr.h"
      9 #include "base/message_loop/message_loop.h"
     10 #include "base/message_loop/message_loop_proxy.h"
     11 #include "base/metrics/histogram.h"
     12 #include "base/stl_util.h"
     13 #include "chrome/browser/password_manager/password_store_consumer.h"
     14 #include "components/autofill/core/common/password_form.h"
     15 #include "content/public/browser/browser_thread.h"
     16 
     17 using autofill::PasswordForm;
     18 using content::BrowserThread;
     19 using std::vector;
     20 
     21 namespace {
     22 
     23 // PasswordStoreConsumer callback requires vector const reference.
     24 void RunConsumerCallbackIfNotCanceled(
     25     const CancelableTaskTracker::IsCanceledCallback& is_canceled_cb,
     26     PasswordStoreConsumer* consumer,
     27     const vector<PasswordForm*>* matched_forms) {
     28   if (is_canceled_cb.Run()) {
     29     STLDeleteContainerPointers(matched_forms->begin(), matched_forms->end());
     30     return;
     31   }
     32 
     33   // OnGetPasswordStoreResults owns PasswordForms in the vector.
     34   consumer->OnGetPasswordStoreResults(*matched_forms);
     35 }
     36 
     37 void PostConsumerCallback(
     38     base::TaskRunner* task_runner,
     39     const CancelableTaskTracker::IsCanceledCallback& is_canceled_cb,
     40     PasswordStoreConsumer* consumer,
     41     const base::Time& ignore_logins_cutoff,
     42     const vector<PasswordForm*>& matched_forms) {
     43   vector<PasswordForm*>* matched_forms_copy = new vector<PasswordForm*>();
     44   if (ignore_logins_cutoff.is_null()) {
     45     *matched_forms_copy = matched_forms;
     46   } else {
     47     // Apply |ignore_logins_cutoff| and delete old ones.
     48     for (size_t i = 0; i < matched_forms.size(); i++) {
     49       if (matched_forms[i]->date_created < ignore_logins_cutoff)
     50         delete matched_forms[i];
     51       else
     52         matched_forms_copy->push_back(matched_forms[i]);
     53     }
     54   }
     55 
     56   task_runner->PostTask(
     57       FROM_HERE,
     58       base::Bind(&RunConsumerCallbackIfNotCanceled,
     59                  is_canceled_cb, consumer, base::Owned(matched_forms_copy)));
     60 }
     61 
     62 }  // namespace
     63 
     64 PasswordStore::GetLoginsRequest::GetLoginsRequest(
     65     const GetLoginsCallback& callback)
     66     : CancelableRequest1<GetLoginsCallback, vector<PasswordForm*> >(callback) {
     67 }
     68 
     69 void PasswordStore::GetLoginsRequest::ApplyIgnoreLoginsCutoff() {
     70   if (!ignore_logins_cutoff_.is_null()) {
     71     // Count down rather than up since we may be deleting elements.
     72     // Note that in principle it could be more efficient to copy the whole array
     73     // since that's worst-case linear time, but we expect that elements will be
     74     // deleted rarely and lists will be small, so this avoids the copies.
     75     for (size_t i = value.size(); i > 0; --i) {
     76       if (value[i - 1]->date_created < ignore_logins_cutoff_) {
     77         delete value[i - 1];
     78         value.erase(value.begin() + (i - 1));
     79       }
     80     }
     81   }
     82 }
     83 
     84 PasswordStore::GetLoginsRequest::~GetLoginsRequest() {
     85   if (canceled()) {
     86     STLDeleteElements(&value);
     87   }
     88 }
     89 
     90 PasswordStore::PasswordStore() {
     91 }
     92 
     93 bool PasswordStore::Init() {
     94   ReportMetrics();
     95   return true;
     96 }
     97 
     98 void PasswordStore::AddLogin(const PasswordForm& form) {
     99   ScheduleTask(base::Bind(&PasswordStore::WrapModificationTask, this,
    100       base::Closure(base::Bind(&PasswordStore::AddLoginImpl, this, form))));
    101 }
    102 
    103 void PasswordStore::UpdateLogin(const PasswordForm& form) {
    104   ScheduleTask(base::Bind(&PasswordStore::WrapModificationTask, this,
    105       base::Closure(base::Bind(&PasswordStore::UpdateLoginImpl, this, form))));
    106 }
    107 
    108 void PasswordStore::RemoveLogin(const PasswordForm& form) {
    109   ScheduleTask(base::Bind(&PasswordStore::WrapModificationTask, this,
    110       base::Closure(base::Bind(&PasswordStore::RemoveLoginImpl, this, form))));
    111 }
    112 
    113 void PasswordStore::RemoveLoginsCreatedBetween(const base::Time& delete_begin,
    114                                                const base::Time& delete_end) {
    115   ScheduleTask(base::Bind(&PasswordStore::WrapModificationTask, this,
    116       base::Closure(
    117           base::Bind(&PasswordStore::RemoveLoginsCreatedBetweenImpl, this,
    118                      delete_begin, delete_end))));
    119 }
    120 
    121 CancelableTaskTracker::TaskId PasswordStore::GetLogins(
    122     const PasswordForm& form,
    123     AuthorizationPromptPolicy prompt_policy,
    124     PasswordStoreConsumer* consumer) {
    125   // Per http://crbug.com/121738, we deliberately ignore saved logins for
    126   // http*://www.google.com/ that were stored prior to 2012. (Google now uses
    127   // https://accounts.google.com/ for all login forms, so these should be
    128   // unused.) We don't delete them just yet, and they'll still be visible in the
    129   // password manager, but we won't use them to autofill any forms. This is a
    130   // security feature to help minimize damage that can be done by XSS attacks.
    131   // TODO(mdm): actually delete them at some point, say M24 or so.
    132   base::Time ignore_logins_cutoff;  // the null time
    133   if (form.scheme == PasswordForm::SCHEME_HTML &&
    134       (form.signon_realm == "http://www.google.com" ||
    135        form.signon_realm == "http://www.google.com/" ||
    136        form.signon_realm == "https://www.google.com" ||
    137        form.signon_realm == "https://www.google.com/")) {
    138     static const base::Time::Exploded exploded_cutoff =
    139         { 2012, 1, 0, 1, 0, 0, 0, 0 };  // 00:00 Jan 1 2012
    140     ignore_logins_cutoff = base::Time::FromUTCExploded(exploded_cutoff);
    141   }
    142 
    143   CancelableTaskTracker::IsCanceledCallback is_canceled_cb;
    144   CancelableTaskTracker::TaskId id =
    145       consumer->cancelable_task_tracker()->NewTrackedTaskId(&is_canceled_cb);
    146 
    147   ConsumerCallbackRunner callback_runner =
    148       base::Bind(&PostConsumerCallback,
    149                  base::MessageLoopProxy::current(),
    150                  is_canceled_cb,
    151                  consumer,
    152                  ignore_logins_cutoff);
    153   ScheduleTask(base::Bind(&PasswordStore::GetLoginsImpl,
    154                           this, form, prompt_policy, callback_runner));
    155   return id;
    156 }
    157 
    158 CancelableRequestProvider::Handle PasswordStore::GetAutofillableLogins(
    159     PasswordStoreConsumer* consumer) {
    160   return Schedule(&PasswordStore::GetAutofillableLoginsImpl, consumer);
    161 }
    162 
    163 CancelableRequestProvider::Handle PasswordStore::GetBlacklistLogins(
    164     PasswordStoreConsumer* consumer) {
    165   return Schedule(&PasswordStore::GetBlacklistLoginsImpl, consumer);
    166 }
    167 
    168 void PasswordStore::ReportMetrics() {
    169   ScheduleTask(base::Bind(&PasswordStore::ReportMetricsImpl, this));
    170 }
    171 
    172 void PasswordStore::AddObserver(Observer* observer) {
    173   observers_.AddObserver(observer);
    174 }
    175 
    176 void PasswordStore::RemoveObserver(Observer* observer) {
    177   observers_.RemoveObserver(observer);
    178 }
    179 
    180 PasswordStore::~PasswordStore() {}
    181 
    182 PasswordStore::GetLoginsRequest* PasswordStore::NewGetLoginsRequest(
    183     const GetLoginsCallback& callback) {
    184   return new GetLoginsRequest(callback);
    185 }
    186 
    187 bool PasswordStore::ScheduleTask(const base::Closure& task) {
    188   return BrowserThread::PostTask(BrowserThread::DB, FROM_HERE, task);
    189 }
    190 
    191 void PasswordStore::ForwardLoginsResult(GetLoginsRequest* request) {
    192   request->ApplyIgnoreLoginsCutoff();
    193   request->ForwardResult(request->handle(), request->value);
    194 }
    195 
    196 void PasswordStore::LogStatsForBulkDeletion(int num_deletions) {
    197   UMA_HISTOGRAM_COUNTS("PasswordManager.NumPasswordsDeletedByBulkDelete",
    198                        num_deletions);
    199 }
    200 
    201 template<typename BackendFunc>
    202 CancelableRequestProvider::Handle PasswordStore::Schedule(
    203     BackendFunc func,
    204     PasswordStoreConsumer* consumer) {
    205   scoped_refptr<GetLoginsRequest> request(
    206       NewGetLoginsRequest(
    207           base::Bind(&PasswordStoreConsumer::OnPasswordStoreRequestDone,
    208                      base::Unretained(consumer))));
    209   AddRequest(request.get(), consumer->cancelable_consumer());
    210   ScheduleTask(base::Bind(func, this, request));
    211   return request->handle();
    212 }
    213 
    214 template<typename BackendFunc>
    215 CancelableRequestProvider::Handle PasswordStore::Schedule(
    216     BackendFunc func,
    217     PasswordStoreConsumer* consumer,
    218     const PasswordForm& form,
    219     const base::Time& ignore_logins_cutoff) {
    220   scoped_refptr<GetLoginsRequest> request(
    221       NewGetLoginsRequest(
    222           base::Bind(&PasswordStoreConsumer::OnPasswordStoreRequestDone,
    223                      base::Unretained(consumer))));
    224   request->set_ignore_logins_cutoff(ignore_logins_cutoff);
    225   AddRequest(request.get(), consumer->cancelable_consumer());
    226   ScheduleTask(base::Bind(func, this, request, form));
    227   return request->handle();
    228 }
    229 
    230 void PasswordStore::WrapModificationTask(base::Closure task) {
    231 #if !defined(OS_MACOSX)
    232   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
    233 #endif  // !defined(OS_MACOSX)
    234   task.Run();
    235   PostNotifyLoginsChanged();
    236 }
    237 
    238 void PasswordStore::PostNotifyLoginsChanged() {
    239 #if !defined(OS_MACOSX)
    240   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
    241 #endif  // !defined(OS_MACOSX)
    242   BrowserThread::PostTask(
    243       BrowserThread::UI, FROM_HERE,
    244       base::Bind(&PasswordStore::NotifyLoginsChanged, this));
    245 }
    246 
    247 void PasswordStore::NotifyLoginsChanged() {
    248   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    249   FOR_EACH_OBSERVER(Observer, observers_, OnLoginsChanged());
    250 }
    251