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/prefs/pref_service.h"
13 #include "base/prefs/testing_pref_service.h"
14 #include "base/run_loop.h"
15 #include "base/strings/stringprintf.h"
16 #include "chrome/browser/browser_process.h"
17 #include "chrome/browser/chrome_notification_types.h"
18 #include "chrome/browser/prefs/browser_prefs.h"
19 #include "chrome/browser/signin/account_tracker_service_factory.h"
20 #include "chrome/browser/signin/chrome_signin_client_factory.h"
21 #include "chrome/browser/signin/fake_account_tracker_service.h"
22 #include "chrome/browser/signin/fake_profile_oauth2_token_service.h"
23 #include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h"
24 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
25 #include "chrome/browser/signin/signin_manager_factory.h"
26 #include "chrome/browser/signin/test_signin_client_builder.h"
27 #include "chrome/common/pref_names.h"
28 #include "chrome/common/url_constants.h"
29 #include "chrome/test/base/testing_browser_process.h"
30 #include "chrome/test/base/testing_profile.h"
31 #include "components/signin/core/browser/profile_oauth2_token_service.h"
32 #include "components/signin/core/browser/test_signin_client.h"
33 #include "content/public/browser/child_process_security_policy.h"
34 #include "content/public/browser/notification_source.h"
35 #include "content/public/test/test_browser_thread_bundle.h"
36 #include "google_apis/gaia/gaia_constants.h"
37 #include "google_apis/gaia/gaia_urls.h"
38 #include "net/cookies/cookie_monster.h"
39 #include "net/url_request/test_url_fetcher_factory.h"
40 #include "net/url_request/url_request.h"
41 #include "net/url_request/url_request_context_getter.h"
42 #include "net/url_request/url_request_status.h"
44 #include "testing/gmock/include/gmock/gmock.h"
45 #include "testing/gtest/include/gtest/gtest.h"
49 KeyedService
* SigninManagerBuild(content::BrowserContext
* context
) {
50 SigninManager
* service
= NULL
;
51 Profile
* profile
= static_cast<Profile
*>(context
);
52 service
= new SigninManager(
53 ChromeSigninClientFactory::GetInstance()->GetForProfile(profile
),
54 ProfileOAuth2TokenServiceFactory::GetForProfile(profile
),
55 AccountTrackerServiceFactory::GetForProfile(profile
));
56 service
->Initialize(NULL
);
60 class TestSigninManagerObserver
: public SigninManagerBase::Observer
{
62 TestSigninManagerObserver() : num_failed_signins_(0),
63 num_successful_signins_(0),
67 ~TestSigninManagerObserver() override
{}
69 int num_failed_signins_
;
70 int num_successful_signins_
;
74 // SigninManagerBase::Observer:
75 void GoogleSigninFailed(const GoogleServiceAuthError
& error
) override
{
76 num_failed_signins_
++;
79 void GoogleSigninSucceeded(const std::string
& account_id
,
80 const std::string
& username
,
81 const std::string
& password
) override
{
82 num_successful_signins_
++;
85 void GoogleSignedOut(const std::string
& account_id
,
86 const std::string
& username
) override
{
94 class SigninManagerTest
: public testing::Test
{
96 SigninManagerTest() : manager_(NULL
) {}
97 ~SigninManagerTest() override
{}
99 void SetUp() override
{
101 prefs_
.reset(new TestingPrefServiceSimple
);
102 chrome::RegisterLocalState(prefs_
->registry());
103 TestingBrowserProcess::GetGlobal()->SetLocalState(
105 TestingProfile::Builder builder
;
106 builder
.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(),
107 BuildFakeProfileOAuth2TokenService
);
108 builder
.AddTestingFactory(ChromeSigninClientFactory::GetInstance(),
109 signin::BuildTestSigninClient
);
110 builder
.AddTestingFactory(SigninManagerFactory::GetInstance(),
112 builder
.AddTestingFactory(AccountTrackerServiceFactory::GetInstance(),
113 FakeAccountTrackerService::Build
);
114 profile_
= builder
.Build();
116 signin_client()->SetURLRequestContext(profile_
->GetRequestContext());
119 void TearDown() override
{
121 manager_
->RemoveObserver(&test_observer_
);
123 // Destroy the SigninManager here, because it relies on profile() which is
124 // freed in the base class.
125 if (naked_manager_
) {
126 naked_manager_
->Shutdown();
127 naked_manager_
.reset(NULL
);
129 TestingBrowserProcess::GetGlobal()->SetLocalState(NULL
);
131 // Manually destroy PrefService and Profile so that they are shutdown
132 // in the correct order. Both need to be destroyed before the
133 // |thread_bundle_| member.
135 prefs_
.reset(); // LocalState needs to outlive the profile.
138 TestingProfile
* profile() { return profile_
.get(); }
140 TestSigninClient
* signin_client() {
141 return static_cast<TestSigninClient
*>(
142 ChromeSigninClientFactory::GetInstance()->GetForProfile(profile()));
145 // Sets up the signin manager as a service if other code will try to get it as
147 void SetUpSigninManagerAsService() {
149 DCHECK(!naked_manager_
);
150 manager_
= static_cast<SigninManager
*>(
151 SigninManagerFactory::GetForProfile(profile()));
152 manager_
->AddObserver(&test_observer_
);
155 // Create a naked signin manager if integration with PKSs is not needed.
156 void CreateNakedSigninManager() {
158 naked_manager_
.reset(new SigninManager(
159 ChromeSigninClientFactory::GetInstance()->GetForProfile(profile()),
160 ProfileOAuth2TokenServiceFactory::GetForProfile(profile()),
161 AccountTrackerServiceFactory::GetForProfile(profile())));
163 manager_
= naked_manager_
.get();
164 manager_
->AddObserver(&test_observer_
);
167 // Shuts down |manager_|.
168 void ShutDownManager() {
170 manager_
->RemoveObserver(&test_observer_
);
171 manager_
->Shutdown();
173 naked_manager_
.reset(NULL
);
177 void ExpectSignInWithRefreshTokenSuccess() {
178 EXPECT_TRUE(manager_
->IsAuthenticated());
180 ProfileOAuth2TokenService
* token_service
=
181 ProfileOAuth2TokenServiceFactory::GetForProfile(profile());
182 EXPECT_TRUE(token_service
->RefreshTokenIsAvailable(
183 manager_
->GetAuthenticatedUsername()));
185 // Should go into token service and stop.
186 EXPECT_EQ(1, test_observer_
.num_successful_signins_
);
187 EXPECT_EQ(0, test_observer_
.num_failed_signins_
);
190 void CompleteSigninCallback(const std::string
& oauth_token
) {
191 oauth_tokens_fetched_
.push_back(oauth_token
);
192 manager_
->CompletePendingSignin();
195 content::TestBrowserThreadBundle thread_bundle_
;
196 net::TestURLFetcherFactory factory_
;
197 scoped_ptr
<SigninManager
> naked_manager_
;
198 SigninManager
* manager_
;
199 TestSigninManagerObserver test_observer_
;
200 scoped_ptr
<TestingProfile
> profile_
;
201 std::vector
<std::string
> oauth_tokens_fetched_
;
202 scoped_ptr
<TestingPrefServiceSimple
> prefs_
;
203 std::vector
<std::string
> cookies_
;
206 TEST_F(SigninManagerTest
, SignInWithRefreshToken
) {
207 SetUpSigninManagerAsService();
208 EXPECT_FALSE(manager_
->IsAuthenticated());
210 manager_
->StartSignInWithRefreshToken(
214 SigninManager::OAuthTokenFetchedCallback());
216 ExpectSignInWithRefreshTokenSuccess();
218 // Should persist across resets.
220 CreateNakedSigninManager();
221 manager_
->Initialize(NULL
);
222 EXPECT_EQ("user@gmail.com", manager_
->GetAuthenticatedUsername());
225 TEST_F(SigninManagerTest
, SignInWithRefreshTokenCallbackComplete
) {
226 SetUpSigninManagerAsService();
227 EXPECT_FALSE(manager_
->IsAuthenticated());
229 // Since the password is empty, must verify the gaia cookies first.
230 SigninManager::OAuthTokenFetchedCallback callback
=
231 base::Bind(&SigninManagerTest::CompleteSigninCallback
,
232 base::Unretained(this));
233 manager_
->StartSignInWithRefreshToken(
239 ExpectSignInWithRefreshTokenSuccess();
240 ASSERT_EQ(1U, oauth_tokens_fetched_
.size());
241 EXPECT_EQ(oauth_tokens_fetched_
[0], "rt1");
244 TEST_F(SigninManagerTest
, SignInWithRefreshTokenCallsPostSignout
) {
245 SetUpSigninManagerAsService();
246 EXPECT_FALSE(manager_
->IsAuthenticated());
248 std::string gaia_id
= "12345";
249 std::string email
= "user@google.com";
251 FakeAccountTrackerService
* account_tracker_service
=
252 static_cast<FakeAccountTrackerService
*>(
253 AccountTrackerServiceFactory::GetForProfile(profile()));
254 account_tracker_service
->SeedAccountInfo(gaia_id
, email
);
255 account_tracker_service
->EnableNetworkFetches();
256 std::string account_id
= account_tracker_service
->PickAccountIdForAccount(
259 ASSERT_TRUE(signin_client()->get_signed_in_password().empty());
261 manager_
->StartSignInWithRefreshToken(
265 SigninManager::OAuthTokenFetchedCallback());
267 // PostSignedIn is not called until the AccountTrackerService returns.
268 ASSERT_EQ("", signin_client()->get_signed_in_password());
270 account_tracker_service
->FakeUserInfoFetchSuccess(
271 account_id
, email
, gaia_id
, "google.com");
273 // AccountTracker and SigninManager are both done and PostSignedIn was called.
274 ASSERT_EQ("password", signin_client()->get_signed_in_password());
276 ExpectSignInWithRefreshTokenSuccess();
280 TEST_F(SigninManagerTest
, SignOut
) {
281 SetUpSigninManagerAsService();
282 manager_
->StartSignInWithRefreshToken(
286 SigninManager::OAuthTokenFetchedCallback());
287 manager_
->SignOut(signin_metrics::SIGNOUT_TEST
);
288 EXPECT_FALSE(manager_
->IsAuthenticated());
289 // Should not be persisted anymore
291 CreateNakedSigninManager();
292 manager_
->Initialize(NULL
);
293 EXPECT_FALSE(manager_
->IsAuthenticated());
296 TEST_F(SigninManagerTest
, SignOutWhileProhibited
) {
297 SetUpSigninManagerAsService();
298 EXPECT_FALSE(manager_
->IsAuthenticated());
300 manager_
->SetAuthenticatedUsername("user@gmail.com");
301 manager_
->ProhibitSignout(true);
302 manager_
->SignOut(signin_metrics::SIGNOUT_TEST
);
303 EXPECT_TRUE(manager_
->IsAuthenticated());
304 manager_
->ProhibitSignout(false);
305 manager_
->SignOut(signin_metrics::SIGNOUT_TEST
);
306 EXPECT_FALSE(manager_
->IsAuthenticated());
309 TEST_F(SigninManagerTest
, TestIsWebBasedSigninFlowURL
) {
310 EXPECT_FALSE(SigninManager::IsWebBasedSigninFlowURL(
311 GURL("http://www.google.com")));
312 EXPECT_TRUE(SigninManager::IsWebBasedSigninFlowURL(
313 GURL("https://accounts.google.com/ServiceLogin?service=chromiumsync")));
314 EXPECT_FALSE(SigninManager::IsWebBasedSigninFlowURL(
315 GURL("http://accounts.google.com/ServiceLogin?service=chromiumsync")));
316 // http, not https, should not be treated as web based signin.
317 EXPECT_FALSE(SigninManager::IsWebBasedSigninFlowURL(
318 GURL("http://accounts.google.com/ServiceLogin?service=googlemail")));
319 // chromiumsync is double-embedded in a continue query param.
320 EXPECT_TRUE(SigninManager::IsWebBasedSigninFlowURL(
321 GURL("https://accounts.google.com/CheckCookie?"
322 "continue=https%3A%2F%2Fwww.google.com%2Fintl%2Fen-US%2Fchrome"
323 "%2Fblank.html%3Fsource%3D3%26nonadv%3D1&service=chromiumsync")));
326 TEST_F(SigninManagerTest
, Prohibited
) {
327 g_browser_process
->local_state()->SetString(
328 prefs::kGoogleServicesUsernamePattern
, ".*@google.com");
329 CreateNakedSigninManager();
330 manager_
->Initialize(g_browser_process
->local_state());
331 EXPECT_TRUE(manager_
->IsAllowedUsername("test@google.com"));
332 EXPECT_TRUE(manager_
->IsAllowedUsername("happy@google.com"));
333 EXPECT_FALSE(manager_
->IsAllowedUsername("test@invalid.com"));
334 EXPECT_FALSE(manager_
->IsAllowedUsername("test@notgoogle.com"));
335 EXPECT_FALSE(manager_
->IsAllowedUsername(std::string()));
338 TEST_F(SigninManagerTest
, TestAlternateWildcard
) {
339 // Test to make sure we accept "*@google.com" as a pattern (treat it as if
340 // the admin entered ".*@google.com").
341 g_browser_process
->local_state()->SetString(
342 prefs::kGoogleServicesUsernamePattern
, "*@google.com");
343 CreateNakedSigninManager();
344 manager_
->Initialize(g_browser_process
->local_state());
345 EXPECT_TRUE(manager_
->IsAllowedUsername("test@google.com"));
346 EXPECT_TRUE(manager_
->IsAllowedUsername("happy@google.com"));
347 EXPECT_FALSE(manager_
->IsAllowedUsername("test@invalid.com"));
348 EXPECT_FALSE(manager_
->IsAllowedUsername("test@notgoogle.com"));
349 EXPECT_FALSE(manager_
->IsAllowedUsername(std::string()));
352 TEST_F(SigninManagerTest
, ProhibitedAtStartup
) {
353 profile()->GetPrefs()->SetString(prefs::kGoogleServicesUsername
,
354 "monkey@invalid.com");
355 g_browser_process
->local_state()->SetString(
356 prefs::kGoogleServicesUsernamePattern
, ".*@google.com");
357 CreateNakedSigninManager();
358 manager_
->Initialize(g_browser_process
->local_state());
359 // Currently signed in user is prohibited by policy, so should be signed out.
360 EXPECT_EQ("", manager_
->GetAuthenticatedUsername());
363 TEST_F(SigninManagerTest
, ProhibitedAfterStartup
) {
364 std::string
user("monkey@invalid.com");
365 profile()->GetPrefs()->SetString(prefs::kGoogleServicesUsername
, user
);
366 CreateNakedSigninManager();
367 manager_
->Initialize(g_browser_process
->local_state());
368 EXPECT_EQ(user
, manager_
->GetAuthenticatedUsername());
369 // Update the profile - user should be signed out.
370 g_browser_process
->local_state()->SetString(
371 prefs::kGoogleServicesUsernamePattern
, ".*@google.com");
372 EXPECT_EQ("", manager_
->GetAuthenticatedUsername());
375 TEST_F(SigninManagerTest
, ExternalSignIn
) {
376 CreateNakedSigninManager();
377 manager_
->Initialize(g_browser_process
->local_state());
379 profile()->GetPrefs()->GetString(prefs::kGoogleServicesUsername
));
380 EXPECT_EQ("", manager_
->GetAuthenticatedUsername());
381 EXPECT_EQ(0, test_observer_
.num_successful_signins_
);
383 manager_
->OnExternalSigninCompleted("external@example.com");
384 EXPECT_EQ(1, test_observer_
.num_successful_signins_
);
385 EXPECT_EQ(0, test_observer_
.num_failed_signins_
);
386 EXPECT_EQ("external@example.com",
387 profile()->GetPrefs()->GetString(prefs::kGoogleServicesUsername
));
388 EXPECT_EQ("external@example.com", manager_
->GetAuthenticatedUsername());
391 TEST_F(SigninManagerTest
, SigninNotAllowed
) {
392 std::string
user("user@google.com");
393 profile()->GetPrefs()->SetString(prefs::kGoogleServicesUsername
, user
);
394 profile()->GetPrefs()->SetBoolean(prefs::kSigninAllowed
, false);
395 SetUpSigninManagerAsService();