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/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" 39 40 #include "testing/gmock/include/gmock/gmock.h" 41 #include "testing/gtest/include/gtest/gtest.h" 42 43 namespace { 44 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); 52 return service; 53 } 54 55 class TestSigninManagerObserver : public SigninManagerBase::Observer { 56 public: 57 TestSigninManagerObserver() : num_failed_signins_(0), 58 num_successful_signins_(0), 59 num_signouts_(0) { 60 } 61 62 virtual ~TestSigninManagerObserver() {} 63 64 int num_failed_signins_; 65 int num_successful_signins_; 66 int num_signouts_; 67 68 private: 69 // SigninManagerBase::Observer: 70 virtual void GoogleSigninFailed( 71 const GoogleServiceAuthError& error) OVERRIDE { 72 num_failed_signins_++; 73 } 74 75 virtual void GoogleSigninSucceeded( 76 const std::string& username, const std::string& password) OVERRIDE { 77 num_successful_signins_++; 78 } 79 80 virtual void GoogleSignedOut(const std::string& username) OVERRIDE { 81 num_signouts_++; 82 } 83 }; 84 85 } // namespace 86 87 88 class SigninManagerTest : public testing::Test { 89 public: 90 SigninManagerTest() : manager_(NULL) {} 91 virtual ~SigninManagerTest() {} 92 93 virtual void SetUp() OVERRIDE { 94 manager_ = NULL; 95 prefs_.reset(new TestingPrefServiceSimple); 96 chrome::RegisterLocalState(prefs_->registry()); 97 TestingBrowserProcess::GetGlobal()->SetLocalState( 98 prefs_.get()); 99 TestingProfile::Builder builder; 100 builder.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(), 101 BuildFakeProfileOAuth2TokenService); 102 builder.AddTestingFactory(SigninManagerFactory::GetInstance(), 103 SigninManagerBuild); 104 profile_ = builder.Build(); 105 } 106 107 virtual void TearDown() OVERRIDE { 108 if (manager_) 109 manager_->RemoveObserver(&test_observer_); 110 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); 116 } 117 TestingBrowserProcess::GetGlobal()->SetLocalState(NULL); 118 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. 122 profile_.reset(); 123 prefs_.reset(); // LocalState needs to outlive the profile. 124 } 125 126 TestingProfile* profile() { return profile_.get(); } 127 128 // Sets up the signin manager as a service if other code will try to get it as 129 // a PKS. 130 void SetUpSigninManagerAsService() { 131 DCHECK(!manager_); 132 DCHECK(!naked_manager_); 133 manager_ = static_cast<SigninManager*>( 134 SigninManagerFactory::GetForProfile(profile())); 135 manager_->AddObserver(&test_observer_); 136 } 137 138 // Create a naked signin manager if integration with PKSs is not needed. 139 void CreateNakedSigninManager() { 140 DCHECK(!manager_); 141 naked_manager_.reset(new SigninManager( 142 ChromeSigninClientFactory::GetInstance()->GetForProfile(profile()), 143 ProfileOAuth2TokenServiceFactory::GetForProfile(profile()))); 144 145 manager_ = naked_manager_.get(); 146 manager_->AddObserver(&test_observer_); 147 } 148 149 // Shuts down |manager_|. 150 void ShutDownManager() { 151 DCHECK(manager_); 152 manager_->RemoveObserver(&test_observer_); 153 manager_->Shutdown(); 154 if (naked_manager_) 155 naked_manager_.reset(NULL); 156 manager_ = NULL; 157 } 158 159 void ExpectSignInWithRefreshTokenSuccess() { 160 EXPECT_FALSE(manager_->GetAuthenticatedUsername().empty()); 161 162 ProfileOAuth2TokenService* token_service = 163 ProfileOAuth2TokenServiceFactory::GetForProfile(profile()); 164 EXPECT_TRUE(token_service->RefreshTokenIsAvailable( 165 manager_->GetAuthenticatedUsername())); 166 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_); 170 } 171 172 void CompleteSigninCallback(const std::string& oauth_token) { 173 oauth_tokens_fetched_.push_back(oauth_token); 174 manager_->CompletePendingSignin(); 175 } 176 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_; 186 }; 187 188 TEST_F(SigninManagerTest, SignInWithRefreshToken) { 189 SetUpSigninManagerAsService(); 190 EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty()); 191 192 manager_->StartSignInWithRefreshToken( 193 "rt1", 194 "user (at) gmail.com", 195 "password", 196 SigninManager::OAuthTokenFetchedCallback()); 197 198 ExpectSignInWithRefreshTokenSuccess(); 199 200 // Should persist across resets. 201 ShutDownManager(); 202 CreateNakedSigninManager(); 203 manager_->Initialize(NULL); 204 EXPECT_EQ("user (at) gmail.com", manager_->GetAuthenticatedUsername()); 205 } 206 207 TEST_F(SigninManagerTest, SignInWithRefreshTokenCallbackComplete) { 208 SetUpSigninManagerAsService(); 209 EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty()); 210 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( 216 "rt1", 217 "user (at) gmail.com", 218 "password", 219 callback); 220 221 ExpectSignInWithRefreshTokenSuccess(); 222 ASSERT_EQ(1U, oauth_tokens_fetched_.size()); 223 EXPECT_EQ(oauth_tokens_fetched_[0], "rt1"); 224 } 225 226 TEST_F(SigninManagerTest, SignOut) { 227 SetUpSigninManagerAsService(); 228 manager_->StartSignInWithRefreshToken( 229 "rt1", 230 "user (at) gmail.com", 231 "password", 232 SigninManager::OAuthTokenFetchedCallback()); 233 manager_->SignOut(signin_metrics::SIGNOUT_TEST); 234 EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty()); 235 // Should not be persisted anymore 236 ShutDownManager(); 237 CreateNakedSigninManager(); 238 manager_->Initialize(NULL); 239 EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty()); 240 } 241 242 TEST_F(SigninManagerTest, SignOutWhileProhibited) { 243 SetUpSigninManagerAsService(); 244 EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty()); 245 246 manager_->SetAuthenticatedUsername("user (at) gmail.com"); 247 manager_->ProhibitSignout(true); 248 manager_->SignOut(signin_metrics::SIGNOUT_TEST); 249 EXPECT_FALSE(manager_->GetAuthenticatedUsername().empty()); 250 manager_->ProhibitSignout(false); 251 manager_->SignOut(signin_metrics::SIGNOUT_TEST); 252 EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty()); 253 } 254 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"))); 270 } 271 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 (at) google.com")); 278 EXPECT_TRUE(manager_->IsAllowedUsername("happy (at) google.com")); 279 EXPECT_FALSE(manager_->IsAllowedUsername("test (at) invalid.com")); 280 EXPECT_FALSE(manager_->IsAllowedUsername("test (at) notgoogle.com")); 281 EXPECT_FALSE(manager_->IsAllowedUsername(std::string())); 282 } 283 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 (at) google.com")); 292 EXPECT_TRUE(manager_->IsAllowedUsername("happy (at) google.com")); 293 EXPECT_FALSE(manager_->IsAllowedUsername("test (at) invalid.com")); 294 EXPECT_FALSE(manager_->IsAllowedUsername("test (at) notgoogle.com")); 295 EXPECT_FALSE(manager_->IsAllowedUsername(std::string())); 296 } 297 298 TEST_F(SigninManagerTest, ProhibitedAtStartup) { 299 profile()->GetPrefs()->SetString(prefs::kGoogleServicesUsername, 300 "monkey (at) 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()); 307 } 308 309 TEST_F(SigninManagerTest, ProhibitedAfterStartup) { 310 std::string user("monkey (at) 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()); 319 } 320 321 TEST_F(SigninManagerTest, ExternalSignIn) { 322 CreateNakedSigninManager(); 323 manager_->Initialize(g_browser_process->local_state()); 324 EXPECT_EQ("", 325 profile()->GetPrefs()->GetString(prefs::kGoogleServicesUsername)); 326 EXPECT_EQ("", manager_->GetAuthenticatedUsername()); 327 EXPECT_EQ(0, test_observer_.num_successful_signins_); 328 329 manager_->OnExternalSigninCompleted("external (at) example.com"); 330 EXPECT_EQ(1, test_observer_.num_successful_signins_); 331 EXPECT_EQ(0, test_observer_.num_failed_signins_); 332 EXPECT_EQ("external (at) example.com", 333 profile()->GetPrefs()->GetString(prefs::kGoogleServicesUsername)); 334 EXPECT_EQ("external (at) example.com", manager_->GetAuthenticatedUsername()); 335 } 336 337 TEST_F(SigninManagerTest, SigninNotAllowed) { 338 std::string user("user (at) google.com"); 339 profile()->GetPrefs()->SetString(prefs::kGoogleServicesUsername, user); 340 profile()->GetPrefs()->SetBoolean(prefs::kSigninAllowed, false); 341 SetUpSigninManagerAsService(); 342 } 343