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 const autofill::PasswordForm& form = form_manager_->pending_credentials(); | |
80 | |
81 if (!form.federation_origin.unique()) { | |
82 // If this is a federated credential, check it against the federated matches | |
83 // produced by the PasswordFormManager. If a match is found, update it and | |
84 // return. | |
85 for (const auto& match : form_manager_->federated_matches()) { | |
86 if (match->username_value == form.username_value && | |
87 match->federation_origin.IsSameOriginWith(form.federation_origin)) { | |
88 form_manager_->Update(*match); | |
89 return; | |
90 } | |
91 } | |
92 } else if (!form_manager_->IsNewLogin()) { | |
93 // Otherwise, if this is not a new password credential, update the existing | |
94 // credential without prompting the user. This will also update the | |
95 // 'skip_zero_click' state, as we've gotten an explicit signal that the page | |
96 // understands the credential management API and so can be trusted to notify | |
97 // us when they sign the user out. | |
98 form_manager_->Update(*form_manager_->preferred_match()); | |
99 return; | |
100 } | |
101 | |
102 // Otherwise, this is a new form, so as the user if they'd like to save. | |
103 client_->PromptUserToSaveOrUpdatePassword( | |
104 std::move(form_manager_), CredentialSourceType::CREDENTIAL_SOURCE_API, | |
105 false); | |
106 } | |
107 | |
108 void CredentialManagerDispatcher::OnRequireUserMediation(int request_id) { | |
109 DCHECK(request_id); | |
110 | |
111 PasswordStore* store = GetPasswordStore(); | |
112 if (!store || !IsUpdatingCredentialAllowed()) { | |
113 web_contents()->GetRenderViewHost()->Send( | |
114 new CredentialManagerMsg_AcknowledgeRequireUserMediation( | |
115 web_contents()->GetRenderViewHost()->GetRoutingID(), request_id)); | |
116 return; | |
117 } | |
118 | |
119 if (store->affiliated_match_helper()) { | |
120 store->affiliated_match_helper()->GetAffiliatedAndroidRealms( | |
121 GetSynthesizedFormForOrigin(), | |
122 base::Bind(&CredentialManagerDispatcher::ScheduleRequireMediationTask, | |
123 weak_factory_.GetWeakPtr(), request_id)); | |
124 } else { | |
125 std::vector<std::string> no_affiliated_realms; | |
126 ScheduleRequireMediationTask(request_id, no_affiliated_realms); | |
127 } | |
128 } | |
129 | |
130 void CredentialManagerDispatcher::ScheduleRequireMediationTask( | |
131 int request_id, | |
132 const std::vector<std::string>& android_realms) { | |
133 DCHECK(GetPasswordStore()); | |
134 if (!pending_require_user_mediation_) { | |
135 pending_require_user_mediation_.reset( | |
136 new CredentialManagerPendingRequireUserMediationTask( | |
137 this, web_contents()->GetLastCommittedURL().GetOrigin(), | |
138 android_realms)); | |
139 | |
140 // This will result in a callback to | |
141 // CredentialManagerPendingRequireUserMediationTask::OnGetPasswordStoreResul
ts(). | |
142 GetPasswordStore()->GetAutofillableLogins( | |
143 pending_require_user_mediation_.get()); | |
144 } else { | |
145 pending_require_user_mediation_->AddOrigin( | |
146 web_contents()->GetLastCommittedURL().GetOrigin()); | |
147 } | |
148 | |
149 web_contents()->GetRenderViewHost()->Send( | |
150 new CredentialManagerMsg_AcknowledgeRequireUserMediation( | |
151 web_contents()->GetRenderViewHost()->GetRoutingID(), request_id)); | |
152 } | |
153 | |
154 void CredentialManagerDispatcher::OnRequestCredential( | |
155 int request_id, | |
156 bool zero_click_only, | |
157 bool include_passwords, | |
158 const std::vector<GURL>& federations) { | |
159 DCHECK(request_id); | |
160 PasswordStore* store = GetPasswordStore(); | |
161 if (pending_request_ || !store) { | |
162 web_contents()->GetRenderViewHost()->Send( | |
163 new CredentialManagerMsg_RejectCredentialRequest( | |
164 web_contents()->GetRenderViewHost()->GetRoutingID(), request_id, | |
165 pending_request_ | |
166 ? blink::WebCredentialManagerPendingRequestError | |
167 : blink::WebCredentialManagerPasswordStoreUnavailableError)); | |
168 return; | |
169 } | |
170 | |
171 // Return an empty credential if zero-click is required but disabled, or if | |
172 // the current page has TLS errors. | |
173 if ((zero_click_only && !IsZeroClickAllowed()) || | |
174 client_->DidLastPageLoadEncounterSSLErrors()) { | |
175 web_contents()->GetRenderViewHost()->Send( | |
176 new CredentialManagerMsg_SendCredential( | |
177 web_contents()->GetRenderViewHost()->GetRoutingID(), request_id, | |
178 CredentialInfo())); | |
179 return; | |
180 } | |
181 | |
182 if (store->affiliated_match_helper()) { | |
183 store->affiliated_match_helper()->GetAffiliatedAndroidRealms( | |
184 GetSynthesizedFormForOrigin(), | |
185 base::Bind(&CredentialManagerDispatcher::ScheduleRequestTask, | |
186 weak_factory_.GetWeakPtr(), request_id, zero_click_only, | |
187 include_passwords, federations)); | |
188 } else { | |
189 std::vector<std::string> no_affiliated_realms; | |
190 ScheduleRequestTask(request_id, zero_click_only, include_passwords, | |
191 federations, no_affiliated_realms); | |
192 } | |
193 } | |
194 | |
195 void CredentialManagerDispatcher::ScheduleRequestTask( | |
196 int request_id, | |
197 bool zero_click_only, | |
198 bool include_passwords, | |
199 const std::vector<GURL>& federations, | |
200 const std::vector<std::string>& android_realms) { | |
201 DCHECK(GetPasswordStore()); | |
202 pending_request_.reset(new CredentialManagerPendingRequestTask( | |
203 this, request_id, zero_click_only, | |
204 web_contents()->GetLastCommittedURL().GetOrigin(), include_passwords, | |
205 federations, android_realms)); | |
206 | |
207 // This will result in a callback to | |
208 // PendingRequestTask::OnGetPasswordStoreResults(). | |
209 GetPasswordStore()->GetAutofillableLogins(pending_request_.get()); | |
210 } | |
211 | |
212 PasswordStore* CredentialManagerDispatcher::GetPasswordStore() { | |
213 return client_ ? client_->GetPasswordStore() : nullptr; | |
214 } | |
215 | |
216 bool CredentialManagerDispatcher::IsZeroClickAllowed() const { | |
217 return *auto_signin_enabled_ && !client_->IsOffTheRecord(); | |
218 } | |
219 | |
220 GURL CredentialManagerDispatcher::GetOrigin() const { | |
221 return web_contents()->GetLastCommittedURL().GetOrigin(); | |
222 } | |
223 | |
224 base::WeakPtr<PasswordManagerDriver> CredentialManagerDispatcher::GetDriver() { | |
225 ContentPasswordManagerDriverFactory* driver_factory = | |
226 ContentPasswordManagerDriverFactory::FromWebContents(web_contents()); | |
227 DCHECK(driver_factory); | |
228 PasswordManagerDriver* driver = | |
229 driver_factory->GetDriverForFrame(web_contents()->GetMainFrame()); | |
230 return driver->AsWeakPtr(); | |
231 } | |
232 | |
233 void CredentialManagerDispatcher::SendCredential(int request_id, | |
234 const CredentialInfo& info) { | |
235 DCHECK(pending_request_); | |
236 DCHECK_EQ(pending_request_->id(), request_id); | |
237 | |
238 web_contents()->GetRenderViewHost()->Send( | |
239 new CredentialManagerMsg_SendCredential( | |
240 web_contents()->GetRenderViewHost()->GetRoutingID(), | |
241 pending_request_->id(), info)); | |
242 pending_request_.reset(); | |
243 } | |
244 | |
245 void CredentialManagerDispatcher::SendPasswordForm( | |
246 int request_id, | |
247 const autofill::PasswordForm* form) { | |
248 CredentialInfo info; | |
249 if (form) { | |
250 password_manager::CredentialType type_to_return = | |
251 form->federation_origin.unique() | |
252 ? CredentialType::CREDENTIAL_TYPE_PASSWORD | |
253 : CredentialType::CREDENTIAL_TYPE_FEDERATED; | |
254 info = CredentialInfo(*form, type_to_return); | |
255 if (PasswordStore* store = GetPasswordStore()) { | |
256 if (form->skip_zero_click && IsZeroClickAllowed()) { | |
257 DCHECK(IsUpdatingCredentialAllowed()); | |
258 autofill::PasswordForm update_form = *form; | |
259 update_form.skip_zero_click = false; | |
260 store->UpdateLogin(update_form); | |
261 } | |
262 } | |
263 } | |
264 SendCredential(request_id, info); | |
265 } | |
266 | |
267 PasswordManagerClient* CredentialManagerDispatcher::client() const { | |
268 return client_; | |
269 } | |
270 | |
271 autofill::PasswordForm | |
272 CredentialManagerDispatcher::GetSynthesizedFormForOrigin() const { | |
273 autofill::PasswordForm synthetic_form; | |
274 synthetic_form.origin = web_contents()->GetLastCommittedURL().GetOrigin(); | |
275 synthetic_form.signon_realm = synthetic_form.origin.spec(); | |
276 synthetic_form.scheme = autofill::PasswordForm::SCHEME_HTML; | |
277 synthetic_form.ssl_valid = synthetic_form.origin.SchemeIsCryptographic() && | |
278 !client_->DidLastPageLoadEncounterSSLErrors(); | |
279 return synthetic_form; | |
280 } | |
281 | |
282 void CredentialManagerDispatcher::DoneRequiringUserMediation() { | |
283 DCHECK(pending_require_user_mediation_); | |
284 pending_require_user_mediation_.reset(); | |
285 } | |
286 | |
287 bool CredentialManagerDispatcher::IsUpdatingCredentialAllowed() const { | |
288 return !client_->DidLastPageLoadEncounterSSLErrors() && | |
289 !client_->IsOffTheRecord(); | |
290 } | |
291 | |
292 } // namespace password_manager | |
OLD | NEW |