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_fetcher_service_factory.h"
21 #include "chrome/browser/signin/account_tracker_service_factory.h"
22 #include "chrome/browser/signin/chrome_signin_client_factory.h"
23 #include "chrome/browser/signin/fake_account_fetcher_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/fake_profile_oauth2_token_service.h"
35 #include "components/signin/core/browser/profile_oauth2_token_service.h"
36 #include "components/signin/core/browser/test_signin_client.h"
37 #include "content/public/browser/child_process_security_policy.h"
38 #include "content/public/browser/notification_source.h"
39 #include "content/public/test/test_browser_thread_bundle.h"
40 #include "google_apis/gaia/gaia_constants.h"
41 #include "google_apis/gaia/gaia_urls.h"
42 #include "net/cookies/cookie_monster.h"
43 #include "net/url_request/test_url_fetcher_factory.h"
44 #include "net/url_request/url_request.h"
45 #include "net/url_request/url_request_context_getter.h"
46 #include "net/url_request/url_request_status.h"
48 #include "testing/gmock/include/gmock/gmock.h"
49 #include "testing/gtest/include/gtest/gtest.h"
53 scoped_ptr
<KeyedService
> SigninManagerBuild(content::BrowserContext
* context
) {
54 Profile
* profile
= static_cast<Profile
*>(context
);
55 scoped_ptr
<SigninManager
> service(new SigninManager(
56 ChromeSigninClientFactory::GetInstance()->GetForProfile(profile
),
57 ProfileOAuth2TokenServiceFactory::GetForProfile(profile
),
58 AccountTrackerServiceFactory::GetForProfile(profile
),
59 GaiaCookieManagerServiceFactory::GetForProfile(profile
)));
60 service
->Initialize(NULL
);
61 return service
.Pass();
64 class TestSigninManagerObserver
: public SigninManagerBase::Observer
{
66 TestSigninManagerObserver() : num_failed_signins_(0),
67 num_successful_signins_(0),
71 ~TestSigninManagerObserver() override
{}
73 int num_failed_signins_
;
74 int num_successful_signins_
;
78 // SigninManagerBase::Observer:
79 void GoogleSigninFailed(const GoogleServiceAuthError
& error
) override
{
80 num_failed_signins_
++;
83 void GoogleSigninSucceeded(const std::string
& account_id
,
84 const std::string
& username
,
85 const std::string
& password
) override
{
86 num_successful_signins_
++;
89 void GoogleSignedOut(const std::string
& account_id
,
90 const std::string
& username
) override
{
98 class SigninManagerTest
: public testing::Test
{
100 SigninManagerTest() : manager_(NULL
) {}
101 ~SigninManagerTest() override
{}
103 void SetUp() override
{
105 prefs_
.reset(new TestingPrefServiceSimple
);
106 chrome::RegisterLocalState(prefs_
->registry());
107 TestingBrowserProcess::GetGlobal()->SetLocalState(
109 TestingProfile::Builder builder
;
110 builder
.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(),
111 BuildFakeProfileOAuth2TokenService
);
112 builder
.AddTestingFactory(ChromeSigninClientFactory::GetInstance(),
113 signin::BuildTestSigninClient
);
114 builder
.AddTestingFactory(SigninManagerFactory::GetInstance(),
116 builder
.AddTestingFactory(AccountFetcherServiceFactory::GetInstance(),
117 FakeAccountFetcherService::BuildForTests
);
118 profile_
= builder
.Build();
120 TestSigninClient
* client
=
121 static_cast<TestSigninClient
*>(
122 ChromeSigninClientFactory::GetForProfile(profile()));
123 client
->SetURLRequestContext(profile_
->GetRequestContext());
126 void TearDown() override
{
128 manager_
->RemoveObserver(&test_observer_
);
130 // Destroy the SigninManager here, because it relies on profile() which is
131 // freed in the base class.
132 if (naked_manager_
) {
133 naked_manager_
->Shutdown();
134 naked_manager_
.reset(NULL
);
136 TestingBrowserProcess::GetGlobal()->SetLocalState(NULL
);
138 // Manually destroy PrefService and Profile so that they are shutdown
139 // in the correct order. Both need to be destroyed before the
140 // |thread_bundle_| member.
142 prefs_
.reset(); // LocalState needs to outlive the profile.
145 TestingProfile
* profile() { return profile_
.get(); }
147 TestSigninClient
* signin_client() {
148 return static_cast<TestSigninClient
*>(
149 ChromeSigninClientFactory::GetInstance()->GetForProfile(profile()));
152 // Seed the account tracker with information from logged in user. Normally
153 // this is done by UI code before calling SigninManager. Returns the string
154 // to use as the account_id.
155 std::string
AddToAccountTracker(const std::string
& gaia_id
,
156 const std::string
& email
) {
157 AccountTrackerService
* service
=
158 AccountTrackerServiceFactory::GetForProfile(profile());
159 service
->SeedAccountInfo(gaia_id
, email
);
160 return service
->PickAccountIdForAccount(gaia_id
, email
);
163 // Sets up the signin manager as a service if other code will try to get it as
165 void SetUpSigninManagerAsService() {
167 DCHECK(!naked_manager_
);
168 manager_
= static_cast<SigninManager
*>(
169 SigninManagerFactory::GetForProfile(profile()));
170 manager_
->AddObserver(&test_observer_
);
173 // Create a naked signin manager if integration with PKSs is not needed.
174 void CreateNakedSigninManager() {
176 naked_manager_
.reset(new SigninManager(
177 ChromeSigninClientFactory::GetInstance()->GetForProfile(profile()),
178 ProfileOAuth2TokenServiceFactory::GetForProfile(profile()),
179 AccountTrackerServiceFactory::GetForProfile(profile()),
180 GaiaCookieManagerServiceFactory::GetForProfile(profile())));
182 manager_
= naked_manager_
.get();
183 manager_
->AddObserver(&test_observer_
);
186 // Shuts down |manager_|.
187 void ShutDownManager() {
189 manager_
->RemoveObserver(&test_observer_
);
190 manager_
->Shutdown();
192 naked_manager_
.reset(NULL
);
196 void ExpectSignInWithRefreshTokenSuccess() {
197 EXPECT_TRUE(manager_
->IsAuthenticated());
198 EXPECT_FALSE(manager_
->GetAuthenticatedAccountId().empty());
199 EXPECT_FALSE(manager_
->GetAuthenticatedUsername().empty());
201 ProfileOAuth2TokenService
* token_service
=
202 ProfileOAuth2TokenServiceFactory::GetForProfile(profile());
203 EXPECT_TRUE(token_service
->RefreshTokenIsAvailable(
204 manager_
->GetAuthenticatedAccountId()));
206 // Should go into token service and stop.
207 EXPECT_EQ(1, test_observer_
.num_successful_signins_
);
208 EXPECT_EQ(0, test_observer_
.num_failed_signins_
);
211 void CompleteSigninCallback(const std::string
& oauth_token
) {
212 oauth_tokens_fetched_
.push_back(oauth_token
);
213 manager_
->CompletePendingSignin();
216 content::TestBrowserThreadBundle thread_bundle_
;
217 net::TestURLFetcherFactory factory_
;
218 scoped_ptr
<SigninManager
> naked_manager_
;
219 SigninManager
* manager_
;
220 TestSigninManagerObserver test_observer_
;
221 scoped_ptr
<TestingProfile
> profile_
;
222 std::vector
<std::string
> oauth_tokens_fetched_
;
223 scoped_ptr
<TestingPrefServiceSimple
> prefs_
;
224 std::vector
<std::string
> cookies_
;
227 TEST_F(SigninManagerTest
, SignInWithRefreshToken
) {
228 SetUpSigninManagerAsService();
229 EXPECT_FALSE(manager_
->IsAuthenticated());
231 std::string account_id
= AddToAccountTracker("gaia_id", "user@gmail.com");
232 manager_
->StartSignInWithRefreshToken(
237 SigninManager::OAuthTokenFetchedCallback());
239 ExpectSignInWithRefreshTokenSuccess();
241 // Should persist across resets.
243 CreateNakedSigninManager();
244 manager_
->Initialize(NULL
);
245 EXPECT_EQ(account_id
, manager_
->GetAuthenticatedAccountId());
248 TEST_F(SigninManagerTest
, SignInWithRefreshTokenCallbackComplete
) {
249 SetUpSigninManagerAsService();
250 EXPECT_FALSE(manager_
->IsAuthenticated());
252 // Since the password is empty, must verify the gaia cookies first.
253 SigninManager::OAuthTokenFetchedCallback callback
=
254 base::Bind(&SigninManagerTest::CompleteSigninCallback
,
255 base::Unretained(this));
256 manager_
->StartSignInWithRefreshToken(
263 ExpectSignInWithRefreshTokenSuccess();
264 ASSERT_EQ(1U, oauth_tokens_fetched_
.size());
265 EXPECT_EQ(oauth_tokens_fetched_
[0], "rt");
268 TEST_F(SigninManagerTest
, SignInWithRefreshTokenCallsPostSignout
) {
269 SetUpSigninManagerAsService();
270 EXPECT_FALSE(manager_
->IsAuthenticated());
272 std::string gaia_id
= "12345";
273 std::string email
= "user@google.com";
275 AccountTrackerServiceFactory::GetForProfile(profile())->
276 SeedAccountInfo(gaia_id
, email
);
277 FakeAccountFetcherService
* account_fetcher_service
=
278 static_cast<FakeAccountFetcherService
*>(
279 AccountFetcherServiceFactory::GetForProfile(profile()));
280 account_fetcher_service
->EnableNetworkFetches();
282 ASSERT_TRUE(signin_client()->get_signed_in_password().empty());
284 manager_
->StartSignInWithRefreshToken(
289 SigninManager::OAuthTokenFetchedCallback());
291 // PostSignedIn is not called until the AccountTrackerService returns.
292 ASSERT_EQ("", signin_client()->get_signed_in_password());
294 account_fetcher_service
->FakeUserInfoFetchSuccess(email
,
300 "http://www.google.com");
302 // AccountTracker and SigninManager are both done and PostSignedIn was called.
303 ASSERT_EQ("password", signin_client()->get_signed_in_password());
305 ExpectSignInWithRefreshTokenSuccess();
309 TEST_F(SigninManagerTest
, SignOut
) {
310 SetUpSigninManagerAsService();
311 manager_
->StartSignInWithRefreshToken(
316 SigninManager::OAuthTokenFetchedCallback());
317 manager_
->SignOut(signin_metrics::SIGNOUT_TEST
);
318 EXPECT_FALSE(manager_
->IsAuthenticated());
319 EXPECT_TRUE(manager_
->GetAuthenticatedUsername().empty());
320 EXPECT_TRUE(manager_
->GetAuthenticatedAccountId().empty());
321 // Should not be persisted anymore
323 CreateNakedSigninManager();
324 manager_
->Initialize(NULL
);
325 EXPECT_FALSE(manager_
->IsAuthenticated());
326 EXPECT_TRUE(manager_
->GetAuthenticatedUsername().empty());
327 EXPECT_TRUE(manager_
->GetAuthenticatedAccountId().empty());
330 TEST_F(SigninManagerTest
, SignOutWhileProhibited
) {
331 SetUpSigninManagerAsService();
332 EXPECT_FALSE(manager_
->IsAuthenticated());
333 EXPECT_TRUE(manager_
->GetAuthenticatedUsername().empty());
334 EXPECT_TRUE(manager_
->GetAuthenticatedAccountId().empty());
336 manager_
->SetAuthenticatedAccountInfo("gaia_id", "user@gmail.com");
337 manager_
->ProhibitSignout(true);
338 manager_
->SignOut(signin_metrics::SIGNOUT_TEST
);
339 EXPECT_TRUE(manager_
->IsAuthenticated());
340 manager_
->ProhibitSignout(false);
341 manager_
->SignOut(signin_metrics::SIGNOUT_TEST
);
342 EXPECT_FALSE(manager_
->IsAuthenticated());
345 TEST_F(SigninManagerTest
, Prohibited
) {
346 g_browser_process
->local_state()->SetString(
347 prefs::kGoogleServicesUsernamePattern
, ".*@google.com");
348 CreateNakedSigninManager();
349 manager_
->Initialize(g_browser_process
->local_state());
350 EXPECT_TRUE(manager_
->IsAllowedUsername("test@google.com"));
351 EXPECT_TRUE(manager_
->IsAllowedUsername("happy@google.com"));
352 EXPECT_FALSE(manager_
->IsAllowedUsername("test@invalid.com"));
353 EXPECT_FALSE(manager_
->IsAllowedUsername("test@notgoogle.com"));
354 EXPECT_FALSE(manager_
->IsAllowedUsername(std::string()));
357 TEST_F(SigninManagerTest
, TestAlternateWildcard
) {
358 // Test to make sure we accept "*@google.com" as a pattern (treat it as if
359 // the admin entered ".*@google.com").
360 g_browser_process
->local_state()->SetString(
361 prefs::kGoogleServicesUsernamePattern
, "*@google.com");
362 CreateNakedSigninManager();
363 manager_
->Initialize(g_browser_process
->local_state());
364 EXPECT_TRUE(manager_
->IsAllowedUsername("test@google.com"));
365 EXPECT_TRUE(manager_
->IsAllowedUsername("happy@google.com"));
366 EXPECT_FALSE(manager_
->IsAllowedUsername("test@invalid.com"));
367 EXPECT_FALSE(manager_
->IsAllowedUsername("test@notgoogle.com"));
368 EXPECT_FALSE(manager_
->IsAllowedUsername(std::string()));
371 TEST_F(SigninManagerTest
, ProhibitedAtStartup
) {
372 std::string account_id
= AddToAccountTracker("gaia_id", "user@gmail.com");
373 profile()->GetPrefs()->SetString(prefs::kGoogleServicesAccountId
, account_id
);
374 g_browser_process
->local_state()->SetString(
375 prefs::kGoogleServicesUsernamePattern
, ".*@google.com");
376 CreateNakedSigninManager();
377 manager_
->Initialize(g_browser_process
->local_state());
378 // Currently signed in user is prohibited by policy, so should be signed out.
379 EXPECT_EQ("", manager_
->GetAuthenticatedUsername());
380 EXPECT_EQ("", manager_
->GetAuthenticatedAccountId());
383 TEST_F(SigninManagerTest
, ProhibitedAfterStartup
) {
384 std::string account_id
= AddToAccountTracker("gaia_id", "user@gmail.com");
385 profile()->GetPrefs()->SetString(prefs::kGoogleServicesAccountId
, account_id
);
386 CreateNakedSigninManager();
387 manager_
->Initialize(g_browser_process
->local_state());
388 EXPECT_EQ("user@gmail.com", manager_
->GetAuthenticatedUsername());
389 EXPECT_EQ(account_id
, manager_
->GetAuthenticatedAccountId());
390 // Update the profile - user should be signed out.
391 g_browser_process
->local_state()->SetString(
392 prefs::kGoogleServicesUsernamePattern
, ".*@google.com");
393 EXPECT_EQ("", manager_
->GetAuthenticatedUsername());
394 EXPECT_EQ("", manager_
->GetAuthenticatedAccountId());
397 TEST_F(SigninManagerTest
, ExternalSignIn
) {
398 CreateNakedSigninManager();
399 manager_
->Initialize(g_browser_process
->local_state());
400 EXPECT_EQ("", manager_
->GetAuthenticatedUsername());
401 EXPECT_EQ("", manager_
->GetAuthenticatedAccountId());
402 EXPECT_EQ(0, test_observer_
.num_successful_signins_
);
404 std::string account_id
= AddToAccountTracker("gaia_id", "user@gmail.com");
405 manager_
->OnExternalSigninCompleted(account_id
);
406 EXPECT_EQ(1, test_observer_
.num_successful_signins_
);
407 EXPECT_EQ(0, test_observer_
.num_failed_signins_
);
408 EXPECT_EQ("user@gmail.com", manager_
->GetAuthenticatedUsername());
409 EXPECT_EQ(account_id
, manager_
->GetAuthenticatedAccountId());
412 TEST_F(SigninManagerTest
, SigninNotAllowed
) {
413 std::string
user("user@google.com");
414 profile()->GetPrefs()->SetString(prefs::kGoogleServicesAccountId
, user
);
415 profile()->GetPrefs()->SetBoolean(prefs::kSigninAllowed
, false);
416 CreateNakedSigninManager();
417 AddToAccountTracker("gaia_id", user
);
418 manager_
->Initialize(g_browser_process
->local_state());
419 // Currently signing in is prohibited by policy, so should be signed out.
420 EXPECT_EQ("", manager_
->GetAuthenticatedUsername());
421 EXPECT_EQ("", manager_
->GetAuthenticatedAccountId());
424 TEST_F(SigninManagerTest
, UpgradeToNewPrefs
) {
425 profile()->GetPrefs()->SetString(prefs::kGoogleServicesUsername
,
427 profile()->GetPrefs()->SetString(prefs::kGoogleServicesUserAccountId
,
429 CreateNakedSigninManager();
430 manager_
->Initialize(g_browser_process
->local_state());
431 EXPECT_EQ("user@gmail.com", manager_
->GetAuthenticatedUsername());
433 // TODO(rogerta): until the migration to gaia id, the account id will remain
435 EXPECT_EQ("user@gmail.com", manager_
->GetAuthenticatedAccountId());
436 EXPECT_EQ("user@gmail.com",
437 profile()->GetPrefs()->GetString(prefs::kGoogleServicesAccountId
));
439 profile()->GetPrefs()->GetString(prefs::kGoogleServicesUsername
));
441 // Make sure account tracker was updated.
442 AccountTrackerService
* service
=
443 AccountTrackerServiceFactory::GetForProfile(profile());
444 AccountTrackerService::AccountInfo info
= service
->GetAccountInfo(
445 manager_
->GetAuthenticatedAccountId());
446 EXPECT_EQ("user@gmail.com", info
.email
);
447 EXPECT_EQ("account_id", info
.gaia
);
450 TEST_F(SigninManagerTest
, CanonicalizesPrefs
) {
451 profile()->GetPrefs()->SetString(prefs::kGoogleServicesUsername
,
453 CreateNakedSigninManager();
454 manager_
->Initialize(g_browser_process
->local_state());
455 EXPECT_EQ("user.C@gmail.com", manager_
->GetAuthenticatedUsername());
457 // TODO(rogerta): until the migration to gaia id, the account id will remain
459 EXPECT_EQ("userc@gmail.com", manager_
->GetAuthenticatedAccountId());
460 EXPECT_EQ("userc@gmail.com",
461 profile()->GetPrefs()->GetString(prefs::kGoogleServicesAccountId
));
463 profile()->GetPrefs()->GetString(prefs::kGoogleServicesUsername
));
465 // Make sure account tracker has a canonicalized username.
466 AccountTrackerService
* service
=
467 AccountTrackerServiceFactory::GetForProfile(profile());
468 AccountTrackerService::AccountInfo info
= service
->GetAccountInfo(
469 manager_
->GetAuthenticatedAccountId());
470 EXPECT_EQ("user.C@gmail.com", info
.email
);
471 EXPECT_EQ("userc@gmail.com", info
.account_id
);