Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / webui / signin / inline_login_handler_impl.cc
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/signin/inline_login_handler_impl.h"
6
7 #include "base/atomic_sequence_num.h"
8 #include "base/bind.h"
9 #include "base/prefs/pref_service.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/string_util.h"
12 #include "base/values.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/signin/signin_global_error.h"
15 #include "chrome/browser/signin/signin_oauth_helper.h"
16 #include "chrome/browser/signin/signin_promo.h"
17 #include "chrome/browser/sync/profile_sync_service.h"
18 #include "chrome/browser/sync/profile_sync_service_factory.h"
19 #include "chrome/browser/ui/browser_finder.h"
20 #include "chrome/browser/ui/sync/one_click_signin_helper.h"
21 #include "chrome/browser/ui/tabs/tab_strip_model.h"
22 #include "chrome/common/pref_names.h"
23 #include "content/public/browser/storage_partition.h"
24 #include "content/public/browser/web_contents.h"
25 #include "content/public/browser/web_ui.h"
26 #include "google_apis/gaia/gaia_auth_fetcher.h"
27 #include "google_apis/gaia/gaia_constants.h"
28 #include "google_apis/gaia/gaia_urls.h"
29 #include "net/base/url_util.h"
30
31 namespace {
32
33 // Global SequenceNumber used for generating unique webview partition IDs.
34 base::StaticAtomicSequenceNumber next_partition_id;
35
36 } // empty namespace
37
38 InlineLoginHandlerImpl::InlineLoginHandlerImpl()
39       : weak_factory_(this), choose_what_to_sync_(false), partition_id_("") {
40 }
41
42 InlineLoginHandlerImpl::~InlineLoginHandlerImpl() {}
43
44 void InlineLoginHandlerImpl::RegisterMessages() {
45   InlineLoginHandler::RegisterMessages();
46
47   web_ui()->RegisterMessageCallback("switchToFullTab",
48       base::Bind(&InlineLoginHandlerImpl::HandleSwitchToFullTabMessage,
49                   base::Unretained(this)));
50 }
51
52 void InlineLoginHandlerImpl::SetExtraInitParams(base::DictionaryValue& params) {
53   params.SetInteger("authMode", InlineLoginHandler::kInlineAuthMode);
54
55   const GURL& current_url = web_ui()->GetWebContents()->GetURL();
56   signin::Source source = signin::GetSourceForPromoURL(current_url);
57   DCHECK(source != signin::SOURCE_UNKNOWN);
58   if (source == signin::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT ||
59       source == signin::SOURCE_AVATAR_BUBBLE_SIGN_IN) {
60     // Drop the leading slash in the path.
61     params.SetString("gaiaPath",
62         GaiaUrls::GetInstance()->embedded_signin_url().path().substr(1));
63   }
64
65   params.SetString("service", "chromiumsync");
66   params.SetString("continueUrl",
67       signin::GetLandingURL("source", static_cast<int>(source)).spec());
68
69   if (source != signin::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT) {
70     std::string last_email = Profile::FromWebUI(web_ui())->GetPrefs()->
71         GetString(prefs::kGoogleServicesLastUsername);
72     if (!last_email.empty())
73       params.SetString("email", last_email);
74   }
75
76   std::string frame_url;
77   net::GetValueForKeyInQuery(current_url, "frameUrl", &frame_url);
78   if (!frame_url.empty())
79     params.SetString("frameUrl", frame_url);
80
81   std::string is_constrained;
82   net::GetValueForKeyInQuery(current_url, "constrained", &is_constrained);
83   if (!is_constrained.empty())
84     params.SetString("constrained", is_constrained);
85
86   net::GetValueForKeyInQuery(current_url, "partitionId", &partition_id_);
87   if (partition_id_.empty()) {
88     partition_id_ =
89         "gaia-webview-" + base::IntToString(next_partition_id.GetNext());
90   }
91   params.SetString("partitionId", partition_id_);
92 }
93
94
95 void InlineLoginHandlerImpl::HandleSwitchToFullTabMessage(
96     const base::ListValue* args) {
97   base::string16 url_str;
98   CHECK(args->GetString(0, &url_str));
99
100   content::WebContents* web_contents = web_ui()->GetWebContents();
101   GURL main_frame_url(web_contents->GetURL());
102   main_frame_url = net::AppendOrReplaceQueryParameter(
103       main_frame_url, "frameUrl", UTF16ToASCII(url_str));
104   main_frame_url = net::AppendOrReplaceQueryParameter(
105       main_frame_url, "partitionId", partition_id_);
106   chrome::NavigateParams params(
107       Profile::FromWebUI(web_ui()),
108       net::AppendOrReplaceQueryParameter(main_frame_url, "constrained", "0"),
109       content::PAGE_TRANSITION_AUTO_TOPLEVEL);
110   chrome::Navigate(&params);
111
112   web_ui()->CallJavascriptFunction("inline.login.closeDialog");
113 }
114
115 void InlineLoginHandlerImpl::CompleteLogin(const base::ListValue* args) {
116   DCHECK(email_.empty() && password_.empty());
117
118   const base::DictionaryValue* dict = NULL;
119   base::string16 email;
120   if (!args->GetDictionary(0, &dict) || !dict ||
121       !dict->GetString("email", &email)) {
122     // User cancelled the signin by clicking 'skip for now'.
123     bool skip_for_now = false;
124     DCHECK(dict->GetBoolean("skipForNow", &skip_for_now) && skip_for_now);
125
126     signin::SetUserSkippedPromo(Profile::FromWebUI(web_ui()));
127     SyncStarterCallback(OneClickSigninSyncStarter::SYNC_SETUP_FAILURE);
128     return;
129   }
130
131   email_ = UTF16ToASCII(email);
132   base::string16 password;
133   dict->GetString("password", &password);
134   password_ = UTF16ToASCII(password);
135
136   dict->GetBoolean("chooseWhatToSync", &choose_what_to_sync_);
137
138   content::WebContents* contents = web_ui()->GetWebContents();
139   signin::Source source = signin::GetSourceForPromoURL(contents->GetURL());
140   OneClickSigninHelper::CanOfferFor can_offer =
141       source == signin::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT ?
142       OneClickSigninHelper::CAN_OFFER_FOR_SECONDARY_ACCOUNT :
143       OneClickSigninHelper::CAN_OFFER_FOR_ALL;
144   std::string error_msg;
145   OneClickSigninHelper::CanOffer(
146       contents, can_offer, email_, &error_msg);
147   if (!error_msg.empty()) {
148     HandleLoginError(error_msg);
149     return;
150   }
151
152   content::StoragePartition* partition =
153       content::BrowserContext::GetStoragePartitionForSite(
154           contents->GetBrowserContext(),
155           GURL("chrome-guest://mfffpogegjflfpflabcdkioaeobkgjik/?" +
156                 partition_id_));
157
158   auth_fetcher_.reset(new GaiaAuthFetcher(this,
159                                           GaiaConstants::kChromeSource,
160                                           partition->GetURLRequestContext()));
161   auth_fetcher_->StartCookieForOAuthCodeExchange("0");
162 }
163
164 void InlineLoginHandlerImpl::OnClientOAuthCodeSuccess(
165     const std::string& oauth_code) {
166   DCHECK(!oauth_code.empty());
167
168   content::WebContents* contents = web_ui()->GetWebContents();
169   Profile* profile = Profile::FromWebUI(web_ui());
170   ProfileSyncService* sync_service =
171       ProfileSyncServiceFactory::GetForProfile(profile);
172   const GURL& current_url = contents->GetURL();
173   signin::Source source = signin::GetSourceForPromoURL(current_url);
174
175   if (source == signin::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT) {
176     // SigninOAuthHelper will delete itself.
177     SigninOAuthHelper* helper = new SigninOAuthHelper(profile);
178     helper->StartAddingAccount(oauth_code);
179   } else {
180     OneClickSigninSyncStarter::StartSyncMode start_mode =
181         source == signin::SOURCE_SETTINGS || choose_what_to_sync_ ?
182             (SigninGlobalError::GetForProfile(profile)->HasMenuItem() &&
183               sync_service && sync_service->HasSyncSetupCompleted()) ?
184                 OneClickSigninSyncStarter::SHOW_SETTINGS_WITHOUT_CONFIGURE :
185                 OneClickSigninSyncStarter::CONFIGURE_SYNC_FIRST :
186             OneClickSigninSyncStarter::SYNC_WITH_DEFAULT_SETTINGS;
187     OneClickSigninSyncStarter::ConfirmationRequired confirmation_required =
188         source == signin::SOURCE_SETTINGS ||
189         source == signin::SOURCE_WEBSTORE_INSTALL ||
190         choose_what_to_sync_?
191             OneClickSigninSyncStarter::NO_CONFIRMATION :
192             OneClickSigninSyncStarter::CONFIRM_AFTER_SIGNIN;
193       OneClickSigninSyncStarter::Callback sync_callback = base::Bind(
194           &InlineLoginHandlerImpl::SyncStarterCallback,
195           weak_factory_.GetWeakPtr());
196
197       bool cross_account_error_handled =
198           OneClickSigninHelper::HandleCrossAccountError(
199               contents, "" /* session_index, not used */,
200               email_, password_, oauth_code,
201               OneClickSigninHelper::AUTO_ACCEPT_EXPLICIT,
202               source, start_mode, sync_callback);
203
204       if (!cross_account_error_handled) {
205         // Call OneClickSigninSyncStarter to exchange oauth code for tokens.
206         // OneClickSigninSyncStarter will delete itself once the job is done.
207         new OneClickSigninSyncStarter(
208             profile, NULL, "" /* session_index, not used */,
209             email_, password_, oauth_code,
210             start_mode,
211             contents,
212             confirmation_required,
213             sync_callback);
214       }
215   }
216
217   email_.clear();
218   password_.clear();
219   web_ui()->CallJavascriptFunction("inline.login.closeDialog");
220 }
221
222 void InlineLoginHandlerImpl::OnClientOAuthCodeFailure(
223     const GoogleServiceAuthError& error) {
224   LOG(ERROR) << "InlineLoginUI::OnClientOAuthCodeFailure";
225   HandleLoginError(error.ToString());
226 }
227
228 void InlineLoginHandlerImpl::HandleLoginError(const std::string& error_msg) {
229   SyncStarterCallback(OneClickSigninSyncStarter::SYNC_SETUP_FAILURE);
230
231   Browser* browser = chrome::FindBrowserWithWebContents(
232       web_ui()->GetWebContents());
233   if (!browser) {
234     browser = chrome::FindLastActiveWithProfile(
235         Profile::FromWebUI(web_ui()), chrome::GetActiveDesktop());
236   }
237   if (browser)
238     OneClickSigninHelper::ShowSigninErrorBubble(browser, error_msg);
239
240   email_.clear();
241   password_.clear();
242 }
243
244 void InlineLoginHandlerImpl::SyncStarterCallback(
245     OneClickSigninSyncStarter::SyncSetupResult result) {
246   content::WebContents* contents = web_ui()->GetWebContents();
247   const GURL& current_url = contents->GetURL();
248   bool auto_close = signin::IsAutoCloseEnabledInURL(current_url);
249   if (auto_close) {
250     base::MessageLoop::current()->PostTask(
251         FROM_HERE,
252         base::Bind(&InlineLoginHandlerImpl::CloseTab,
253                    weak_factory_.GetWeakPtr()));
254   } else {
255      signin::Source source = signin::GetSourceForPromoURL(current_url);
256      DCHECK(source != signin::SOURCE_UNKNOWN);
257      OneClickSigninHelper::RedirectToNtpOrAppsPageIfNecessary(contents, source);
258   }
259 }
260
261 void InlineLoginHandlerImpl::CloseTab() {
262   content::WebContents* tab = web_ui()->GetWebContents();
263   Browser* browser = chrome::FindBrowserWithWebContents(tab);
264   if (browser) {
265     TabStripModel* tab_strip_model = browser->tab_strip_model();
266     if (tab_strip_model) {
267       int index = tab_strip_model->GetIndexOfWebContents(tab);
268       if (index != TabStripModel::kNoTab) {
269         tab_strip_model->ExecuteContextMenuCommand(
270             index, TabStripModel::CommandCloseTab);
271       }
272     }
273   }
274 }