Home | History | Annotate | Download | only in signin
      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