| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CHROME_BROWSER_ASH_HTTP_AUTH_DIALOG_H_ |
| #define CHROME_BROWSER_ASH_HTTP_AUTH_DIALOG_H_ |
| |
| #include "base/memory/weak_ptr.h" |
| #include "base/observer_list.h" |
| #include "content/public/browser/login_delegate.h" |
| #include "content/public/browser/web_contents.h" |
| #include "ui/views/controls/textfield/textfield.h" |
| #include "ui/views/widget/widget.h" |
| #include "ui/views/window/dialog_delegate.h" |
| |
| namespace ash { |
| |
| // HTTP authentication is a feature that gates network resources behind a |
| // plaintext username/password ACL. This is typically implemented by |
| // web-browsers by showing a dialog to users part-way through a navigation with |
| // username/password textfields. |
| // https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication |
| // |
| // There are some pieces of UI in ash-chrome unrelated to web-browsing that |
| // expect fine grained control over the dialog that is shown. This class |
| // provides a mechanism to do so. |
| |
| class HttpAuthDialog : public content::LoginDelegate { |
| public: |
| // There are two ways for this class to be deleted. |
| // (1) The //content layer can decide the class is no longer necessary, in |
| // which case the destructor will be directly invoked. In this case, clear |
| // `callback_` and close the widget. |
| // (2) The widget can be closed by the user. In this case, invoke the |
| // `callback_`. This will cause (1) to trigger. |
| ~HttpAuthDialog() override; |
| |
| class ScopedEnabler { |
| public: |
| ScopedEnabler(); |
| ~ScopedEnabler(); |
| ScopedEnabler(const ScopedEnabler&) = delete; |
| ScopedEnabler& operator=(const ScopedEnabler&) = delete; |
| }; |
| // Prior to shipping Lacros, ash-chrome needs to handle both browser-based |
| // http-auth dialogs, and OS-based http-auth dialogs. Classes that need the |
| // latter should call this method and keep the returned ScopedEnabler alive. |
| // This forces the latter use-case. |
| // After shipping Lacros, this method will be unnecessary as the OS-based |
| // http-auth dialog will be the only remaining use case. |
| static std::unique_ptr<ScopedEnabler> Enable(); |
| static bool IsEnabled(); |
| |
| static std::unique_ptr<HttpAuthDialog> Create( |
| const net::AuthChallengeInfo& auth_info, |
| content::WebContents* web_contents, |
| const GURL& url, |
| LoginAuthRequiredCallback auth_required_callback); |
| |
| class Observer : public base::CheckedObserver { |
| public: |
| // Called when the dialog is shown. |
| virtual void HttpAuthDialogShown(content::WebContents* web_contents) = 0; |
| |
| // Called when the dialog is cancelled. This can happen if the user presses |
| // the "cancel" button, or if the network request is cancelled. |
| virtual void HttpAuthDialogCancelled( |
| content::WebContents* web_contents) = 0; |
| |
| // Called when the user presses the "continue" button. There is no guarantee |
| // that the username/password are valid. |
| virtual void HttpAuthDialogSupplied(content::WebContents* web_contents) = 0; |
| }; |
| |
| static void AddObserver(Observer* observer); |
| static void RemoveObserver(Observer* observer); |
| |
| // Exposed for testing. |
| static std::vector<HttpAuthDialog*> GetAllDialogsForTest(); |
| |
| void SupplyCredentialsForTest(std::u16string_view username, |
| std::u16string_view password); |
| void CancelForTest(); |
| |
| private: |
| // A basic view with username/password text fields. |
| class DialogView : public views::View { |
| public: |
| DialogView(std::u16string_view authority, std::u16string_view explanation); |
| ~DialogView() override; |
| |
| // Intentionally return by copy so that the return value can be used even if |
| // DialogView is destroyed. |
| std::u16string GetUsername() const; |
| std::u16string GetPassword() const; |
| |
| void SetCredentialsForTest(std::u16string_view username, |
| std::u16string_view password); |
| |
| views::View* GetInitiallyFocusedView(); |
| |
| private: |
| // Non-owning refs to the input text fields. |
| raw_ptr<views::Textfield> username_field_; |
| raw_ptr<views::Textfield> password_field_; |
| }; |
| |
| // The constructor creates and shows a dialog. |
| HttpAuthDialog(const net::AuthChallengeInfo& auth_info, |
| content::WebContents* web_contents, |
| const GURL& url, |
| LoginAuthRequiredCallback auth_required_callback); |
| |
| // In the production use-case, this method is called by views when the user |
| // clicks the OK button. The dialog is in the process of closing. This method |
| // merely needs to invoke `callback_`. |
| // When this method is called from tests, the dialog is not in the process of |
| // closing. Calling this method will invoke `callback_`, which will result in |
| // destruction of this object, which will close the dialog. |
| void SupplyCredentials(std::u16string_view username, |
| std::u16string_view password); |
| |
| // Similar to `SupplyCredentials` except this is the path for clicking the |
| // cancel button or otherwise dismissing the dialog. |
| void Cancel(); |
| |
| static void NotifyShownAsync(content::WebContents* web_contents); |
| static void NotifySuppliedAsync(content::WebContents* web_contents); |
| static void NotifyCancelledAsync(content::WebContents* web_contents); |
| |
| net::AuthChallengeInfo auth_info_; |
| |
| // This class is owned by the //content layer. The only way to delete this |
| // class is to invoke this callback. |
| LoginAuthRequiredCallback callback_; |
| |
| // Handles configuration and callbacks from the dialog. |
| views::DialogDelegate dialog_delegate_; |
| |
| // `dialog_view_` is owned by the views framework. The dialog is showing if |
| // and only if these members are not `nullptr`. dialog_widget_ is created in |
| // the constructor and destroyed in the destructor, so this means that the |
| // lifetime of the dialog corresponds exactly to the lifetime of this class. |
| raw_ptr<DialogView> dialog_view_ = nullptr; |
| std::unique_ptr<views::Widget> dialog_widget_; |
| |
| // Tracks the WebContents instance that is showing the dialog. |
| raw_ptr<content::WebContents> web_contents_ = nullptr; |
| base::WeakPtrFactory<HttpAuthDialog> weak_factory_{this}; |
| }; |
| |
| } // namespace ash |
| |
| #endif // CHROME_BROWSER_ASH_HTTP_AUTH_DIALOG_H_ |