- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / signin / signin_manager_unittest.cc
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/signin/signin_manager.h"
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/compiler_specific.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/prefs/testing_pref_service.h"
12 #include "base/run_loop.h"
13 #include "base/strings/stringprintf.h"
14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/chrome_notification_types.h"
16 #include "chrome/browser/prefs/browser_prefs.h"
17 #include "chrome/browser/signin/chrome_signin_manager_delegate.h"
18 #include "chrome/browser/signin/signin_manager_factory.h"
19 #include "chrome/browser/signin/token_service.h"
20 #include "chrome/browser/signin/token_service_unittest.h"
21 #include "chrome/common/pref_names.h"
22 #include "chrome/common/url_constants.h"
23 #include "chrome/test/base/testing_browser_process.h"
24 #include "chrome/test/base/testing_profile.h"
25 #include "components/webdata/encryptor/encryptor.h"
26 #include "content/public/browser/child_process_security_policy.h"
27 #include "content/public/test/test_browser_thread_bundle.h"
28 #include "google_apis/gaia/gaia_constants.h"
29 #include "google_apis/gaia/gaia_urls.h"
30 #include "net/cookies/cookie_monster.h"
31 #include "net/url_request/test_url_fetcher_factory.h"
32 #include "net/url_request/url_request.h"
33 #include "net/url_request/url_request_context_getter.h"
34 #include "net/url_request/url_request_status.h"
35
36 #include "testing/gmock/include/gmock/gmock.h"
37 #include "testing/gtest/include/gtest/gtest.h"
38
39 namespace {
40
41 const char kGetTokenPairValidResponse[] =
42     "{"
43     "  \"refresh_token\": \"rt1\","
44     "  \"access_token\": \"at1\","
45     "  \"expires_in\": 3600,"
46     "  \"token_type\": \"Bearer\""
47     "}";
48
49 const char kUberAuthTokenURLFormat[] = "?source=%s&issueuberauth=1";
50
51 BrowserContextKeyedService* SigninManagerBuild(
52     content::BrowserContext* context) {
53   SigninManager* service = NULL;
54   Profile* profile = static_cast<Profile*>(context);
55   service = new SigninManager(
56       scoped_ptr<SigninManagerDelegate>(
57           new ChromeSigninManagerDelegate(profile)));
58   return service;
59 }
60
61 }  // namespace
62
63
64 class SigninManagerTest : public TokenServiceTestHarness {
65  public:
66    SigninManagerTest() : manager_(NULL) {}
67    virtual ~SigninManagerTest() {}
68
69   virtual void SetUp() OVERRIDE {
70     manager_ = NULL;
71     prefs_.reset(new TestingPrefServiceSimple);
72     chrome::RegisterLocalState(prefs_->registry());
73     TestingBrowserProcess::GetGlobal()->SetLocalState(
74         prefs_.get());
75     TokenServiceTestHarness::SetUp();
76     google_login_success_.ListenFor(
77         chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL,
78         content::Source<Profile>(profile()));
79     google_login_failure_.ListenFor(chrome::NOTIFICATION_GOOGLE_SIGNIN_FAILED,
80                                     content::Source<Profile>(profile()));
81   }
82
83   virtual void TearDown() OVERRIDE {
84     // Destroy the SigninManager here, because it relies on profile() which is
85     // freed in the base class.
86     if (naked_manager_) {
87       naked_manager_->Shutdown();
88       naked_manager_.reset(NULL);
89     }
90     TestingBrowserProcess::GetGlobal()->SetLocalState(NULL);
91     prefs_.reset(NULL);
92     TokenServiceTestHarness::TearDown();
93   }
94
95   // Create a signin manager as a service if other code will try to get it as
96   // a PKS.
97   void CreateSigninManagerAsService() {
98     DCHECK(!manager_);
99     DCHECK(!naked_manager_);
100     manager_ = static_cast<SigninManager*>(
101         SigninManagerFactory::GetInstance()->SetTestingFactoryAndUse(
102             profile(), SigninManagerBuild));
103   }
104
105   // Create a naked signin manager if integration with PKSs is not needed.
106   void CreateNakedSigninManager() {
107     DCHECK(!manager_);
108     naked_manager_.reset(new SigninManager(
109         scoped_ptr<SigninManagerDelegate>(
110             new ChromeSigninManagerDelegate(profile()))));
111
112     manager_ = naked_manager_.get();
113   }
114
115   void SetupFetcherAndComplete(const GURL& url,
116                                int response_code,
117                                const net::ResponseCookies& cookies,
118                                const std::string& response_string) {
119     net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0);
120     DCHECK(fetcher);
121     DCHECK(fetcher->delegate());
122
123     cookies_.insert(cookies_.end(), cookies.begin(), cookies.end());
124     fetcher->set_url(url);
125     fetcher->set_status(net::URLRequestStatus());
126     fetcher->set_response_code(response_code);
127     fetcher->SetResponseString(response_string);
128     fetcher->set_cookies(cookies);
129     fetcher->delegate()->OnURLFetchComplete(fetcher);
130   }
131
132   void SimulateValidResponseSignInWithCredentials() {
133     // Simulate the correct StartOAuthLoginTokenFetch response.  This involves
134     // two separate fetches.
135     SetupFetcherAndComplete(
136         GaiaUrls::GetInstance()->client_login_to_oauth2_url(), 200,
137         net::ResponseCookies(), kGetTokenPairValidResponse);
138
139     SetupFetcherAndComplete(GaiaUrls::GetInstance()->oauth2_token_url(), 200,
140                             net::ResponseCookies(), kGetTokenPairValidResponse);
141
142     // Simulate the correct StartOAuthLogin response.
143     SetupFetcherAndComplete(GaiaUrls::GetInstance()->oauth1_login_url(), 200,
144                             net::ResponseCookies(),
145                             "SID=sid\nLSID=lsid\nAuth=auth_token");
146
147     SimulateValidResponseGetClientInfo(false);
148   }
149
150   void SimulateValidResponseClientLogin(bool isGPlusUser) {
151     SetupFetcherAndComplete(GaiaUrls::GetInstance()->client_login_url(), 200,
152                             net::ResponseCookies(),
153                             "SID=sid\nLSID=lsid\nAuth=auth");
154     SimulateValidResponseGetClientInfo(isGPlusUser);
155   }
156
157   void SimulateValidResponseGetClientInfo(bool isGPlusUser) {
158     // Simulate the correct ClientLogin response.
159     std::string response_string = isGPlusUser ?
160         "email=user@gmail.com\ndisplayEmail=USER@gmail.com\n"
161         "allServices=googleme" :
162         "email=user@gmail.com\ndisplayEmail=USER@gmail.com\n"
163         "allServices=";
164     SetupFetcherAndComplete(GaiaUrls::GetInstance()->get_user_info_url(), 200,
165                             net::ResponseCookies(), response_string);
166   }
167
168   void SimulateValidUberToken() {
169     SetupFetcherAndComplete(GaiaUrls::GetInstance()->oauth2_token_url(), 200,
170                             net::ResponseCookies(), kGetTokenPairValidResponse);
171     const GURL uberauth_token_gurl =
172         GaiaUrls::GetInstance()->oauth1_login_url().Resolve(
173             base::StringPrintf(kUberAuthTokenURLFormat, "source"));
174     SetupFetcherAndComplete(uberauth_token_gurl, 200,
175                             net::ResponseCookies(), "ut1");
176
177     net::ResponseCookies cookies;
178     cookies.push_back("checkCookie = true");
179     SetupFetcherAndComplete(GaiaUrls::GetInstance()->merge_session_url(), 200,
180                             cookies, "<html></html>");
181   }
182
183   void ExpectSignInWithCredentialsSuccess() {
184     EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty());
185
186     SimulateValidResponseSignInWithCredentials();
187
188     EXPECT_FALSE(manager_->GetAuthenticatedUsername().empty());
189
190     // This is flow, the oauth2 credentials should already be available in
191     // the token service.
192     EXPECT_TRUE(service()->HasOAuthLoginToken());
193
194     // Should go into token service and stop.
195     EXPECT_EQ(1U, google_login_success_.size());
196     EXPECT_EQ(0U, google_login_failure_.size());
197   }
198
199   // Helper method that wraps the logic when signin with credentials
200   // should fail. If |requestSent| is true, then simulate valid resopnse.
201   // Otherwise the sign-in is aborted before any request is sent, thus no need
202   // to simulatate response.
203   void ExpectSignInWithCredentialsFail(bool requestSent) {
204     EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty());
205
206     if (requestSent)
207       SimulateValidResponseSignInWithCredentials();
208
209     // The oauth2 credentials should not be available in the token service
210     // because the email was incorrect.
211     EXPECT_FALSE(service()->HasOAuthLoginToken());
212
213     // Should go into token service and stop.
214     EXPECT_EQ(0U, google_login_success_.size());
215     EXPECT_EQ(1U, google_login_failure_.size());
216   }
217
218   void CompleteSigninCallback(const std::string& oauth_token) {
219     oauth_tokens_fetched_.push_back(oauth_token);
220     manager_->CompletePendingSignin();
221   }
222
223   void CancelSigninCallback(const std::string& oauth_token) {
224     oauth_tokens_fetched_.push_back(oauth_token);
225     manager_->SignOut();
226   }
227
228   net::TestURLFetcherFactory factory_;
229   scoped_ptr<SigninManager> naked_manager_;
230   SigninManager* manager_;
231   content::TestNotificationTracker google_login_success_;
232   content::TestNotificationTracker google_login_failure_;
233   std::vector<std::string> oauth_tokens_fetched_;
234   scoped_ptr<TestingPrefServiceSimple> prefs_;
235   std::vector<std::string> cookies_;
236 };
237
238 TEST_F(SigninManagerTest, SignInWithCredentials) {
239   CreateSigninManagerAsService();
240   manager_->Initialize(profile(), NULL);
241   EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty());
242
243   manager_->StartSignInWithCredentials(
244       "0",
245       "user@gmail.com",
246       "password",
247       SigninManager::OAuthTokenFetchedCallback());
248
249   ExpectSignInWithCredentialsSuccess();
250
251   // Should persist across resets.
252   manager_->Shutdown();
253   manager_ = NULL;
254   CreateNakedSigninManager();
255   manager_->Initialize(profile(), NULL);
256   EXPECT_EQ("user@gmail.com", manager_->GetAuthenticatedUsername());
257 }
258
259 TEST_F(SigninManagerTest, SignInWithCredentialsNonCanonicalEmail) {
260   CreateSigninManagerAsService();
261   manager_->Initialize(profile(), NULL);
262   EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty());
263
264   manager_->StartSignInWithCredentials(
265       "0",
266       "user",
267       "password",
268       SigninManager::OAuthTokenFetchedCallback());
269
270   ExpectSignInWithCredentialsSuccess();
271 }
272
273 TEST_F(SigninManagerTest, SignInWithCredentialsWrongEmail) {
274   CreateSigninManagerAsService();
275   manager_->Initialize(profile(), NULL);
276   EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty());
277
278   // If the email address used to start the sign in does not match the
279   // email address returned by /GetUserInfo, the sign in should fail.
280   manager_->StartSignInWithCredentials(
281       "0",
282       "user2@gmail.com",
283       "password",
284       SigninManager::OAuthTokenFetchedCallback());
285
286   ExpectSignInWithCredentialsFail(true /* requestSent */);
287 }
288
289 TEST_F(SigninManagerTest, SignInWithCredentialsEmptyPasswordValidCookie) {
290   CreateSigninManagerAsService();
291   manager_->Initialize(profile(), NULL);
292   EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty());
293
294   // Set a valid LSID cookie in the test cookie store.
295   scoped_refptr<net::CookieMonster> cookie_monster =
296       profile()->GetCookieMonster();
297   net::CookieOptions options;
298   options.set_include_httponly();
299   cookie_monster->SetCookieWithOptionsAsync(
300         GURL("https://accounts.google.com"),
301         "LSID=1234; secure; httponly", options,
302         net::CookieMonster::SetCookiesCallback());
303
304   // Since the password is empty, will verify the gaia cookies first.
305   manager_->StartSignInWithCredentials(
306       "0",
307       "user@gmail.com",
308       std::string(),
309       SigninManager::OAuthTokenFetchedCallback());
310
311   base::RunLoop().RunUntilIdle();
312
313   // Verification should succeed and continue with auto signin.
314   ExpectSignInWithCredentialsSuccess();
315 }
316
317 TEST_F(SigninManagerTest, SignInWithCredentialsEmptyPasswordNoValidCookie) {
318   CreateSigninManagerAsService();
319   manager_->Initialize(profile(), NULL);
320   EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty());
321
322   // Since the password is empty, will verify the gaia cookies first.
323   manager_->StartSignInWithCredentials(
324       "0",
325       "user@gmail.com",
326       std::string(),
327       SigninManager::OAuthTokenFetchedCallback());
328
329   base::RunLoop().RunUntilIdle();
330
331   // Since the test cookie store is empty, verification should fail and throws
332   // a login error.
333   ExpectSignInWithCredentialsFail(false /* requestSent */);
334 }
335
336 TEST_F(SigninManagerTest, SignInWithCredentialsEmptyPasswordInValidCookie) {
337   CreateSigninManagerAsService();
338   manager_->Initialize(profile(), NULL);
339   EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty());
340
341   // Set an invalid LSID cookie in the test cookie store.
342   scoped_refptr<net::CookieMonster> cookie_monster =
343       profile()->GetCookieMonster();
344   net::CookieOptions options;
345   options.set_include_httponly();
346   cookie_monster->SetCookieWithOptionsAsync(
347         GURL("https://accounts.google.com"),
348         "LSID=1234; domain=google.com; secure; httponly", options,
349         net::CookieMonster::SetCookiesCallback());
350
351   // Since the password is empty, must verify the gaia cookies first.
352   manager_->StartSignInWithCredentials(
353       "0",
354       "user@gmail.com",
355       std::string(),
356       SigninManager::OAuthTokenFetchedCallback());
357
358   base::RunLoop().RunUntilIdle();
359
360   // Since the LSID cookie is invalid, verification should fail and throws
361   // a login error.
362   ExpectSignInWithCredentialsFail(false /* requestSent */);
363 }
364
365 TEST_F(SigninManagerTest, SignInWithCredentialsCallbackComplete) {
366   CreateSigninManagerAsService();
367   manager_->Initialize(profile(), NULL);
368   EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty());
369
370   // Since the password is empty, must verify the gaia cookies first.
371   SigninManager::OAuthTokenFetchedCallback callback =
372       base::Bind(&SigninManagerTest::CompleteSigninCallback,
373                  base::Unretained(this));
374   manager_->StartSignInWithCredentials(
375       "0",
376       "user@gmail.com",
377       "password",
378       callback);
379
380   ExpectSignInWithCredentialsSuccess();
381   ASSERT_EQ(1U, oauth_tokens_fetched_.size());
382   EXPECT_EQ(oauth_tokens_fetched_[0], "rt1");
383 }
384
385 TEST_F(SigninManagerTest, SignInWithCredentialsCallbackCancel) {
386   CreateSigninManagerAsService();
387   manager_->Initialize(profile(), NULL);
388   EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty());
389
390   // Since the password is empty, must verify the gaia cookies first.
391   SigninManager::OAuthTokenFetchedCallback callback =
392       base::Bind(&SigninManagerTest::CancelSigninCallback,
393                  base::Unretained(this));
394   manager_->StartSignInWithCredentials(
395       "0",
396       "user@gmail.com",
397       "password",
398       callback);
399
400   // Signin should fail since it would be cancelled by the callback.
401   ExpectSignInWithCredentialsFail(true);
402   ASSERT_EQ(1U, oauth_tokens_fetched_.size());
403   EXPECT_EQ(oauth_tokens_fetched_[0], "rt1");
404 }
405
406 TEST_F(SigninManagerTest, SignOut) {
407   CreateSigninManagerAsService();
408   manager_->Initialize(profile(), NULL);
409   SigninManager::OAuthTokenFetchedCallback dummy;
410   manager_->StartSignInWithCredentials("0", "user@gmail.com", "password",
411                                        dummy);
412   ExpectSignInWithCredentialsSuccess();
413
414   manager_->SignOut();
415   EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty());
416   // Should not be persisted anymore
417   manager_->Shutdown();
418   manager_ = NULL;
419   CreateNakedSigninManager();
420   manager_->Initialize(profile(), NULL);
421   EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty());
422 }
423
424 TEST_F(SigninManagerTest, SignOutMidConnect) {
425   CreateSigninManagerAsService();
426   manager_->Initialize(profile(), NULL);
427   SigninManager::OAuthTokenFetchedCallback dummy;
428   manager_->StartSignInWithCredentials("0", "user@gmail.com", "password",
429                                        dummy);
430
431   manager_->SignOut();
432   EXPECT_EQ(0U, google_login_success_.size());
433   EXPECT_EQ(1U, google_login_failure_.size());
434
435   EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty());
436   EXPECT_TRUE(manager_->GetUsernameForAuthInProgress().empty());
437 }
438
439 TEST_F(SigninManagerTest, SignOutWhileProhibited) {
440   CreateSigninManagerAsService();
441   manager_->Initialize(profile(), NULL);
442   EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty());
443
444   manager_->SetAuthenticatedUsername("user@gmail.com");
445   manager_->ProhibitSignout(true);
446   manager_->SignOut();
447   EXPECT_FALSE(manager_->GetAuthenticatedUsername().empty());
448   manager_->ProhibitSignout(false);
449   manager_->SignOut();
450   EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty());
451 }
452
453 TEST_F(SigninManagerTest, TestIsWebBasedSigninFlowURL) {
454   EXPECT_FALSE(SigninManager::IsWebBasedSigninFlowURL(
455       GURL("http://www.google.com")));
456   EXPECT_TRUE(SigninManager::IsWebBasedSigninFlowURL(
457       GURL("https://accounts.google.com/ServiceLogin?service=chromiumsync")));
458   EXPECT_FALSE(SigninManager::IsWebBasedSigninFlowURL(
459       GURL("http://accounts.google.com/ServiceLogin?service=chromiumsync")));
460   // http, not https, should not be treated as web based signin.
461   EXPECT_FALSE(SigninManager::IsWebBasedSigninFlowURL(
462       GURL("http://accounts.google.com/ServiceLogin?service=googlemail")));
463   // chromiumsync is double-embedded in a continue query param.
464   EXPECT_TRUE(SigninManager::IsWebBasedSigninFlowURL(
465       GURL("https://accounts.google.com/CheckCookie?"
466            "continue=https%3A%2F%2Fwww.google.com%2Fintl%2Fen-US%2Fchrome"
467            "%2Fblank.html%3Fsource%3D3%26nonadv%3D1&service=chromiumsync")));
468 }
469
470 TEST_F(SigninManagerTest, Prohibited) {
471   g_browser_process->local_state()->SetString(
472       prefs::kGoogleServicesUsernamePattern, ".*@google.com");
473   CreateNakedSigninManager();
474   manager_->Initialize(profile(), g_browser_process->local_state());
475   EXPECT_TRUE(manager_->IsAllowedUsername("test@google.com"));
476   EXPECT_TRUE(manager_->IsAllowedUsername("happy@google.com"));
477   EXPECT_FALSE(manager_->IsAllowedUsername("test@invalid.com"));
478   EXPECT_FALSE(manager_->IsAllowedUsername("test@notgoogle.com"));
479   EXPECT_FALSE(manager_->IsAllowedUsername(std::string()));
480 }
481
482 TEST_F(SigninManagerTest, TestAlternateWildcard) {
483   // Test to make sure we accept "*@google.com" as a pattern (treat it as if
484   // the admin entered ".*@google.com").
485   g_browser_process->local_state()->SetString(
486       prefs::kGoogleServicesUsernamePattern, "*@google.com");
487   CreateNakedSigninManager();
488   manager_->Initialize(profile(), g_browser_process->local_state());
489   EXPECT_TRUE(manager_->IsAllowedUsername("test@google.com"));
490   EXPECT_TRUE(manager_->IsAllowedUsername("happy@google.com"));
491   EXPECT_FALSE(manager_->IsAllowedUsername("test@invalid.com"));
492   EXPECT_FALSE(manager_->IsAllowedUsername("test@notgoogle.com"));
493   EXPECT_FALSE(manager_->IsAllowedUsername(std::string()));
494 }
495
496 TEST_F(SigninManagerTest, ProhibitedAtStartup) {
497   profile()->GetPrefs()->SetString(prefs::kGoogleServicesUsername,
498                                    "monkey@invalid.com");
499   g_browser_process->local_state()->SetString(
500       prefs::kGoogleServicesUsernamePattern, ".*@google.com");
501   CreateNakedSigninManager();
502   manager_->Initialize(profile(), g_browser_process->local_state());
503   // Currently signed in user is prohibited by policy, so should be signed out.
504   EXPECT_EQ("", manager_->GetAuthenticatedUsername());
505 }
506
507 TEST_F(SigninManagerTest, ProhibitedAfterStartup) {
508   std::string user("monkey@invalid.com");
509   profile()->GetPrefs()->SetString(prefs::kGoogleServicesUsername, user);
510   CreateNakedSigninManager();
511   manager_->Initialize(profile(), g_browser_process->local_state());
512   EXPECT_EQ(user, manager_->GetAuthenticatedUsername());
513   // Update the profile - user should be signed out.
514   g_browser_process->local_state()->SetString(
515       prefs::kGoogleServicesUsernamePattern, ".*@google.com");
516   EXPECT_EQ("", manager_->GetAuthenticatedUsername());
517 }
518
519 TEST_F(SigninManagerTest, ExternalSignIn) {
520   CreateNakedSigninManager();
521   manager_->Initialize(profile(), g_browser_process->local_state());
522   EXPECT_EQ("",
523             profile()->GetPrefs()->GetString(prefs::kGoogleServicesUsername));
524   EXPECT_EQ("", manager_->GetAuthenticatedUsername());
525   EXPECT_EQ(0u, google_login_success_.size());
526
527   manager_->OnExternalSigninCompleted("external@example.com");
528   EXPECT_EQ(1u, google_login_success_.size());
529   EXPECT_EQ(0u, google_login_failure_.size());
530   EXPECT_EQ("external@example.com",
531             profile()->GetPrefs()->GetString(prefs::kGoogleServicesUsername));
532   EXPECT_EQ("external@example.com", manager_->GetAuthenticatedUsername());
533 }