Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / password_manager / password_store_win.cc
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 }