| Index: chrome/browser/login_prompt.cc
|
| ===================================================================
|
| --- chrome/browser/login_prompt.cc (revision 68047)
|
| +++ chrome/browser/login_prompt.cc (working copy)
|
| @@ -1,453 +0,0 @@
|
| -// Copyright (c) 2009 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "chrome/browser/login_prompt.h"
|
| -
|
| -#include <vector>
|
| -
|
| -#include "app/l10n_util.h"
|
| -#include "base/command_line.h"
|
| -#include "base/lock.h"
|
| -#include "base/utf_string_conversions.h"
|
| -#include "chrome/browser/browser_thread.h"
|
| -#include "chrome/browser/password_manager/password_manager.h"
|
| -#include "chrome/browser/renderer_host/render_process_host.h"
|
| -#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
|
| -#include "chrome/browser/renderer_host/resource_dispatcher_host_request_info.h"
|
| -#include "chrome/browser/tab_contents/constrained_window.h"
|
| -#include "chrome/browser/tab_contents/tab_contents.h"
|
| -#include "chrome/browser/tab_contents/tab_util.h"
|
| -#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
|
| -#include "chrome/common/chrome_switches.h"
|
| -#include "chrome/common/notification_service.h"
|
| -#include "grit/generated_resources.h"
|
| -#include "net/base/auth.h"
|
| -#include "net/base/net_util.h"
|
| -#include "net/url_request/url_request.h"
|
| -
|
| -using webkit_glue::PasswordForm;
|
| -
|
| -class LoginHandlerImpl;
|
| -
|
| -// Helper to remove the ref from an net::URLRequest to the LoginHandler.
|
| -// Should only be called from the IO thread, since it accesses an
|
| -// net::URLRequest.
|
| -void ResetLoginHandlerForRequest(net::URLRequest* request) {
|
| - ResourceDispatcherHostRequestInfo* info =
|
| - ResourceDispatcherHost::InfoForRequest(request);
|
| - if (!info)
|
| - return;
|
| -
|
| - info->set_login_handler(NULL);
|
| -}
|
| -
|
| -// Get the signon_realm under which this auth info should be stored.
|
| -//
|
| -// The format of the signon_realm for proxy auth is:
|
| -// proxy-host/auth-realm
|
| -// The format of the signon_realm for server auth is:
|
| -// url-scheme://url-host[:url-port]/auth-realm
|
| -//
|
| -// Be careful when changing this function, since you could make existing
|
| -// saved logins un-retrievable.
|
| -std::string GetSignonRealm(const GURL& url,
|
| - const net::AuthChallengeInfo& auth_info) {
|
| - std::string signon_realm;
|
| - if (auth_info.is_proxy) {
|
| - signon_realm = WideToASCII(auth_info.host_and_port);
|
| - signon_realm.append("/");
|
| - } else {
|
| - // Take scheme, host, and port from the url.
|
| - signon_realm = url.GetOrigin().spec();
|
| - // This ends with a "/".
|
| - }
|
| - signon_realm.append(WideToUTF8(auth_info.realm));
|
| - return signon_realm;
|
| -}
|
| -
|
| -// ----------------------------------------------------------------------------
|
| -// LoginHandler
|
| -
|
| -LoginHandler::LoginHandler(net::AuthChallengeInfo* auth_info,
|
| - net::URLRequest* request)
|
| - : handled_auth_(false),
|
| - dialog_(NULL),
|
| - auth_info_(auth_info),
|
| - request_(request),
|
| - password_manager_(NULL),
|
| - login_model_(NULL) {
|
| - // This constructor is called on the I/O thread, so we cannot load the nib
|
| - // here. BuildViewForPasswordManager() will be invoked on the UI thread
|
| - // later, so wait with loading the nib until then.
|
| - DCHECK(request_) << "LoginHandler constructed with NULL request";
|
| - DCHECK(auth_info_) << "LoginHandler constructed with NULL auth info";
|
| -
|
| - AddRef(); // matched by LoginHandler::ReleaseSoon().
|
| -
|
| - BrowserThread::PostTask(
|
| - BrowserThread::UI, FROM_HERE,
|
| - NewRunnableMethod(this, &LoginHandler::AddObservers));
|
| -
|
| - if (!ResourceDispatcherHost::RenderViewForRequest(
|
| - request_, &render_process_host_id_, &tab_contents_id_)) {
|
| - NOTREACHED();
|
| - }
|
| -}
|
| -
|
| -LoginHandler::~LoginHandler() {
|
| - SetModel(NULL);
|
| -}
|
| -
|
| -void LoginHandler::SetPasswordForm(const webkit_glue::PasswordForm& form) {
|
| - password_form_ = form;
|
| -}
|
| -
|
| -void LoginHandler::SetPasswordManager(PasswordManager* password_manager) {
|
| - password_manager_ = password_manager;
|
| -}
|
| -
|
| -TabContents* LoginHandler::GetTabContentsForLogin() const {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| -
|
| - return tab_util::GetTabContentsByID(render_process_host_id_,
|
| - tab_contents_id_);
|
| -}
|
| -
|
| -void LoginHandler::SetAuth(const std::wstring& username,
|
| - const std::wstring& password) {
|
| - if (WasAuthHandled(true))
|
| - return;
|
| -
|
| - // Tell the password manager the credentials were submitted / accepted.
|
| - if (password_manager_) {
|
| - password_form_.username_value = WideToUTF16Hack(username);
|
| - password_form_.password_value = WideToUTF16Hack(password);
|
| - password_manager_->ProvisionallySavePassword(password_form_);
|
| - }
|
| -
|
| - BrowserThread::PostTask(
|
| - BrowserThread::UI, FROM_HERE,
|
| - NewRunnableMethod(this, &LoginHandler::CloseContentsDeferred));
|
| - BrowserThread::PostTask(
|
| - BrowserThread::UI, FROM_HERE,
|
| - NewRunnableMethod(
|
| - this, &LoginHandler::NotifyAuthSupplied, username, password));
|
| - BrowserThread::PostTask(
|
| - BrowserThread::IO, FROM_HERE,
|
| - NewRunnableMethod(
|
| - this, &LoginHandler::SetAuthDeferred, username, password));
|
| -}
|
| -
|
| -void LoginHandler::CancelAuth() {
|
| - if (WasAuthHandled(true))
|
| - return;
|
| -
|
| - BrowserThread::PostTask(
|
| - BrowserThread::UI, FROM_HERE,
|
| - NewRunnableMethod(this, &LoginHandler::CloseContentsDeferred));
|
| - BrowserThread::PostTask(
|
| - BrowserThread::UI, FROM_HERE,
|
| - NewRunnableMethod(this, &LoginHandler::NotifyAuthCancelled));
|
| - BrowserThread::PostTask(
|
| - BrowserThread::IO, FROM_HERE,
|
| - NewRunnableMethod(this, &LoginHandler::CancelAuthDeferred));
|
| -}
|
| -
|
| -void LoginHandler::OnRequestCancelled() {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)) <<
|
| - "Why is OnRequestCancelled called from the UI thread?";
|
| -
|
| - // Reference is no longer valid.
|
| - request_ = NULL;
|
| -
|
| - // Give up on auth if the request was cancelled.
|
| - CancelAuth();
|
| -}
|
| -
|
| -void LoginHandler::AddObservers() {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| -
|
| - registrar_.Add(this, NotificationType::AUTH_SUPPLIED,
|
| - NotificationService::AllSources());
|
| - registrar_.Add(this, NotificationType::AUTH_CANCELLED,
|
| - NotificationService::AllSources());
|
| -}
|
| -
|
| -void LoginHandler::RemoveObservers() {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| -
|
| - registrar_.Remove(this, NotificationType::AUTH_SUPPLIED,
|
| - NotificationService::AllSources());
|
| - registrar_.Remove(this, NotificationType::AUTH_CANCELLED,
|
| - NotificationService::AllSources());
|
| -
|
| - DCHECK(registrar_.IsEmpty());
|
| -}
|
| -
|
| -void LoginHandler::Observe(NotificationType type,
|
| - const NotificationSource& source,
|
| - const NotificationDetails& details) {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| - DCHECK(type == NotificationType::AUTH_SUPPLIED ||
|
| - type == NotificationType::AUTH_CANCELLED);
|
| -
|
| - TabContents* requesting_contents = GetTabContentsForLogin();
|
| - if (!requesting_contents)
|
| - return;
|
| -
|
| - NavigationController* this_controller = &requesting_contents->controller();
|
| - NavigationController* that_controller =
|
| - Source<NavigationController>(source).ptr();
|
| -
|
| - // Only handle notifications from other handlers.
|
| - if (this_controller == that_controller)
|
| - return;
|
| -
|
| - LoginNotificationDetails* login_details =
|
| - Details<LoginNotificationDetails>(details).ptr();
|
| -
|
| - // Only handle notification for the identical auth info.
|
| - if (*login_details->handler()->auth_info() != *auth_info())
|
| - return;
|
| -
|
| - // Set or cancel the auth in this handler.
|
| - if (type == NotificationType::AUTH_SUPPLIED) {
|
| - AuthSuppliedLoginNotificationDetails* supplied_details =
|
| - Details<AuthSuppliedLoginNotificationDetails>(details).ptr();
|
| - SetAuth(supplied_details->username(), supplied_details->password());
|
| - } else {
|
| - DCHECK(type == NotificationType::AUTH_CANCELLED);
|
| - CancelAuth();
|
| - }
|
| -}
|
| -
|
| -void LoginHandler::SetModel(LoginModel* model) {
|
| - if (login_model_)
|
| - login_model_->SetObserver(NULL);
|
| - login_model_ = model;
|
| - if (login_model_)
|
| - login_model_->SetObserver(this);
|
| -}
|
| -
|
| -void LoginHandler::SetDialog(ConstrainedWindow* dialog) {
|
| - dialog_ = dialog;
|
| -}
|
| -
|
| -void LoginHandler::NotifyAuthNeeded() {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| - if (WasAuthHandled(false))
|
| - return;
|
| -
|
| - TabContents* requesting_contents = GetTabContentsForLogin();
|
| - if (!requesting_contents)
|
| - return;
|
| -
|
| - NotificationService* service = NotificationService::current();
|
| - NavigationController* controller = &requesting_contents->controller();
|
| - LoginNotificationDetails details(this);
|
| -
|
| - service->Notify(NotificationType::AUTH_NEEDED,
|
| - Source<NavigationController>(controller),
|
| - Details<LoginNotificationDetails>(&details));
|
| -}
|
| -
|
| -void LoginHandler::NotifyAuthCancelled() {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| - DCHECK(WasAuthHandled(false));
|
| -
|
| - TabContents* requesting_contents = GetTabContentsForLogin();
|
| - if (!requesting_contents)
|
| - return;
|
| -
|
| - NotificationService* service = NotificationService::current();
|
| - NavigationController* controller = &requesting_contents->controller();
|
| - LoginNotificationDetails details(this);
|
| -
|
| - service->Notify(NotificationType::AUTH_CANCELLED,
|
| - Source<NavigationController>(controller),
|
| - Details<LoginNotificationDetails>(&details));
|
| -}
|
| -
|
| -void LoginHandler::NotifyAuthSupplied(const std::wstring& username,
|
| - const std::wstring& password) {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| - DCHECK(WasAuthHandled(false));
|
| -
|
| - TabContents* requesting_contents = GetTabContentsForLogin();
|
| - if (!requesting_contents)
|
| - return;
|
| -
|
| - NotificationService* service = NotificationService::current();
|
| - NavigationController* controller = &requesting_contents->controller();
|
| - AuthSuppliedLoginNotificationDetails details(this, username, password);
|
| -
|
| - service->Notify(NotificationType::AUTH_SUPPLIED,
|
| - Source<NavigationController>(controller),
|
| - Details<AuthSuppliedLoginNotificationDetails>(&details));
|
| -}
|
| -
|
| -void LoginHandler::ReleaseSoon() {
|
| - if (!WasAuthHandled(true)) {
|
| - BrowserThread::PostTask(
|
| - BrowserThread::IO, FROM_HERE,
|
| - NewRunnableMethod(this, &LoginHandler::CancelAuthDeferred));
|
| - BrowserThread::PostTask(
|
| - BrowserThread::UI, FROM_HERE,
|
| - NewRunnableMethod(this, &LoginHandler::NotifyAuthCancelled));
|
| - }
|
| -
|
| - BrowserThread::PostTask(
|
| - BrowserThread::UI, FROM_HERE,
|
| - NewRunnableMethod(this, &LoginHandler::RemoveObservers));
|
| -
|
| - // Delete this object once all InvokeLaters have been called.
|
| - BrowserThread::ReleaseSoon(BrowserThread::IO, FROM_HERE, this);
|
| -}
|
| -
|
| -// Returns whether authentication had been handled (SetAuth or CancelAuth).
|
| -// If |set_handled| is true, it will mark authentication as handled.
|
| -bool LoginHandler::WasAuthHandled(bool set_handled) {
|
| - AutoLock lock(handled_auth_lock_);
|
| - bool was_handled = handled_auth_;
|
| - if (set_handled)
|
| - handled_auth_ = true;
|
| - return was_handled;
|
| -}
|
| -
|
| -// Calls SetAuth from the IO loop.
|
| -void LoginHandler::SetAuthDeferred(const std::wstring& username,
|
| - const std::wstring& password) {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
| -
|
| - if (request_) {
|
| - request_->SetAuth(WideToUTF16Hack(username), WideToUTF16Hack(password));
|
| - ResetLoginHandlerForRequest(request_);
|
| - }
|
| -}
|
| -
|
| -// Calls CancelAuth from the IO loop.
|
| -void LoginHandler::CancelAuthDeferred() {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
| -
|
| - if (request_) {
|
| - request_->CancelAuth();
|
| - // Verify that CancelAuth doesn't destroy the request via our delegate.
|
| - DCHECK(request_ != NULL);
|
| - ResetLoginHandlerForRequest(request_);
|
| - }
|
| -}
|
| -
|
| -// Closes the view_contents from the UI loop.
|
| -void LoginHandler::CloseContentsDeferred() {
|
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
| -
|
| - // The hosting ConstrainedWindow may have been freed.
|
| - if (dialog_)
|
| - dialog_->CloseConstrainedWindow();
|
| -}
|
| -
|
| -// ----------------------------------------------------------------------------
|
| -// LoginDialogTask
|
| -
|
| -// This task is run on the UI thread and creates a constrained window with
|
| -// a LoginView to prompt the user. The response will be sent to LoginHandler,
|
| -// which then routes it to the net::URLRequest on the I/O thread.
|
| -class LoginDialogTask : public Task {
|
| - public:
|
| - LoginDialogTask(const GURL& request_url,
|
| - net::AuthChallengeInfo* auth_info,
|
| - LoginHandler* handler)
|
| - : request_url_(request_url), auth_info_(auth_info), handler_(handler) {
|
| - }
|
| - virtual ~LoginDialogTask() {
|
| - }
|
| -
|
| - void Run() {
|
| - TabContents* parent_contents = handler_->GetTabContentsForLogin();
|
| - if (!parent_contents) {
|
| - // The request may have been cancelled, or it may be for a renderer
|
| - // not hosted by a tab (e.g. an extension). Cancel just in case
|
| - // (cancelling twice is a no-op).
|
| - handler_->CancelAuth();
|
| - return;
|
| - }
|
| -
|
| - // Tell the password manager to look for saved passwords.
|
| - TabContentsWrapper** wrapper =
|
| - TabContentsWrapper::property_accessor()->GetProperty(
|
| - parent_contents->property_bag());
|
| - if (!wrapper)
|
| - return;
|
| - PasswordManager* password_manager = (*wrapper)->GetPasswordManager();
|
| - std::vector<PasswordForm> v;
|
| - MakeInputForPasswordManager(&v);
|
| - password_manager->PasswordFormsFound(v);
|
| - handler_->SetPasswordManager(password_manager);
|
| -
|
| - std::wstring explanation = auth_info_->realm.empty() ?
|
| - l10n_util::GetStringF(IDS_LOGIN_DIALOG_DESCRIPTION_NO_REALM,
|
| - auth_info_->host_and_port) :
|
| - l10n_util::GetStringF(IDS_LOGIN_DIALOG_DESCRIPTION,
|
| - auth_info_->host_and_port,
|
| - auth_info_->realm);
|
| - handler_->BuildViewForPasswordManager(password_manager,
|
| - explanation);
|
| - }
|
| -
|
| - private:
|
| - // Helper to create a PasswordForm and stuff it into a vector as input
|
| - // for PasswordManager::PasswordFormsFound, the hook into PasswordManager.
|
| - void MakeInputForPasswordManager(
|
| - std::vector<PasswordForm>* password_manager_input) {
|
| - PasswordForm dialog_form;
|
| - if (LowerCaseEqualsASCII(auth_info_->scheme, "basic")) {
|
| - dialog_form.scheme = PasswordForm::SCHEME_BASIC;
|
| - } else if (LowerCaseEqualsASCII(auth_info_->scheme, "digest")) {
|
| - dialog_form.scheme = PasswordForm::SCHEME_DIGEST;
|
| - } else {
|
| - dialog_form.scheme = PasswordForm::SCHEME_OTHER;
|
| - }
|
| - std::string host_and_port(WideToASCII(auth_info_->host_and_port));
|
| - if (auth_info_->is_proxy) {
|
| - std::string origin = host_and_port;
|
| - // We don't expect this to already start with http:// or https://.
|
| - DCHECK(origin.find("http://") != 0 && origin.find("https://") != 0);
|
| - origin = std::string("http://") + origin;
|
| - dialog_form.origin = GURL(origin);
|
| - } else if (net::GetHostAndPort(request_url_) != host_and_port) {
|
| - dialog_form.origin = GURL();
|
| - NOTREACHED(); // crbug.com/32718
|
| - } else {
|
| - dialog_form.origin = GURL(request_url_.scheme() + "://" + host_and_port);
|
| - }
|
| - dialog_form.signon_realm = GetSignonRealm(dialog_form.origin, *auth_info_);
|
| - password_manager_input->push_back(dialog_form);
|
| - // Set the password form for the handler (by copy).
|
| - handler_->SetPasswordForm(dialog_form);
|
| - }
|
| -
|
| - // The url from the net::URLRequest initiating the auth challenge.
|
| - GURL request_url_;
|
| -
|
| - // Info about who/where/what is asking for authentication.
|
| - scoped_refptr<net::AuthChallengeInfo> auth_info_;
|
| -
|
| - // Where to send the authentication when obtained.
|
| - // This is owned by the ResourceDispatcherHost that invoked us.
|
| - LoginHandler* handler_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(LoginDialogTask);
|
| -};
|
| -
|
| -// ----------------------------------------------------------------------------
|
| -// Public API
|
| -
|
| -LoginHandler* CreateLoginPrompt(net::AuthChallengeInfo* auth_info,
|
| - net::URLRequest* request) {
|
| - LoginHandler* handler = LoginHandler::Create(auth_info, request);
|
| - BrowserThread::PostTask(
|
| - BrowserThread::UI, FROM_HERE, new LoginDialogTask(
|
| - request->url(), auth_info, handler));
|
| - return handler;
|
| -}
|
|
|