password_store.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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
22using autofill::PasswordForm;
23
24namespace password_manager {
25
26namespace {
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.
31void 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.
40void 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
49PasswordStore::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
57PasswordStore::GetLoginsRequest::~GetLoginsRequest() {
58}
59
60void 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
75void PasswordStore::GetLoginsRequest::ForwardResult() {
76  origin_loop_->PostTask(FROM_HERE,
77                         base::Bind(&MaybeCallConsumerCallback,
78                                    consumer_weak_,
79                                    base::Passed(result_.Pass())));
80}
81
82PasswordStore::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
90bool 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
99void 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
106void 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
113void PasswordStore::RemoveLogin(const PasswordForm& form) {
114  ScheduleTask(
115      base::Bind(&PasswordStore::WrapModificationTask, this,
116                 base::Bind(&PasswordStore::RemoveLoginImpl, this, form)));
117}
118
119void 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
127void 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
138void 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
169void PasswordStore::GetAutofillableLogins(PasswordStoreConsumer* consumer) {
170  Schedule(&PasswordStore::GetAutofillableLoginsImpl, consumer);
171}
172
173void PasswordStore::GetBlacklistLogins(PasswordStoreConsumer* consumer) {
174  Schedule(&PasswordStore::GetBlacklistLoginsImpl, consumer);
175}
176
177void PasswordStore::ReportMetrics(const std::string& sync_username) {
178  ScheduleTask(base::Bind(&PasswordStore::ReportMetricsImpl, this,
179                          sync_username));
180}
181
182void PasswordStore::AddObserver(Observer* observer) {
183  observers_->AddObserver(observer);
184}
185
186void PasswordStore::RemoveObserver(Observer* observer) {
187  observers_->RemoveObserver(observer);
188}
189
190bool 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
198void 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)
206base::WeakPtr<syncer::SyncableService>
207    PasswordStore::GetPasswordSyncableService() {
208  DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
209  DCHECK(syncable_service_);
210  return syncable_service_->AsWeakPtr();
211}
212#endif
213
214PasswordStore::~PasswordStore() { DCHECK(shutdown_called_); }
215
216scoped_refptr<base::SingleThreadTaskRunner>
217PasswordStore::GetBackgroundTaskRunner() {
218  return db_thread_runner_;
219}
220
221void PasswordStore::ForwardLoginsResult(GetLoginsRequest* request) {
222  request->ApplyIgnoreLoginsCutoff();
223  request->ForwardResult();
224}
225
226void 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
235void PasswordStore::LogStatsForBulkDeletion(int num_deletions) {
236  UMA_HISTOGRAM_COUNTS("PasswordManager.NumPasswordsDeletedByBulkDelete",
237                       num_deletions);
238}
239
240void 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
252template<typename BackendFunc>
253void 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
263void PasswordStore::WrapModificationTask(ModificationTask task) {
264  PasswordStoreChangeList changes = task.Run();
265  NotifyLoginsChanged(changes);
266}
267
268#if defined(PASSWORD_MANAGER_ENABLE_SYNC)
269void 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
277void PasswordStore::DestroySyncableService() {
278  DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
279  syncable_service_.reset();
280}
281#endif
282
283}  // namespace password_manager
284