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