auto_login_infobar_delegate.cc revision f2477e01787aa58f445919b809d89e252beef54f
1// Copyright (c) 2012 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/auto_login_infobar_delegate.h"
6
7#include "base/bind.h"
8#include "base/logging.h"
9#include "base/message_loop/message_loop.h"
10#include "base/metrics/histogram.h"
11#include "base/prefs/pref_service.h"
12#include "base/strings/utf_string_conversions.h"
13#include "chrome/browser/browser_process.h"
14#include "chrome/browser/chrome_notification_types.h"
15#include "chrome/browser/google/google_util.h"
16#include "chrome/browser/infobars/infobar_service.h"
17#include "chrome/browser/profiles/profile.h"
18#include "chrome/browser/signin/ubertoken_fetcher.h"
19#include "chrome/browser/ui/sync/sync_promo_ui.h"
20#include "chrome/common/chrome_switches.h"
21#include "chrome/common/pref_names.h"
22#include "chrome/common/url_constants.h"
23#include "content/public/browser/navigation_controller.h"
24#include "content/public/browser/notification_details.h"
25#include "content/public/browser/notification_observer.h"
26#include "content/public/browser/notification_registrar.h"
27#include "content/public/browser/notification_source.h"
28#include "content/public/browser/notification_types.h"
29#include "content/public/browser/page_navigator.h"
30#include "content/public/browser/web_contents.h"
31#include "content/public/browser/web_contents_observer.h"
32#include "content/public/common/referrer.h"
33#include "google_apis/gaia/gaia_constants.h"
34#include "google_apis/gaia/gaia_urls.h"
35#include "grit/chromium_strings.h"
36#include "grit/generated_resources.h"
37#include "grit/theme_resources.h"
38#include "net/base/escape.h"
39#include "net/url_request/url_request.h"
40#include "ui/base/l10n/l10n_util.h"
41
42#if defined(OS_ANDROID)
43#include "chrome/browser/ui/android/infobars/auto_login_infobar_delegate_android.h"
44#endif
45
46
47// AutoLoginRedirector --------------------------------------------------------
48
49namespace {
50
51// This class is created by the AutoLoginInfoBarDelegate when the user wishes to
52// auto-login.  It holds context information needed while re-issuing service
53// tokens using the OAuth2TokenService, gets the browser cookies with the
54// TokenAuth API, and finally redirects the user to the correct page.
55class AutoLoginRedirector : public UbertokenConsumer,
56                            public content::WebContentsObserver {
57 public:
58  AutoLoginRedirector(content::WebContents* web_contents,
59                      const std::string& args);
60  virtual ~AutoLoginRedirector();
61
62 private:
63  // Overriden from UbertokenConsumer:
64  virtual void OnUbertokenSuccess(const std::string& token) OVERRIDE;
65  virtual void OnUbertokenFailure(const GoogleServiceAuthError& error) OVERRIDE;
66
67  // Implementation of content::WebContentsObserver
68  virtual void WebContentsDestroyed(
69      content::WebContents* web_contents) OVERRIDE;
70
71  // Redirect tab to MergeSession URL, logging the user in and navigating
72  // to the desired page.
73  void RedirectToMergeSession(const std::string& token);
74
75  const std::string args_;
76  scoped_ptr<UbertokenFetcher> ubertoken_fetcher_;
77
78  DISALLOW_COPY_AND_ASSIGN(AutoLoginRedirector);
79};
80
81AutoLoginRedirector::AutoLoginRedirector(
82    content::WebContents* web_contents,
83    const std::string& args)
84    : content::WebContentsObserver(web_contents),
85      args_(args) {
86  ubertoken_fetcher_.reset(new UbertokenFetcher(
87      Profile::FromBrowserContext(web_contents->GetBrowserContext()), this));
88  ubertoken_fetcher_->StartFetchingToken();
89}
90
91AutoLoginRedirector::~AutoLoginRedirector() {
92}
93
94void AutoLoginRedirector::WebContentsDestroyed(
95    content::WebContents* web_contents) {
96  // The WebContents that started this has been destroyed. The request must be
97  // cancelled and this object must be deleted.
98  ubertoken_fetcher_.reset();
99  base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
100}
101
102void AutoLoginRedirector::OnUbertokenSuccess(const std::string& token) {
103  RedirectToMergeSession(token);
104  base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
105}
106
107void AutoLoginRedirector::OnUbertokenFailure(
108    const GoogleServiceAuthError& error) {
109  LOG(WARNING) << "AutoLoginRedirector: token request failed";
110  base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
111}
112
113void AutoLoginRedirector::RedirectToMergeSession(const std::string& token) {
114  // TODO(rogerta): what is the correct page transition?
115  web_contents()->GetController().LoadURL(
116      GaiaUrls::GetInstance()->merge_session_url().Resolve(
117          "?source=chrome&uberauth=" + token + "&" + args_),
118      content::Referrer(), content::PAGE_TRANSITION_AUTO_BOOKMARK,
119      std::string());
120}
121
122}  // namespace
123
124
125// AutoLoginInfoBarDelegate ---------------------------------------------------
126
127// static
128void AutoLoginInfoBarDelegate::Create(InfoBarService* infobar_service,
129                                      const Params& params) {
130  infobar_service->AddInfoBar(scoped_ptr<InfoBarDelegate>(
131#if defined(OS_ANDROID)
132      new AutoLoginInfoBarDelegateAndroid(infobar_service, params)
133#else
134      new AutoLoginInfoBarDelegate(infobar_service, params)
135#endif
136      ));
137}
138
139AutoLoginInfoBarDelegate::AutoLoginInfoBarDelegate(
140    InfoBarService* owner,
141    const Params& params)
142    : ConfirmInfoBarDelegate(owner),
143      params_(params),
144      button_pressed_(false) {
145  RecordHistogramAction(SHOWN);
146  registrar_.Add(this, chrome::NOTIFICATION_GOOGLE_SIGNED_OUT,
147                 content::Source<Profile>(Profile::FromBrowserContext(
148                     web_contents()->GetBrowserContext())));
149}
150
151AutoLoginInfoBarDelegate::~AutoLoginInfoBarDelegate() {
152  if (!button_pressed_)
153    RecordHistogramAction(IGNORED);
154}
155
156void AutoLoginInfoBarDelegate::InfoBarDismissed() {
157  RecordHistogramAction(DISMISSED);
158  button_pressed_ = true;
159}
160
161int AutoLoginInfoBarDelegate::GetIconID() const {
162  return IDR_INFOBAR_AUTOLOGIN;
163}
164
165InfoBarDelegate::Type AutoLoginInfoBarDelegate::GetInfoBarType() const {
166  return PAGE_ACTION_TYPE;
167}
168
169AutoLoginInfoBarDelegate*
170    AutoLoginInfoBarDelegate::AsAutoLoginInfoBarDelegate() {
171  return this;
172}
173
174string16 AutoLoginInfoBarDelegate::GetMessageText() const {
175  return l10n_util::GetStringFUTF16(IDS_AUTOLOGIN_INFOBAR_MESSAGE,
176                                    UTF8ToUTF16(params_.username));
177}
178
179string16 AutoLoginInfoBarDelegate::GetButtonLabel(
180    InfoBarButton button) const {
181  return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
182      IDS_AUTOLOGIN_INFOBAR_OK_BUTTON : IDS_AUTOLOGIN_INFOBAR_CANCEL_BUTTON);
183}
184
185bool AutoLoginInfoBarDelegate::Accept() {
186  // AutoLoginRedirector deletes itself.
187  new AutoLoginRedirector(web_contents(), params_.header.args);
188  RecordHistogramAction(ACCEPTED);
189  button_pressed_ = true;
190  return true;
191}
192
193bool AutoLoginInfoBarDelegate::Cancel() {
194  PrefService* pref_service = Profile::FromBrowserContext(
195      web_contents()->GetBrowserContext())->GetPrefs();
196  pref_service->SetBoolean(prefs::kAutologinEnabled, false);
197  RecordHistogramAction(REJECTED);
198  button_pressed_ = true;
199  return true;
200}
201
202void AutoLoginInfoBarDelegate::Observe(
203    int type,
204    const content::NotificationSource& source,
205    const content::NotificationDetails& details) {
206  DCHECK_EQ(chrome::NOTIFICATION_GOOGLE_SIGNED_OUT, type);
207  // owner() can be NULL when InfoBarService removes us. See
208  // |InfoBarDelegate::clear_owner|.
209  if (owner())
210    owner()->RemoveInfoBar(this);
211}
212
213void AutoLoginInfoBarDelegate::RecordHistogramAction(Actions action) {
214  UMA_HISTOGRAM_ENUMERATION("AutoLogin.Regular", action,
215                            HISTOGRAM_BOUNDING_VALUE);
216}
217