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 45namespace { 46 47KeyedService* 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 57class TestSigninManagerObserver : public SigninManagerBase::Observer { 58 public: 59 TestSigninManagerObserver() : num_failed_signins_(0), 60 num_successful_signins_(0), 61 num_signouts_(0) { 62 } 63 64 virtual ~TestSigninManagerObserver() {} 65 66 int num_failed_signins_; 67 int num_successful_signins_; 68 int num_signouts_; 69 70 private: 71 // SigninManagerBase::Observer: 72 virtual void GoogleSigninFailed( 73 const GoogleServiceAuthError& error) OVERRIDE { 74 num_failed_signins_++; 75 } 76 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 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 93class SigninManagerTest : public testing::Test { 94 public: 95 SigninManagerTest() : manager_(NULL) {} 96 virtual ~SigninManagerTest() {} 97 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 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 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. 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. 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_|. 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 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 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 199TEST_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 218TEST_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 237TEST_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 253TEST_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 266TEST_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 283TEST_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 295TEST_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 309TEST_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 320TEST_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 332TEST_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 348TEST_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