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