Home | History | Annotate | Download | only in login
      1 // Copyright (c) 2011 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/ui/login/login_prompt.h"
      6 
      7 #include <string>
      8 
      9 #include "base/json/json_reader.h"
     10 #include "base/utf_string_conversions.h"
     11 #include "base/values.h"
     12 #include "chrome/browser/profiles/profile.h"
     13 #include "chrome/browser/ui/webui/chrome_url_data_manager.h"
     14 #include "chrome/browser/ui/webui/constrained_html_ui.h"
     15 #include "chrome/browser/ui/webui/html_dialog_ui.h"
     16 #include "chrome/common/jstemplate_builder.h"
     17 #include "chrome/common/url_constants.h"
     18 #include "content/browser/tab_contents/tab_contents.h"
     19 #include "grit/browser_resources.h"
     20 #include "grit/generated_resources.h"
     21 #include "ui/base/l10n/l10n_util.h"
     22 #include "ui/base/resource/resource_bundle.h"
     23 #include "ui/gfx/size.h"
     24 
     25 class LoginHandlerSource : public ChromeURLDataManager::DataSource {
     26  public:
     27   LoginHandlerSource()
     28       : DataSource(chrome::kChromeUIHttpAuthHost, MessageLoop::current()) {}
     29 
     30   virtual void StartDataRequest(const std::string& path,
     31                                 bool is_off_the_record,
     32                                 int request_id) {
     33     DictionaryValue dict;
     34     dict.SetString("username",
     35                    l10n_util::GetStringUTF16(IDS_LOGIN_DIALOG_USERNAME_FIELD));
     36     dict.SetString("password",
     37                    l10n_util::GetStringUTF16(IDS_LOGIN_DIALOG_PASSWORD_FIELD));
     38     dict.SetString("signin",
     39                    l10n_util::GetStringUTF16(IDS_LOGIN_DIALOG_OK_BUTTON_LABEL));
     40     dict.SetString("cancel", l10n_util::GetStringUTF16(IDS_CANCEL));
     41 
     42     SetFontAndTextDirection(&dict);
     43 
     44     const base::StringPiece html(
     45         ResourceBundle::GetSharedInstance().GetRawDataResource(
     46             IDR_HTTP_AUTH_HTML));
     47     std::string response = jstemplate_builder::GetI18nTemplateHtml(html, &dict);
     48 
     49     // Send the response.
     50     scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes);
     51     html_bytes->data.resize(response.size());
     52     std::copy(response.begin(), response.end(), html_bytes->data.begin());
     53     SendResponse(request_id, html_bytes);
     54   }
     55 
     56   virtual std::string GetMimeType(const std::string& path) const {
     57     return "text/html";
     58   }
     59 
     60   static void RegisterDataSource(Profile *profile) {
     61     ChromeURLDataManager* url_manager = profile->GetChromeURLDataManager();
     62     LoginHandlerSource *source = new LoginHandlerSource();
     63     url_manager->AddDataSource(source);
     64   }
     65 
     66  private:
     67   virtual ~LoginHandlerSource() {}
     68 
     69   DISALLOW_COPY_AND_ASSIGN(LoginHandlerSource);
     70 };
     71 
     72 class LoginHandlerHtml;
     73 
     74 class LoginHandlerHtmlDelegate : public HtmlDialogUIDelegate,
     75                                  public WebUIMessageHandler {
     76  public:
     77   LoginHandlerHtmlDelegate(LoginHandlerHtml *login_handler,
     78                            TabContents *tab_contents,
     79                            const string16 explanation)
     80       : login_handler_(login_handler),
     81         tab_contents_(tab_contents),
     82         explanation_(UTF16ToUTF8(explanation)),
     83         closed_(false),
     84         has_autofill_(false),
     85         ready_for_autofill_(false) {
     86   }
     87 
     88   // HtmlDialogUIDelegate methods:
     89   virtual bool IsDialogModal() const {
     90     return true;
     91   }
     92 
     93   virtual std::wstring GetDialogTitle() const {
     94     return UTF16ToWide(l10n_util::GetStringUTF16(IDS_LOGIN_DIALOG_TITLE));
     95   }
     96 
     97   virtual GURL GetDialogContentURL() const {
     98     return GURL(chrome::kChromeUIHttpAuthURL);
     99   }
    100 
    101   virtual void GetWebUIMessageHandlers(
    102       std::vector<WebUIMessageHandler*>* handlers) const {
    103     const WebUIMessageHandler* handler = this;
    104     handlers->push_back(const_cast<WebUIMessageHandler*>(handler));
    105   }
    106 
    107   virtual void GetDialogSize(gfx::Size* size) const {
    108     size->set_width(kDialogWidth);
    109     size->set_height(kDialogHeight);
    110   }
    111 
    112   virtual std::string GetDialogArgs() const {
    113     return explanation_;
    114   }
    115 
    116   virtual void OnDialogClosed(const std::string& json_retval);
    117 
    118   virtual void OnCloseContents(TabContents* source, bool* out_close_dialog) {}
    119 
    120   virtual bool ShouldShowDialogTitle() const {
    121     return true;
    122   }
    123 
    124   // WebUIMessageHandler method:
    125   virtual void RegisterMessages() {
    126     web_ui_->RegisterMessageCallback(
    127         "GetAutofill",
    128         NewCallback(this, &LoginHandlerHtmlDelegate::GetAutofill));
    129   }
    130 
    131   void ShowAutofillData(const std::wstring& username,
    132                         const std::wstring& password);
    133 
    134  private:
    135   // Send autofill data to HTML once the dialog is ready and the data is
    136   // available.
    137   void SendAutofillData();
    138 
    139   // Handle the request for autofill data from HTML.
    140   void GetAutofill(const ListValue* args) {
    141     ready_for_autofill_ = true;
    142     SendAutofillData();
    143   }
    144 
    145   LoginHandlerHtml *login_handler_;
    146   TabContents *tab_contents_;
    147   std::string explanation_;
    148   bool closed_;
    149 
    150   bool has_autofill_;
    151   bool ready_for_autofill_;
    152   std::string autofill_username_;
    153   std::string autofill_password_;
    154 
    155   static const int kDialogWidth = 400;
    156   static const int kDialogHeight = 130;
    157 
    158   DISALLOW_COPY_AND_ASSIGN(LoginHandlerHtmlDelegate);
    159 };
    160 
    161 class LoginHandlerHtml : public LoginHandler {
    162  public:
    163   LoginHandlerHtml(net::AuthChallengeInfo* auth_info, net::URLRequest* request)
    164       : LoginHandler(auth_info, request),
    165         delegate_(NULL) {
    166   }
    167 
    168   // LoginModelObserver method:
    169   virtual void OnAutofillDataAvailable(const std::wstring& username,
    170                                        const std::wstring& password) {
    171     if (delegate_)
    172       delegate_->ShowAutofillData(username, password);
    173   }
    174 
    175   // LoginHandler method:
    176   virtual void BuildViewForPasswordManager(PasswordManager* manager,
    177                                            const string16& explanation);
    178 
    179   friend class LoginHandlerHtmlDelegate;
    180 
    181  protected:
    182   virtual ~LoginHandlerHtml() {}
    183 
    184  private:
    185   LoginHandlerHtmlDelegate *delegate_;
    186 
    187   void FreeAndRelease() {
    188     SetDialog(NULL);
    189     SetModel(NULL);
    190     ReleaseSoon();
    191   }
    192 
    193   DISALLOW_COPY_AND_ASSIGN(LoginHandlerHtml);
    194 };
    195 
    196 void LoginHandlerHtmlDelegate::OnDialogClosed(const std::string& json_retval) {
    197   if (closed_)
    198     return;
    199   closed_ = true;
    200 
    201   scoped_ptr<Value> parsed_value(base::JSONReader::Read(json_retval, false));
    202 
    203   if (!parsed_value.get() || !parsed_value->IsType(Value::TYPE_DICTIONARY)) {
    204     login_handler_->CancelAuth();
    205   } else {
    206     DictionaryValue* res = static_cast<DictionaryValue*>(parsed_value.get());
    207     string16 username;
    208     string16 password;
    209 
    210     if (!res->GetString("username", &username) ||
    211         !res->GetString("password", &password)) {
    212       login_handler_->CancelAuth();
    213     } else {
    214       login_handler_->SetAuth(username, password);
    215     }
    216   }
    217 
    218   login_handler_->FreeAndRelease();
    219 }
    220 
    221 void LoginHandlerHtmlDelegate::ShowAutofillData(const std::wstring& username,
    222                                                 const std::wstring& password) {
    223   autofill_username_ = WideToUTF8(username);
    224   autofill_password_ = WideToUTF8(password);
    225   has_autofill_ = true;
    226   SendAutofillData();
    227 }
    228 
    229 void LoginHandlerHtmlDelegate::SendAutofillData() {
    230   if (!closed_ && web_ui_ && has_autofill_ && ready_for_autofill_) {
    231     StringValue username_v(autofill_username_);
    232     StringValue password_v(autofill_password_);
    233     web_ui_->CallJavascriptFunction("setAutofillCredentials",
    234                                     username_v, password_v);
    235   }
    236 }
    237 
    238 void LoginHandlerHtml::BuildViewForPasswordManager(
    239     PasswordManager* manager, const string16& explanation) {
    240   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    241 
    242   LOG(INFO) << "BuildViewForPasswordManager";
    243 
    244   TabContents* tab_contents = GetTabContentsForLogin();
    245   LoginHandlerSource::RegisterDataSource(tab_contents->profile());
    246   delegate_ = new LoginHandlerHtmlDelegate(this, tab_contents, explanation);
    247   ConstrainedWindow* dialog = ConstrainedHtmlUI::CreateConstrainedHtmlDialog(
    248       tab_contents->profile(), delegate_, tab_contents);
    249 
    250   SetModel(manager);
    251   SetDialog(dialog);
    252 
    253   NotifyAuthNeeded();
    254 }
    255 
    256 // static
    257 LoginHandler* LoginHandler::Create(net::AuthChallengeInfo* auth_info,
    258                                    net::URLRequest* request) {
    259   return new LoginHandlerHtml(auth_info, request);
    260 }
    261