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