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_tracker.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 typedef base::Callback
<void(ScopedVector
<PasswordForm
>)> ResultCallback
;
29 DBHandler(const scoped_refptr
<PasswordWebDataService
>& web_data_service
,
30 PasswordStoreWin
* password_store
)
31 : web_data_service_(web_data_service
), password_store_(password_store
) {}
35 // Requests the IE7 login for |form|. This is async. |result_callback| will be
37 void GetIE7Login(const PasswordForm
& form
,
38 const ResultCallback
& result_callback
);
44 RequestInfo(PasswordForm
* request_form
,
45 const ResultCallback
& result_callback
)
46 : form(request_form
), result_callback(result_callback
) {}
49 ResultCallback result_callback
;
52 // Holds info associated with in-flight GetIE7Login requests.
53 typedef std::map
<PasswordWebDataService::Handle
, RequestInfo
>
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 ScopedVector
<autofill::PasswordForm
> GetIE7Results(
59 const WDTypedResult
* result
,
60 const PasswordForm
& form
);
62 // WebDataServiceConsumer implementation.
63 virtual void OnWebDataServiceRequestDone(
64 PasswordWebDataService::Handle handle
,
65 const WDTypedResult
* result
) override
;
67 scoped_refptr
<PasswordWebDataService
> web_data_service_
;
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_
;
73 PendingRequestMap pending_requests_
;
75 DISALLOW_COPY_AND_ASSIGN(DBHandler
);
78 PasswordStoreWin::DBHandler::~DBHandler() {
79 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB
));
80 for (PendingRequestMap::const_iterator i
= pending_requests_
.begin();
81 i
!= pending_requests_
.end();
83 web_data_service_
->CancelRequest(i
->first
);
84 delete i
->second
.form
;
88 void PasswordStoreWin::DBHandler::GetIE7Login(
89 const PasswordForm
& form
,
90 const ResultCallback
& result_callback
) {
91 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB
));
94 ie7_password::GetUrlHash(base::UTF8ToWide(form
.origin
.spec()));
95 PasswordWebDataService::Handle handle
=
96 web_data_service_
->GetIE7Login(info
, this);
97 pending_requests_
[handle
] =
98 RequestInfo(new PasswordForm(form
), result_callback
);
101 ScopedVector
<autofill::PasswordForm
> PasswordStoreWin::DBHandler::GetIE7Results(
102 const WDTypedResult
* result
,
103 const PasswordForm
& form
) {
104 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB
));
105 ScopedVector
<autofill::PasswordForm
> matched_forms
;
106 const WDResult
<IE7PasswordInfo
>* r
=
107 static_cast<const WDResult
<IE7PasswordInfo
>*>(result
);
108 IE7PasswordInfo info
= r
->GetValue();
110 if (!info
.encrypted_data
.empty()) {
112 // Delete the entry. If it's good we will add it to the real saved password
114 web_data_service_
->RemoveIE7Login(info
);
115 std::vector
<ie7_password::DecryptedCredentials
> credentials
;
116 base::string16 url
= base::ASCIIToUTF16(form
.origin
.spec());
117 if (ie7_password::DecryptPasswords(url
,
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
;
130 matched_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
);
137 return matched_forms
.Pass();
140 void PasswordStoreWin::DBHandler::OnWebDataServiceRequestDone(
141 PasswordWebDataService::Handle handle
,
142 const WDTypedResult
* result
) {
143 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460 is
145 tracked_objects::ScopedTracker
tracking_profile(
146 FROM_HERE_WITH_EXPLICIT_FUNCTION(
147 "422460 PasswordStoreWin::DBHandler::OnWebDataServiceRequestDone"));
149 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB
));
151 PendingRequestMap::iterator i
= pending_requests_
.find(handle
);
152 DCHECK(i
!= pending_requests_
.end());
154 scoped_ptr
<PasswordForm
> form(i
->second
.form
);
155 ResultCallback
result_callback(i
->second
.result_callback
);
156 pending_requests_
.erase(i
);
159 // The WDS returns NULL if it is shutting down. Run callback with empty
161 result_callback
.Run(ScopedVector
<autofill::PasswordForm
>());
165 DCHECK_EQ(PASSWORD_IE7_RESULT
, result
->GetType());
166 result_callback
.Run(GetIE7Results(result
, *form
));
169 PasswordStoreWin::PasswordStoreWin(
170 scoped_refptr
<base::SingleThreadTaskRunner
> main_thread_runner
,
171 scoped_refptr
<base::SingleThreadTaskRunner
> db_thread_runner
,
172 scoped_ptr
<password_manager::LoginDatabase
> login_db
,
173 const scoped_refptr
<PasswordWebDataService
>& web_data_service
)
174 : PasswordStoreDefault(main_thread_runner
,
177 db_handler_
.reset(new DBHandler(web_data_service
, this));
180 PasswordStoreWin::~PasswordStoreWin() {
183 void PasswordStoreWin::ShutdownOnDBThread() {
184 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB
));
188 void PasswordStoreWin::Shutdown() {
189 BrowserThread::PostTask(
190 BrowserThread::DB
, FROM_HERE
,
191 base::Bind(&PasswordStoreWin::ShutdownOnDBThread
, this));
192 PasswordStoreDefault::Shutdown();
195 void PasswordStoreWin::GetLoginsImpl(const PasswordForm
& form
,
196 AuthorizationPromptPolicy prompt_policy
,
197 scoped_ptr
<GetLoginsRequest
> request
) {
198 // When importing from IE7, the credentials are first stored into a temporary
199 // Web SQL database. Then, after each GetLogins() request that does not yield
200 // any matches from the LoginDatabase, the matching credentials in the Web SQL
201 // database, if any, are returned as results instead, and simultaneously get
202 // moved to the LoginDatabase, so next time they will be found immediately.
203 // TODO(engedy): Make the IE7-specific code synchronous, so FillMatchingLogins
204 // can be overridden instead. See: https://crbug.com/78830.
205 // TODO(engedy): Credentials should be imported into the LoginDatabase in the
206 // first place. See: https://crbug.com/456119.
207 ScopedVector
<autofill::PasswordForm
> matched_forms(
208 FillMatchingLogins(form
, prompt_policy
));
209 if (matched_forms
.empty() && db_handler_
) {
210 db_handler_
->GetIE7Login(
211 form
, base::Bind(&GetLoginsRequest::NotifyConsumerWithResults
,
212 base::Owned(request
.release())));
214 request
->NotifyConsumerWithResults(matched_forms
.Pass());