Upstream version 6.35.121.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / sync / one_click_signin_helper.h
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 #ifndef CHROME_BROWSER_UI_SYNC_ONE_CLICK_SIGNIN_HELPER_H_
6 #define CHROME_BROWSER_UI_SYNC_ONE_CLICK_SIGNIN_HELPER_H_
7
8 #include <string>
9
10 #include "base/gtest_prod_util.h"
11 #include "base/memory/weak_ptr.h"
12 #include "chrome/browser/signin/signin_oauth_helper.h"
13 #include "chrome/browser/signin/signin_promo.h"
14 #include "chrome/browser/sync/profile_sync_service_observer.h"
15 #include "chrome/browser/ui/sync/one_click_signin_sync_starter.h"
16 #include "content/public/browser/navigation_controller.h"
17 #include "content/public/browser/web_contents_observer.h"
18 #include "content/public/browser/web_contents_user_data.h"
19 #include "google_apis/gaia/google_service_auth_error.h"
20
21 class Browser;
22 class GURL;
23 class PasswordManager;
24 class ProfileIOData;
25
26 namespace autofill {
27 struct PasswordForm;
28 }
29
30 namespace content {
31 class WebContents;
32 struct FrameNavigateParams;
33 struct LoadCommittedDetails;
34 }
35
36 namespace net {
37 class URLRequest;
38 }
39
40 // Per-tab one-click signin helper.  When a user signs in to a Google service
41 // and the profile is not yet connected to a Google account, will start the
42 // process of helping the user connect his profile with one click.  The process
43 // begins with an infobar and is followed with a confirmation dialog explaining
44 // more about what this means.
45 class OneClickSigninHelper
46     : public content::WebContentsObserver,
47       public content::WebContentsUserData<OneClickSigninHelper>,
48       public ProfileSyncServiceObserver {
49  public:
50   // Represents user's decision about sign in process.
51   enum AutoAccept {
52     // User decision not yet known.  Assume cancel.
53     AUTO_ACCEPT_NONE,
54
55     // User has explicitly accepted to sign in.  A bubble is shown with the
56     // option to start sync, configure it first, or abort.
57     AUTO_ACCEPT_ACCEPTED,
58
59     // User has explicitly accepted to sign in, but wants to configure sync
60     // settings before turning it on.
61     AUTO_ACCEPT_CONFIGURE,
62
63     // User has explicitly rejected to sign in.  Furthermore, the user does
64     // not want to be prompted to see the interstitial again in this profile.
65     AUTO_ACCEPT_REJECTED_FOR_PROFILE,
66
67     // This is an explicit sign in from either first run, NTP, wrench menu,
68     // or settings page.  The user will be signed in automatically with sync
69     // enabled using default settings.
70     AUTO_ACCEPT_EXPLICIT
71   };
72
73   // Return value of CanOfferOnIOThread().
74   enum Offer {
75     CAN_OFFER,
76     DONT_OFFER,
77     IGNORE_REQUEST
78   };
79
80   // Argument to CanOffer().
81   enum CanOfferFor {
82     CAN_OFFER_FOR_ALL,
83     CAN_OFFER_FOR_INTERSTITAL_ONLY,
84     CAN_OFFER_FOR_SECONDARY_ACCOUNT
85     // TODO(guohui): needs to handle adding secondary account through
86     // interstitial.
87   };
88
89   // Arguments used with StartSync function.  base::Bind() cannot support too
90   // many args for performance reasons, so they are packaged up into a struct.
91   struct StartSyncArgs {
92     // Default contructor for testing only.
93     StartSyncArgs();
94     StartSyncArgs(Profile* profile,
95                   Browser* browser,
96                   OneClickSigninHelper::AutoAccept auto_accept,
97                   const std::string& session_index,
98                   const std::string& email,
99                   const std::string& password,
100                   const std::string& refresh_token,
101                   content::WebContents* web_contents,
102                   bool untrusted_confirmation_required,
103                   signin::Source source,
104                   OneClickSigninSyncStarter::Callback callback);
105     ~StartSyncArgs();
106
107     Profile* profile;
108     Browser* browser;
109     OneClickSigninHelper::AutoAccept auto_accept;
110     std::string session_index;
111     std::string email;
112     std::string password;
113     std::string refresh_token;
114
115     // Web contents in which the sync setup page should be displayed,
116     // if necessary. Can be NULL.
117     content::WebContents* web_contents;
118
119     OneClickSigninSyncStarter::ConfirmationRequired confirmation_required;
120     signin::Source source;
121     OneClickSigninSyncStarter::Callback callback;
122   };
123
124   // Wrapper to call OneClickSigninSyncStarter after fetching the refresh token
125   // if needed.  Also verifies that the cookies are correct if no password is
126   // specified, and checks that the email from the cookies match the expected
127   // email address.
128   class SyncStarterWrapper : public SigninOAuthHelper::Consumer,
129                              public chrome::BrowserListObserver {
130    public:
131     SyncStarterWrapper(
132         const OneClickSigninHelper::StartSyncArgs& args,
133         OneClickSigninSyncStarter::StartSyncMode start_mode);
134     virtual ~SyncStarterWrapper();
135
136     void Start();
137
138    private:
139     void VerifyGaiaCookiesBeforeSignIn();
140     void OnGaiaCookiesFetched(const std::string session_index,
141                               const net::CookieList& cookie_list);
142
143     // Virtual to be overridden in tests.
144     virtual void DisplayErrorBubble(const std::string& error_message);
145     virtual void StartSigninOAuthHelper();
146     virtual void StartOneClickSigninSyncStarter(
147         const std::string& email,
148         const std::string& refresh_token);
149
150     // Overriden from SigninOAuthHelper::Consumer.
151     virtual void OnSigninOAuthInformationAvailable(
152         const std::string& email,
153         const std::string& display_email,
154         const std::string& refresh_token) OVERRIDE;
155     virtual void OnSigninOAuthInformationFailure(
156         const GoogleServiceAuthError& error) OVERRIDE;
157
158     // Overriden from chrome::BrowserListObserver.
159     virtual void OnBrowserRemoved(Browser* browser) OVERRIDE;
160
161     OneClickSigninHelper::StartSyncArgs args_;
162     chrome::HostDesktopType desktop_type_;
163     OneClickSigninSyncStarter::StartSyncMode start_mode_;
164     scoped_ptr<SigninOAuthHelper> signin_oauth_helper_;
165     base::WeakPtrFactory<SyncStarterWrapper> weak_pointer_factory_;
166
167     DISALLOW_COPY_AND_ASSIGN(SyncStarterWrapper);
168   };
169
170   static void LogHistogramValue(signin::Source source, int action);
171
172   static void CreateForWebContentsWithPasswordManager(
173       content::WebContents* contents,
174       PasswordManager* password_manager);
175
176   // Returns true if the one-click signin feature can be offered at this time.
177   // If |email| is not empty, then the profile is checked to see if it's
178   // already connected to a google account or if the user has already rejected
179   // one-click sign-in with this email, in which cases a one click signin
180   // should not be offered.
181   //
182   // If |can_offer_for| is |CAN_OFFER_FOR_INTERSTITAL_ONLY|, then only do the
183   // checks that would affect the interstitial page.  Otherwise, do the checks
184   // that would affect the interstitial and the explicit sign ins.
185   //
186   // Returns in |error_message_id| an explanation as a string resource ID for
187   // why one-clicked cannot be offered.  |error_message_id| is valid only if
188   // the return value is false.  If no explanation is needed, |error_message_id|
189   // may be null.
190   static bool CanOffer(content::WebContents* web_contents,
191                        CanOfferFor can_offer_for,
192                        const std::string& email,
193                        std::string* error_message);
194
195   // Returns true if the one-click signin feature can be offered at this time.
196   // It can be offered if the io_data is not in an incognito window and if the
197   // origin of |url| is a valid Gaia sign in origin.  This function is meant
198   // to called only from the IO thread.
199   static Offer CanOfferOnIOThread(net::URLRequest* request,
200                                   ProfileIOData* io_data);
201
202   // Looks for the Google-Accounts-SignIn response header, and if found,
203   // tries to display an infobar in the tab contents identified by the
204   // child/route id.
205   static void ShowInfoBarIfPossible(net::URLRequest* request,
206                                     ProfileIOData* io_data,
207                                     int child_id,
208                                     int route_id);
209
210   // Handles cross account sign in error. If the supplied |email| does not match
211   // the last signed in email of the current profile, then Chrome will show a
212   // confirmation dialog before starting sync. It returns true if there is a
213   // cross ccount error, and false otherwise.
214   static bool HandleCrossAccountError(
215       content::WebContents* contents,
216       const std::string& session_index,
217       const std::string& email,
218       const std::string& password,
219       const std::string& refresh_token,
220       OneClickSigninHelper::AutoAccept auto_accept,
221       signin::Source source,
222       OneClickSigninSyncStarter::StartSyncMode start_mode,
223       OneClickSigninSyncStarter::Callback sync_callback);
224
225   static void RedirectToNtpOrAppsPage(
226       content::WebContents* contents, signin::Source source);
227
228   // If the |source| is not settings page/webstore, redirects to
229   // the NTP/Apps page.
230   static void RedirectToNtpOrAppsPageIfNecessary(
231       content::WebContents* contents, signin::Source source);
232
233   static void ShowSigninErrorBubble(Browser* browser, const std::string& error);
234
235   // Remove the item currently at the top of the history list if it's
236   // the Gaia redirect URL. Due to limitations of the NavigationController
237   // this cannot be done until a new page becomes "current".
238   static void RemoveSigninRedirectURLHistoryItem(
239       content::WebContents* web_contents);
240
241   static void LogConfirmHistogramValue(int action);
242
243  private:
244   friend class content::WebContentsUserData<OneClickSigninHelper>;
245   friend class OneClickSigninHelperTest;
246   FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperIncognitoTest,
247                            ShowInfoBarUIThreadIncognito);
248   FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperTest,
249                            SigninFromWebstoreWithConfigSyncfirst);
250   FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperTest,
251                            ShowSigninBubbleAfterSigninComplete);
252   FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperTest, SigninCancelled);
253   FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperTest, SigninFailed);
254   FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperTest,
255                            CleanTransientStateOnNavigate);
256   FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperTest,
257                            RemoveObserverFromProfileSyncService);
258   FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperIOTest, CanOfferOnIOThread);
259   FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperIOTest,
260                            CanOfferOnIOThreadIncognito);
261   FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperIOTest,
262                            CanOfferOnIOThreadNoIOData);
263   FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperIOTest,
264                            CanOfferOnIOThreadBadURL);
265   FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperIOTest,
266                            CanOfferOnIOThreadDisabled);
267   FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperIOTest,
268                            CanOfferOnIOThreadSignedIn);
269   FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperIOTest,
270                            CanOfferOnIOThreadEmailNotAllowed);
271   FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperIOTest,
272                            CanOfferOnIOThreadEmailAlreadyUsed);
273   FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperIOTest,
274                            CreateTestProfileIOData);
275   FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperIOTest,
276                            CanOfferOnIOThreadWithRejectedEmail);
277   FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperIOTest,
278                            CanOfferOnIOThreadNoSigninCookies);
279   FRIEND_TEST_ALL_PREFIXES(OneClickSigninHelperIOTest,
280                            CanOfferOnIOThreadDisabledByPolicy);
281
282   // Maximum number of navigations away from the set of valid Gaia URLs before
283   // clearing the internal state of the helper.  This is necessary to support
284   // SAML-based accounts, but causes bug crbug.com/181163.
285   static const int kMaxNavigationsSince;
286
287   OneClickSigninHelper(content::WebContents* web_contents,
288                        PasswordManager* password_manager);
289
290   virtual ~OneClickSigninHelper();
291
292   // Returns true if the one-click signin feature can be offered at this time.
293   // It can be offered if the io_data is not in an incognito window and if the
294   // origin of |url| is a valid Gaia sign in origin.  This function is meant
295   // to called only from the IO thread.
296   static Offer CanOfferOnIOThreadImpl(const GURL& url,
297                                       base::SupportsUserData* request,
298                                       ProfileIOData* io_data);
299
300   // The portion of ShowInfoBarIfPossible() that needs to run on the UI thread.
301   // |session_index| and |email| are extracted from the Google-Accounts-SignIn
302   // header.  |auto_accept| is extracted from the Google-Chrome-SignIn header.
303   // |source| is used to determine which of the explicit sign in mechanism is
304   // being used.
305   //
306   // |continue_url| is where Gaia will continue to when the sign in process is
307   // done.  For explicit sign ins, this is a URL chrome controls. For one-click
308   // sign in, this could be any google property.  This URL is used to know
309   // when the sign process is over and to collect infomation from the user
310   // entered on the Gaia sign in page (for explicit sign ins).
311   static void ShowInfoBarUIThread(const std::string& session_index,
312                                   const std::string& email,
313                                   AutoAccept auto_accept,
314                                   signin::Source source,
315                                   const GURL& continue_url,
316                                   int child_id,
317                                   int route_id);
318
319   void RedirectToSignin();
320
321   // Clear all data member of the helper, except for the error.
322   void CleanTransientState();
323
324   // Unitests that use a TestingProfile should call this.
325   // Otherwise, clearing the pending e-mail crashes because the code expects
326   // a real ResourceContext rather than the MockResourceContext a
327   // TestingProfile provides.
328   void SetDoNotClearPendingEmailForTesting();
329
330   // In unit tests, disable starting the actual sync.
331   void set_do_not_start_sync_for_testing();
332
333   // Called when password has been submitted.
334   void PasswordSubmitted(const autofill::PasswordForm& form);
335
336   // content::WebContentsObserver overrides.
337   virtual void DidStartNavigationToPendingEntry(
338       const GURL& url,
339       content::NavigationController::ReloadType reload_type) OVERRIDE;
340   virtual void DidNavigateMainFrame(
341       const content::LoadCommittedDetails& details,
342       const content::FrameNavigateParams& params) OVERRIDE;
343   virtual void DidStopLoading(
344       content::RenderViewHost* render_view_host) OVERRIDE;
345   virtual void WebContentsDestroyed(content::WebContents* contents) OVERRIDE;
346
347   // ProfileSyncServiceObserver.
348   virtual void OnStateChanged() OVERRIDE;
349
350   OneClickSigninSyncStarter::Callback CreateSyncStarterCallback();
351
352   // Callback invoked when OneClickSigninSyncStarter completes sync setup.
353   void SyncSetupCompletedCallback(
354       OneClickSigninSyncStarter::SyncSetupResult result);
355
356   // Tracks if we are in the process of showing the signin or one click
357   // interstitial page. It's set to true the first time we load one of those
358   // pages and set to false when transient state is cleaned.
359   // Note: This should only be used for logging purposes.
360   bool showing_signin_;
361
362   // Information about the account that has just logged in.
363   std::string session_index_;
364   std::string email_;
365   std::string password_;
366   AutoAccept auto_accept_;
367   signin::Source source_;
368   bool switched_to_advanced_;
369   GURL continue_url_;
370   // The orignal continue URL after sync setup is complete.
371   GURL original_continue_url_;
372   std::string error_message_;
373
374   // Number of navigations since starting a sign in that is outside the
375   // the set of trusted Gaia URLs.  Sign in attempts that include visits to
376   // one more untrusted will cause a modal dialog to appear asking the user
377   // to confirm, similar to the interstitial flow.
378   int untrusted_navigations_since_signin_visit_;
379
380   // Whether a Gaia URL during the sign in process was not handled by the
381   // dedicated sign in process (e.g. SAML login, which redirects to a
382   // non-google-controlled domain).
383   // This is set to true if at least one such URL is detected.
384   bool untrusted_confirmation_required_;
385
386   // Allows unittests to avoid accessing the ResourceContext for clearing a
387   // pending e-mail.
388   bool do_not_clear_pending_email_;
389
390   // Allows unittest to avoid starting sync for real.
391   bool do_not_start_sync_for_testing_;
392
393   base::WeakPtrFactory<OneClickSigninHelper> weak_pointer_factory_;
394
395   DISALLOW_COPY_AND_ASSIGN(OneClickSigninHelper);
396 };
397
398 #endif  // CHROME_BROWSER_UI_SYNC_ONE_CLICK_SIGNIN_HELPER_H_