blob: c0d5b283ae9eab229b93a4d5fad4238510bf7de3 [file] [log] [blame]
// Copyright (c) 2012 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.
#ifndef CHROME_BROWSER_UI_LOGIN_LOGIN_PROMPT_H_
#define CHROME_BROWSER_UI_LOGIN_LOGIN_PROMPT_H_
#include <string>
#include "base/basictypes.h"
#include "base/memory/weak_ptr.h"
#include "base/synchronization/lock.h"
#include "components/password_manager/core/browser/password_manager.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/resource_dispatcher_host_login_delegate.h"
#include "content/public/browser/resource_request_info.h"
class GURL;
class LoginInterstitialDelegate;
namespace content {
class RenderViewHostDelegate;
class NotificationRegistrar;
class WebContents;
} // namespace content
namespace net {
class AuthChallengeInfo;
class HttpNetworkSession;
class URLRequest;
} // namespace net
// This is the base implementation for the OS-specific classes that route
// authentication info to the net::URLRequest that needs it. These functions
// must be implemented in a thread safe manner.
class LoginHandler : public content::ResourceDispatcherHostLoginDelegate,
public password_manager::LoginModelObserver,
public content::NotificationObserver {
public:
// The purpose of this struct is to enforce that BuildViewImpl receives either
// both the login model and the observed form, or none. That is a bit spoiled
// by the fact that the model is a pointer to LoginModel, as opposed to a
// reference. Having it as a reference would go against the style guide, which
// forbids non-const references in arguments, presumably also inside passed
// structs, because the guide's rationale still applies. Therefore at least
// the constructor DCHECKs that |login_model| is not null.
struct LoginModelData {
LoginModelData(password_manager::LoginModel* login_model,
const autofill::PasswordForm& observed_form);
password_manager::LoginModel* const model;
const autofill::PasswordForm& form;
};
LoginHandler(net::AuthChallengeInfo* auth_info, net::URLRequest* request);
// Builds the platform specific LoginHandler. Used from within
// CreateLoginPrompt() which creates tasks.
static LoginHandler* Create(net::AuthChallengeInfo* auth_info,
net::URLRequest* request);
void SetInterstitialDelegate(
const base::WeakPtr<LoginInterstitialDelegate> delegate) {
interstitial_delegate_ = delegate;
}
// ResourceDispatcherHostLoginDelegate implementation:
void OnRequestCancelled() override;
// Use this to build a view with password manager support. |password_manager|
// must not be null.
void BuildViewWithPasswordManager(
const base::string16& authority,
const base::string16& explanation,
password_manager::PasswordManager* password_manager,
const autofill::PasswordForm& observed_form);
// Use this to build a view without password manager support.
void BuildViewWithoutPasswordManager(const base::string16& authority,
const base::string16& explanation);
// Returns the WebContents that needs authentication.
content::WebContents* GetWebContentsForLogin() const;
// Returns the PasswordManager for the web contents that needs login.
password_manager::PasswordManager* GetPasswordManagerForLogin();
// Resend the request with authentication credentials.
// This function can be called from either thread.
void SetAuth(const base::string16& username, const base::string16& password);
// Display the error page without asking for credentials again.
// This function can be called from either thread.
void CancelAuth();
// Implements the content::NotificationObserver interface.
// Listens for AUTH_SUPPLIED and AUTH_CANCELLED notifications from other
// LoginHandlers so that this LoginHandler has the chance to dismiss itself
// if it was waiting for the same authentication.
void Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) override;
// Who/where/what asked for the authentication.
const net::AuthChallengeInfo* auth_info() const { return auth_info_.get(); }
// Returns whether authentication had been handled (SetAuth or CancelAuth).
bool WasAuthHandled() const;
protected:
~LoginHandler() override;
// Implement this to initialize the underlying platform specific view. If
// |login_model_data| is not null, the contained LoginModel and PasswordForm
// can be used to register the view.
virtual void BuildViewImpl(const base::string16& authority,
const base::string16& explanation,
LoginModelData* login_model_data) = 0;
// Sets |model_data.model| as |login_model_| and registers |this| as an
// observer for |model_data.form|-related events.
void SetModel(LoginModelData model_data);
// Clears |login_model_| and removes |this| as an observer.
void ResetModel();
// Notify observers that authentication is needed.
void NotifyAuthNeeded();
// Performs necessary cleanup before deletion.
void ReleaseSoon();
// Closes the native dialog.
virtual void CloseDialog() = 0;
private:
// Starts observing notifications from other LoginHandlers.
void AddObservers();
// Stops observing notifications from other LoginHandlers.
void RemoveObservers();
// Notify observers that authentication is supplied.
void NotifyAuthSupplied(const base::string16& username,
const base::string16& password);
// Notify observers that authentication is cancelled.
void NotifyAuthCancelled(bool cancel_navigation);
// Marks authentication as handled and returns the previous handled
// state.
bool TestAndSetAuthHandled();
// Calls SetAuth from the IO loop.
void SetAuthDeferred(const base::string16& username,
const base::string16& password);
// Cancels the auth. If |cancel_navigation| is true, the existing login
// interstitial (if any) is closed and the pending navigation is cancelled.
void DoCancelAuth(bool cancel_navigation);
// Calls CancelAuth from the IO loop.
void CancelAuthDeferred();
// Closes the view_contents from the UI loop.
void CloseContentsDeferred();
// True if we've handled auth (SetAuth or CancelAuth has been called).
bool handled_auth_;
mutable base::Lock handled_auth_lock_;
// Who/where/what asked for the authentication.
scoped_refptr<net::AuthChallengeInfo> auth_info_;
// The request that wants login data.
// This should only be accessed on the IO loop.
net::URLRequest* request_;
// The HttpNetworkSession |request_| is associated with.
const net::HttpNetworkSession* http_network_session_;
// The PasswordForm sent to the PasswordManager. This is so we can refer to it
// when later notifying the password manager if the credentials were accepted
// or rejected.
// This should only be accessed on the UI loop.
autofill::PasswordForm password_form_;
// Points to the password manager owned by the WebContents requesting auth.
// This should only be accessed on the UI loop.
password_manager::PasswordManager* password_manager_;
// Cached from the net::URLRequest, in case it goes NULL on us.
content::ResourceRequestInfo::WebContentsGetter web_contents_getter_;
// If not null, points to a model we need to notify of our own destruction
// so it doesn't try and access this when its too late.
password_manager::LoginModel* login_model_;
// Observes other login handlers so this login handler can respond.
// This is only accessed on the UI thread.
scoped_ptr<content::NotificationRegistrar> registrar_;
base::WeakPtr<LoginInterstitialDelegate> interstitial_delegate_;
};
// Details to provide the content::NotificationObserver. Used by the automation
// proxy for testing.
class LoginNotificationDetails {
public:
explicit LoginNotificationDetails(LoginHandler* handler)
: handler_(handler) {}
LoginHandler* handler() const { return handler_; }
private:
LoginNotificationDetails() {}
LoginHandler* handler_; // Where to send the response.
DISALLOW_COPY_AND_ASSIGN(LoginNotificationDetails);
};
// Details to provide the NotificationObserver. Used by the automation proxy
// for testing and by other LoginHandlers to dismiss themselves when an
// identical auth is supplied.
class AuthSuppliedLoginNotificationDetails : public LoginNotificationDetails {
public:
AuthSuppliedLoginNotificationDetails(LoginHandler* handler,
const base::string16& username,
const base::string16& password)
: LoginNotificationDetails(handler),
username_(username),
password_(password) {}
const base::string16& username() const { return username_; }
const base::string16& password() const { return password_; }
private:
// The username that was used for the authentication.
const base::string16 username_;
// The password that was used for the authentication.
const base::string16 password_;
DISALLOW_COPY_AND_ASSIGN(AuthSuppliedLoginNotificationDetails);
};
// Prompts the user for their username and password. This is designed to
// be called on the background (I/O) thread, in response to
// net::URLRequest::Delegate::OnAuthRequired. The prompt will be created
// on the main UI thread via a call to UI loop's InvokeLater, and will send the
// credentials back to the net::URLRequest on the calling thread.
// A LoginHandler object (which lives on the calling thread) is returned,
// which can be used to set or cancel authentication programmatically. The
// caller must invoke OnRequestCancelled() on this LoginHandler before
// destroying the net::URLRequest.
LoginHandler* CreateLoginPrompt(net::AuthChallengeInfo* auth_info,
net::URLRequest* request);
// Get the signon_realm under which the identity should be saved.
std::string GetSignonRealm(const GURL& url,
const net::AuthChallengeInfo& auth_info);
#endif // CHROME_BROWSER_UI_LOGIN_LOGIN_PROMPT_H_