password_store_win.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
1// Copyright (c) 2012 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 "chrome/browser/password_manager/password_store_win.h" 6 7#include <map> 8 9#include "base/bind.h" 10#include "base/logging.h" 11#include "base/memory/scoped_ptr.h" 12#include "base/strings/string_util.h" 13#include "base/strings/utf_string_conversions.h" 14#include "chrome/browser/password_manager/password_manager.h" 15#include "chrome/browser/webdata/web_data_service.h" 16#include "components/webdata/encryptor/ie7_password_win.h" 17#include "content/public/browser/browser_thread.h" 18 19using autofill::PasswordForm; 20using content::BrowserThread; 21 22// Handles requests to WebDataService. 23class PasswordStoreWin::DBHandler : public WebDataServiceConsumer { 24 public: 25 DBHandler(WebDataService* web_data_service, 26 PasswordStoreWin* password_store) 27 : web_data_service_(web_data_service), 28 password_store_(password_store) { 29 } 30 31 ~DBHandler(); 32 33 // Requests the IE7 login for |form|. This is async. |callback_runner| will be 34 // run when complete. 35 void GetIE7Login( 36 const PasswordForm& form, 37 const PasswordStoreWin::ConsumerCallbackRunner& callback_runner); 38 39 private: 40 struct RequestInfo { 41 RequestInfo() {} 42 43 RequestInfo(PasswordForm* request_form, 44 const PasswordStoreWin::ConsumerCallbackRunner& runner) 45 : form(request_form), 46 callback_runner(runner) {} 47 48 PasswordForm* form; 49 PasswordStoreWin::ConsumerCallbackRunner callback_runner; 50 }; 51 52 // Holds info associated with in-flight GetIE7Login requests. 53 typedef std::map<WebDataService::Handle, RequestInfo> PendingRequestMap; 54 55 // Gets logins from IE7 if no others are found. Also copies them into 56 // Chrome's WebDatabase so we don't need to look next time. 57 std::vector<autofill::PasswordForm*> GetIE7Results( 58 const WDTypedResult* result, 59 const PasswordForm& form); 60 61 // WebDataServiceConsumer implementation. 62 virtual void OnWebDataServiceRequestDone( 63 WebDataService::Handle handle, 64 const WDTypedResult* result) OVERRIDE; 65 66 scoped_refptr<WebDataService> web_data_service_; 67 68 // This creates a cycle between us and PasswordStore. The cycle is broken 69 // from PasswordStoreWin::Shutdown, which deletes us. 70 scoped_refptr<PasswordStoreWin> password_store_; 71 72 PendingRequestMap pending_requests_; 73 74 DISALLOW_COPY_AND_ASSIGN(DBHandler); 75}; 76 77PasswordStoreWin::DBHandler::~DBHandler() { 78 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 79 for (PendingRequestMap::const_iterator i = pending_requests_.begin(); 80 i != pending_requests_.end(); 81 ++i) { 82 web_data_service_->CancelRequest(i->first); 83 delete i->second.form; 84 } 85} 86 87void PasswordStoreWin::DBHandler::GetIE7Login( 88 const PasswordForm& form, 89 const PasswordStoreWin::ConsumerCallbackRunner& callback_runner) { 90 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 91 IE7PasswordInfo info; 92 info.url_hash = 93 ie7_password::GetUrlHash(base::UTF8ToWide(form.origin.spec())); 94 WebDataService::Handle handle = web_data_service_->GetIE7Login(info, this); 95 pending_requests_[handle] = 96 RequestInfo(new PasswordForm(form), callback_runner); 97} 98 99std::vector<PasswordForm*> PasswordStoreWin::DBHandler::GetIE7Results( 100 const WDTypedResult *result, 101 const PasswordForm& form) { 102 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 103 std::vector<PasswordForm*> matching_forms; 104 105 const WDResult<IE7PasswordInfo>* r = 106 static_cast<const WDResult<IE7PasswordInfo>*>(result); 107 IE7PasswordInfo info = r->GetValue(); 108 109 if (!info.encrypted_data.empty()) { 110 // We got a result. 111 // Delete the entry. If it's good we will add it to the real saved password 112 // table. 113 web_data_service_->RemoveIE7Login(info); 114 std::vector<ie7_password::DecryptedCredentials> credentials; 115 std::wstring url = base::ASCIIToWide(form.origin.spec()); 116 if (ie7_password::DecryptPasswords(url, 117 info.encrypted_data, 118 &credentials)) { 119 for (size_t i = 0; i < credentials.size(); ++i) { 120 PasswordForm* autofill = new PasswordForm(); 121 autofill->username_value = credentials[i].username; 122 autofill->password_value = credentials[i].password; 123 autofill->signon_realm = form.signon_realm; 124 autofill->origin = form.origin; 125 autofill->preferred = true; 126 autofill->ssl_valid = form.origin.SchemeIsSecure(); 127 autofill->date_created = info.date_created; 128 129 matching_forms.push_back(autofill); 130 // Add this PasswordForm to the saved password table. We're on the DB 131 // thread already, so we use AddLoginImpl. 132 password_store_->AddLoginImpl(*autofill); 133 } 134 } 135 } 136 return matching_forms; 137} 138 139void PasswordStoreWin::DBHandler::OnWebDataServiceRequestDone( 140 WebDataService::Handle handle, 141 const WDTypedResult* result) { 142 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 143 144 PendingRequestMap::iterator i = pending_requests_.find(handle); 145 DCHECK(i != pending_requests_.end()); 146 147 scoped_ptr<PasswordForm> form(i->second.form); 148 PasswordStoreWin::ConsumerCallbackRunner callback_runner( 149 i->second.callback_runner); 150 pending_requests_.erase(i); 151 152 if (!result) { 153 // The WDS returns NULL if it is shutting down. Run callback with empty 154 // result. 155 callback_runner.Run(std::vector<autofill::PasswordForm*>()); 156 return; 157 } 158 159 DCHECK_EQ(PASSWORD_IE7_RESULT, result->GetType()); 160 std::vector<autofill::PasswordForm*> matched_forms = 161 GetIE7Results(result, *form); 162 163 callback_runner.Run(matched_forms); 164} 165 166PasswordStoreWin::PasswordStoreWin( 167 scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner, 168 scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner, 169 LoginDatabase* login_database, 170 WebDataService* web_data_service) 171 : PasswordStoreDefault(main_thread_runner, 172 db_thread_runner, 173 login_database) { 174 db_handler_.reset(new DBHandler(web_data_service, this)); 175} 176 177PasswordStoreWin::~PasswordStoreWin() { 178} 179 180void PasswordStoreWin::ShutdownOnDBThread() { 181 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 182 db_handler_.reset(); 183} 184 185void PasswordStoreWin::Shutdown() { 186 BrowserThread::PostTask( 187 BrowserThread::DB, FROM_HERE, 188 base::Bind(&PasswordStoreWin::ShutdownOnDBThread, this)); 189 PasswordStoreDefault::Shutdown(); 190} 191 192void PasswordStoreWin::GetIE7LoginIfNecessary( 193 const PasswordForm& form, 194 const ConsumerCallbackRunner& callback_runner, 195 const std::vector<autofill::PasswordForm*>& matched_forms) { 196 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); 197 if (matched_forms.empty() && db_handler_.get()) { 198 db_handler_->GetIE7Login(form, callback_runner); 199 } else { 200 // No need to get IE7 login. 201 callback_runner.Run(matched_forms); 202 } 203} 204 205void PasswordStoreWin::GetLoginsImpl( 206 const PasswordForm& form, 207 AuthorizationPromptPolicy prompt_policy, 208 const ConsumerCallbackRunner& callback_runner) { 209 ConsumerCallbackRunner get_ie7_login = 210 base::Bind(&PasswordStoreWin::GetIE7LoginIfNecessary, 211 this, form, callback_runner); 212 PasswordStoreDefault::GetLoginsImpl(form, prompt_policy, get_ie7_login); 213} 214