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