• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "components/signin/core/browser/signin_manager.h"
6 
7 #include <vector>
8 
9 #include "base/bind.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"
41 
42 #include "testing/gmock/include/gmock/gmock.h"
43 #include "testing/gtest/include/gtest/gtest.h"
44 
45 namespace {
46 
SigninManagerBuild(content::BrowserContext * context)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);
54   return service;
55 }
56 
57 class TestSigninManagerObserver : public SigninManagerBase::Observer {
58  public:
TestSigninManagerObserver()59   TestSigninManagerObserver() : num_failed_signins_(0),
60                                 num_successful_signins_(0),
61                                 num_signouts_(0) {
62   }
63 
~TestSigninManagerObserver()64   virtual ~TestSigninManagerObserver() {}
65 
66   int num_failed_signins_;
67   int num_successful_signins_;
68   int num_signouts_;
69 
70  private:
71   // SigninManagerBase::Observer:
GoogleSigninFailed(const GoogleServiceAuthError & error)72   virtual void GoogleSigninFailed(
73       const GoogleServiceAuthError& error) OVERRIDE {
74     num_failed_signins_++;
75   }
76 
GoogleSigninSucceeded(const std::string & account_id,const std::string & username,const std::string & password)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_++;
82   }
83 
GoogleSignedOut(const std::string & account_id,const std::string & username)84   virtual void GoogleSignedOut(const std::string& account_id,
85                                const std::string& username) OVERRIDE {
86     num_signouts_++;
87   }
88 };
89 
90 }  // namespace
91 
92 
93 class SigninManagerTest : public testing::Test {
94  public:
SigninManagerTest()95   SigninManagerTest() : manager_(NULL) {}
~SigninManagerTest()96   virtual ~SigninManagerTest() {}
97 
SetUp()98   virtual void SetUp() OVERRIDE {
99     manager_ = NULL;
100     prefs_.reset(new TestingPrefServiceSimple);
101     chrome::RegisterLocalState(prefs_->registry());
102     TestingBrowserProcess::GetGlobal()->SetLocalState(
103         prefs_.get());
104     TestingProfile::Builder builder;
105     builder.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(),
106                               BuildFakeProfileOAuth2TokenService);
107     builder.AddTestingFactory(ChromeSigninClientFactory::GetInstance(),
108                               signin::BuildTestSigninClient);
109     builder.AddTestingFactory(SigninManagerFactory::GetInstance(),
110                               SigninManagerBuild);
111     profile_ = builder.Build();
112 
113     static_cast<TestSigninClient*>(
114         ChromeSigninClientFactory::GetInstance()->GetForProfile(profile()))->
115             SetURLRequestContext(profile_->GetRequestContext());
116   }
117 
TearDown()118   virtual void TearDown() OVERRIDE {
119     if (manager_)
120       manager_->RemoveObserver(&test_observer_);
121 
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);
127     }
128     TestingBrowserProcess::GetGlobal()->SetLocalState(NULL);
129 
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.
133     profile_.reset();
134     prefs_.reset();  // LocalState needs to outlive the profile.
135   }
136 
profile()137   TestingProfile* profile() { return profile_.get(); }
138 
139   // Sets up the signin manager as a service if other code will try to get it as
140   // a PKS.
SetUpSigninManagerAsService()141   void SetUpSigninManagerAsService() {
142     DCHECK(!manager_);
143     DCHECK(!naked_manager_);
144     manager_ = static_cast<SigninManager*>(
145         SigninManagerFactory::GetForProfile(profile()));
146     manager_->AddObserver(&test_observer_);
147   }
148 
149   // Create a naked signin manager if integration with PKSs is not needed.
CreateNakedSigninManager()150   void CreateNakedSigninManager() {
151     DCHECK(!manager_);
152     naked_manager_.reset(new SigninManager(
153         ChromeSigninClientFactory::GetInstance()->GetForProfile(profile()),
154         ProfileOAuth2TokenServiceFactory::GetForProfile(profile())));
155 
156     manager_ = naked_manager_.get();
157     manager_->AddObserver(&test_observer_);
158   }
159 
160   // Shuts down |manager_|.
ShutDownManager()161   void ShutDownManager() {
162     DCHECK(manager_);
163     manager_->RemoveObserver(&test_observer_);
164     manager_->Shutdown();
165     if (naked_manager_)
166       naked_manager_.reset(NULL);
167     manager_ = NULL;
168   }
169 
ExpectSignInWithRefreshTokenSuccess()170   void ExpectSignInWithRefreshTokenSuccess() {
171     EXPECT_TRUE(manager_->IsAuthenticated());
172 
173     ProfileOAuth2TokenService* token_service =
174         ProfileOAuth2TokenServiceFactory::GetForProfile(profile());
175     EXPECT_TRUE(token_service->RefreshTokenIsAvailable(
176         manager_->GetAuthenticatedUsername()));
177 
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_);
181   }
182 
CompleteSigninCallback(const std::string & oauth_token)183   void CompleteSigninCallback(const std::string& oauth_token) {
184     oauth_tokens_fetched_.push_back(oauth_token);
185     manager_->CompletePendingSignin();
186   }
187 
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_;
197 };
198 
TEST_F(SigninManagerTest,SignInWithRefreshToken)199 TEST_F(SigninManagerTest, SignInWithRefreshToken) {
200   SetUpSigninManagerAsService();
201   EXPECT_FALSE(manager_->IsAuthenticated());
202 
203   manager_->StartSignInWithRefreshToken(
204       "rt1",
205       "user@gmail.com",
206       "password",
207       SigninManager::OAuthTokenFetchedCallback());
208 
209   ExpectSignInWithRefreshTokenSuccess();
210 
211   // Should persist across resets.
212   ShutDownManager();
213   CreateNakedSigninManager();
214   manager_->Initialize(NULL);
215   EXPECT_EQ("user@gmail.com", manager_->GetAuthenticatedUsername());
216 }
217 
TEST_F(SigninManagerTest,SignInWithRefreshTokenCallbackComplete)218 TEST_F(SigninManagerTest, SignInWithRefreshTokenCallbackComplete) {
219   SetUpSigninManagerAsService();
220   EXPECT_FALSE(manager_->IsAuthenticated());
221 
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(
227       "rt1",
228       "user@gmail.com",
229       "password",
230       callback);
231 
232   ExpectSignInWithRefreshTokenSuccess();
233   ASSERT_EQ(1U, oauth_tokens_fetched_.size());
234   EXPECT_EQ(oauth_tokens_fetched_[0], "rt1");
235 }
236 
TEST_F(SigninManagerTest,SignOut)237 TEST_F(SigninManagerTest, SignOut) {
238   SetUpSigninManagerAsService();
239   manager_->StartSignInWithRefreshToken(
240       "rt1",
241       "user@gmail.com",
242       "password",
243       SigninManager::OAuthTokenFetchedCallback());
244   manager_->SignOut(signin_metrics::SIGNOUT_TEST);
245   EXPECT_FALSE(manager_->IsAuthenticated());
246   // Should not be persisted anymore
247   ShutDownManager();
248   CreateNakedSigninManager();
249   manager_->Initialize(NULL);
250   EXPECT_FALSE(manager_->IsAuthenticated());
251 }
252 
TEST_F(SigninManagerTest,SignOutWhileProhibited)253 TEST_F(SigninManagerTest, SignOutWhileProhibited) {
254   SetUpSigninManagerAsService();
255   EXPECT_FALSE(manager_->IsAuthenticated());
256 
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());
264 }
265 
TEST_F(SigninManagerTest,TestIsWebBasedSigninFlowURL)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")));
281 }
282 
TEST_F(SigninManagerTest,Prohibited)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()));
293 }
294 
TEST_F(SigninManagerTest,TestAlternateWildcard)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()));
307 }
308 
TEST_F(SigninManagerTest,ProhibitedAtStartup)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());
318 }
319 
TEST_F(SigninManagerTest,ProhibitedAfterStartup)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());
330 }
331 
TEST_F(SigninManagerTest,ExternalSignIn)332 TEST_F(SigninManagerTest, ExternalSignIn) {
333   CreateNakedSigninManager();
334   manager_->Initialize(g_browser_process->local_state());
335   EXPECT_EQ("",
336             profile()->GetPrefs()->GetString(prefs::kGoogleServicesUsername));
337   EXPECT_EQ("", manager_->GetAuthenticatedUsername());
338   EXPECT_EQ(0, test_observer_.num_successful_signins_);
339 
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());
346 }
347 
TEST_F(SigninManagerTest,SigninNotAllowed)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();
353 }
354