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/chrome_signin_client_factory.h"
20 #include "chrome/browser/signin/fake_profile_oauth2_token_service.h"
21 #include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h"
22 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
23 #include "chrome/browser/signin/signin_manager_factory.h"
24 #include "chrome/browser/signin/test_signin_client_builder.h"
25 #include "chrome/common/pref_names.h"
26 #include "chrome/common/url_constants.h"
27 #include "chrome/test/base/testing_browser_process.h"
28 #include "chrome/test/base/testing_profile.h"
29 #include "components/signin/core/browser/profile_oauth2_token_service.h"
30 #include "components/signin/core/browser/test_signin_client.h"
31 #include "content/public/browser/child_process_security_policy.h"
32 #include "content/public/browser/notification_source.h"
33 #include "content/public/test/test_browser_thread_bundle.h"
34 #include "google_apis/gaia/gaia_constants.h"
35 #include "google_apis/gaia/gaia_urls.h"
36 #include "net/cookies/cookie_monster.h"
37 #include "net/url_request/test_url_fetcher_factory.h"
38 #include "net/url_request/url_request.h"
39 #include "net/url_request/url_request_context_getter.h"
40 #include "net/url_request/url_request_status.h"
42 #include "testing/gmock/include/gmock/gmock.h"
43 #include "testing/gtest/include/gtest/gtest.h"
47 KeyedService
* SigninManagerBuild(content::BrowserContext
* context
) {
48 SigninManager
* service
= NULL
;
49 Profile
* profile
= static_cast<Profile
*>(context
);
50 service
= new SigninManager(
51 ChromeSigninClientFactory::GetInstance()->GetForProfile(profile
),
52 ProfileOAuth2TokenServiceFactory::GetForProfile(profile
));
53 service
->Initialize(NULL
);
57 class TestSigninManagerObserver
: public SigninManagerBase::Observer
{
59 TestSigninManagerObserver() : num_failed_signins_(0),
60 num_successful_signins_(0),
64 virtual ~TestSigninManagerObserver() {}
66 int num_failed_signins_
;
67 int num_successful_signins_
;
71 // SigninManagerBase::Observer:
72 virtual void GoogleSigninFailed(
73 const GoogleServiceAuthError
& error
) OVERRIDE
{
74 num_failed_signins_
++;
77 virtual void GoogleSigninSucceeded(
78 const std::string
& account_id
,
79 const std::string
& username
,
80 const std::string
& password
) OVERRIDE
{
81 num_successful_signins_
++;
84 virtual void GoogleSignedOut(const std::string
& account_id
,
85 const std::string
& username
) OVERRIDE
{
93 class SigninManagerTest
: public testing::Test
{
95 SigninManagerTest() : manager_(NULL
) {}
96 virtual ~SigninManagerTest() {}
98 virtual void SetUp() OVERRIDE
{
100 prefs_
.reset(new TestingPrefServiceSimple
);
101 chrome::RegisterLocalState(prefs_
->registry());
102 TestingBrowserProcess::GetGlobal()->SetLocalState(
104 TestingProfile::Builder builder
;
105 builder
.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(),
106 BuildFakeProfileOAuth2TokenService
);
107 builder
.AddTestingFactory(ChromeSigninClientFactory::GetInstance(),
108 signin::BuildTestSigninClient
);
109 builder
.AddTestingFactory(SigninManagerFactory::GetInstance(),
111 profile_
= builder
.Build();
113 static_cast<TestSigninClient
*>(
114 ChromeSigninClientFactory::GetInstance()->GetForProfile(profile()))->
115 SetURLRequestContext(profile_
->GetRequestContext());
118 virtual void TearDown() OVERRIDE
{
120 manager_
->RemoveObserver(&test_observer_
);
122 // Destroy the SigninManager here, because it relies on profile() which is
123 // freed in the base class.
124 if (naked_manager_
) {
125 naked_manager_
->Shutdown();
126 naked_manager_
.reset(NULL
);
128 TestingBrowserProcess::GetGlobal()->SetLocalState(NULL
);
130 // Manually destroy PrefService and Profile so that they are shutdown
131 // in the correct order. Both need to be destroyed before the
132 // |thread_bundle_| member.
134 prefs_
.reset(); // LocalState needs to outlive the profile.
137 TestingProfile
* profile() { return profile_
.get(); }
139 // Sets up the signin manager as a service if other code will try to get it as
141 void SetUpSigninManagerAsService() {
143 DCHECK(!naked_manager_
);
144 manager_
= static_cast<SigninManager
*>(
145 SigninManagerFactory::GetForProfile(profile()));
146 manager_
->AddObserver(&test_observer_
);
149 // Create a naked signin manager if integration with PKSs is not needed.
150 void CreateNakedSigninManager() {
152 naked_manager_
.reset(new SigninManager(
153 ChromeSigninClientFactory::GetInstance()->GetForProfile(profile()),
154 ProfileOAuth2TokenServiceFactory::GetForProfile(profile())));
156 manager_
= naked_manager_
.get();
157 manager_
->AddObserver(&test_observer_
);
160 // Shuts down |manager_|.
161 void ShutDownManager() {
163 manager_
->RemoveObserver(&test_observer_
);
164 manager_
->Shutdown();
166 naked_manager_
.reset(NULL
);
170 void ExpectSignInWithRefreshTokenSuccess() {
171 EXPECT_TRUE(manager_
->IsAuthenticated());
173 ProfileOAuth2TokenService
* token_service
=
174 ProfileOAuth2TokenServiceFactory::GetForProfile(profile());
175 EXPECT_TRUE(token_service
->RefreshTokenIsAvailable(
176 manager_
->GetAuthenticatedUsername()));
178 // Should go into token service and stop.
179 EXPECT_EQ(1, test_observer_
.num_successful_signins_
);
180 EXPECT_EQ(0, test_observer_
.num_failed_signins_
);
183 void CompleteSigninCallback(const std::string
& oauth_token
) {
184 oauth_tokens_fetched_
.push_back(oauth_token
);
185 manager_
->CompletePendingSignin();
188 content::TestBrowserThreadBundle thread_bundle_
;
189 net::TestURLFetcherFactory factory_
;
190 scoped_ptr
<SigninManager
> naked_manager_
;
191 SigninManager
* manager_
;
192 TestSigninManagerObserver test_observer_
;
193 scoped_ptr
<TestingProfile
> profile_
;
194 std::vector
<std::string
> oauth_tokens_fetched_
;
195 scoped_ptr
<TestingPrefServiceSimple
> prefs_
;
196 std::vector
<std::string
> cookies_
;
199 TEST_F(SigninManagerTest
, SignInWithRefreshToken
) {
200 SetUpSigninManagerAsService();
201 EXPECT_FALSE(manager_
->IsAuthenticated());
203 manager_
->StartSignInWithRefreshToken(
207 SigninManager::OAuthTokenFetchedCallback());
209 ExpectSignInWithRefreshTokenSuccess();
211 // Should persist across resets.
213 CreateNakedSigninManager();
214 manager_
->Initialize(NULL
);
215 EXPECT_EQ("user@gmail.com", manager_
->GetAuthenticatedUsername());
218 TEST_F(SigninManagerTest
, SignInWithRefreshTokenCallbackComplete
) {
219 SetUpSigninManagerAsService();
220 EXPECT_FALSE(manager_
->IsAuthenticated());
222 // Since the password is empty, must verify the gaia cookies first.
223 SigninManager::OAuthTokenFetchedCallback callback
=
224 base::Bind(&SigninManagerTest::CompleteSigninCallback
,
225 base::Unretained(this));
226 manager_
->StartSignInWithRefreshToken(
232 ExpectSignInWithRefreshTokenSuccess();
233 ASSERT_EQ(1U, oauth_tokens_fetched_
.size());
234 EXPECT_EQ(oauth_tokens_fetched_
[0], "rt1");
237 TEST_F(SigninManagerTest
, SignOut
) {
238 SetUpSigninManagerAsService();
239 manager_
->StartSignInWithRefreshToken(
243 SigninManager::OAuthTokenFetchedCallback());
244 manager_
->SignOut(signin_metrics::SIGNOUT_TEST
);
245 EXPECT_FALSE(manager_
->IsAuthenticated());
246 // Should not be persisted anymore
248 CreateNakedSigninManager();
249 manager_
->Initialize(NULL
);
250 EXPECT_FALSE(manager_
->IsAuthenticated());
253 TEST_F(SigninManagerTest
, SignOutWhileProhibited
) {
254 SetUpSigninManagerAsService();
255 EXPECT_FALSE(manager_
->IsAuthenticated());
257 manager_
->SetAuthenticatedUsername("user@gmail.com");
258 manager_
->ProhibitSignout(true);
259 manager_
->SignOut(signin_metrics::SIGNOUT_TEST
);
260 EXPECT_TRUE(manager_
->IsAuthenticated());
261 manager_
->ProhibitSignout(false);
262 manager_
->SignOut(signin_metrics::SIGNOUT_TEST
);
263 EXPECT_FALSE(manager_
->IsAuthenticated());
266 TEST_F(SigninManagerTest
, TestIsWebBasedSigninFlowURL
) {
267 EXPECT_FALSE(SigninManager::IsWebBasedSigninFlowURL(
268 GURL("http://www.google.com")));
269 EXPECT_TRUE(SigninManager::IsWebBasedSigninFlowURL(
270 GURL("https://accounts.google.com/ServiceLogin?service=chromiumsync")));
271 EXPECT_FALSE(SigninManager::IsWebBasedSigninFlowURL(
272 GURL("http://accounts.google.com/ServiceLogin?service=chromiumsync")));
273 // http, not https, should not be treated as web based signin.
274 EXPECT_FALSE(SigninManager::IsWebBasedSigninFlowURL(
275 GURL("http://accounts.google.com/ServiceLogin?service=googlemail")));
276 // chromiumsync is double-embedded in a continue query param.
277 EXPECT_TRUE(SigninManager::IsWebBasedSigninFlowURL(
278 GURL("https://accounts.google.com/CheckCookie?"
279 "continue=https%3A%2F%2Fwww.google.com%2Fintl%2Fen-US%2Fchrome"
280 "%2Fblank.html%3Fsource%3D3%26nonadv%3D1&service=chromiumsync")));
283 TEST_F(SigninManagerTest
, Prohibited
) {
284 g_browser_process
->local_state()->SetString(
285 prefs::kGoogleServicesUsernamePattern
, ".*@google.com");
286 CreateNakedSigninManager();
287 manager_
->Initialize(g_browser_process
->local_state());
288 EXPECT_TRUE(manager_
->IsAllowedUsername("test@google.com"));
289 EXPECT_TRUE(manager_
->IsAllowedUsername("happy@google.com"));
290 EXPECT_FALSE(manager_
->IsAllowedUsername("test@invalid.com"));
291 EXPECT_FALSE(manager_
->IsAllowedUsername("test@notgoogle.com"));
292 EXPECT_FALSE(manager_
->IsAllowedUsername(std::string()));
295 TEST_F(SigninManagerTest
, TestAlternateWildcard
) {
296 // Test to make sure we accept "*@google.com" as a pattern (treat it as if
297 // the admin entered ".*@google.com").
298 g_browser_process
->local_state()->SetString(
299 prefs::kGoogleServicesUsernamePattern
, "*@google.com");
300 CreateNakedSigninManager();
301 manager_
->Initialize(g_browser_process
->local_state());
302 EXPECT_TRUE(manager_
->IsAllowedUsername("test@google.com"));
303 EXPECT_TRUE(manager_
->IsAllowedUsername("happy@google.com"));
304 EXPECT_FALSE(manager_
->IsAllowedUsername("test@invalid.com"));
305 EXPECT_FALSE(manager_
->IsAllowedUsername("test@notgoogle.com"));
306 EXPECT_FALSE(manager_
->IsAllowedUsername(std::string()));
309 TEST_F(SigninManagerTest
, ProhibitedAtStartup
) {
310 profile()->GetPrefs()->SetString(prefs::kGoogleServicesUsername
,
311 "monkey@invalid.com");
312 g_browser_process
->local_state()->SetString(
313 prefs::kGoogleServicesUsernamePattern
, ".*@google.com");
314 CreateNakedSigninManager();
315 manager_
->Initialize(g_browser_process
->local_state());
316 // Currently signed in user is prohibited by policy, so should be signed out.
317 EXPECT_EQ("", manager_
->GetAuthenticatedUsername());
320 TEST_F(SigninManagerTest
, ProhibitedAfterStartup
) {
321 std::string
user("monkey@invalid.com");
322 profile()->GetPrefs()->SetString(prefs::kGoogleServicesUsername
, user
);
323 CreateNakedSigninManager();
324 manager_
->Initialize(g_browser_process
->local_state());
325 EXPECT_EQ(user
, manager_
->GetAuthenticatedUsername());
326 // Update the profile - user should be signed out.
327 g_browser_process
->local_state()->SetString(
328 prefs::kGoogleServicesUsernamePattern
, ".*@google.com");
329 EXPECT_EQ("", manager_
->GetAuthenticatedUsername());
332 TEST_F(SigninManagerTest
, ExternalSignIn
) {
333 CreateNakedSigninManager();
334 manager_
->Initialize(g_browser_process
->local_state());
336 profile()->GetPrefs()->GetString(prefs::kGoogleServicesUsername
));
337 EXPECT_EQ("", manager_
->GetAuthenticatedUsername());
338 EXPECT_EQ(0, test_observer_
.num_successful_signins_
);
340 manager_
->OnExternalSigninCompleted("external@example.com");
341 EXPECT_EQ(1, test_observer_
.num_successful_signins_
);
342 EXPECT_EQ(0, test_observer_
.num_failed_signins_
);
343 EXPECT_EQ("external@example.com",
344 profile()->GetPrefs()->GetString(prefs::kGoogleServicesUsername
));
345 EXPECT_EQ("external@example.com", manager_
->GetAuthenticatedUsername());
348 TEST_F(SigninManagerTest
, SigninNotAllowed
) {
349 std::string
user("user@google.com");
350 profile()->GetPrefs()->SetString(prefs::kGoogleServicesUsername
, user
);
351 profile()->GetPrefs()->SetBoolean(prefs::kSigninAllowed
, false);
352 SetUpSigninManagerAsService();