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