File: one_click_signin_helper.h

package info (click to toggle)
chromium-browser 41.0.2272.118-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie-kfreebsd
  • size: 2,189,132 kB
  • sloc: cpp: 9,691,462; ansic: 3,341,451; python: 712,689; asm: 518,779; xml: 208,926; java: 169,820; sh: 119,353; perl: 68,907; makefile: 28,311; yacc: 13,305; objc: 11,385; tcl: 3,186; cs: 2,225; sql: 2,217; lex: 2,215; lisp: 1,349; pascal: 1,256; awk: 407; ruby: 155; sed: 53; php: 14; exp: 11
file content (386 lines) | stat: -rw-r--r-- 16,185 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_UI_SYNC_ONE_CLICK_SIGNIN_HELPER_H_
#define CHROME_BROWSER_UI_SYNC_ONE_CLICK_SIGNIN_HELPER_H_

#include <string>

#include "base/gtest_prod_util.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/signin/signin_promo.h"
#include "chrome/browser/sync/profile_sync_service_observer.h"
#include "chrome/browser/ui/sync/one_click_signin_sync_starter.h"
#include "components/signin/core/browser/signin_oauth_helper.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
#include "google_apis/gaia/google_service_auth_error.h"

class Browser;
class GURL;
class ProfileIOData;

namespace autofill {
struct PasswordForm;
}

namespace content {
class WebContents;
struct FrameNavigateParams;
struct LoadCommittedDetails;
}

namespace net {
class URLRequest;
}

namespace password_manager {
class PasswordManager;
}

// Per-tab one-click signin helper.  When a user signs in to a Google service
// and the profile is not yet connected to a Google account, will start the
// process of helping the user connect his profile with one click.  The process
// begins with an infobar and is followed with a confirmation dialog explaining
// more about what this means.
class OneClickSigninHelper
    : public content::WebContentsObserver,
      public content::WebContentsUserData<OneClickSigninHelper> {
 public:
  // Represents user's decision about sign in process.
  enum AutoAccept {
    // User decision not yet known.  Assume cancel.
    AUTO_ACCEPT_NONE,

    // User has explicitly accepted to sign in.  A bubble is shown with the
    // option to start sync, configure it first, or abort.
    AUTO_ACCEPT_ACCEPTED,

    // User has explicitly accepted to sign in, but wants to configure sync
    // settings before turning it on.
    AUTO_ACCEPT_CONFIGURE,

    // User has explicitly rejected to sign in.  Furthermore, the user does
    // not want to be prompted to see the interstitial again in this profile.
    AUTO_ACCEPT_REJECTED_FOR_PROFILE,

    // This is an explicit sign in from either first run, NTP, wrench menu,
    // or settings page.  The user will be signed in automatically with sync
    // enabled using default settings.
    AUTO_ACCEPT_EXPLICIT
  };

  // Return value of CanOfferOnIOThread().
  enum Offer {
    CAN_OFFER,
    DONT_OFFER,
    IGNORE_REQUEST
  };

  // Argument to CanOffer().
  enum CanOfferFor {
    CAN_OFFER_FOR_ALL,
    CAN_OFFER_FOR_INTERSTITAL_ONLY,
    CAN_OFFER_FOR_SECONDARY_ACCOUNT
    // TODO(guohui): needs to handle adding secondary account through
    // interstitial.
  };

  // Arguments used with StartSync function.  base::Bind() cannot support too
  // many args for performance reasons, so they are packaged up into a struct.
  struct StartSyncArgs {
    // Default contructor for testing only.
    StartSyncArgs();
    StartSyncArgs(Profile* profile,
                  Browser* browser,
                  OneClickSigninHelper::AutoAccept auto_accept,
                  const std::string& session_index,
                  const std::string& email,
                  const std::string& password,
                  const std::string& refresh_token,
                  content::WebContents* web_contents,
                  bool untrusted_confirmation_required,
                  signin_metrics::Source source,
                  OneClickSigninSyncStarter::Callback callback);
    ~StartSyncArgs();

    Profile* profile;
    Browser* browser;
    OneClickSigninHelper::AutoAccept auto_accept;
    std::string session_index;
    std::string email;
    std::string password;
    std::string refresh_token;

    // Web contents in which the sync setup page should be displayed,
    // if necessary. Can be NULL.
    content::WebContents* web_contents;

    OneClickSigninSyncStarter::ConfirmationRequired confirmation_required;
    signin_metrics::Source source;
    OneClickSigninSyncStarter::Callback callback;
  };

  // Wrapper to call OneClickSigninSyncStarter after fetching the refresh token
  // if needed.  Also verifies that the cookies are correct if no password is
  // specified, and checks that the email from the cookies match the expected
  // email address.
  class SyncStarterWrapper : public SigninOAuthHelper::Consumer,
                             public chrome::BrowserListObserver {
   public:
    SyncStarterWrapper(
        const OneClickSigninHelper::StartSyncArgs& args,
        OneClickSigninSyncStarter::StartSyncMode start_mode);
    ~SyncStarterWrapper() override;

    void Start();

   private:
    void VerifyGaiaCookiesBeforeSignIn();
    void OnGaiaCookiesFetched(const std::string session_index,
                              const net::CookieList& cookie_list);

    // Virtual to be overridden in tests.
    virtual void DisplayErrorBubble(const std::string& error_message);
    virtual void StartSigninOAuthHelper();
    virtual void StartOneClickSigninSyncStarter(
        const std::string& email,
        const std::string& refresh_token);

    // Overriden from SigninOAuthHelper::Consumer.
    void OnSigninOAuthInformationAvailable(
        const std::string& email,
        const std::string& display_email,
        const std::string& refresh_token) override;
    void OnSigninOAuthInformationFailure(
        const GoogleServiceAuthError& error) override;

    // Overriden from chrome::BrowserListObserver.
    void OnBrowserRemoved(Browser* browser) override;

    OneClickSigninHelper::StartSyncArgs args_;
    chrome::HostDesktopType desktop_type_;
    OneClickSigninSyncStarter::StartSyncMode start_mode_;
    scoped_ptr<SigninOAuthHelper> signin_oauth_helper_;
    base::WeakPtrFactory<SyncStarterWrapper> weak_pointer_factory_;

    DISALLOW_COPY_AND_ASSIGN(SyncStarterWrapper);
  };

  static void LogHistogramValue(int action);

  // Returns true if the one-click signin feature can be offered at this time.
  // If |email| is not empty, then the profile is checked to see if it's
  // already connected to a google account or if the user has already rejected
  // one-click sign-in with this email, in which cases a one click signin
  // should not be offered.
  //
  // If |can_offer_for| is |CAN_OFFER_FOR_INTERSTITAL_ONLY|, then only do the
  // checks that would affect the interstitial page.  Otherwise, do the checks
  // that would affect the interstitial and the explicit sign ins.
  //
  // Returns in |error_message_id| an explanation as a string resource ID for
  // why one-clicked cannot be offered.  |error_message_id| is valid only if
  // the return value is false.  If no explanation is needed, |error_message_id|
  // may be null.
  static bool CanOffer(content::WebContents* web_contents,
                       CanOfferFor can_offer_for,
                       const std::string& email,
                       std::string* error_message);

  // Returns true if the one-click signin feature can be offered at this time.
  // It can be offered if the io_data is not in an incognito window and if the
  // origin of |url| is a valid Gaia sign in origin.  This function is meant
  // to called only from the IO thread.
  static Offer CanOfferOnIOThread(net::URLRequest* request,
                                  ProfileIOData* io_data);

  // Looks for the Google-Accounts-SignIn response header, and if found,
  // tries to display an infobar in the tab contents identified by the
  // child/route id.
  static void ShowInfoBarIfPossible(net::URLRequest* request,
                                    ProfileIOData* io_data,
                                    int child_id,
                                    int route_id);

  // Handles cross account sign in error. If the supplied |email| does not match
  // the last signed in email of the current profile, then Chrome will show a
  // confirmation dialog before starting sync. It returns true if there is a
  // cross account error, and false otherwise.
  static bool HandleCrossAccountError(
      Profile* profile,
      const std::string& session_index,
      const std::string& email,
      const std::string& password,
      const std::string& refresh_token,
      OneClickSigninHelper::AutoAccept auto_accept,
      signin_metrics::Source source,
      OneClickSigninSyncStarter::StartSyncMode start_mode,
      OneClickSigninSyncStarter::Callback sync_callback);

  static void RedirectToNtpOrAppsPage(
      content::WebContents* contents, signin_metrics::Source source);

  // If the |source| is not settings page/webstore, redirects to
  // the NTP/Apps page.
  static void RedirectToNtpOrAppsPageIfNecessary(
      content::WebContents* contents, signin_metrics::Source source);

  // Remove the item currently at the top of the history list if it's
  // the Gaia redirect URL. Due to limitations of the NavigationController
  // this cannot be done until a new page becomes "current".
  static void RemoveSigninRedirectURLHistoryItem(
      content::WebContents* web_contents);

  static void LogConfirmHistogramValue(int action);

 private:
  friend class content::WebContentsUserData<OneClickSigninHelper>;
  friend class OneClickSigninHelperTest;
  FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperIncognitoTest,
                           ShowInfoBarUIThreadIncognito);
  FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperTest,
                           SigninFromWebstoreWithConfigSyncfirst);
  FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperTest,
                           ShowSigninBubbleAfterSigninComplete);
  FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperTest, SigninCancelled);
  FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperTest, SigninFailed);
  FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperTest,
                           CleanTransientStateOnNavigate);
  FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperIOTest, CanOfferOnIOThread);
  FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperIOTest,
                           CanOfferOnIOThreadIncognito);
  FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperIOTest,
                           CanOfferOnIOThreadNoIOData);
  FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperIOTest,
                           CanOfferOnIOThreadBadURL);
  FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperIOTest,
                           CanOfferOnIOThreadDisabled);
  FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperIOTest,
                           CanOfferOnIOThreadSignedIn);
  FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperIOTest,
                           CanOfferOnIOThreadEmailNotAllowed);
  FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperIOTest,
                           CanOfferOnIOThreadEmailAlreadyUsed);
  FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperIOTest,
                           CreateTestProfileIOData);
  FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperIOTest,
                           CanOfferOnIOThreadWithRejectedEmail);
  FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperIOTest,
                           CanOfferOnIOThreadNoSigninCookies);
  FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperIOTest,
                           CanOfferOnIOThreadDisabledByPolicy);

  // Maximum number of navigations away from the set of valid Gaia URLs before
  // clearing the internal state of the helper.  This is necessary to support
  // SAML-based accounts, but causes bug crbug.com/181163.
  static const int kMaxNavigationsSince;

  explicit OneClickSigninHelper(content::WebContents* web_contents);

  ~OneClickSigninHelper() override;

  // Returns true if the one-click signin feature can be offered at this time.
  // It can be offered if the io_data is not in an incognito window and if the
  // origin of |url| is a valid Gaia sign in origin.  This function is meant
  // to called only from the IO thread.
  static Offer CanOfferOnIOThreadImpl(const GURL& url,
                                      base::SupportsUserData* request,
                                      ProfileIOData* io_data);

  // The portion of ShowInfoBarIfPossible() that needs to run on the UI thread.
  // |session_index| and |email| are extracted from the Google-Accounts-SignIn
  // header.  |auto_accept| is extracted from the Google-Chrome-SignIn header.
  // |source| is used to determine which of the explicit sign in mechanism is
  // being used.
  //
  // |continue_url| is where Gaia will continue to when the sign in process is
  // done.  For explicit sign ins, this is a URL chrome controls. For one-click
  // sign in, this could be any google property.  This URL is used to know
  // when the sign process is over and to collect infomation from the user
  // entered on the Gaia sign in page (for explicit sign ins).
  static void ShowInfoBarUIThread(const std::string& session_index,
                                  const std::string& email,
                                  AutoAccept auto_accept,
                                  signin_metrics::Source source,
                                  const GURL& continue_url,
                                  int child_id,
                                  int route_id);

  void RedirectToSignin();

  // Clear all data member of the helper, except for the error.
  void CleanTransientState();

  // Unitests that use a TestingProfile should call this.
  // Otherwise, clearing the pending e-mail crashes because the code expects
  // a real ResourceContext rather than the MockResourceContext a
  // TestingProfile provides.
  void SetDoNotClearPendingEmailForTesting();

  // In unit tests, disable starting the actual sync.
  void set_do_not_start_sync_for_testing();

  // Called when password has been submitted.
  void PasswordSubmitted(const autofill::PasswordForm& form);

  // content::WebContentsObserver overrides.
  void DidStartNavigationToPendingEntry(
      const GURL& url,
      content::NavigationController::ReloadType reload_type) override;
  void DidNavigateMainFrame(
      const content::LoadCommittedDetails& details,
      const content::FrameNavigateParams& params) override;
  void DidStopLoading(content::RenderViewHost* render_view_host) override;

  OneClickSigninSyncStarter::Callback CreateSyncStarterCallback();

  // Callback invoked when OneClickSigninSyncStarter completes sync setup.
  void SyncSetupCompletedCallback(
      OneClickSigninSyncStarter::SyncSetupResult result);

  // Tracks if we are in the process of showing the signin or one click
  // interstitial page. It's set to true the first time we load one of those
  // pages and set to false when transient state is cleaned.
  // Note: This should only be used for logging purposes.
  bool showing_signin_;

  // Information about the account that has just logged in.
  std::string session_index_;
  std::string email_;
  std::string password_;
  AutoAccept auto_accept_;
  signin_metrics::Source source_;
  bool switched_to_advanced_;
  GURL continue_url_;
  // The orignal continue URL after sync setup is complete.
  GURL original_continue_url_;
  std::string error_message_;

  // Number of navigations since starting a sign in that is outside the
  // the set of trusted Gaia URLs.  Sign in attempts that include visits to
  // one more untrusted will cause a modal dialog to appear asking the user
  // to confirm, similar to the interstitial flow.
  int untrusted_navigations_since_signin_visit_;

  // Whether a Gaia URL during the sign in process was not handled by the
  // dedicated sign in process (e.g. SAML login, which redirects to a
  // non-google-controlled domain).
  // This is set to true if at least one such URL is detected.
  bool untrusted_confirmation_required_;

  // Allows unittests to avoid accessing the ResourceContext for clearing a
  // pending e-mail.
  bool do_not_clear_pending_email_;

  // Allows unittest to avoid starting sync for real.
  bool do_not_start_sync_for_testing_;

  base::WeakPtrFactory<OneClickSigninHelper> weak_pointer_factory_;

  DISALLOW_COPY_AND_ASSIGN(OneClickSigninHelper);
};

#endif  // CHROME_BROWSER_UI_SYNC_ONE_CLICK_SIGNIN_HELPER_H_