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