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:
LoginHandlerSource()27 LoginHandlerSource()
28 : DataSource(chrome::kChromeUIHttpAuthHost, MessageLoop::current()) {}
29
StartDataRequest(const std::string & path,bool is_off_the_record,int request_id)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
GetMimeType(const std::string & path) const56 virtual std::string GetMimeType(const std::string& path) const {
57 return "text/html";
58 }
59
RegisterDataSource(Profile * profile)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:
~LoginHandlerSource()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:
LoginHandlerHtmlDelegate(LoginHandlerHtml * login_handler,TabContents * tab_contents,const string16 explanation)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:
IsDialogModal() const89 virtual bool IsDialogModal() const {
90 return true;
91 }
92
GetDialogTitle() const93 virtual std::wstring GetDialogTitle() const {
94 return UTF16ToWide(l10n_util::GetStringUTF16(IDS_LOGIN_DIALOG_TITLE));
95 }
96
GetDialogContentURL() const97 virtual GURL GetDialogContentURL() const {
98 return GURL(chrome::kChromeUIHttpAuthURL);
99 }
100
GetWebUIMessageHandlers(std::vector<WebUIMessageHandler * > * handlers) const101 virtual void GetWebUIMessageHandlers(
102 std::vector<WebUIMessageHandler*>* handlers) const {
103 const WebUIMessageHandler* handler = this;
104 handlers->push_back(const_cast<WebUIMessageHandler*>(handler));
105 }
106
GetDialogSize(gfx::Size * size) const107 virtual void GetDialogSize(gfx::Size* size) const {
108 size->set_width(kDialogWidth);
109 size->set_height(kDialogHeight);
110 }
111
GetDialogArgs() const112 virtual std::string GetDialogArgs() const {
113 return explanation_;
114 }
115
116 virtual void OnDialogClosed(const std::string& json_retval);
117
OnCloseContents(TabContents * source,bool * out_close_dialog)118 virtual void OnCloseContents(TabContents* source, bool* out_close_dialog) {}
119
ShouldShowDialogTitle() const120 virtual bool ShouldShowDialogTitle() const {
121 return true;
122 }
123
124 // WebUIMessageHandler method:
RegisterMessages()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.
GetAutofill(const ListValue * args)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:
LoginHandlerHtml(net::AuthChallengeInfo * auth_info,net::URLRequest * request)163 LoginHandlerHtml(net::AuthChallengeInfo* auth_info, net::URLRequest* request)
164 : LoginHandler(auth_info, request),
165 delegate_(NULL) {
166 }
167
168 // LoginModelObserver method:
OnAutofillDataAvailable(const std::wstring & username,const std::wstring & password)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:
~LoginHandlerHtml()182 virtual ~LoginHandlerHtml() {}
183
184 private:
185 LoginHandlerHtmlDelegate *delegate_;
186
FreeAndRelease()187 void FreeAndRelease() {
188 SetDialog(NULL);
189 SetModel(NULL);
190 ReleaseSoon();
191 }
192
193 DISALLOW_COPY_AND_ASSIGN(LoginHandlerHtml);
194 };
195
OnDialogClosed(const std::string & json_retval)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
ShowAutofillData(const std::wstring & username,const std::wstring & password)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
SendAutofillData()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
BuildViewForPasswordManager(PasswordManager * manager,const string16 & explanation)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
Create(net::AuthChallengeInfo * auth_info,net::URLRequest * request)257 LoginHandler* LoginHandler::Create(net::AuthChallengeInfo* auth_info,
258 net::URLRequest* request) {
259 return new LoginHandlerHtml(auth_info, request);
260 }
261