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/webui/chromeos/enterprise_enrollment_ui.h"
6
7 #include "base/json/json_reader.h"
8 #include "base/json/json_writer.h"
9 #include "base/lazy_instance.h"
10 #include "base/memory/ref_counted_memory.h"
11 #include "base/message_loop.h"
12 #include "base/stringprintf.h"
13 #include "base/values.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/ui/webui/chrome_url_data_manager.h"
16 #include "chrome/common/jstemplate_builder.h"
17 #include "chrome/common/url_constants.h"
18 #include "content/browser/renderer_host/render_view_host.h"
19 #include "content/browser/tab_contents/tab_contents.h"
20 #include "content/common/bindings_policy.h"
21 #include "content/common/property_bag.h"
22 #include "grit/browser_resources.h"
23 #include "grit/chromium_strings.h"
24 #include "grit/generated_resources.h"
25 #include "ui/base/l10n/l10n_util.h"
26 #include "ui/base/resource/resource_bundle.h"
27
28 namespace chromeos {
29
30 static base::LazyInstance<
31 PropertyAccessor<EnterpriseEnrollmentUI::Controller*> >
32 g_enrollment_ui_controller_property(base::LINKER_INITIALIZED);
33
34 static const char kEnterpriseEnrollmentGaiaLoginPath[] = "gaialogin";
35
36 // WebUIMessageHandler implementation which handles events occuring on the page,
37 // such as the user pressing the signin button.
38 class EnterpriseEnrollmentMessageHandler : public WebUIMessageHandler {
39 public:
40 EnterpriseEnrollmentMessageHandler();
41 virtual ~EnterpriseEnrollmentMessageHandler();
42
43 // WebUIMessageHandler implementation.
44 virtual void RegisterMessages() OVERRIDE;
45
46 private:
47 // Handlers for WebUI messages.
48 void HandleSubmitAuth(const ListValue* args);
49 void HandleCancelAuth(const ListValue* args);
50 void HandleConfirmationClose(const ListValue* args);
51
52 // Gets the currently installed enrollment controller (if any).
53 EnterpriseEnrollmentUI::Controller* GetController();
54
55 DISALLOW_COPY_AND_ASSIGN(EnterpriseEnrollmentMessageHandler);
56 };
57
58 // A data source that provides the resources for the enterprise enrollment page.
59 // The enterprise enrollment page requests the HTML and other resources from
60 // this source.
61 class EnterpriseEnrollmentDataSource : public ChromeURLDataManager::DataSource {
62 public:
63 EnterpriseEnrollmentDataSource();
64
65 // DataSource implementation.
66 virtual void StartDataRequest(const std::string& path,
67 bool is_off_the_record,
68 int request_id) OVERRIDE;
69 virtual std::string GetMimeType(const std::string& path) const OVERRIDE;
70
71 private:
72 virtual ~EnterpriseEnrollmentDataSource();
73
74 // Saves i18n string for |resource_id| to the |key| property of |dictionary|.
75 static void AddString(DictionaryValue* dictionary,
76 const std::string& key,
77 int resource_id);
78 static void AddString(DictionaryValue* dictionary,
79 const std::string& key,
80 int resource_id,
81 const string16& arg1);
82
83 DISALLOW_COPY_AND_ASSIGN(EnterpriseEnrollmentDataSource);
84 };
85
EnterpriseEnrollmentMessageHandler()86 EnterpriseEnrollmentMessageHandler::EnterpriseEnrollmentMessageHandler() {}
87
~EnterpriseEnrollmentMessageHandler()88 EnterpriseEnrollmentMessageHandler::~EnterpriseEnrollmentMessageHandler() {}
89
RegisterMessages()90 void EnterpriseEnrollmentMessageHandler::RegisterMessages() {
91 web_ui_->RegisterMessageCallback(
92 "SubmitAuth",
93 NewCallback(
94 this, &EnterpriseEnrollmentMessageHandler::HandleSubmitAuth));
95 web_ui_->RegisterMessageCallback(
96 "DialogClose",
97 NewCallback(
98 this, &EnterpriseEnrollmentMessageHandler::HandleCancelAuth));
99 web_ui_->RegisterMessageCallback(
100 "confirmationClose",
101 NewCallback(
102 this, &EnterpriseEnrollmentMessageHandler::HandleConfirmationClose));
103 }
104
HandleSubmitAuth(const ListValue * value)105 void EnterpriseEnrollmentMessageHandler::HandleSubmitAuth(
106 const ListValue* value) {
107 EnterpriseEnrollmentUI::Controller* controller = GetController();
108 if (!controller) {
109 NOTREACHED();
110 return;
111 }
112
113 // Value carries single list entry, which is a json-encoded string that
114 // contains the auth parameters (see gaia_login.js).
115 std::string json_params;
116 if (!value->GetString(0, &json_params)) {
117 NOTREACHED();
118 return;
119 }
120
121 // Check the value type.
122 scoped_ptr<Value> params(base::JSONReader::Read(json_params, false));
123 if (!params.get() || !params->IsType(Value::TYPE_DICTIONARY)) {
124 NOTREACHED();
125 return;
126 }
127
128 // Read the parameters.
129 DictionaryValue* params_dict = static_cast<DictionaryValue*>(params.get());
130 std::string user;
131 std::string pass;
132 std::string captcha;
133 std::string access_code;
134 if (!params_dict->GetString("user", &user) ||
135 !params_dict->GetString("pass", &pass) ||
136 !params_dict->GetString("captcha", &captcha) ||
137 !params_dict->GetString("access_code", &access_code)) {
138 NOTREACHED();
139 return;
140 }
141
142 controller->OnAuthSubmitted(user, pass, captcha, access_code);
143 }
144
HandleCancelAuth(const ListValue * value)145 void EnterpriseEnrollmentMessageHandler::HandleCancelAuth(
146 const ListValue* value) {
147 EnterpriseEnrollmentUI::Controller* controller = GetController();
148 if (!controller) {
149 NOTREACHED();
150 return;
151 }
152
153 controller->OnAuthCancelled();
154 }
155
HandleConfirmationClose(const ListValue * value)156 void EnterpriseEnrollmentMessageHandler::HandleConfirmationClose(
157 const ListValue* value) {
158 EnterpriseEnrollmentUI::Controller* controller = GetController();
159 if (!controller) {
160 NOTREACHED();
161 return;
162 }
163
164 controller->OnConfirmationClosed();
165 }
166
167 EnterpriseEnrollmentUI::Controller*
GetController()168 EnterpriseEnrollmentMessageHandler::GetController() {
169 return EnterpriseEnrollmentUI::GetController(web_ui_);
170 }
171
EnterpriseEnrollmentDataSource()172 EnterpriseEnrollmentDataSource::EnterpriseEnrollmentDataSource()
173 : DataSource(chrome::kChromeUIEnterpriseEnrollmentHost,
174 MessageLoop::current()) {}
175
StartDataRequest(const std::string & path,bool is_off_the_record,int request_id)176 void EnterpriseEnrollmentDataSource::StartDataRequest(const std::string& path,
177 bool is_off_the_record,
178 int request_id) {
179 ResourceBundle& resource_bundle = ResourceBundle::GetSharedInstance();
180
181 DictionaryValue strings;
182 std::string response;
183 if (path.empty()) {
184 AddString(&strings, "loginHeader",
185 IDS_ENTERPRISE_ENROLLMENT_LOGIN_HEADER),
186 AddString(&strings, "loginExplain",
187 IDS_ENTERPRISE_ENROLLMENT_LOGIN_EXPLAIN,
188 l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
189 AddString(&strings, "cloudHeader",
190 IDS_ENTERPRISE_ENROLLMENT_CLOUD_HEADER),
191 AddString(&strings, "cloudExplain",
192 IDS_ENTERPRISE_ENROLLMENT_CLOUD_EXPLAIN);
193 AddString(&strings, "accesscontrolHeader",
194 IDS_ENTERPRISE_ENROLLMENT_ACCESSCONTROL_HEADER),
195 AddString(&strings, "accesscontrolExplain",
196 IDS_ENTERPRISE_ENROLLMENT_ACCESSCONTROL_EXPLAIN);
197 AddString(&strings, "confirmationHeader",
198 IDS_ENTERPRISE_ENROLLMENT_CONFIRMATION_HEADER);
199 AddString(&strings, "confirmationMessage",
200 IDS_ENTERPRISE_ENROLLMENT_CONFIRMATION_MESSAGE);
201 AddString(&strings, "confirmationClose",
202 IDS_ENTERPRISE_ENROLLMENT_CONFIRMATION_CLOSE);
203
204 static const base::StringPiece html(
205 resource_bundle.GetRawDataResource(IDR_ENTERPRISE_ENROLLMENT_HTML));
206 SetFontAndTextDirection(&strings);
207 response = jstemplate_builder::GetI18nTemplateHtml(html, &strings);
208 } else if (path == kEnterpriseEnrollmentGaiaLoginPath) {
209 strings.SetString("invalidpasswordhelpurl", "");
210 strings.SetString("invalidaccessaccounturl", "");
211 strings.SetString("cannotaccessaccount", "");
212 strings.SetString("cannotaccessaccounturl", "");
213 strings.SetString("createaccount", "");
214 strings.SetString("createnewaccounturl", "");
215 strings.SetString("getaccesscodehelp", "");
216 strings.SetString("getaccesscodeurl", "");
217
218 // None of the strings used here currently have sync-specific wording in
219 // them. We have a unit test to catch if that happens.
220 strings.SetString("introduction", "");
221 AddString(&strings, "signinprefix", IDS_SYNC_LOGIN_SIGNIN_PREFIX);
222 AddString(&strings, "signinsuffix", IDS_SYNC_LOGIN_SIGNIN_SUFFIX);
223 AddString(&strings, "cannotbeblank", IDS_SYNC_CANNOT_BE_BLANK);
224 AddString(&strings, "emaillabel", IDS_SYNC_LOGIN_EMAIL);
225 AddString(&strings, "passwordlabel", IDS_SYNC_LOGIN_PASSWORD);
226 AddString(&strings, "invalidcredentials",
227 IDS_SYNC_INVALID_USER_CREDENTIALS);
228 AddString(&strings, "signin", IDS_SYNC_SIGNIN);
229 AddString(&strings, "couldnotconnect", IDS_SYNC_LOGIN_COULD_NOT_CONNECT);
230 AddString(&strings, "cancel", IDS_CANCEL);
231 AddString(&strings, "settingup", IDS_SYNC_LOGIN_SETTING_UP);
232 AddString(&strings, "success", IDS_SYNC_SUCCESS);
233 AddString(&strings, "errorsigningin", IDS_SYNC_ERROR_SIGNING_IN);
234 AddString(&strings, "captchainstructions",
235 IDS_SYNC_GAIA_CAPTCHA_INSTRUCTIONS);
236 AddString(&strings, "invalidaccesscode",
237 IDS_SYNC_INVALID_ACCESS_CODE_LABEL);
238 AddString(&strings, "enteraccesscode", IDS_SYNC_ENTER_ACCESS_CODE_LABEL);
239
240 static const base::StringPiece html(resource_bundle.GetRawDataResource(
241 IDR_GAIA_LOGIN_HTML));
242 SetFontAndTextDirection(&strings);
243 response = jstemplate_builder::GetI18nTemplateHtml(html, &strings);
244 }
245
246 // Send the response.
247 scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes());
248 html_bytes->data.resize(response.size());
249 std::copy(response.begin(), response.end(), html_bytes->data.begin());
250 SendResponse(request_id, html_bytes);
251 }
252
GetMimeType(const std::string & path) const253 std::string EnterpriseEnrollmentDataSource::GetMimeType(
254 const std::string& path) const {
255 return "text/html";
256 }
257
~EnterpriseEnrollmentDataSource()258 EnterpriseEnrollmentDataSource::~EnterpriseEnrollmentDataSource() {}
259
AddString(DictionaryValue * dictionary,const std::string & key,int resource_id)260 void EnterpriseEnrollmentDataSource::AddString(DictionaryValue* dictionary,
261 const std::string& key,
262 int resource_id) {
263 dictionary->SetString(key, l10n_util::GetStringUTF16(resource_id));
264 }
265
AddString(DictionaryValue * dictionary,const std::string & key,int resource_id,const string16 & arg1)266 void EnterpriseEnrollmentDataSource::AddString(DictionaryValue* dictionary,
267 const std::string& key,
268 int resource_id,
269 const string16& arg1) {
270 dictionary->SetString(key, l10n_util::GetStringFUTF16(resource_id, arg1));
271 }
272
EnterpriseEnrollmentUI(TabContents * contents)273 EnterpriseEnrollmentUI::EnterpriseEnrollmentUI(TabContents* contents)
274 : WebUI(contents) {}
275
~EnterpriseEnrollmentUI()276 EnterpriseEnrollmentUI::~EnterpriseEnrollmentUI() {}
277
RenderViewCreated(RenderViewHost * render_view_host)278 void EnterpriseEnrollmentUI::RenderViewCreated(
279 RenderViewHost* render_view_host) {
280 // Bail out early if the controller doesn't exist or web ui is disabled.
281 if (!GetController(this) || !(bindings_ & BindingsPolicy::WEB_UI))
282 return;
283
284 WebUIMessageHandler* handler = new EnterpriseEnrollmentMessageHandler();
285 AddMessageHandler(handler->Attach(this));
286
287 // Set up the data source, so the enrollment page can be loaded.
288 tab_contents()->profile()->GetChromeURLDataManager()->AddDataSource(
289 new EnterpriseEnrollmentDataSource());
290
291 std::string user;
292 bool has_init_user = GetController(this)->GetInitialUser(&user);
293 if (!has_init_user)
294 user = "";
295 // Set the arguments for showing the gaia login page.
296 DictionaryValue args;
297 args.SetString("user", user);
298 args.SetInteger("error", 0);
299 args.SetBoolean("editable_user", !has_init_user);
300 args.SetString("initialScreen", "login-screen");
301 std::string json_args;
302 base::JSONWriter::Write(&args, false, &json_args);
303 render_view_host->SetWebUIProperty("dialogArguments", json_args);
304 }
305
306 // static
GetController(WebUI * ui)307 EnterpriseEnrollmentUI::Controller* EnterpriseEnrollmentUI::GetController(
308 WebUI* ui) {
309 Controller** controller =
310 g_enrollment_ui_controller_property.Get().GetProperty(
311 ui->tab_contents()->property_bag());
312
313 return controller ? *controller : NULL;
314 }
315
316 // static
SetController(TabContents * contents,EnterpriseEnrollmentUI::Controller * controller)317 void EnterpriseEnrollmentUI::SetController(
318 TabContents* contents,
319 EnterpriseEnrollmentUI::Controller* controller) {
320 g_enrollment_ui_controller_property.Get().SetProperty(
321 contents->property_bag(),
322 controller);
323 }
324
325 } // namespace chromeos
326