auto_login_infobar_delegate.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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.h"
10#include "base/metrics/histogram.h"
11#include "base/prefs/pref_service.h"
12#include "base/utf_string_conversions.h"
13#include "chrome/browser/browser_process.h"
14#include "chrome/browser/google/google_util.h"
15#include "chrome/browser/infobars/confirm_infobar_delegate.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/webui/sync_promo/sync_promo_ui.h"
20#include "chrome/common/chrome_notification_types.h"
21#include "chrome/common/chrome_switches.h"
22#include "chrome/common/pref_names.h"
23#include "chrome/common/url_constants.h"
24#include "content/public/browser/navigation_controller.h"
25#include "content/public/browser/notification_details.h"
26#include "content/public/browser/notification_observer.h"
27#include "content/public/browser/notification_registrar.h"
28#include "content/public/browser/notification_source.h"
29#include "content/public/browser/notification_types.h"
30#include "content/public/browser/page_navigator.h"
31#include "content/public/browser/web_contents.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#include "ui/base/resource/resource_bundle.h"
42
43using content::NavigationController;
44using content::NotificationSource;
45using content::NotificationDetails;
46
47
48// AutoLoginRedirector --------------------------------------------------------
49
50namespace {
51
52// This class is created by the AutoLoginInfoBarDelegate when the user wishes to
53// auto-login.  It holds context information needed while re-issuing service
54// tokens using the TokenService, gets the browser cookies with the TokenAuth
55// API, and finally redirects the user to the correct page.
56class AutoLoginRedirector : public UbertokenConsumer,
57                            public content::NotificationObserver {
58 public:
59  AutoLoginRedirector(NavigationController* navigation_controller,
60                      const std::string& args);
61  virtual ~AutoLoginRedirector();
62
63 private:
64  // Overriden from UbertokenConsumer:
65  virtual void OnUbertokenSuccess(const std::string& token) OVERRIDE;
66  virtual void OnUbertokenFailure(const GoogleServiceAuthError& error) OVERRIDE;
67
68  // Implementation of content::NotificationObserver
69  virtual void Observe(int type,
70                       const content::NotificationSource& source,
71                       const content::NotificationDetails& details) OVERRIDE;
72
73  // Redirect tab to MergeSession URL, logging the user in and navigating
74  // to the desired page.
75  void RedirectToMergeSession(const std::string& token);
76
77  NavigationController* navigation_controller_;
78  const std::string args_;
79  scoped_ptr<UbertokenFetcher> ubertoken_fetcher_;
80
81  // For listening to NavigationController destruction.
82  content::NotificationRegistrar registrar_;
83
84  DISALLOW_COPY_AND_ASSIGN(AutoLoginRedirector);
85};
86
87AutoLoginRedirector::AutoLoginRedirector(
88    NavigationController* navigation_controller,
89    const std::string& args)
90    : navigation_controller_(navigation_controller),
91      args_(args) {
92  ubertoken_fetcher_.reset(new UbertokenFetcher(
93      Profile::FromBrowserContext(navigation_controller_->GetBrowserContext()),
94      this));
95  registrar_.Add(this,
96                 content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
97                 content::Source<content::WebContents>(
98                     navigation_controller_->GetWebContents()));
99  ubertoken_fetcher_->StartFetchingToken();
100}
101
102AutoLoginRedirector::~AutoLoginRedirector() {
103}
104
105void AutoLoginRedirector::Observe(int type,
106                                  const NotificationSource& source,
107                                  const NotificationDetails& details) {
108  DCHECK(type == content::NOTIFICATION_WEB_CONTENTS_DESTROYED);
109  // The WebContents that started this has been destroyed. The request must be
110  // cancelled and this object must be deleted.
111  ubertoken_fetcher_.reset();
112  MessageLoop::current()->DeleteSoon(FROM_HERE, this);
113}
114
115void AutoLoginRedirector::OnUbertokenSuccess(const std::string& token) {
116  RedirectToMergeSession(token);
117  MessageLoop::current()->DeleteSoon(FROM_HERE, this);
118}
119
120void AutoLoginRedirector::OnUbertokenFailure(
121    const GoogleServiceAuthError& error) {
122  LOG(WARNING) << "AutoLoginRedirector: token request failed";
123  MessageLoop::current()->DeleteSoon(FROM_HERE, this);
124}
125
126void AutoLoginRedirector::RedirectToMergeSession(const std::string& token) {
127  // TODO(rogerta): what is the correct page transition?
128  navigation_controller_->LoadURL(
129      GURL(GaiaUrls::GetInstance()->merge_session_url() +
130          "?source=chrome&uberauth=" + token + "&" + args_),
131      content::Referrer(), content::PAGE_TRANSITION_AUTO_BOOKMARK,
132      std::string());
133}
134
135}  // namepsace
136
137
138// AutoLoginInfoBarDelegate::Params -------------------------------------------
139
140AutoLoginInfoBarDelegate::Params::Params() {}
141AutoLoginInfoBarDelegate::Params::~Params() {}
142
143
144// AutoLoginInfoBarDelegate ---------------------------------------------------
145
146// static
147void AutoLoginInfoBarDelegate::Create(InfoBarService* infobar_service,
148                                      const Params& params) {
149  infobar_service->AddInfoBar(scoped_ptr<InfoBarDelegate>(
150      new AutoLoginInfoBarDelegate(infobar_service, params)));
151}
152
153string16 AutoLoginInfoBarDelegate::GetMessageText(
154    const std::string& username) const {
155  return l10n_util::GetStringFUTF16(IDS_AUTOLOGIN_INFOBAR_MESSAGE,
156                                    UTF8ToUTF16(username));
157}
158
159AutoLoginInfoBarDelegate::AutoLoginInfoBarDelegate(
160    InfoBarService* owner,
161    const Params& params)
162    : ConfirmInfoBarDelegate(owner),
163      params_(params),
164      button_pressed_(false) {
165  RecordHistogramAction(HISTOGRAM_SHOWN);
166  registrar_.Add(this,
167                 chrome::NOTIFICATION_GOOGLE_SIGNED_OUT,
168                 content::Source<Profile>(Profile::FromBrowserContext(
169                     web_contents()->GetBrowserContext())));
170}
171
172AutoLoginInfoBarDelegate::~AutoLoginInfoBarDelegate() {
173  if (!button_pressed_)
174    RecordHistogramAction(HISTOGRAM_IGNORED);
175}
176
177void AutoLoginInfoBarDelegate::InfoBarDismissed() {
178  RecordHistogramAction(HISTOGRAM_DISMISSED);
179  button_pressed_ = true;
180}
181
182gfx::Image* AutoLoginInfoBarDelegate::GetIcon() const {
183  return &ResourceBundle::GetSharedInstance().GetNativeImageNamed(
184      IDR_INFOBAR_AUTOLOGIN);
185}
186
187InfoBarDelegate::Type AutoLoginInfoBarDelegate::GetInfoBarType() const {
188  return PAGE_ACTION_TYPE;
189}
190
191AutoLoginInfoBarDelegate*
192    AutoLoginInfoBarDelegate::AsAutoLoginInfoBarDelegate() {
193  return this;
194}
195
196string16 AutoLoginInfoBarDelegate::GetMessageText() const {
197  return GetMessageText(params_.username);
198}
199
200string16 AutoLoginInfoBarDelegate::GetButtonLabel(
201    InfoBarButton button) const {
202  return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
203      IDS_AUTOLOGIN_INFOBAR_OK_BUTTON : IDS_AUTOLOGIN_INFOBAR_CANCEL_BUTTON);
204}
205
206bool AutoLoginInfoBarDelegate::Accept() {
207  // AutoLoginRedirector deletes itself.
208  new AutoLoginRedirector(&web_contents()->GetController(),
209                          params_.header.args);
210  RecordHistogramAction(HISTOGRAM_ACCEPTED);
211  button_pressed_ = true;
212  return true;
213}
214
215bool AutoLoginInfoBarDelegate::Cancel() {
216  Profile* profile = Profile::FromBrowserContext(
217      web_contents()->GetBrowserContext());
218  PrefService* pref_service = profile->GetPrefs();
219  pref_service->SetBoolean(prefs::kAutologinEnabled, false);
220  RecordHistogramAction(HISTOGRAM_REJECTED);
221  button_pressed_ = true;
222  return true;
223}
224
225void AutoLoginInfoBarDelegate::Observe(int type,
226                                       const NotificationSource& source,
227                                       const NotificationDetails& details) {
228  DCHECK_EQ(chrome::NOTIFICATION_GOOGLE_SIGNED_OUT, type);
229  // owner() can be NULL when InfoBarService removes us. See
230  // |InfoBarDelegate::clear_owner|.
231  if (owner())
232    owner()->RemoveInfoBar(this);
233}
234
235void AutoLoginInfoBarDelegate::RecordHistogramAction(Actions action) {
236  UMA_HISTOGRAM_ENUMERATION("AutoLogin.Regular", action, HISTOGRAM_MAX);
237}
238