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