OLD | NEW |
| (Empty) |
1 // Copyright 2014 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 "components/password_manager/content/browser/credential_manager_dispatc
her.h" | |
6 | |
7 #include <utility> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/strings/string16.h" | |
11 #include "base/strings/utf_string_conversions.h" | |
12 #include "components/autofill/core/common/password_form.h" | |
13 #include "components/password_manager/content/browser/content_password_manager_d
river.h" | |
14 #include "components/password_manager/content/browser/content_password_manager_d
river_factory.h" | |
15 #include "components/password_manager/content/common/credential_manager_messages
.h" | |
16 #include "components/password_manager/core/browser/affiliated_match_helper.h" | |
17 #include "components/password_manager/core/browser/password_manager_client.h" | |
18 #include "components/password_manager/core/browser/password_store.h" | |
19 #include "components/password_manager/core/common/credential_manager_types.h" | |
20 #include "components/password_manager/core/common/password_manager_pref_names.h" | |
21 #include "content/public/browser/render_view_host.h" | |
22 #include "content/public/browser/web_contents.h" | |
23 #include "ipc/ipc_message_macros.h" | |
24 | |
25 namespace password_manager { | |
26 | |
27 // CredentialManagerDispatcher ------------------------------------------------- | |
28 | |
29 CredentialManagerDispatcher::CredentialManagerDispatcher( | |
30 content::WebContents* web_contents, | |
31 PasswordManagerClient* client) | |
32 : WebContentsObserver(web_contents), client_(client), weak_factory_(this) { | |
33 DCHECK(web_contents); | |
34 auto_signin_enabled_.Init(prefs::kCredentialsEnableAutosignin, | |
35 client_->GetPrefs()); | |
36 } | |
37 | |
38 CredentialManagerDispatcher::~CredentialManagerDispatcher() { | |
39 } | |
40 | |
41 bool CredentialManagerDispatcher::OnMessageReceived( | |
42 const IPC::Message& message) { | |
43 bool handled = true; | |
44 IPC_BEGIN_MESSAGE_MAP(CredentialManagerDispatcher, message) | |
45 IPC_MESSAGE_HANDLER(CredentialManagerHostMsg_Store, OnStore); | |
46 IPC_MESSAGE_HANDLER(CredentialManagerHostMsg_RequireUserMediation, | |
47 OnRequireUserMediation); | |
48 IPC_MESSAGE_HANDLER(CredentialManagerHostMsg_RequestCredential, | |
49 OnRequestCredential); | |
50 IPC_MESSAGE_UNHANDLED(handled = false) | |
51 IPC_END_MESSAGE_MAP() | |
52 return handled; | |
53 } | |
54 | |
55 void CredentialManagerDispatcher::OnStore( | |
56 int request_id, | |
57 const password_manager::CredentialInfo& credential) { | |
58 DCHECK(credential.type != CredentialType::CREDENTIAL_TYPE_EMPTY); | |
59 DCHECK(request_id); | |
60 web_contents()->GetRenderViewHost()->Send( | |
61 new CredentialManagerMsg_AcknowledgeStore( | |
62 web_contents()->GetRenderViewHost()->GetRoutingID(), request_id)); | |
63 | |
64 if (!client_->IsSavingAndFillingEnabledForCurrentPage()) | |
65 return; | |
66 | |
67 std::unique_ptr<autofill::PasswordForm> form( | |
68 CreatePasswordFormFromCredentialInfo( | |
69 credential, web_contents()->GetLastCommittedURL().GetOrigin())); | |
70 form->skip_zero_click = !IsZeroClickAllowed(); | |
71 | |
72 form_manager_.reset(new CredentialManagerPasswordFormManager( | |
73 client_, GetDriver(), *form, this)); | |
74 } | |
75 | |
76 void CredentialManagerDispatcher::OnProvisionalSaveComplete() { | |
77 DCHECK(form_manager_); | |
78 DCHECK(client_->IsSavingAndFillingEnabledForCurrentPage()); | |
79 | |
80 if (form_manager_->IsNewLogin()) { | |
81 // If the PasswordForm we were given does not match an existing | |
82 // PasswordForm, ask the user if they'd like to save. | |
83 client_->PromptUserToSaveOrUpdatePassword( | |
84 std::move(form_manager_), CredentialSourceType::CREDENTIAL_SOURCE_API, | |
85 false); | |
86 } else { | |
87 // Otherwise, update the existing form, as we've been told by the site | |
88 // that the new PasswordForm is a functioning credential for the user. | |
89 // We use 'PasswordFormManager::Update(PasswordForm&)' here rather than | |
90 // 'PasswordFormManager::UpdateLogin', as we need to port over the | |
91 // 'skip_zero_click' state to ensure that we don't accidentally start | |
92 // signing users in just because the site asks us to. The simplest way | |
93 // to do so is simply to update the password field of the existing | |
94 // credential. | |
95 form_manager_->Update(*form_manager_->preferred_match()); | |
96 } | |
97 } | |
98 | |
99 void CredentialManagerDispatcher::OnRequireUserMediation(int request_id) { | |
100 DCHECK(request_id); | |
101 | |
102 PasswordStore* store = GetPasswordStore(); | |
103 if (!store || !IsUpdatingCredentialAllowed()) { | |
104 web_contents()->GetRenderViewHost()->Send( | |
105 new CredentialManagerMsg_AcknowledgeRequireUserMediation( | |
106 web_contents()->GetRenderViewHost()->GetRoutingID(), request_id)); | |
107 return; | |
108 } | |
109 | |
110 if (store->affiliated_match_helper()) { | |
111 store->affiliated_match_helper()->GetAffiliatedAndroidRealms( | |
112 GetSynthesizedFormForOrigin(), | |
113 base::Bind(&CredentialManagerDispatcher::ScheduleRequireMediationTask, | |
114 weak_factory_.GetWeakPtr(), request_id)); | |
115 } else { | |
116 std::vector<std::string> no_affiliated_realms; | |
117 ScheduleRequireMediationTask(request_id, no_affiliated_realms); | |
118 } | |
119 } | |
120 | |
121 void CredentialManagerDispatcher::ScheduleRequireMediationTask( | |
122 int request_id, | |
123 const std::vector<std::string>& android_realms) { | |
124 DCHECK(GetPasswordStore()); | |
125 if (!pending_require_user_mediation_) { | |
126 pending_require_user_mediation_.reset( | |
127 new CredentialManagerPendingRequireUserMediationTask( | |
128 this, web_contents()->GetLastCommittedURL().GetOrigin(), | |
129 android_realms)); | |
130 | |
131 // This will result in a callback to | |
132 // CredentialManagerPendingRequireUserMediationTask::OnGetPasswordStoreResul
ts(). | |
133 GetPasswordStore()->GetAutofillableLogins( | |
134 pending_require_user_mediation_.get()); | |
135 } else { | |
136 pending_require_user_mediation_->AddOrigin( | |
137 web_contents()->GetLastCommittedURL().GetOrigin()); | |
138 } | |
139 | |
140 web_contents()->GetRenderViewHost()->Send( | |
141 new CredentialManagerMsg_AcknowledgeRequireUserMediation( | |
142 web_contents()->GetRenderViewHost()->GetRoutingID(), request_id)); | |
143 } | |
144 | |
145 void CredentialManagerDispatcher::OnRequestCredential( | |
146 int request_id, | |
147 bool zero_click_only, | |
148 bool include_passwords, | |
149 const std::vector<GURL>& federations) { | |
150 DCHECK(request_id); | |
151 PasswordStore* store = GetPasswordStore(); | |
152 if (pending_request_ || !store) { | |
153 web_contents()->GetRenderViewHost()->Send( | |
154 new CredentialManagerMsg_RejectCredentialRequest( | |
155 web_contents()->GetRenderViewHost()->GetRoutingID(), request_id, | |
156 pending_request_ | |
157 ? blink::WebCredentialManagerPendingRequestError | |
158 : blink::WebCredentialManagerPasswordStoreUnavailableError)); | |
159 return; | |
160 } | |
161 | |
162 // Return an empty credential if zero-click is required but disabled, or if | |
163 // the current page has TLS errors. | |
164 if ((zero_click_only && !IsZeroClickAllowed()) || | |
165 client_->DidLastPageLoadEncounterSSLErrors()) { | |
166 web_contents()->GetRenderViewHost()->Send( | |
167 new CredentialManagerMsg_SendCredential( | |
168 web_contents()->GetRenderViewHost()->GetRoutingID(), request_id, | |
169 CredentialInfo())); | |
170 return; | |
171 } | |
172 | |
173 if (store->affiliated_match_helper()) { | |
174 store->affiliated_match_helper()->GetAffiliatedAndroidRealms( | |
175 GetSynthesizedFormForOrigin(), | |
176 base::Bind(&CredentialManagerDispatcher::ScheduleRequestTask, | |
177 weak_factory_.GetWeakPtr(), request_id, zero_click_only, | |
178 include_passwords, federations)); | |
179 } else { | |
180 std::vector<std::string> no_affiliated_realms; | |
181 ScheduleRequestTask(request_id, zero_click_only, include_passwords, | |
182 federations, no_affiliated_realms); | |
183 } | |
184 } | |
185 | |
186 void CredentialManagerDispatcher::ScheduleRequestTask( | |
187 int request_id, | |
188 bool zero_click_only, | |
189 bool include_passwords, | |
190 const std::vector<GURL>& federations, | |
191 const std::vector<std::string>& android_realms) { | |
192 DCHECK(GetPasswordStore()); | |
193 pending_request_.reset(new CredentialManagerPendingRequestTask( | |
194 this, request_id, zero_click_only, | |
195 web_contents()->GetLastCommittedURL().GetOrigin(), include_passwords, | |
196 federations, android_realms)); | |
197 | |
198 // This will result in a callback to | |
199 // PendingRequestTask::OnGetPasswordStoreResults(). | |
200 GetPasswordStore()->GetAutofillableLogins(pending_request_.get()); | |
201 } | |
202 | |
203 PasswordStore* CredentialManagerDispatcher::GetPasswordStore() { | |
204 return client_ ? client_->GetPasswordStore() : nullptr; | |
205 } | |
206 | |
207 bool CredentialManagerDispatcher::IsZeroClickAllowed() const { | |
208 return *auto_signin_enabled_ && !client_->IsOffTheRecord(); | |
209 } | |
210 | |
211 GURL CredentialManagerDispatcher::GetOrigin() const { | |
212 return web_contents()->GetLastCommittedURL().GetOrigin(); | |
213 } | |
214 | |
215 base::WeakPtr<PasswordManagerDriver> CredentialManagerDispatcher::GetDriver() { | |
216 ContentPasswordManagerDriverFactory* driver_factory = | |
217 ContentPasswordManagerDriverFactory::FromWebContents(web_contents()); | |
218 DCHECK(driver_factory); | |
219 PasswordManagerDriver* driver = | |
220 driver_factory->GetDriverForFrame(web_contents()->GetMainFrame()); | |
221 return driver->AsWeakPtr(); | |
222 } | |
223 | |
224 void CredentialManagerDispatcher::SendCredential(int request_id, | |
225 const CredentialInfo& info) { | |
226 DCHECK(pending_request_); | |
227 DCHECK_EQ(pending_request_->id(), request_id); | |
228 | |
229 web_contents()->GetRenderViewHost()->Send( | |
230 new CredentialManagerMsg_SendCredential( | |
231 web_contents()->GetRenderViewHost()->GetRoutingID(), | |
232 pending_request_->id(), info)); | |
233 pending_request_.reset(); | |
234 } | |
235 | |
236 void CredentialManagerDispatcher::SendPasswordForm( | |
237 int request_id, | |
238 const autofill::PasswordForm* form) { | |
239 CredentialInfo info; | |
240 if (form) { | |
241 password_manager::CredentialType type_to_return = | |
242 form->federation_origin.unique() | |
243 ? CredentialType::CREDENTIAL_TYPE_PASSWORD | |
244 : CredentialType::CREDENTIAL_TYPE_FEDERATED; | |
245 info = CredentialInfo(*form, type_to_return); | |
246 if (PasswordStore* store = GetPasswordStore()) { | |
247 if (form->skip_zero_click && IsZeroClickAllowed()) { | |
248 DCHECK(IsUpdatingCredentialAllowed()); | |
249 autofill::PasswordForm update_form = *form; | |
250 update_form.skip_zero_click = false; | |
251 store->UpdateLogin(update_form); | |
252 } | |
253 } | |
254 } | |
255 SendCredential(request_id, info); | |
256 } | |
257 | |
258 PasswordManagerClient* CredentialManagerDispatcher::client() const { | |
259 return client_; | |
260 } | |
261 | |
262 autofill::PasswordForm | |
263 CredentialManagerDispatcher::GetSynthesizedFormForOrigin() const { | |
264 autofill::PasswordForm synthetic_form; | |
265 synthetic_form.origin = web_contents()->GetLastCommittedURL().GetOrigin(); | |
266 synthetic_form.signon_realm = synthetic_form.origin.spec(); | |
267 synthetic_form.scheme = autofill::PasswordForm::SCHEME_HTML; | |
268 synthetic_form.ssl_valid = synthetic_form.origin.SchemeIsCryptographic() && | |
269 !client_->DidLastPageLoadEncounterSSLErrors(); | |
270 return synthetic_form; | |
271 } | |
272 | |
273 void CredentialManagerDispatcher::DoneRequiringUserMediation() { | |
274 DCHECK(pending_require_user_mediation_); | |
275 pending_require_user_mediation_.reset(); | |
276 } | |
277 | |
278 bool CredentialManagerDispatcher::IsUpdatingCredentialAllowed() const { | |
279 return !client_->DidLastPageLoadEncounterSSLErrors() && | |
280 !client_->IsOffTheRecord(); | |
281 } | |
282 | |
283 } // namespace password_manager | |
OLD | NEW |