| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/login/login_prompt.h" | 5 #include "chrome/browser/ui/login/login_prompt.h" |
| 6 | 6 |
| 7 #include <vector> | 7 #include <vector> |
| 8 | 8 |
| 9 #include "app/l10n_util.h" | 9 #include "app/l10n_util.h" |
| 10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 109 | 109 |
| 110 TabContents* LoginHandler::GetTabContentsForLogin() const { | 110 TabContents* LoginHandler::GetTabContentsForLogin() const { |
| 111 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 111 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 112 | 112 |
| 113 return tab_util::GetTabContentsByID(render_process_host_id_, | 113 return tab_util::GetTabContentsByID(render_process_host_id_, |
| 114 tab_contents_id_); | 114 tab_contents_id_); |
| 115 } | 115 } |
| 116 | 116 |
| 117 void LoginHandler::SetAuth(const std::wstring& username, | 117 void LoginHandler::SetAuth(const std::wstring& username, |
| 118 const std::wstring& password) { | 118 const std::wstring& password) { |
| 119 if (WasAuthHandled(true)) | 119 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 120 |
| 121 if (TestAndSetAuthHandled()) |
| 120 return; | 122 return; |
| 121 | 123 |
| 122 // Tell the password manager the credentials were submitted / accepted. | 124 // Tell the password manager the credentials were submitted / accepted. |
| 123 if (password_manager_) { | 125 if (password_manager_) { |
| 124 password_form_.username_value = WideToUTF16Hack(username); | 126 password_form_.username_value = WideToUTF16Hack(username); |
| 125 password_form_.password_value = WideToUTF16Hack(password); | 127 password_form_.password_value = WideToUTF16Hack(password); |
| 126 password_manager_->ProvisionallySavePassword(password_form_); | 128 password_manager_->ProvisionallySavePassword(password_form_); |
| 127 } | 129 } |
| 128 | 130 |
| 131 // Calling NotifyAuthSupplied() directly instead of posting a task |
| 132 // allows other LoginHandler instances to queue their |
| 133 // CloseContentsDeferred() before ours. Closing dialogs in the |
| 134 // opposite order as they were created avoids races where remaining |
| 135 // dialogs in the same tab may be briefly displayed to the user |
| 136 // before they are removed. |
| 137 NotifyAuthSupplied(username, password); |
| 138 |
| 129 BrowserThread::PostTask( | 139 BrowserThread::PostTask( |
| 130 BrowserThread::UI, FROM_HERE, | 140 BrowserThread::UI, FROM_HERE, |
| 131 NewRunnableMethod(this, &LoginHandler::CloseContentsDeferred)); | 141 NewRunnableMethod(this, &LoginHandler::CloseContentsDeferred)); |
| 132 BrowserThread::PostTask( | 142 BrowserThread::PostTask( |
| 133 BrowserThread::UI, FROM_HERE, | |
| 134 NewRunnableMethod( | |
| 135 this, &LoginHandler::NotifyAuthSupplied, username, password)); | |
| 136 BrowserThread::PostTask( | |
| 137 BrowserThread::IO, FROM_HERE, | 143 BrowserThread::IO, FROM_HERE, |
| 138 NewRunnableMethod( | 144 NewRunnableMethod( |
| 139 this, &LoginHandler::SetAuthDeferred, username, password)); | 145 this, &LoginHandler::SetAuthDeferred, username, password)); |
| 140 } | 146 } |
| 141 | 147 |
| 142 void LoginHandler::CancelAuth() { | 148 void LoginHandler::CancelAuth() { |
| 143 if (WasAuthHandled(true)) | 149 if (TestAndSetAuthHandled()) |
| 144 return; | 150 return; |
| 145 | 151 |
| 152 // Similar to how we deal with notifications above in SetAuth() |
| 153 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
| 154 NotifyAuthCancelled(); |
| 155 } else { |
| 156 BrowserThread::PostTask( |
| 157 BrowserThread::UI, FROM_HERE, |
| 158 NewRunnableMethod(this, &LoginHandler::NotifyAuthCancelled)); |
| 159 } |
| 160 |
| 146 BrowserThread::PostTask( | 161 BrowserThread::PostTask( |
| 147 BrowserThread::UI, FROM_HERE, | 162 BrowserThread::UI, FROM_HERE, |
| 148 NewRunnableMethod(this, &LoginHandler::CloseContentsDeferred)); | 163 NewRunnableMethod(this, &LoginHandler::CloseContentsDeferred)); |
| 149 BrowserThread::PostTask( | 164 BrowserThread::PostTask( |
| 150 BrowserThread::UI, FROM_HERE, | |
| 151 NewRunnableMethod(this, &LoginHandler::NotifyAuthCancelled)); | |
| 152 BrowserThread::PostTask( | |
| 153 BrowserThread::IO, FROM_HERE, | 165 BrowserThread::IO, FROM_HERE, |
| 154 NewRunnableMethod(this, &LoginHandler::CancelAuthDeferred)); | 166 NewRunnableMethod(this, &LoginHandler::CancelAuthDeferred)); |
| 155 } | 167 } |
| 156 | 168 |
| 157 void LoginHandler::OnRequestCancelled() { | 169 void LoginHandler::OnRequestCancelled() { |
| 158 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)) << | 170 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)) << |
| 159 "Why is OnRequestCancelled called from the UI thread?"; | 171 "Why is OnRequestCancelled called from the UI thread?"; |
| 160 | 172 |
| 161 // Reference is no longer valid. | 173 // Reference is no longer valid. |
| 162 request_ = NULL; | 174 request_ = NULL; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 189 const NotificationSource& source, | 201 const NotificationSource& source, |
| 190 const NotificationDetails& details) { | 202 const NotificationDetails& details) { |
| 191 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 203 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 192 DCHECK(type == NotificationType::AUTH_SUPPLIED || | 204 DCHECK(type == NotificationType::AUTH_SUPPLIED || |
| 193 type == NotificationType::AUTH_CANCELLED); | 205 type == NotificationType::AUTH_CANCELLED); |
| 194 | 206 |
| 195 TabContents* requesting_contents = GetTabContentsForLogin(); | 207 TabContents* requesting_contents = GetTabContentsForLogin(); |
| 196 if (!requesting_contents) | 208 if (!requesting_contents) |
| 197 return; | 209 return; |
| 198 | 210 |
| 199 NavigationController* this_controller = &requesting_contents->controller(); | 211 // Break out early if we aren't interested in the notification. |
| 200 NavigationController* that_controller = | 212 if (WasAuthHandled()) |
| 201 Source<NavigationController>(source).ptr(); | |
| 202 | |
| 203 // Only handle notifications from other handlers. | |
| 204 if (this_controller == that_controller) | |
| 205 return; | 213 return; |
| 206 | 214 |
| 207 LoginNotificationDetails* login_details = | 215 LoginNotificationDetails* login_details = |
| 208 Details<LoginNotificationDetails>(details).ptr(); | 216 Details<LoginNotificationDetails>(details).ptr(); |
| 209 | 217 |
| 218 // WasAuthHandled() should always test positive before we publish |
| 219 // AUTH_SUPPLIED or AUTH_CANCELLED notifications. |
| 220 DCHECK(login_details->handler() != this); |
| 221 |
| 210 // Only handle notification for the identical auth info. | 222 // Only handle notification for the identical auth info. |
| 211 if (*login_details->handler()->auth_info() != *auth_info()) | 223 if (*login_details->handler()->auth_info() != *auth_info()) |
| 212 return; | 224 return; |
| 213 | 225 |
| 214 // Set or cancel the auth in this handler. | 226 // Set or cancel the auth in this handler. |
| 215 if (type == NotificationType::AUTH_SUPPLIED) { | 227 if (type == NotificationType::AUTH_SUPPLIED) { |
| 216 AuthSuppliedLoginNotificationDetails* supplied_details = | 228 AuthSuppliedLoginNotificationDetails* supplied_details = |
| 217 Details<AuthSuppliedLoginNotificationDetails>(details).ptr(); | 229 Details<AuthSuppliedLoginNotificationDetails>(details).ptr(); |
| 218 SetAuth(supplied_details->username(), supplied_details->password()); | 230 SetAuth(supplied_details->username(), supplied_details->password()); |
| 219 } else { | 231 } else { |
| 220 DCHECK(type == NotificationType::AUTH_CANCELLED); | 232 DCHECK(type == NotificationType::AUTH_CANCELLED); |
| 221 CancelAuth(); | 233 CancelAuth(); |
| 222 } | 234 } |
| 223 } | 235 } |
| 224 | 236 |
| 225 void LoginHandler::SetModel(LoginModel* model) { | 237 void LoginHandler::SetModel(LoginModel* model) { |
| 226 if (login_model_) | 238 if (login_model_) |
| 227 login_model_->SetObserver(NULL); | 239 login_model_->SetObserver(NULL); |
| 228 login_model_ = model; | 240 login_model_ = model; |
| 229 if (login_model_) | 241 if (login_model_) |
| 230 login_model_->SetObserver(this); | 242 login_model_->SetObserver(this); |
| 231 } | 243 } |
| 232 | 244 |
| 233 void LoginHandler::SetDialog(ConstrainedWindow* dialog) { | 245 void LoginHandler::SetDialog(ConstrainedWindow* dialog) { |
| 234 dialog_ = dialog; | 246 dialog_ = dialog; |
| 235 } | 247 } |
| 236 | 248 |
| 237 void LoginHandler::NotifyAuthNeeded() { | 249 void LoginHandler::NotifyAuthNeeded() { |
| 238 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 250 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 239 if (WasAuthHandled(false)) | 251 if (WasAuthHandled()) |
| 240 return; | 252 return; |
| 241 | 253 |
| 242 TabContents* requesting_contents = GetTabContentsForLogin(); | 254 TabContents* requesting_contents = GetTabContentsForLogin(); |
| 243 if (!requesting_contents) | 255 if (!requesting_contents) |
| 244 return; | 256 return; |
| 245 | 257 |
| 246 NotificationService* service = NotificationService::current(); | 258 NotificationService* service = NotificationService::current(); |
| 247 NavigationController* controller = &requesting_contents->controller(); | 259 NavigationController* controller = &requesting_contents->controller(); |
| 248 LoginNotificationDetails details(this); | 260 LoginNotificationDetails details(this); |
| 249 | 261 |
| 250 service->Notify(NotificationType::AUTH_NEEDED, | 262 service->Notify(NotificationType::AUTH_NEEDED, |
| 251 Source<NavigationController>(controller), | 263 Source<NavigationController>(controller), |
| 252 Details<LoginNotificationDetails>(&details)); | 264 Details<LoginNotificationDetails>(&details)); |
| 253 } | 265 } |
| 254 | 266 |
| 255 void LoginHandler::NotifyAuthCancelled() { | 267 void LoginHandler::NotifyAuthCancelled() { |
| 256 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 268 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 257 DCHECK(WasAuthHandled(false)); | 269 DCHECK(WasAuthHandled()); |
| 258 | 270 |
| 259 TabContents* requesting_contents = GetTabContentsForLogin(); | 271 TabContents* requesting_contents = GetTabContentsForLogin(); |
| 260 if (!requesting_contents) | 272 if (!requesting_contents) |
| 261 return; | 273 return; |
| 262 | 274 |
| 263 NotificationService* service = NotificationService::current(); | 275 NotificationService* service = NotificationService::current(); |
| 264 NavigationController* controller = &requesting_contents->controller(); | 276 NavigationController* controller = &requesting_contents->controller(); |
| 265 LoginNotificationDetails details(this); | 277 LoginNotificationDetails details(this); |
| 266 | 278 |
| 267 service->Notify(NotificationType::AUTH_CANCELLED, | 279 service->Notify(NotificationType::AUTH_CANCELLED, |
| 268 Source<NavigationController>(controller), | 280 Source<NavigationController>(controller), |
| 269 Details<LoginNotificationDetails>(&details)); | 281 Details<LoginNotificationDetails>(&details)); |
| 270 } | 282 } |
| 271 | 283 |
| 272 void LoginHandler::NotifyAuthSupplied(const std::wstring& username, | 284 void LoginHandler::NotifyAuthSupplied(const std::wstring& username, |
| 273 const std::wstring& password) { | 285 const std::wstring& password) { |
| 274 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 286 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 275 DCHECK(WasAuthHandled(false)); | 287 DCHECK(WasAuthHandled()); |
| 276 | 288 |
| 277 TabContents* requesting_contents = GetTabContentsForLogin(); | 289 TabContents* requesting_contents = GetTabContentsForLogin(); |
| 278 if (!requesting_contents) | 290 if (!requesting_contents) |
| 279 return; | 291 return; |
| 280 | 292 |
| 281 NotificationService* service = NotificationService::current(); | 293 NotificationService* service = NotificationService::current(); |
| 282 NavigationController* controller = &requesting_contents->controller(); | 294 NavigationController* controller = &requesting_contents->controller(); |
| 283 AuthSuppliedLoginNotificationDetails details(this, username, password); | 295 AuthSuppliedLoginNotificationDetails details(this, username, password); |
| 284 | 296 |
| 285 service->Notify(NotificationType::AUTH_SUPPLIED, | 297 service->Notify(NotificationType::AUTH_SUPPLIED, |
| 286 Source<NavigationController>(controller), | 298 Source<NavigationController>(controller), |
| 287 Details<AuthSuppliedLoginNotificationDetails>(&details)); | 299 Details<AuthSuppliedLoginNotificationDetails>(&details)); |
| 288 } | 300 } |
| 289 | 301 |
| 290 void LoginHandler::ReleaseSoon() { | 302 void LoginHandler::ReleaseSoon() { |
| 291 if (!WasAuthHandled(true)) { | 303 if (!TestAndSetAuthHandled()) { |
| 292 BrowserThread::PostTask( | 304 BrowserThread::PostTask( |
| 293 BrowserThread::IO, FROM_HERE, | 305 BrowserThread::IO, FROM_HERE, |
| 294 NewRunnableMethod(this, &LoginHandler::CancelAuthDeferred)); | 306 NewRunnableMethod(this, &LoginHandler::CancelAuthDeferred)); |
| 295 BrowserThread::PostTask( | 307 BrowserThread::PostTask( |
| 296 BrowserThread::UI, FROM_HERE, | 308 BrowserThread::UI, FROM_HERE, |
| 297 NewRunnableMethod(this, &LoginHandler::NotifyAuthCancelled)); | 309 NewRunnableMethod(this, &LoginHandler::NotifyAuthCancelled)); |
| 298 } | 310 } |
| 299 | 311 |
| 300 BrowserThread::PostTask( | 312 BrowserThread::PostTask( |
| 301 BrowserThread::UI, FROM_HERE, | 313 BrowserThread::UI, FROM_HERE, |
| 302 NewRunnableMethod(this, &LoginHandler::RemoveObservers)); | 314 NewRunnableMethod(this, &LoginHandler::RemoveObservers)); |
| 303 | 315 |
| 304 // Delete this object once all InvokeLaters have been called. | 316 // Delete this object once all InvokeLaters have been called. |
| 305 BrowserThread::ReleaseSoon(BrowserThread::IO, FROM_HERE, this); | 317 BrowserThread::ReleaseSoon(BrowserThread::IO, FROM_HERE, this); |
| 306 } | 318 } |
| 307 | 319 |
| 308 // Returns whether authentication had been handled (SetAuth or CancelAuth). | 320 // Returns whether authentication had been handled (SetAuth or CancelAuth). |
| 309 // If |set_handled| is true, it will mark authentication as handled. | 321 bool LoginHandler::WasAuthHandled() const { |
| 310 bool LoginHandler::WasAuthHandled(bool set_handled) { | |
| 311 AutoLock lock(handled_auth_lock_); | 322 AutoLock lock(handled_auth_lock_); |
| 312 bool was_handled = handled_auth_; | 323 bool was_handled = handled_auth_; |
| 313 if (set_handled) | |
| 314 handled_auth_ = true; | |
| 315 return was_handled; | 324 return was_handled; |
| 316 } | 325 } |
| 317 | 326 |
| 327 // Marks authentication as handled and returns the previous handled state. |
| 328 bool LoginHandler::TestAndSetAuthHandled() { |
| 329 AutoLock lock(handled_auth_lock_); |
| 330 bool was_handled = handled_auth_; |
| 331 handled_auth_ = true; |
| 332 return was_handled; |
| 333 } |
| 334 |
| 318 // Calls SetAuth from the IO loop. | 335 // Calls SetAuth from the IO loop. |
| 319 void LoginHandler::SetAuthDeferred(const std::wstring& username, | 336 void LoginHandler::SetAuthDeferred(const std::wstring& username, |
| 320 const std::wstring& password) { | 337 const std::wstring& password) { |
| 321 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 338 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 322 | 339 |
| 323 if (request_) { | 340 if (request_) { |
| 324 request_->SetAuth(WideToUTF16Hack(username), WideToUTF16Hack(password)); | 341 request_->SetAuth(WideToUTF16Hack(username), WideToUTF16Hack(password)); |
| 325 ResetLoginHandlerForRequest(request_); | 342 ResetLoginHandlerForRequest(request_); |
| 326 } | 343 } |
| 327 } | 344 } |
| (...skipping 30 matching lines...) Expand all Loading... |
| 358 LoginDialogTask(const GURL& request_url, | 375 LoginDialogTask(const GURL& request_url, |
| 359 net::AuthChallengeInfo* auth_info, | 376 net::AuthChallengeInfo* auth_info, |
| 360 LoginHandler* handler) | 377 LoginHandler* handler) |
| 361 : request_url_(request_url), auth_info_(auth_info), handler_(handler) { | 378 : request_url_(request_url), auth_info_(auth_info), handler_(handler) { |
| 362 } | 379 } |
| 363 virtual ~LoginDialogTask() { | 380 virtual ~LoginDialogTask() { |
| 364 } | 381 } |
| 365 | 382 |
| 366 void Run() { | 383 void Run() { |
| 367 TabContents* parent_contents = handler_->GetTabContentsForLogin(); | 384 TabContents* parent_contents = handler_->GetTabContentsForLogin(); |
| 368 if (!parent_contents) { | 385 if (!parent_contents || handler_->WasAuthHandled()) { |
| 369 // The request may have been cancelled, or it may be for a renderer | 386 // 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 | 387 // not hosted by a tab (e.g. an extension). Cancel just in case |
| 371 // (cancelling twice is a no-op). | 388 // (cancelling twice is a no-op). |
| 372 handler_->CancelAuth(); | 389 handler_->CancelAuth(); |
| 373 return; | 390 return; |
| 374 } | 391 } |
| 375 | 392 |
| 376 // Tell the password manager to look for saved passwords. | 393 // Tell the password manager to look for saved passwords. |
| 377 TabContentsWrapper** wrapper = | 394 TabContentsWrapper** wrapper = |
| 378 TabContentsWrapper::property_accessor()->GetProperty( | 395 TabContentsWrapper::property_accessor()->GetProperty( |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 446 // Public API | 463 // Public API |
| 447 | 464 |
| 448 LoginHandler* CreateLoginPrompt(net::AuthChallengeInfo* auth_info, | 465 LoginHandler* CreateLoginPrompt(net::AuthChallengeInfo* auth_info, |
| 449 net::URLRequest* request) { | 466 net::URLRequest* request) { |
| 450 LoginHandler* handler = LoginHandler::Create(auth_info, request); | 467 LoginHandler* handler = LoginHandler::Create(auth_info, request); |
| 451 BrowserThread::PostTask( | 468 BrowserThread::PostTask( |
| 452 BrowserThread::UI, FROM_HERE, new LoginDialogTask( | 469 BrowserThread::UI, FROM_HERE, new LoginDialogTask( |
| 453 request->url(), auth_info, handler)); | 470 request->url(), auth_info, handler)); |
| 454 return handler; | 471 return handler; |
| 455 } | 472 } |
| OLD | NEW |