password_store.cc revision 6e8cce623b6e4fe0c9e4af605d675dd9d0338c38
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 229void PasswordStore::NotifyLoginsChanged( 230 const PasswordStoreChangeList& changes) { 231 DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread()); 232 if (!changes.empty()) { 233 observers_->Notify(&Observer::OnLoginsChanged, changes); 234#if defined(PASSWORD_MANAGER_ENABLE_SYNC) 235 if (syncable_service_) 236 syncable_service_->ActOnPasswordStoreChanges(changes); 237#endif 238 } 239} 240 241template<typename BackendFunc> 242void PasswordStore::Schedule( 243 BackendFunc func, 244 PasswordStoreConsumer* consumer) { 245 GetLoginsRequest* request = new GetLoginsRequest(consumer); 246 consumer->cancelable_task_tracker()->PostTask( 247 GetBackgroundTaskRunner(), 248 FROM_HERE, 249 base::Bind(func, this, base::Owned(request))); 250} 251 252void PasswordStore::WrapModificationTask(ModificationTask task) { 253 PasswordStoreChangeList changes = task.Run(); 254 NotifyLoginsChanged(changes); 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