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/common/pref_names.h"
25 #include "chrome/common/url_constants.h"
26 #include "chrome/test/base/testing_browser_process.h"
27 #include "chrome/test/base/testing_profile.h"
28 #include "components/signin/core/browser/profile_oauth2_token_service.h"
29 #include "content/public/browser/child_process_security_policy.h"
30 #include "content/public/browser/notification_source.h"
31 #include "content/public/test/test_browser_thread_bundle.h"
32 #include "google_apis/gaia/gaia_constants.h"
33 #include "google_apis/gaia/gaia_urls.h"
34 #include "net/cookies/cookie_monster.h"
35 #include "net/url_request/test_url_fetcher_factory.h"
36 #include "net/url_request/url_request.h"
37 #include "net/url_request/url_request_context_getter.h"
38 #include "net/url_request/url_request_status.h"
40 #include "testing/gmock/include/gmock/gmock.h"
41 #include "testing/gtest/include/gtest/gtest.h"
45 KeyedService
* SigninManagerBuild(content::BrowserContext
* context
) {
46 SigninManager
* service
= NULL
;
47 Profile
* profile
= static_cast<Profile
*>(context
);
48 service
= new SigninManager(
49 ChromeSigninClientFactory::GetInstance()->GetForProfile(profile
),
50 ProfileOAuth2TokenServiceFactory::GetForProfile(profile
));
51 service
->Initialize(NULL
);
55 class TestSigninManagerObserver
: public SigninManagerBase::Observer
{
57 TestSigninManagerObserver() : num_failed_signins_(0),
58 num_successful_signins_(0),
62 virtual ~TestSigninManagerObserver() {}
64 int num_failed_signins_
;
65 int num_successful_signins_
;
69 // SigninManagerBase::Observer:
70 virtual void GoogleSigninFailed(
71 const GoogleServiceAuthError
& error
) OVERRIDE
{
72 num_failed_signins_
++;
75 virtual void GoogleSigninSucceeded(
76 const std::string
& username
, const std::string
& password
) OVERRIDE
{
77 num_successful_signins_
++;
80 virtual void GoogleSignedOut(const std::string
& username
) OVERRIDE
{
88 class SigninManagerTest
: public testing::Test
{
90 SigninManagerTest() : manager_(NULL
) {}
91 virtual ~SigninManagerTest() {}
93 virtual void SetUp() OVERRIDE
{
95 prefs_
.reset(new TestingPrefServiceSimple
);
96 chrome::RegisterLocalState(prefs_
->registry());
97 TestingBrowserProcess::GetGlobal()->SetLocalState(
99 TestingProfile::Builder builder
;
100 builder
.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(),
101 BuildFakeProfileOAuth2TokenService
);
102 builder
.AddTestingFactory(SigninManagerFactory::GetInstance(),
104 profile_
= builder
.Build();
107 virtual void TearDown() OVERRIDE
{
109 manager_
->RemoveObserver(&test_observer_
);
111 // Destroy the SigninManager here, because it relies on profile() which is
112 // freed in the base class.
113 if (naked_manager_
) {
114 naked_manager_
->Shutdown();
115 naked_manager_
.reset(NULL
);
117 TestingBrowserProcess::GetGlobal()->SetLocalState(NULL
);
119 // Manually destroy PrefService and Profile so that they are shutdown
120 // in the correct order. Both need to be destroyed before the
121 // |thread_bundle_| member.
123 prefs_
.reset(); // LocalState needs to outlive the profile.
126 TestingProfile
* profile() { return profile_
.get(); }
128 // Sets up the signin manager as a service if other code will try to get it as
130 void SetUpSigninManagerAsService() {
132 DCHECK(!naked_manager_
);
133 manager_
= static_cast<SigninManager
*>(
134 SigninManagerFactory::GetForProfile(profile()));
135 manager_
->AddObserver(&test_observer_
);
138 // Create a naked signin manager if integration with PKSs is not needed.
139 void CreateNakedSigninManager() {
141 naked_manager_
.reset(new SigninManager(
142 ChromeSigninClientFactory::GetInstance()->GetForProfile(profile()),
143 ProfileOAuth2TokenServiceFactory::GetForProfile(profile())));
145 manager_
= naked_manager_
.get();
146 manager_
->AddObserver(&test_observer_
);
149 // Shuts down |manager_|.
150 void ShutDownManager() {
152 manager_
->RemoveObserver(&test_observer_
);
153 manager_
->Shutdown();
155 naked_manager_
.reset(NULL
);
159 void ExpectSignInWithRefreshTokenSuccess() {
160 EXPECT_FALSE(manager_
->GetAuthenticatedUsername().empty());
162 ProfileOAuth2TokenService
* token_service
=
163 ProfileOAuth2TokenServiceFactory::GetForProfile(profile());
164 EXPECT_TRUE(token_service
->RefreshTokenIsAvailable(
165 manager_
->GetAuthenticatedUsername()));
167 // Should go into token service and stop.
168 EXPECT_EQ(1, test_observer_
.num_successful_signins_
);
169 EXPECT_EQ(0, test_observer_
.num_failed_signins_
);
172 void CompleteSigninCallback(const std::string
& oauth_token
) {
173 oauth_tokens_fetched_
.push_back(oauth_token
);
174 manager_
->CompletePendingSignin();
177 content::TestBrowserThreadBundle thread_bundle_
;
178 net::TestURLFetcherFactory factory_
;
179 scoped_ptr
<SigninManager
> naked_manager_
;
180 SigninManager
* manager_
;
181 TestSigninManagerObserver test_observer_
;
182 scoped_ptr
<TestingProfile
> profile_
;
183 std::vector
<std::string
> oauth_tokens_fetched_
;
184 scoped_ptr
<TestingPrefServiceSimple
> prefs_
;
185 std::vector
<std::string
> cookies_
;
188 TEST_F(SigninManagerTest
, SignInWithRefreshToken
) {
189 SetUpSigninManagerAsService();
190 EXPECT_TRUE(manager_
->GetAuthenticatedUsername().empty());
192 manager_
->StartSignInWithRefreshToken(
196 SigninManager::OAuthTokenFetchedCallback());
198 ExpectSignInWithRefreshTokenSuccess();
200 // Should persist across resets.
202 CreateNakedSigninManager();
203 manager_
->Initialize(NULL
);
204 EXPECT_EQ("user@gmail.com", manager_
->GetAuthenticatedUsername());
207 TEST_F(SigninManagerTest
, SignInWithRefreshTokenCallbackComplete
) {
208 SetUpSigninManagerAsService();
209 EXPECT_TRUE(manager_
->GetAuthenticatedUsername().empty());
211 // Since the password is empty, must verify the gaia cookies first.
212 SigninManager::OAuthTokenFetchedCallback callback
=
213 base::Bind(&SigninManagerTest::CompleteSigninCallback
,
214 base::Unretained(this));
215 manager_
->StartSignInWithRefreshToken(
221 ExpectSignInWithRefreshTokenSuccess();
222 ASSERT_EQ(1U, oauth_tokens_fetched_
.size());
223 EXPECT_EQ(oauth_tokens_fetched_
[0], "rt1");
226 TEST_F(SigninManagerTest
, SignOut
) {
227 SetUpSigninManagerAsService();
228 manager_
->StartSignInWithRefreshToken(
232 SigninManager::OAuthTokenFetchedCallback());
234 EXPECT_TRUE(manager_
->GetAuthenticatedUsername().empty());
235 // Should not be persisted anymore
237 CreateNakedSigninManager();
238 manager_
->Initialize(NULL
);
239 EXPECT_TRUE(manager_
->GetAuthenticatedUsername().empty());
242 TEST_F(SigninManagerTest
, SignOutWhileProhibited
) {
243 SetUpSigninManagerAsService();
244 EXPECT_TRUE(manager_
->GetAuthenticatedUsername().empty());
246 manager_
->SetAuthenticatedUsername("user@gmail.com");
247 manager_
->ProhibitSignout(true);
249 EXPECT_FALSE(manager_
->GetAuthenticatedUsername().empty());
250 manager_
->ProhibitSignout(false);
252 EXPECT_TRUE(manager_
->GetAuthenticatedUsername().empty());
255 TEST_F(SigninManagerTest
, TestIsWebBasedSigninFlowURL
) {
256 EXPECT_FALSE(SigninManager::IsWebBasedSigninFlowURL(
257 GURL("http://www.google.com")));
258 EXPECT_TRUE(SigninManager::IsWebBasedSigninFlowURL(
259 GURL("https://accounts.google.com/ServiceLogin?service=chromiumsync")));
260 EXPECT_FALSE(SigninManager::IsWebBasedSigninFlowURL(
261 GURL("http://accounts.google.com/ServiceLogin?service=chromiumsync")));
262 // http, not https, should not be treated as web based signin.
263 EXPECT_FALSE(SigninManager::IsWebBasedSigninFlowURL(
264 GURL("http://accounts.google.com/ServiceLogin?service=googlemail")));
265 // chromiumsync is double-embedded in a continue query param.
266 EXPECT_TRUE(SigninManager::IsWebBasedSigninFlowURL(
267 GURL("https://accounts.google.com/CheckCookie?"
268 "continue=https%3A%2F%2Fwww.google.com%2Fintl%2Fen-US%2Fchrome"
269 "%2Fblank.html%3Fsource%3D3%26nonadv%3D1&service=chromiumsync")));
272 TEST_F(SigninManagerTest
, Prohibited
) {
273 g_browser_process
->local_state()->SetString(
274 prefs::kGoogleServicesUsernamePattern
, ".*@google.com");
275 CreateNakedSigninManager();
276 manager_
->Initialize(g_browser_process
->local_state());
277 EXPECT_TRUE(manager_
->IsAllowedUsername("test@google.com"));
278 EXPECT_TRUE(manager_
->IsAllowedUsername("happy@google.com"));
279 EXPECT_FALSE(manager_
->IsAllowedUsername("test@invalid.com"));
280 EXPECT_FALSE(manager_
->IsAllowedUsername("test@notgoogle.com"));
281 EXPECT_FALSE(manager_
->IsAllowedUsername(std::string()));
284 TEST_F(SigninManagerTest
, TestAlternateWildcard
) {
285 // Test to make sure we accept "*@google.com" as a pattern (treat it as if
286 // the admin entered ".*@google.com").
287 g_browser_process
->local_state()->SetString(
288 prefs::kGoogleServicesUsernamePattern
, "*@google.com");
289 CreateNakedSigninManager();
290 manager_
->Initialize(g_browser_process
->local_state());
291 EXPECT_TRUE(manager_
->IsAllowedUsername("test@google.com"));
292 EXPECT_TRUE(manager_
->IsAllowedUsername("happy@google.com"));
293 EXPECT_FALSE(manager_
->IsAllowedUsername("test@invalid.com"));
294 EXPECT_FALSE(manager_
->IsAllowedUsername("test@notgoogle.com"));
295 EXPECT_FALSE(manager_
->IsAllowedUsername(std::string()));
298 TEST_F(SigninManagerTest
, ProhibitedAtStartup
) {
299 profile()->GetPrefs()->SetString(prefs::kGoogleServicesUsername
,
300 "monkey@invalid.com");
301 g_browser_process
->local_state()->SetString(
302 prefs::kGoogleServicesUsernamePattern
, ".*@google.com");
303 CreateNakedSigninManager();
304 manager_
->Initialize(g_browser_process
->local_state());
305 // Currently signed in user is prohibited by policy, so should be signed out.
306 EXPECT_EQ("", manager_
->GetAuthenticatedUsername());
309 TEST_F(SigninManagerTest
, ProhibitedAfterStartup
) {
310 std::string
user("monkey@invalid.com");
311 profile()->GetPrefs()->SetString(prefs::kGoogleServicesUsername
, user
);
312 CreateNakedSigninManager();
313 manager_
->Initialize(g_browser_process
->local_state());
314 EXPECT_EQ(user
, manager_
->GetAuthenticatedUsername());
315 // Update the profile - user should be signed out.
316 g_browser_process
->local_state()->SetString(
317 prefs::kGoogleServicesUsernamePattern
, ".*@google.com");
318 EXPECT_EQ("", manager_
->GetAuthenticatedUsername());
321 TEST_F(SigninManagerTest
, ExternalSignIn
) {
322 CreateNakedSigninManager();
323 manager_
->Initialize(g_browser_process
->local_state());
325 profile()->GetPrefs()->GetString(prefs::kGoogleServicesUsername
));
326 EXPECT_EQ("", manager_
->GetAuthenticatedUsername());
327 EXPECT_EQ(0, test_observer_
.num_successful_signins_
);
329 manager_
->OnExternalSigninCompleted("external@example.com");
330 EXPECT_EQ(1, test_observer_
.num_successful_signins_
);
331 EXPECT_EQ(0, test_observer_
.num_failed_signins_
);
332 EXPECT_EQ("external@example.com",
333 profile()->GetPrefs()->GetString(prefs::kGoogleServicesUsername
));
334 EXPECT_EQ("external@example.com", manager_
->GetAuthenticatedUsername());
337 TEST_F(SigninManagerTest
, SigninNotAllowed
) {
338 std::string
user("user@google.com");
339 profile()->GetPrefs()->SetString(prefs::kGoogleServicesUsername
, user
);
340 profile()->GetPrefs()->SetBoolean(prefs::kSigninAllowed
, false);
341 SetUpSigninManagerAsService();