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.
5 #include "chrome/browser/password_manager/password_store_win.h"
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/profiler/scoped_profile.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "components/os_crypt/ie7_password_win.h"
16 #include "components/password_manager/core/browser/password_manager.h"
17 #include "components/password_manager/core/browser/webdata/password_web_data_service_win.h"
18 #include "content/public/browser/browser_thread.h"
20 using autofill::PasswordForm
;
21 using content::BrowserThread
;
22 using password_manager::PasswordStoreDefault
;
24 // Handles requests to PasswordWebDataService.
25 class PasswordStoreWin::DBHandler
: public WebDataServiceConsumer
{
27 DBHandler(PasswordWebDataService
* web_data_service
,
28 PasswordStoreWin
* password_store
)
29 : web_data_service_(web_data_service
),
30 password_store_(password_store
) {
35 // Requests the IE7 login for |form|. This is async. |callback_runner| will be
38 const PasswordForm
& form
,
39 const PasswordStoreWin::ConsumerCallbackRunner
& callback_runner
);
45 RequestInfo(PasswordForm
* request_form
,
46 const PasswordStoreWin::ConsumerCallbackRunner
& runner
)
48 callback_runner(runner
) {}
51 PasswordStoreWin::ConsumerCallbackRunner callback_runner
;
54 // Holds info associated with in-flight GetIE7Login requests.
55 typedef std::map
<PasswordWebDataService::Handle
, RequestInfo
>
58 // Gets logins from IE7 if no others are found. Also copies them into
59 // Chrome's WebDatabase so we don't need to look next time.
60 std::vector
<autofill::PasswordForm
*> GetIE7Results(
61 const WDTypedResult
* result
,
62 const PasswordForm
& form
);
64 // WebDataServiceConsumer implementation.
65 virtual void OnWebDataServiceRequestDone(
66 PasswordWebDataService::Handle handle
,
67 const WDTypedResult
* result
) override
;
69 scoped_refptr
<PasswordWebDataService
> web_data_service_
;
71 // This creates a cycle between us and PasswordStore. The cycle is broken
72 // from PasswordStoreWin::Shutdown, which deletes us.
73 scoped_refptr
<PasswordStoreWin
> password_store_
;
75 PendingRequestMap pending_requests_
;
77 DISALLOW_COPY_AND_ASSIGN(DBHandler
);
80 PasswordStoreWin::DBHandler::~DBHandler() {
81 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB
));
82 for (PendingRequestMap::const_iterator i
= pending_requests_
.begin();
83 i
!= pending_requests_
.end();
85 web_data_service_
->CancelRequest(i
->first
);
86 delete i
->second
.form
;
90 void PasswordStoreWin::DBHandler::GetIE7Login(
91 const PasswordForm
& form
,
92 const PasswordStoreWin::ConsumerCallbackRunner
& callback_runner
) {
93 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB
));
96 ie7_password::GetUrlHash(base::UTF8ToWide(form
.origin
.spec()));
97 PasswordWebDataService::Handle handle
=
98 web_data_service_
->GetIE7Login(info
, this);
99 pending_requests_
[handle
] =
100 RequestInfo(new PasswordForm(form
), callback_runner
);
103 std::vector
<PasswordForm
*> PasswordStoreWin::DBHandler::GetIE7Results(
104 const WDTypedResult
*result
,
105 const PasswordForm
& form
) {
106 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB
));
107 std::vector
<PasswordForm
*> matching_forms
;
109 const WDResult
<IE7PasswordInfo
>* r
=
110 static_cast<const WDResult
<IE7PasswordInfo
>*>(result
);
111 IE7PasswordInfo info
= r
->GetValue();
113 if (!info
.encrypted_data
.empty()) {
115 // Delete the entry. If it's good we will add it to the real saved password
117 web_data_service_
->RemoveIE7Login(info
);
118 std::vector
<ie7_password::DecryptedCredentials
> credentials
;
119 std::wstring url
= base::ASCIIToWide(form
.origin
.spec());
120 if (ie7_password::DecryptPasswords(url
,
123 for (size_t i
= 0; i
< credentials
.size(); ++i
) {
124 PasswordForm
* autofill
= new PasswordForm();
125 autofill
->username_value
= credentials
[i
].username
;
126 autofill
->password_value
= credentials
[i
].password
;
127 autofill
->signon_realm
= form
.signon_realm
;
128 autofill
->origin
= form
.origin
;
129 autofill
->preferred
= true;
130 autofill
->ssl_valid
= form
.origin
.SchemeIsSecure();
131 autofill
->date_created
= info
.date_created
;
133 matching_forms
.push_back(autofill
);
134 // Add this PasswordForm to the saved password table. We're on the DB
135 // thread already, so we use AddLoginImpl.
136 password_store_
->AddLoginImpl(*autofill
);
140 return matching_forms
;
143 void PasswordStoreWin::DBHandler::OnWebDataServiceRequestDone(
144 PasswordWebDataService::Handle handle
,
145 const WDTypedResult
* result
) {
146 // TODO(vadimt): Remove ScopedProfile below once crbug.com/422460 is fixed.
147 tracked_objects::ScopedProfile
tracking_profile(
148 FROM_HERE_WITH_EXPLICIT_FUNCTION(
149 "422460 PasswordStoreWin::DBHandler::OnWebDataServiceRequestDone"));
151 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB
));
153 PendingRequestMap::iterator i
= pending_requests_
.find(handle
);
154 DCHECK(i
!= pending_requests_
.end());
156 scoped_ptr
<PasswordForm
> form(i
->second
.form
);
157 PasswordStoreWin::ConsumerCallbackRunner
callback_runner(
158 i
->second
.callback_runner
);
159 pending_requests_
.erase(i
);
162 // The WDS returns NULL if it is shutting down. Run callback with empty
164 callback_runner
.Run(std::vector
<autofill::PasswordForm
*>());
168 DCHECK_EQ(PASSWORD_IE7_RESULT
, result
->GetType());
169 std::vector
<autofill::PasswordForm
*> matched_forms
=
170 GetIE7Results(result
, *form
);
172 callback_runner
.Run(matched_forms
);
175 PasswordStoreWin::PasswordStoreWin(
176 scoped_refptr
<base::SingleThreadTaskRunner
> main_thread_runner
,
177 scoped_refptr
<base::SingleThreadTaskRunner
> db_thread_runner
,
178 password_manager::LoginDatabase
* login_database
,
179 PasswordWebDataService
* web_data_service
)
180 : PasswordStoreDefault(main_thread_runner
,
183 db_handler_
.reset(new DBHandler(web_data_service
, this));
186 PasswordStoreWin::~PasswordStoreWin() {
189 void PasswordStoreWin::ShutdownOnDBThread() {
190 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB
));
194 void PasswordStoreWin::Shutdown() {
195 BrowserThread::PostTask(
196 BrowserThread::DB
, FROM_HERE
,
197 base::Bind(&PasswordStoreWin::ShutdownOnDBThread
, this));
198 PasswordStoreDefault::Shutdown();
201 void PasswordStoreWin::GetIE7LoginIfNecessary(
202 const PasswordForm
& form
,
203 const ConsumerCallbackRunner
& callback_runner
,
204 const std::vector
<autofill::PasswordForm
*>& matched_forms
) {
205 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB
));
206 if (matched_forms
.empty() && db_handler_
.get()) {
207 db_handler_
->GetIE7Login(form
, callback_runner
);
209 // No need to get IE7 login.
210 callback_runner
.Run(matched_forms
);
214 void PasswordStoreWin::GetLoginsImpl(
215 const PasswordForm
& form
,
216 AuthorizationPromptPolicy prompt_policy
,
217 const ConsumerCallbackRunner
& callback_runner
) {
218 ConsumerCallbackRunner get_ie7_login
=
219 base::Bind(&PasswordStoreWin::GetIE7LoginIfNecessary
,
220 this, form
, callback_runner
);
221 PasswordStoreDefault::GetLoginsImpl(form
, prompt_policy
, get_ie7_login
);