Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(302)

Side by Side Diff: chrome/browser/ui/webui/inline_login_ui.cc

Issue 118343003: Refactor inline_login_ui (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2013 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/inline_login_ui.h"
6
7 #include "base/atomic_sequence_num.h"
8 #include "base/bind.h"
9 #include "base/command_line.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/values.h"
15 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/extensions/tab_helper.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/signin/profile_oauth2_token_service.h"
19 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
20 #include "chrome/browser/signin/signin_global_error.h"
21 #include "chrome/browser/signin/signin_names_io_thread.h"
22 #include "chrome/browser/signin/signin_oauth_helper.h"
23 #include "chrome/browser/signin/signin_promo.h"
24 #include "chrome/browser/sync/profile_sync_service.h"
25 #include "chrome/browser/sync/profile_sync_service_factory.h"
26 #include "chrome/browser/ui/browser_finder.h"
27 #include "chrome/browser/ui/sync/one_click_signin_helper.h"
28 #include "chrome/browser/ui/sync/one_click_signin_sync_starter.h"
29 #include "chrome/browser/ui/tabs/tab_strip_model.h"
30 #include "chrome/common/chrome_switches.h"
31 #include "chrome/common/url_constants.h"
32 #include "content/public/browser/storage_partition.h"
33 #include "content/public/browser/web_contents.h"
34 #include "content/public/browser/web_ui.h"
35 #include "content/public/browser/web_ui_data_source.h"
36 #include "content/public/browser/web_ui_message_handler.h"
37 #include "google_apis/gaia/gaia_auth_consumer.h"
38 #include "google_apis/gaia/gaia_auth_fetcher.h"
39 #include "google_apis/gaia/gaia_constants.h"
40 #include "google_apis/gaia/gaia_switches.h"
41 #include "google_apis/gaia/gaia_urls.h"
42 #include "grit/browser_resources.h"
43 #include "net/base/escape.h"
44 #include "net/base/url_util.h"
45
46 #if defined(OS_CHROMEOS)
47 #include "chrome/browser/chromeos/login/oauth2_token_fetcher.h"
48 #endif
49
50 namespace {
51
52 content::WebUIDataSource* CreateWebUIDataSource() {
53 content::WebUIDataSource* source =
54 content::WebUIDataSource::Create(chrome::kChromeUIChromeSigninHost);
55 source->SetUseJsonJSFormatV2();
56 source->SetJsonPath("strings.js");
57
58 source->SetDefaultResource(IDR_INLINE_LOGIN_HTML);
59 source->AddResourcePath("inline_login.css", IDR_INLINE_LOGIN_CSS);
60 source->AddResourcePath("inline_login.js", IDR_INLINE_LOGIN_JS);
61 return source;
62 };
63
64 #if defined(OS_CHROMEOS)
65 class InlineLoginUIOAuth2Delegate
66 : public chromeos::OAuth2TokenFetcher::Delegate {
67 public:
68 explicit InlineLoginUIOAuth2Delegate(content::WebUI* web_ui)
69 : web_ui_(web_ui) {}
70 virtual ~InlineLoginUIOAuth2Delegate() {}
71
72 // OAuth2TokenFetcher::Delegate overrides:
73 virtual void OnOAuth2TokensAvailable(
74 const GaiaAuthConsumer::ClientOAuthResult& oauth2_tokens) OVERRIDE {
75 // Closes sign-in dialog before update token service. Token service update
76 // might trigger a permission dialog and if this dialog does not close,
77 // a DCHECK would be triggered because attempting to activate a window
78 // while there is a modal dialog.
79 web_ui_->CallJavascriptFunction("inline.login.closeDialog");
80
81 Profile* profile = Profile::FromWebUI(web_ui_);
82 ProfileOAuth2TokenService* token_service =
83 ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
84 token_service->UpdateCredentials(token_service->GetPrimaryAccountId(),
85 oauth2_tokens.refresh_token);
86 }
87
88 virtual void OnOAuth2TokensFetchFailed() OVERRIDE {
89 LOG(ERROR) << "Failed to fetch oauth2 token with inline login.";
90 web_ui_->CallJavascriptFunction("inline.login.handleOAuth2TokenFailure");
91 }
92
93 private:
94 content::WebUI* web_ui_;
95 };
96 #else
97 // Global SequenceNumber used for generating unique webview partition IDs.
98 base::StaticAtomicSequenceNumber next_partition_id;
99 #endif // OS_CHROMEOS
100
101 class InlineLoginUIHandler : public GaiaAuthConsumer,
102 public content::WebUIMessageHandler {
103 public:
104 explicit InlineLoginUIHandler(Profile* profile)
105 : profile_(profile), weak_factory_(this), choose_what_to_sync_(false),
106 partition_id_("") {}
107 virtual ~InlineLoginUIHandler() {}
108
109 // content::WebUIMessageHandler overrides:
110 virtual void RegisterMessages() OVERRIDE {
111 web_ui()->RegisterMessageCallback("initialize",
112 base::Bind(&InlineLoginUIHandler::HandleInitialize,
113 base::Unretained(this)));
114 web_ui()->RegisterMessageCallback("completeLogin",
115 base::Bind(&InlineLoginUIHandler::HandleCompleteLogin,
116 base::Unretained(this)));
117 web_ui()->RegisterMessageCallback("switchToFullTab",
118 base::Bind(&InlineLoginUIHandler::HandleSwitchToFullTab,
119 base::Unretained(this)));
120 }
121
122 private:
123 // Enum for gaia auth mode, must match AuthMode defined in
124 // chrome/browser/resources/gaia_auth_host/gaia_auth_host.js.
125 enum AuthMode {
126 kDefaultAuthMode = 0,
127 kOfflineAuthMode = 1,
128 kInlineAuthMode = 2
129 };
130
131 void LoadAuthExtension() {
132 base::DictionaryValue params;
133
134 const std::string& app_locale = g_browser_process->GetApplicationLocale();
135 params.SetString("hl", app_locale);
136
137 GaiaUrls* gaiaUrls = GaiaUrls::GetInstance();
138 params.SetString("gaiaUrl", gaiaUrls->gaia_url().spec());
139
140 bool enable_inline = CommandLine::ForCurrentProcess()->HasSwitch(
141 switches::kEnableInlineSignin);
142 params.SetInteger("authMode",
143 enable_inline ? kInlineAuthMode : kDefaultAuthMode);
144
145 // Set parameters specific for inline signin flow.
146 #if !defined(OS_CHROMEOS)
147 if (enable_inline) {
148
149 const GURL& current_url = web_ui()->GetWebContents()->GetURL();
150 signin::Source source = signin::GetSourceForPromoURL(current_url);
151 DCHECK(source != signin::SOURCE_UNKNOWN);
152 if (source == signin::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT ||
153 source == signin::SOURCE_AVATAR_BUBBLE_SIGN_IN) {
154 // Drop the leading slash in the path.
155 params.SetString("gaiaPath",
156 gaiaUrls->embedded_signin_url().path().substr(1));
157 }
158
159 params.SetString("service", "chromiumsync");
160 params.SetString("continueUrl",
161 signin::GetLandingURL("source", static_cast<int>(source)).spec());
162
163 std::string email;
164 net::GetValueForKeyInQuery(current_url, "Email", &email);
165 if (!email.empty())
166 params.SetString("email", email);
167
168 std::string frame_url;
169 net::GetValueForKeyInQuery(current_url, "frameUrl", &frame_url);
170 if (!frame_url.empty())
171 params.SetString("frameUrl", frame_url);
172
173 std::string is_constrained;
174 net::GetValueForKeyInQuery(current_url, "constrained", &is_constrained);
175 if (!is_constrained.empty())
176 params.SetString("constrained", is_constrained);
177
178 net::GetValueForKeyInQuery(current_url, "partitionId", &partition_id_);
179 if (partition_id_.empty()) {
180 partition_id_ =
181 "gaia-webview-" + base::IntToString(next_partition_id.GetNext());
182 }
183 params.SetString("partitionId", partition_id_);
184 }
185 #endif // OS_CHROMEOS
186
187 web_ui()->CallJavascriptFunction("inline.login.loadAuthExtension", params);
188 }
189
190 // JS callback:
191 void HandleInitialize(const base::ListValue* args) {
192 LoadAuthExtension();
193 }
194
195 // JS callback:
196 void HandleSwitchToFullTab(const base::ListValue* args) {
197 base::string16 url_str;
198 CHECK(args->GetString(0, &url_str));
199
200 content::WebContents* web_contents = web_ui()->GetWebContents();
201 GURL main_frame_url(web_contents->GetURL());
202 main_frame_url = net::AppendOrReplaceQueryParameter(
203 main_frame_url, "frameUrl", UTF16ToASCII(url_str));
204 main_frame_url = net::AppendOrReplaceQueryParameter(
205 main_frame_url, "partitionId", partition_id_);
206 chrome::NavigateParams params(
207 profile_,
208 net::AppendOrReplaceQueryParameter(main_frame_url, "constrained", "0"),
209 content::PAGE_TRANSITION_AUTO_TOPLEVEL);
210 chrome::Navigate(&params);
211
212 web_ui()->CallJavascriptFunction("inline.login.closeDialog");
213 }
214
215 void HandleCompleteLogin(const base::ListValue* args) {
216 // TODO(guohui, xiyuan): we should investigate if it is possible to unify
217 // the signin-with-cookies flow across ChromeOS and Chrome.
218 DCHECK(email_.empty() && password_.empty());
219
220 #if defined(OS_CHROMEOS)
221 oauth2_delegate_.reset(new InlineLoginUIOAuth2Delegate(web_ui()));
222 oauth2_token_fetcher_.reset(new chromeos::OAuth2TokenFetcher(
223 oauth2_delegate_.get(), profile_->GetRequestContext()));
224 oauth2_token_fetcher_->StartExchangeFromCookies();
225 #else
226 const base::DictionaryValue* dict = NULL;
227 base::string16 email;
228 if (!args->GetDictionary(0, &dict) || !dict ||
229 !dict->GetString("email", &email)) {
230 // User cancelled the signin by clicking 'skip for now'.
231 bool skip_for_now = false;
232 DCHECK(dict->GetBoolean("skipForNow", &skip_for_now) && skip_for_now);
233
234 signin::SetUserSkippedPromo(profile_);
235 SyncStarterCallback(OneClickSigninSyncStarter::SYNC_SETUP_FAILURE);
236 return;
237 }
238
239 email_ = UTF16ToASCII(email);
240 base::string16 password;
241 dict->GetString("password", &password);
242 password_ = UTF16ToASCII(password);
243
244 dict->GetBoolean("chooseWhatToSync", &choose_what_to_sync_);
245
246 content::WebContents* contents = web_ui()->GetWebContents();
247 signin::Source source = signin::GetSourceForPromoURL(contents->GetURL());
248 OneClickSigninHelper::CanOfferFor can_offer =
249 source == signin::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT ?
250 OneClickSigninHelper::CAN_OFFER_FOR_SECONDARY_ACCOUNT :
251 OneClickSigninHelper::CAN_OFFER_FOR_ALL;
252 std::string error_msg;
253 OneClickSigninHelper::CanOffer(
254 contents, can_offer, email_, &error_msg);
255 if (!error_msg.empty()) {
256 HandleLoginError(error_msg);
257 return;
258 }
259
260 content::StoragePartition* partition =
261 content::BrowserContext::GetStoragePartitionForSite(
262 contents->GetBrowserContext(),
263 GURL("chrome-guest://mfffpogegjflfpflabcdkioaeobkgjik/?" +
264 partition_id_));
265
266 auth_fetcher_.reset(new GaiaAuthFetcher(this,
267 GaiaConstants::kChromeSource,
268 partition->GetURLRequestContext()));
269 auth_fetcher_->StartCookieForOAuthCodeExchange("0");
270 #endif // OS_CHROMEOS
271 }
272
273 // GaiaAuthConsumer override.
274 virtual void OnClientOAuthCodeSuccess(
275 const std::string& oauth_code) OVERRIDE {
276 #if !defined(OS_CHROMEOS)
277 DCHECK(!oauth_code.empty());
278
279 content::WebContents* contents = web_ui()->GetWebContents();
280 ProfileSyncService* sync_service =
281 ProfileSyncServiceFactory::GetForProfile(profile_);
282 const GURL& current_url = contents->GetURL();
283 signin::Source source = signin::GetSourceForPromoURL(current_url);
284
285 if (source == signin::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT) {
286 // SigninOAuthHelper will delete itself.
287 SigninOAuthHelper* helper = new SigninOAuthHelper(profile_);
288 helper->StartAddingAccount(oauth_code);
289 } else {
290 OneClickSigninSyncStarter::StartSyncMode start_mode =
291 source == signin::SOURCE_SETTINGS || choose_what_to_sync_ ?
292 (SigninGlobalError::GetForProfile(profile_)->HasMenuItem() &&
293 sync_service && sync_service->HasSyncSetupCompleted()) ?
294 OneClickSigninSyncStarter::SHOW_SETTINGS_WITHOUT_CONFIGURE :
295 OneClickSigninSyncStarter::CONFIGURE_SYNC_FIRST :
296 OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS;
297 OneClickSigninSyncStarter::ConfirmationRequired confirmation_required =
298 source == signin::SOURCE_SETTINGS ||
299 source == signin::SOURCE_WEBSTORE_INSTALL ||
300 choose_what_to_sync_?
301 OneClickSigninSyncStarter::NO_CONFIRMATION :
302 OneClickSigninSyncStarter::CONFIRM_AFTER_SIGNIN;
303 // Call OneClickSigninSyncStarter to exchange oauth code for tokens.
304 // OneClickSigninSyncStarter will delete itself once the job is done.
305 new OneClickSigninSyncStarter(
306 profile_, NULL, "" /* session_index, not used */,
307 email_, password_, oauth_code,
308 start_mode,
309 contents,
310 confirmation_required,
311 base::Bind(&InlineLoginUIHandler::SyncStarterCallback,
312 weak_factory_.GetWeakPtr()));
313 }
314
315 email_.clear();
316 password_.clear();
317 web_ui()->CallJavascriptFunction("inline.login.closeDialog");
318 #endif // OS_CHROMEOS
319 }
320
321 // GaiaAuthConsumer override.
322 virtual void OnClientOAuthCodeFailure(const GoogleServiceAuthError& error)
323 OVERRIDE {
324 #if !defined(OS_CHROMEOS)
325 LOG(ERROR) << "InlineLoginUI::OnClientOAuthCodeFailure";
326 HandleLoginError(error.ToString());
327 #endif // OS_CHROMEOS
328 }
329
330 void HandleLoginError(const std::string& error_msg) {
331 SyncStarterCallback(
332 OneClickSigninSyncStarter::SYNC_SETUP_FAILURE);
333
334 Browser* browser = chrome::FindBrowserWithWebContents(
335 web_ui()->GetWebContents());
336 if (!browser) {
337 browser = chrome::FindLastActiveWithProfile(
338 profile_, chrome::GetActiveDesktop());
339 }
340 if (browser)
341 OneClickSigninHelper::ShowSigninErrorBubble(browser, error_msg);
342
343 email_.clear();
344 password_.clear();
345 }
346
347 void SyncStarterCallback(OneClickSigninSyncStarter::SyncSetupResult result) {
348 content::WebContents* contents = web_ui()->GetWebContents();
349 const GURL& current_url = contents->GetURL();
350 bool auto_close = signin::IsAutoCloseEnabledInURL(current_url);
351 signin::Source source = signin::GetSourceForPromoURL(current_url);
352 if (auto_close) {
353 base::MessageLoop::current()->PostTask(
354 FROM_HERE,
355 base::Bind(
356 &InlineLoginUIHandler::CloseTab, weak_factory_.GetWeakPtr()));
357 return;
358 }
359
360 OneClickSigninHelper::RedirectToNtpOrAppsPageIfNecessary(contents, source);
361 }
362
363 void CloseTab() {
364 content::WebContents* tab = web_ui()->GetWebContents();
365 Browser* browser = chrome::FindBrowserWithWebContents(tab);
366 if (browser) {
367 TabStripModel* tab_strip_model = browser->tab_strip_model();
368 if (tab_strip_model) {
369 int index = tab_strip_model->GetIndexOfWebContents(tab);
370 if (index != TabStripModel::kNoTab) {
371 tab_strip_model->ExecuteContextMenuCommand(
372 index, TabStripModel::CommandCloseTab);
373 }
374 }
375 }
376 }
377
378 Profile* profile_;
379 base::WeakPtrFactory<InlineLoginUIHandler> weak_factory_;
380 scoped_ptr<GaiaAuthFetcher> auth_fetcher_;
381 std::string email_;
382 std::string password_;
383 bool choose_what_to_sync_;
384 // Partition id for the gaia webview;
385 std::string partition_id_;
386
387 #if defined(OS_CHROMEOS)
388 scoped_ptr<chromeos::OAuth2TokenFetcher> oauth2_token_fetcher_;
389 scoped_ptr<InlineLoginUIOAuth2Delegate> oauth2_delegate_;
390 #endif
391
392 DISALLOW_COPY_AND_ASSIGN(InlineLoginUIHandler);
393 };
394
395 } // namespace
396
397 InlineLoginUI::InlineLoginUI(content::WebUI* web_ui)
398 : WebDialogUI(web_ui),
399 auth_extension_(Profile::FromWebUI(web_ui)) {
400 Profile* profile = Profile::FromWebUI(web_ui);
401 content::WebUIDataSource::Add(profile, CreateWebUIDataSource());
402
403 web_ui->AddMessageHandler(new InlineLoginUIHandler(profile));
404 // Required for intercepting extension function calls when the page is loaded
405 // in a bubble (not a full tab, thus tab helpers are not registered
406 // automatically).
407 extensions::TabHelper::CreateForWebContents(web_ui->GetWebContents());
408 }
409
410 InlineLoginUI::~InlineLoginUI() {}
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698