Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(207)

Side by Side Diff: chrome/browser/login_prompt.cc

Issue 5606002: Move:... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 10 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/login_prompt.h ('k') | chrome/browser/login_prompt_gtk.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2009 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/login_prompt.h"
6
7 #include <vector>
8
9 #include "app/l10n_util.h"
10 #include "base/command_line.h"
11 #include "base/lock.h"
12 #include "base/utf_string_conversions.h"
13 #include "chrome/browser/browser_thread.h"
14 #include "chrome/browser/password_manager/password_manager.h"
15 #include "chrome/browser/renderer_host/render_process_host.h"
16 #include "chrome/browser/renderer_host/resource_dispatcher_host.h"
17 #include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h"
18 #include "chrome/browser/tab_contents/constrained_window.h"
19 #include "chrome/browser/tab_contents/tab_contents.h"
20 #include "chrome/browser/tab_contents/tab_util.h"
21 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
22 #include "chrome/common/chrome_switches.h"
23 #include "chrome/common/notification_service.h"
24 #include "grit/generated_resources.h"
25 #include "net/base/auth.h"
26 #include "net/base/net_util.h"
27 #include "net/url_request/url_request.h"
28
29 using webkit_glue::PasswordForm;
30
31 class LoginHandlerImpl;
32
33 // Helper to remove the ref from an net::URLRequest to the LoginHandler.
34 // Should only be called from the IO thread, since it accesses an
35 // net::URLRequest.
36 void ResetLoginHandlerForRequest(net::URLRequest* request) {
37 ResourceDispatcherHostRequestInfo* info =
38 ResourceDispatcherHost::InfoForRequest(request);
39 if (!info)
40 return;
41
42 info->set_login_handler(NULL);
43 }
44
45 // Get the signon_realm under which this auth info should be stored.
46 //
47 // The format of the signon_realm for proxy auth is:
48 // proxy-host/auth-realm
49 // The format of the signon_realm for server auth is:
50 // url-scheme://url-host[:url-port]/auth-realm
51 //
52 // Be careful when changing this function, since you could make existing
53 // saved logins un-retrievable.
54 std::string GetSignonRealm(const GURL& url,
55 const net::AuthChallengeInfo& auth_info) {
56 std::string signon_realm;
57 if (auth_info.is_proxy) {
58 signon_realm = WideToASCII(auth_info.host_and_port);
59 signon_realm.append("/");
60 } else {
61 // Take scheme, host, and port from the url.
62 signon_realm = url.GetOrigin().spec();
63 // This ends with a "/".
64 }
65 signon_realm.append(WideToUTF8(auth_info.realm));
66 return signon_realm;
67 }
68
69 // ----------------------------------------------------------------------------
70 // LoginHandler
71
72 LoginHandler::LoginHandler(net::AuthChallengeInfo* auth_info,
73 net::URLRequest* request)
74 : handled_auth_(false),
75 dialog_(NULL),
76 auth_info_(auth_info),
77 request_(request),
78 password_manager_(NULL),
79 login_model_(NULL) {
80 // This constructor is called on the I/O thread, so we cannot load the nib
81 // here. BuildViewForPasswordManager() will be invoked on the UI thread
82 // later, so wait with loading the nib until then.
83 DCHECK(request_) << "LoginHandler constructed with NULL request";
84 DCHECK(auth_info_) << "LoginHandler constructed with NULL auth info";
85
86 AddRef(); // matched by LoginHandler::ReleaseSoon().
87
88 BrowserThread::PostTask(
89 BrowserThread::UI, FROM_HERE,
90 NewRunnableMethod(this, &LoginHandler::AddObservers));
91
92 if (!ResourceDispatcherHost::RenderViewForRequest(
93 request_, &render_process_host_id_, &tab_contents_id_)) {
94 NOTREACHED();
95 }
96 }
97
98 LoginHandler::~LoginHandler() {
99 SetModel(NULL);
100 }
101
102 void LoginHandler::SetPasswordForm(const webkit_glue::PasswordForm& form) {
103 password_form_ = form;
104 }
105
106 void LoginHandler::SetPasswordManager(PasswordManager* password_manager) {
107 password_manager_ = password_manager;
108 }
109
110 TabContents* LoginHandler::GetTabContentsForLogin() const {
111 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
112
113 return tab_util::GetTabContentsByID(render_process_host_id_,
114 tab_contents_id_);
115 }
116
117 void LoginHandler::SetAuth(const std::wstring& username,
118 const std::wstring& password) {
119 if (WasAuthHandled(true))
120 return;
121
122 // Tell the password manager the credentials were submitted / accepted.
123 if (password_manager_) {
124 password_form_.username_value = WideToUTF16Hack(username);
125 password_form_.password_value = WideToUTF16Hack(password);
126 password_manager_->ProvisionallySavePassword(password_form_);
127 }
128
129 BrowserThread::PostTask(
130 BrowserThread::UI, FROM_HERE,
131 NewRunnableMethod(this, &LoginHandler::CloseContentsDeferred));
132 BrowserThread::PostTask(
133 BrowserThread::UI, FROM_HERE,
134 NewRunnableMethod(
135 this, &LoginHandler::NotifyAuthSupplied, username, password));
136 BrowserThread::PostTask(
137 BrowserThread::IO, FROM_HERE,
138 NewRunnableMethod(
139 this, &LoginHandler::SetAuthDeferred, username, password));
140 }
141
142 void LoginHandler::CancelAuth() {
143 if (WasAuthHandled(true))
144 return;
145
146 BrowserThread::PostTask(
147 BrowserThread::UI, FROM_HERE,
148 NewRunnableMethod(this, &LoginHandler::CloseContentsDeferred));
149 BrowserThread::PostTask(
150 BrowserThread::UI, FROM_HERE,
151 NewRunnableMethod(this, &LoginHandler::NotifyAuthCancelled));
152 BrowserThread::PostTask(
153 BrowserThread::IO, FROM_HERE,
154 NewRunnableMethod(this, &LoginHandler::CancelAuthDeferred));
155 }
156
157 void LoginHandler::OnRequestCancelled() {
158 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)) <<
159 "Why is OnRequestCancelled called from the UI thread?";
160
161 // Reference is no longer valid.
162 request_ = NULL;
163
164 // Give up on auth if the request was cancelled.
165 CancelAuth();
166 }
167
168 void LoginHandler::AddObservers() {
169 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
170
171 registrar_.Add(this, NotificationType::AUTH_SUPPLIED,
172 NotificationService::AllSources());
173 registrar_.Add(this, NotificationType::AUTH_CANCELLED,
174 NotificationService::AllSources());
175 }
176
177 void LoginHandler::RemoveObservers() {
178 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
179
180 registrar_.Remove(this, NotificationType::AUTH_SUPPLIED,
181 NotificationService::AllSources());
182 registrar_.Remove(this, NotificationType::AUTH_CANCELLED,
183 NotificationService::AllSources());
184
185 DCHECK(registrar_.IsEmpty());
186 }
187
188 void LoginHandler::Observe(NotificationType type,
189 const NotificationSource& source,
190 const NotificationDetails& details) {
191 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
192 DCHECK(type == NotificationType::AUTH_SUPPLIED ||
193 type == NotificationType::AUTH_CANCELLED);
194
195 TabContents* requesting_contents = GetTabContentsForLogin();
196 if (!requesting_contents)
197 return;
198
199 NavigationController* this_controller = &requesting_contents->controller();
200 NavigationController* that_controller =
201 Source<NavigationController>(source).ptr();
202
203 // Only handle notifications from other handlers.
204 if (this_controller == that_controller)
205 return;
206
207 LoginNotificationDetails* login_details =
208 Details<LoginNotificationDetails>(details).ptr();
209
210 // Only handle notification for the identical auth info.
211 if (*login_details->handler()->auth_info() != *auth_info())
212 return;
213
214 // Set or cancel the auth in this handler.
215 if (type == NotificationType::AUTH_SUPPLIED) {
216 AuthSuppliedLoginNotificationDetails* supplied_details =
217 Details<AuthSuppliedLoginNotificationDetails>(details).ptr();
218 SetAuth(supplied_details->username(), supplied_details->password());
219 } else {
220 DCHECK(type == NotificationType::AUTH_CANCELLED);
221 CancelAuth();
222 }
223 }
224
225 void LoginHandler::SetModel(LoginModel* model) {
226 if (login_model_)
227 login_model_->SetObserver(NULL);
228 login_model_ = model;
229 if (login_model_)
230 login_model_->SetObserver(this);
231 }
232
233 void LoginHandler::SetDialog(ConstrainedWindow* dialog) {
234 dialog_ = dialog;
235 }
236
237 void LoginHandler::NotifyAuthNeeded() {
238 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
239 if (WasAuthHandled(false))
240 return;
241
242 TabContents* requesting_contents = GetTabContentsForLogin();
243 if (!requesting_contents)
244 return;
245
246 NotificationService* service = NotificationService::current();
247 NavigationController* controller = &requesting_contents->controller();
248 LoginNotificationDetails details(this);
249
250 service->Notify(NotificationType::AUTH_NEEDED,
251 Source<NavigationController>(controller),
252 Details<LoginNotificationDetails>(&details));
253 }
254
255 void LoginHandler::NotifyAuthCancelled() {
256 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
257 DCHECK(WasAuthHandled(false));
258
259 TabContents* requesting_contents = GetTabContentsForLogin();
260 if (!requesting_contents)
261 return;
262
263 NotificationService* service = NotificationService::current();
264 NavigationController* controller = &requesting_contents->controller();
265 LoginNotificationDetails details(this);
266
267 service->Notify(NotificationType::AUTH_CANCELLED,
268 Source<NavigationController>(controller),
269 Details<LoginNotificationDetails>(&details));
270 }
271
272 void LoginHandler::NotifyAuthSupplied(const std::wstring& username,
273 const std::wstring& password) {
274 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
275 DCHECK(WasAuthHandled(false));
276
277 TabContents* requesting_contents = GetTabContentsForLogin();
278 if (!requesting_contents)
279 return;
280
281 NotificationService* service = NotificationService::current();
282 NavigationController* controller = &requesting_contents->controller();
283 AuthSuppliedLoginNotificationDetails details(this, username, password);
284
285 service->Notify(NotificationType::AUTH_SUPPLIED,
286 Source<NavigationController>(controller),
287 Details<AuthSuppliedLoginNotificationDetails>(&details));
288 }
289
290 void LoginHandler::ReleaseSoon() {
291 if (!WasAuthHandled(true)) {
292 BrowserThread::PostTask(
293 BrowserThread::IO, FROM_HERE,
294 NewRunnableMethod(this, &LoginHandler::CancelAuthDeferred));
295 BrowserThread::PostTask(
296 BrowserThread::UI, FROM_HERE,
297 NewRunnableMethod(this, &LoginHandler::NotifyAuthCancelled));
298 }
299
300 BrowserThread::PostTask(
301 BrowserThread::UI, FROM_HERE,
302 NewRunnableMethod(this, &LoginHandler::RemoveObservers));
303
304 // Delete this object once all InvokeLaters have been called.
305 BrowserThread::ReleaseSoon(BrowserThread::IO, FROM_HERE, this);
306 }
307
308 // Returns whether authentication had been handled (SetAuth or CancelAuth).
309 // If |set_handled| is true, it will mark authentication as handled.
310 bool LoginHandler::WasAuthHandled(bool set_handled) {
311 AutoLock lock(handled_auth_lock_);
312 bool was_handled = handled_auth_;
313 if (set_handled)
314 handled_auth_ = true;
315 return was_handled;
316 }
317
318 // Calls SetAuth from the IO loop.
319 void LoginHandler::SetAuthDeferred(const std::wstring& username,
320 const std::wstring& password) {
321 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
322
323 if (request_) {
324 request_->SetAuth(WideToUTF16Hack(username), WideToUTF16Hack(password));
325 ResetLoginHandlerForRequest(request_);
326 }
327 }
328
329 // Calls CancelAuth from the IO loop.
330 void LoginHandler::CancelAuthDeferred() {
331 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
332
333 if (request_) {
334 request_->CancelAuth();
335 // Verify that CancelAuth doesn't destroy the request via our delegate.
336 DCHECK(request_ != NULL);
337 ResetLoginHandlerForRequest(request_);
338 }
339 }
340
341 // Closes the view_contents from the UI loop.
342 void LoginHandler::CloseContentsDeferred() {
343 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
344
345 // The hosting ConstrainedWindow may have been freed.
346 if (dialog_)
347 dialog_->CloseConstrainedWindow();
348 }
349
350 // ----------------------------------------------------------------------------
351 // LoginDialogTask
352
353 // This task is run on the UI thread and creates a constrained window with
354 // a LoginView to prompt the user. The response will be sent to LoginHandler,
355 // which then routes it to the net::URLRequest on the I/O thread.
356 class LoginDialogTask : public Task {
357 public:
358 LoginDialogTask(const GURL& request_url,
359 net::AuthChallengeInfo* auth_info,
360 LoginHandler* handler)
361 : request_url_(request_url), auth_info_(auth_info), handler_(handler) {
362 }
363 virtual ~LoginDialogTask() {
364 }
365
366 void Run() {
367 TabContents* parent_contents = handler_->GetTabContentsForLogin();
368 if (!parent_contents) {
369 // The request may have been cancelled, or it may be for a renderer
370 // not hosted by a tab (e.g. an extension). Cancel just in case
371 // (cancelling twice is a no-op).
372 handler_->CancelAuth();
373 return;
374 }
375
376 // Tell the password manager to look for saved passwords.
377 TabContentsWrapper** wrapper =
378 TabContentsWrapper::property_accessor()->GetProperty(
379 parent_contents->property_bag());
380 if (!wrapper)
381 return;
382 PasswordManager* password_manager = (*wrapper)->GetPasswordManager();
383 std::vector<PasswordForm> v;
384 MakeInputForPasswordManager(&v);
385 password_manager->PasswordFormsFound(v);
386 handler_->SetPasswordManager(password_manager);
387
388 std::wstring explanation = auth_info_->realm.empty() ?
389 l10n_util::GetStringF(IDS_LOGIN_DIALOG_DESCRIPTION_NO_REALM,
390 auth_info_->host_and_port) :
391 l10n_util::GetStringF(IDS_LOGIN_DIALOG_DESCRIPTION,
392 auth_info_->host_and_port,
393 auth_info_->realm);
394 handler_->BuildViewForPasswordManager(password_manager,
395 explanation);
396 }
397
398 private:
399 // Helper to create a PasswordForm and stuff it into a vector as input
400 // for PasswordManager::PasswordFormsFound, the hook into PasswordManager.
401 void MakeInputForPasswordManager(
402 std::vector<PasswordForm>* password_manager_input) {
403 PasswordForm dialog_form;
404 if (LowerCaseEqualsASCII(auth_info_->scheme, "basic")) {
405 dialog_form.scheme = PasswordForm::SCHEME_BASIC;
406 } else if (LowerCaseEqualsASCII(auth_info_->scheme, "digest")) {
407 dialog_form.scheme = PasswordForm::SCHEME_DIGEST;
408 } else {
409 dialog_form.scheme = PasswordForm::SCHEME_OTHER;
410 }
411 std::string host_and_port(WideToASCII(auth_info_->host_and_port));
412 if (auth_info_->is_proxy) {
413 std::string origin = host_and_port;
414 // We don't expect this to already start with http:// or https://.
415 DCHECK(origin.find("http://") != 0 && origin.find("https://") != 0);
416 origin = std::string("http://") + origin;
417 dialog_form.origin = GURL(origin);
418 } else if (net::GetHostAndPort(request_url_) != host_and_port) {
419 dialog_form.origin = GURL();
420 NOTREACHED(); // crbug.com/32718
421 } else {
422 dialog_form.origin = GURL(request_url_.scheme() + "://" + host_and_port);
423 }
424 dialog_form.signon_realm = GetSignonRealm(dialog_form.origin, *auth_info_);
425 password_manager_input->push_back(dialog_form);
426 // Set the password form for the handler (by copy).
427 handler_->SetPasswordForm(dialog_form);
428 }
429
430 // The url from the net::URLRequest initiating the auth challenge.
431 GURL request_url_;
432
433 // Info about who/where/what is asking for authentication.
434 scoped_refptr<net::AuthChallengeInfo> auth_info_;
435
436 // Where to send the authentication when obtained.
437 // This is owned by the ResourceDispatcherHost that invoked us.
438 LoginHandler* handler_;
439
440 DISALLOW_COPY_AND_ASSIGN(LoginDialogTask);
441 };
442
443 // ----------------------------------------------------------------------------
444 // Public API
445
446 LoginHandler* CreateLoginPrompt(net::AuthChallengeInfo* auth_info,
447 net::URLRequest* request) {
448 LoginHandler* handler = LoginHandler::Create(auth_info, request);
449 BrowserThread::PostTask(
450 BrowserThread::UI, FROM_HERE, new LoginDialogTask(
451 request->url(), auth_info, handler));
452 return handler;
453 }
OLDNEW
« no previous file with comments | « chrome/browser/login_prompt.h ('k') | chrome/browser/login_prompt_gtk.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698