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 "components/signin/core/browser/signin_manager.h"
10 #include "base/bind_helpers.h"
11 #include "base/compiler_specific.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/prefs/pref_service.h"
14 #include "base/prefs/testing_pref_service.h"
15 #include "base/run_loop.h"
16 #include "base/strings/stringprintf.h"
17 #include "chrome/browser/browser_process.h"
18 #include "chrome/browser/chrome_notification_types.h"
19 #include "chrome/browser/prefs/browser_prefs.h"
20 #include "chrome/browser/signin/account_tracker_service_factory.h"
21 #include "chrome/browser/signin/chrome_signin_client_factory.h"
22 #include "chrome/browser/signin/fake_account_tracker_service.h"
23 #include "chrome/browser/signin/fake_profile_oauth2_token_service.h"
24 #include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h"
25 #include "chrome/browser/signin/gaia_cookie_manager_service_factory.h"
26 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
27 #include "chrome/browser/signin/signin_manager_factory.h"
28 #include "chrome/browser/signin/test_signin_client_builder.h"
29 #include "chrome/common/pref_names.h"
30 #include "chrome/common/url_constants.h"
31 #include "chrome/test/base/testing_browser_process.h"
32 #include "chrome/test/base/testing_profile.h"
33 #include "components/signin/core/browser/account_tracker_service.h"
34 #include "components/signin/core/browser/profile_oauth2_token_service.h"
35 #include "components/signin/core/browser/test_signin_client.h"
36 #include "content/public/browser/child_process_security_policy.h"
37 #include "content/public/browser/notification_source.h"
38 #include "content/public/test/test_browser_thread_bundle.h"
39 #include "google_apis/gaia/gaia_constants.h"
40 #include "google_apis/gaia/gaia_urls.h"
41 #include "net/cookies/cookie_monster.h"
42 #include "net/url_request/test_url_fetcher_factory.h"
43 #include "net/url_request/url_request.h"
44 #include "net/url_request/url_request_context_getter.h"
45 #include "net/url_request/url_request_status.h"
47 #include "testing/gmock/include/gmock/gmock.h"
48 #include "testing/gtest/include/gtest/gtest.h"
52 scoped_ptr
<KeyedService
> SigninManagerBuild(content::BrowserContext
* context
) {
53 Profile
* profile
= static_cast<Profile
*>(context
);
54 scoped_ptr
<SigninManager
> service(new SigninManager(
55 ChromeSigninClientFactory::GetInstance()->GetForProfile(profile
),
56 ProfileOAuth2TokenServiceFactory::GetForProfile(profile
),
57 AccountTrackerServiceFactory::GetForProfile(profile
),
58 GaiaCookieManagerServiceFactory::GetForProfile(profile
)));
59 service
->Initialize(NULL
);
60 return service
.Pass();
63 class TestSigninManagerObserver
: public SigninManagerBase::Observer
{
65 TestSigninManagerObserver() : num_failed_signins_(0),
66 num_successful_signins_(0),
70 ~TestSigninManagerObserver() override
{}
72 int num_failed_signins_
;
73 int num_successful_signins_
;
77 // SigninManagerBase::Observer:
78 void GoogleSigninFailed(const GoogleServiceAuthError
& error
) override
{
79 num_failed_signins_
++;
82 void GoogleSigninSucceeded(const std::string
& account_id
,
83 const std::string
& username
,
84 const std::string
& password
) override
{
85 num_successful_signins_
++;
88 void GoogleSignedOut(const std::string
& account_id
,
89 const std::string
& username
) override
{
97 class SigninManagerTest
: public testing::Test
{
99 SigninManagerTest() : manager_(NULL
) {}
100 ~SigninManagerTest() override
{}
102 void SetUp() override
{
104 prefs_
.reset(new TestingPrefServiceSimple
);
105 chrome::RegisterLocalState(prefs_
->registry());
106 TestingBrowserProcess::GetGlobal()->SetLocalState(
108 TestingProfile::Builder builder
;
109 builder
.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(),
110 BuildFakeProfileOAuth2TokenService
);
111 builder
.AddTestingFactory(ChromeSigninClientFactory::GetInstance(),
112 signin::BuildTestSigninClient
);
113 builder
.AddTestingFactory(SigninManagerFactory::GetInstance(),
115 builder
.AddTestingFactory(AccountTrackerServiceFactory::GetInstance(),
116 FakeAccountTrackerService::Build
);
117 profile_
= builder
.Build();
119 TestSigninClient
* client
=
120 static_cast<TestSigninClient
*>(
121 ChromeSigninClientFactory::GetForProfile(profile()));
122 client
->SetURLRequestContext(profile_
->GetRequestContext());
125 void TearDown() override
{
127 manager_
->RemoveObserver(&test_observer_
);
129 // Destroy the SigninManager here, because it relies on profile() which is
130 // freed in the base class.
131 if (naked_manager_
) {
132 naked_manager_
->Shutdown();
133 naked_manager_
.reset(NULL
);
135 TestingBrowserProcess::GetGlobal()->SetLocalState(NULL
);
137 // Manually destroy PrefService and Profile so that they are shutdown
138 // in the correct order. Both need to be destroyed before the
139 // |thread_bundle_| member.
141 prefs_
.reset(); // LocalState needs to outlive the profile.
144 TestingProfile
* profile() { return profile_
.get(); }
146 TestSigninClient
* signin_client() {
147 return static_cast<TestSigninClient
*>(
148 ChromeSigninClientFactory::GetInstance()->GetForProfile(profile()));
151 // Seed the account tracker with information from logged in user. Normally
152 // this is done by UI code before calling SigninManager. Returns the string
153 // to use as the account_id.
154 std::string
AddToAccountTracker(const std::string
& gaia_id
,
155 const std::string
& email
) {
156 AccountTrackerService
* service
=
157 AccountTrackerServiceFactory::GetForProfile(profile());
158 service
->SeedAccountInfo(gaia_id
, email
);
159 return service
->PickAccountIdForAccount(gaia_id
, email
);
162 // Sets up the signin manager as a service if other code will try to get it as
164 void SetUpSigninManagerAsService() {
166 DCHECK(!naked_manager_
);
167 manager_
= static_cast<SigninManager
*>(
168 SigninManagerFactory::GetForProfile(profile()));
169 manager_
->AddObserver(&test_observer_
);
172 // Create a naked signin manager if integration with PKSs is not needed.
173 void CreateNakedSigninManager() {
175 naked_manager_
.reset(new SigninManager(
176 ChromeSigninClientFactory::GetInstance()->GetForProfile(profile()),
177 ProfileOAuth2TokenServiceFactory::GetForProfile(profile()),
178 AccountTrackerServiceFactory::GetForProfile(profile()),
179 GaiaCookieManagerServiceFactory::GetForProfile(profile())));
181 manager_
= naked_manager_
.get();
182 manager_
->AddObserver(&test_observer_
);
185 // Shuts down |manager_|.
186 void ShutDownManager() {
188 manager_
->RemoveObserver(&test_observer_
);
189 manager_
->Shutdown();
191 naked_manager_
.reset(NULL
);
195 void ExpectSignInWithRefreshTokenSuccess() {
196 EXPECT_TRUE(manager_
->IsAuthenticated());
197 EXPECT_FALSE(manager_
->GetAuthenticatedAccountId().empty());
198 EXPECT_FALSE(manager_
->GetAuthenticatedUsername().empty());
200 ProfileOAuth2TokenService
* token_service
=
201 ProfileOAuth2TokenServiceFactory::GetForProfile(profile());
202 EXPECT_TRUE(token_service
->RefreshTokenIsAvailable(
203 manager_
->GetAuthenticatedAccountId()));
205 // Should go into token service and stop.
206 EXPECT_EQ(1, test_observer_
.num_successful_signins_
);
207 EXPECT_EQ(0, test_observer_
.num_failed_signins_
);
210 void CompleteSigninCallback(const std::string
& oauth_token
) {
211 oauth_tokens_fetched_
.push_back(oauth_token
);
212 manager_
->CompletePendingSignin();
215 content::TestBrowserThreadBundle thread_bundle_
;
216 net::TestURLFetcherFactory factory_
;
217 scoped_ptr
<SigninManager
> naked_manager_
;
218 SigninManager
* manager_
;
219 TestSigninManagerObserver test_observer_
;
220 scoped_ptr
<TestingProfile
> profile_
;
221 std::vector
<std::string
> oauth_tokens_fetched_
;
222 scoped_ptr
<TestingPrefServiceSimple
> prefs_
;
223 std::vector
<std::string
> cookies_
;
226 TEST_F(SigninManagerTest
, SignInWithRefreshToken
) {
227 SetUpSigninManagerAsService();
228 EXPECT_FALSE(manager_
->IsAuthenticated());
230 std::string account_id
= AddToAccountTracker("gaia_id", "user@gmail.com");
231 manager_
->StartSignInWithRefreshToken(
236 SigninManager::OAuthTokenFetchedCallback());
238 ExpectSignInWithRefreshTokenSuccess();
240 // Should persist across resets.
242 CreateNakedSigninManager();
243 manager_
->Initialize(NULL
);
244 EXPECT_EQ(account_id
, manager_
->GetAuthenticatedAccountId());
247 TEST_F(SigninManagerTest
, SignInWithRefreshTokenCallbackComplete
) {
248 SetUpSigninManagerAsService();
249 EXPECT_FALSE(manager_
->IsAuthenticated());
251 // Since the password is empty, must verify the gaia cookies first.
252 SigninManager::OAuthTokenFetchedCallback callback
=
253 base::Bind(&SigninManagerTest::CompleteSigninCallback
,
254 base::Unretained(this));
255 manager_
->StartSignInWithRefreshToken(
262 ExpectSignInWithRefreshTokenSuccess();
263 ASSERT_EQ(1U, oauth_tokens_fetched_
.size());
264 EXPECT_EQ(oauth_tokens_fetched_
[0], "rt");
267 TEST_F(SigninManagerTest
, SignInWithRefreshTokenCallsPostSignout
) {
268 SetUpSigninManagerAsService();
269 EXPECT_FALSE(manager_
->IsAuthenticated());
271 std::string gaia_id
= "12345";
272 std::string email
= "user@google.com";
274 FakeAccountTrackerService
* account_tracker_service
=
275 static_cast<FakeAccountTrackerService
*>(
276 AccountTrackerServiceFactory::GetForProfile(profile()));
277 account_tracker_service
->SeedAccountInfo(gaia_id
, email
);
278 account_tracker_service
->EnableNetworkFetches();
280 ASSERT_TRUE(signin_client()->get_signed_in_password().empty());
282 manager_
->StartSignInWithRefreshToken(
287 SigninManager::OAuthTokenFetchedCallback());
289 // PostSignedIn is not called until the AccountTrackerService returns.
290 ASSERT_EQ("", signin_client()->get_signed_in_password());
292 account_tracker_service
->FakeUserInfoFetchSuccess(email
,
298 "http://www.google.com");
300 // AccountTracker and SigninManager are both done and PostSignedIn was called.
301 ASSERT_EQ("password", signin_client()->get_signed_in_password());
303 ExpectSignInWithRefreshTokenSuccess();
307 TEST_F(SigninManagerTest
, SignOut
) {
308 SetUpSigninManagerAsService();
309 manager_
->StartSignInWithRefreshToken(
314 SigninManager::OAuthTokenFetchedCallback());
315 manager_
->SignOut(signin_metrics::SIGNOUT_TEST
);
316 EXPECT_FALSE(manager_
->IsAuthenticated());
317 EXPECT_TRUE(manager_
->GetAuthenticatedUsername().empty());
318 EXPECT_TRUE(manager_
->GetAuthenticatedAccountId().empty());
319 // Should not be persisted anymore
321 CreateNakedSigninManager();
322 manager_
->Initialize(NULL
);
323 EXPECT_FALSE(manager_
->IsAuthenticated());
324 EXPECT_TRUE(manager_
->GetAuthenticatedUsername().empty());
325 EXPECT_TRUE(manager_
->GetAuthenticatedAccountId().empty());
328 TEST_F(SigninManagerTest
, SignOutWhileProhibited
) {
329 SetUpSigninManagerAsService();
330 EXPECT_FALSE(manager_
->IsAuthenticated());
331 EXPECT_TRUE(manager_
->GetAuthenticatedUsername().empty());
332 EXPECT_TRUE(manager_
->GetAuthenticatedAccountId().empty());
334 manager_
->SetAuthenticatedAccountInfo("gaia_id", "user@gmail.com");
335 manager_
->ProhibitSignout(true);
336 manager_
->SignOut(signin_metrics::SIGNOUT_TEST
);
337 EXPECT_TRUE(manager_
->IsAuthenticated());
338 manager_
->ProhibitSignout(false);
339 manager_
->SignOut(signin_metrics::SIGNOUT_TEST
);
340 EXPECT_FALSE(manager_
->IsAuthenticated());
343 TEST_F(SigninManagerTest
, Prohibited
) {
344 g_browser_process
->local_state()->SetString(
345 prefs::kGoogleServicesUsernamePattern
, ".*@google.com");
346 CreateNakedSigninManager();
347 manager_
->Initialize(g_browser_process
->local_state());
348 EXPECT_TRUE(manager_
->IsAllowedUsername("test@google.com"));
349 EXPECT_TRUE(manager_
->IsAllowedUsername("happy@google.com"));
350 EXPECT_FALSE(manager_
->IsAllowedUsername("test@invalid.com"));
351 EXPECT_FALSE(manager_
->IsAllowedUsername("test@notgoogle.com"));
352 EXPECT_FALSE(manager_
->IsAllowedUsername(std::string()));
355 TEST_F(SigninManagerTest
, TestAlternateWildcard
) {
356 // Test to make sure we accept "*@google.com" as a pattern (treat it as if
357 // the admin entered ".*@google.com").
358 g_browser_process
->local_state()->SetString(
359 prefs::kGoogleServicesUsernamePattern
, "*@google.com");
360 CreateNakedSigninManager();
361 manager_
->Initialize(g_browser_process
->local_state());
362 EXPECT_TRUE(manager_
->IsAllowedUsername("test@google.com"));
363 EXPECT_TRUE(manager_
->IsAllowedUsername("happy@google.com"));
364 EXPECT_FALSE(manager_
->IsAllowedUsername("test@invalid.com"));
365 EXPECT_FALSE(manager_
->IsAllowedUsername("test@notgoogle.com"));
366 EXPECT_FALSE(manager_
->IsAllowedUsername(std::string()));
369 TEST_F(SigninManagerTest
, ProhibitedAtStartup
) {
370 std::string account_id
= AddToAccountTracker("gaia_id", "user@gmail.com");
371 profile()->GetPrefs()->SetString(prefs::kGoogleServicesAccountId
, account_id
);
372 g_browser_process
->local_state()->SetString(
373 prefs::kGoogleServicesUsernamePattern
, ".*@google.com");
374 CreateNakedSigninManager();
375 manager_
->Initialize(g_browser_process
->local_state());
376 // Currently signed in user is prohibited by policy, so should be signed out.
377 EXPECT_EQ("", manager_
->GetAuthenticatedUsername());
378 EXPECT_EQ("", manager_
->GetAuthenticatedAccountId());
381 TEST_F(SigninManagerTest
, ProhibitedAfterStartup
) {
382 std::string account_id
= AddToAccountTracker("gaia_id", "user@gmail.com");
383 profile()->GetPrefs()->SetString(prefs::kGoogleServicesAccountId
, account_id
);
384 CreateNakedSigninManager();
385 manager_
->Initialize(g_browser_process
->local_state());
386 EXPECT_EQ("user@gmail.com", manager_
->GetAuthenticatedUsername());
387 EXPECT_EQ(account_id
, manager_
->GetAuthenticatedAccountId());
388 // Update the profile - user should be signed out.
389 g_browser_process
->local_state()->SetString(
390 prefs::kGoogleServicesUsernamePattern
, ".*@google.com");
391 EXPECT_EQ("", manager_
->GetAuthenticatedUsername());
392 EXPECT_EQ("", manager_
->GetAuthenticatedAccountId());
395 TEST_F(SigninManagerTest
, ExternalSignIn
) {
396 CreateNakedSigninManager();
397 manager_
->Initialize(g_browser_process
->local_state());
398 EXPECT_EQ("", manager_
->GetAuthenticatedUsername());
399 EXPECT_EQ("", manager_
->GetAuthenticatedAccountId());
400 EXPECT_EQ(0, test_observer_
.num_successful_signins_
);
402 std::string account_id
= AddToAccountTracker("gaia_id", "user@gmail.com");
403 manager_
->OnExternalSigninCompleted(account_id
);
404 EXPECT_EQ(1, test_observer_
.num_successful_signins_
);
405 EXPECT_EQ(0, test_observer_
.num_failed_signins_
);
406 EXPECT_EQ("user@gmail.com", manager_
->GetAuthenticatedUsername());
407 EXPECT_EQ(account_id
, manager_
->GetAuthenticatedAccountId());
410 TEST_F(SigninManagerTest
, SigninNotAllowed
) {
411 std::string
user("user@google.com");
412 profile()->GetPrefs()->SetString(prefs::kGoogleServicesAccountId
, user
);
413 profile()->GetPrefs()->SetBoolean(prefs::kSigninAllowed
, false);
414 CreateNakedSigninManager();
415 AddToAccountTracker("gaia_id", user
);
416 manager_
->Initialize(g_browser_process
->local_state());
417 // Currently signing in is prohibited by policy, so should be signed out.
418 EXPECT_EQ("", manager_
->GetAuthenticatedUsername());
419 EXPECT_EQ("", manager_
->GetAuthenticatedAccountId());
422 TEST_F(SigninManagerTest
, UpgradeToNewPrefs
) {
423 profile()->GetPrefs()->SetString(prefs::kGoogleServicesUsername
,
425 profile()->GetPrefs()->SetString(prefs::kGoogleServicesUserAccountId
,
427 CreateNakedSigninManager();
428 manager_
->Initialize(g_browser_process
->local_state());
429 EXPECT_EQ("user@gmail.com", manager_
->GetAuthenticatedUsername());
431 // TODO(rogerta): until the migration to gaia id, the account id will remain
433 EXPECT_EQ("user@gmail.com", manager_
->GetAuthenticatedAccountId());
434 EXPECT_EQ("user@gmail.com",
435 profile()->GetPrefs()->GetString(prefs::kGoogleServicesAccountId
));
437 profile()->GetPrefs()->GetString(prefs::kGoogleServicesUsername
));
439 // Make sure account tracker was updated.
440 AccountTrackerService
* service
=
441 AccountTrackerServiceFactory::GetForProfile(profile());
442 AccountTrackerService::AccountInfo info
= service
->GetAccountInfo(
443 manager_
->GetAuthenticatedAccountId());
444 EXPECT_EQ("user@gmail.com", info
.email
);
445 EXPECT_EQ("account_id", info
.gaia
);
448 TEST_F(SigninManagerTest
, CanonicalizesPrefs
) {
449 profile()->GetPrefs()->SetString(prefs::kGoogleServicesUsername
,
451 CreateNakedSigninManager();
452 manager_
->Initialize(g_browser_process
->local_state());
453 EXPECT_EQ("user.C@gmail.com", manager_
->GetAuthenticatedUsername());
455 // TODO(rogerta): until the migration to gaia id, the account id will remain
457 EXPECT_EQ("userc@gmail.com", manager_
->GetAuthenticatedAccountId());
458 EXPECT_EQ("userc@gmail.com",
459 profile()->GetPrefs()->GetString(prefs::kGoogleServicesAccountId
));
461 profile()->GetPrefs()->GetString(prefs::kGoogleServicesUsername
));
463 // Make sure account tracker has a canonicalized username.
464 AccountTrackerService
* service
=
465 AccountTrackerServiceFactory::GetForProfile(profile());
466 AccountTrackerService::AccountInfo info
= service
->GetAccountInfo(
467 manager_
->GetAuthenticatedAccountId());
468 EXPECT_EQ("user.C@gmail.com", info
.email
);
469 EXPECT_EQ("userc@gmail.com", info
.account_id
);