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