Home | History | Annotate | Download | only in password_manager
      1 // Copyright 2014 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 "chrome/browser/password_manager/chrome_password_manager_client.h"
      6 
      7 #include "base/command_line.h"
      8 #include "base/strings/string16.h"
      9 #include "base/strings/utf_string_conversions.h"
     10 #include "chrome/common/chrome_version_info.h"
     11 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
     12 #include "chrome/test/base/testing_profile.h"
     13 #include "components/autofill/content/common/autofill_messages.h"
     14 #include "components/password_manager/content/browser/password_manager_internals_service_factory.h"
     15 #include "components/password_manager/content/common/credential_manager_messages.h"
     16 #include "components/password_manager/content/common/credential_manager_types.h"
     17 #include "components/password_manager/core/browser/log_receiver.h"
     18 #include "components/password_manager/core/browser/password_manager_internals_service.h"
     19 #include "components/password_manager/core/common/password_manager_switches.h"
     20 #include "content/public/browser/browser_context.h"
     21 #include "content/public/browser/web_contents.h"
     22 #include "content/public/test/mock_render_process_host.h"
     23 #include "testing/gmock/include/gmock/gmock.h"
     24 #include "testing/gtest/include/gtest/gtest.h"
     25 
     26 using content::BrowserContext;
     27 using content::WebContents;
     28 
     29 namespace {
     30 
     31 const char kTestText[] = "abcd1234";
     32 const int kRequestId = 4;
     33 
     34 class MockLogReceiver : public password_manager::LogReceiver {
     35  public:
     36   MOCK_METHOD1(LogSavePasswordProgress, void(const std::string&));
     37 };
     38 
     39 class TestChromePasswordManagerClient : public ChromePasswordManagerClient {
     40  public:
     41   explicit TestChromePasswordManagerClient(content::WebContents* web_contents)
     42       : ChromePasswordManagerClient(web_contents, NULL),
     43         is_sync_account_credential_(false) {}
     44   virtual ~TestChromePasswordManagerClient() {}
     45 
     46   virtual bool IsSyncAccountCredential(
     47       const std::string& username,
     48       const std::string& origin) const OVERRIDE {
     49     return is_sync_account_credential_;
     50   }
     51 
     52   void set_is_sync_account_credential(bool is_sync_account_credential) {
     53     is_sync_account_credential_ = is_sync_account_credential;
     54   }
     55 
     56  private:
     57   bool is_sync_account_credential_;
     58 
     59   DISALLOW_COPY_AND_ASSIGN(TestChromePasswordManagerClient);
     60 };
     61 
     62 }  // namespace
     63 
     64 class ChromePasswordManagerClientTest : public ChromeRenderViewHostTestHarness {
     65  public:
     66   ChromePasswordManagerClientTest();
     67 
     68   virtual void SetUp() OVERRIDE;
     69 
     70  protected:
     71   ChromePasswordManagerClient* GetClient();
     72 
     73   // If the test IPC sink contains an AutofillMsg_SetLoggingState message, then
     74   // copies its argument into |activation_flag| and returns true. Otherwise
     75   // returns false.
     76   bool WasLoggingActivationMessageSent(bool* activation_flag);
     77 
     78   password_manager::PasswordManagerInternalsService* service_;
     79 
     80   testing::StrictMock<MockLogReceiver> receiver_;
     81 };
     82 
     83 ChromePasswordManagerClientTest::ChromePasswordManagerClientTest()
     84     : service_(NULL) {
     85 }
     86 
     87 void ChromePasswordManagerClientTest::SetUp() {
     88   ChromeRenderViewHostTestHarness::SetUp();
     89   ChromePasswordManagerClient::CreateForWebContentsWithAutofillClient(
     90       web_contents(), NULL);
     91   service_ = password_manager::PasswordManagerInternalsServiceFactory::
     92       GetForBrowserContext(profile());
     93   ASSERT_TRUE(service_);
     94 }
     95 
     96 ChromePasswordManagerClient* ChromePasswordManagerClientTest::GetClient() {
     97   return ChromePasswordManagerClient::FromWebContents(web_contents());
     98 }
     99 
    100 bool ChromePasswordManagerClientTest::WasLoggingActivationMessageSent(
    101     bool* activation_flag) {
    102   const uint32 kMsgID = AutofillMsg_SetLoggingState::ID;
    103   const IPC::Message* message =
    104       process()->sink().GetFirstMessageMatching(kMsgID);
    105   if (!message)
    106     return false;
    107   Tuple1<bool> param;
    108   AutofillMsg_SetLoggingState::Read(message, &param);
    109   *activation_flag = param.a;
    110   process()->sink().ClearMessages();
    111   return true;
    112 }
    113 
    114 TEST_F(ChromePasswordManagerClientTest, LogSavePasswordProgressNoReceiver) {
    115   ChromePasswordManagerClient* client = GetClient();
    116 
    117   EXPECT_CALL(receiver_, LogSavePasswordProgress(kTestText)).Times(0);
    118   // Before attaching the receiver, no text should be passed.
    119   client->LogSavePasswordProgress(kTestText);
    120   EXPECT_FALSE(client->IsLoggingActive());
    121 }
    122 
    123 TEST_F(ChromePasswordManagerClientTest, LogSavePasswordProgressAttachReceiver) {
    124   ChromePasswordManagerClient* client = GetClient();
    125   EXPECT_FALSE(client->IsLoggingActive());
    126 
    127   // After attaching the logger, text should be passed.
    128   service_->RegisterReceiver(&receiver_);
    129   EXPECT_TRUE(client->IsLoggingActive());
    130   EXPECT_CALL(receiver_, LogSavePasswordProgress(kTestText)).Times(1);
    131   client->LogSavePasswordProgress(kTestText);
    132   service_->UnregisterReceiver(&receiver_);
    133   EXPECT_FALSE(client->IsLoggingActive());
    134 }
    135 
    136 TEST_F(ChromePasswordManagerClientTest, LogSavePasswordProgressDetachReceiver) {
    137   ChromePasswordManagerClient* client = GetClient();
    138 
    139   service_->RegisterReceiver(&receiver_);
    140   EXPECT_TRUE(client->IsLoggingActive());
    141   service_->UnregisterReceiver(&receiver_);
    142   EXPECT_FALSE(client->IsLoggingActive());
    143 
    144   // After detaching the logger, no text should be passed.
    145   EXPECT_CALL(receiver_, LogSavePasswordProgress(kTestText)).Times(0);
    146   client->LogSavePasswordProgress(kTestText);
    147 }
    148 
    149 TEST_F(ChromePasswordManagerClientTest, LogSavePasswordProgressNotifyRenderer) {
    150   ChromePasswordManagerClient* client = GetClient();
    151   bool logging_active = false;
    152 
    153   // Initially, the logging should be off, so no IPC messages.
    154   EXPECT_FALSE(WasLoggingActivationMessageSent(&logging_active));
    155 
    156   service_->RegisterReceiver(&receiver_);
    157   EXPECT_TRUE(client->IsLoggingActive());
    158   EXPECT_TRUE(WasLoggingActivationMessageSent(&logging_active));
    159   EXPECT_TRUE(logging_active);
    160 
    161   service_->UnregisterReceiver(&receiver_);
    162   EXPECT_FALSE(client->IsLoggingActive());
    163   EXPECT_TRUE(WasLoggingActivationMessageSent(&logging_active));
    164   EXPECT_FALSE(logging_active);
    165 }
    166 
    167 TEST_F(ChromePasswordManagerClientTest, AnswerToPingsAboutLoggingState_Active) {
    168   service_->RegisterReceiver(&receiver_);
    169 
    170   process()->sink().ClearMessages();
    171 
    172   // Ping the client for logging activity update.
    173   AutofillHostMsg_PasswordAutofillAgentConstructed msg(0);
    174   static_cast<IPC::Listener*>(GetClient())->OnMessageReceived(msg);
    175 
    176   bool logging_active = false;
    177   EXPECT_TRUE(WasLoggingActivationMessageSent(&logging_active));
    178   EXPECT_TRUE(logging_active);
    179 
    180   service_->UnregisterReceiver(&receiver_);
    181 }
    182 
    183 TEST_F(ChromePasswordManagerClientTest,
    184        AnswerToPingsAboutLoggingState_Inactive) {
    185   process()->sink().ClearMessages();
    186 
    187   // Ping the client for logging activity update.
    188   AutofillHostMsg_PasswordAutofillAgentConstructed msg(0);
    189   static_cast<IPC::Listener*>(GetClient())->OnMessageReceived(msg);
    190 
    191   bool logging_active = true;
    192   EXPECT_TRUE(WasLoggingActivationMessageSent(&logging_active));
    193   EXPECT_FALSE(logging_active);
    194 }
    195 
    196 TEST_F(ChromePasswordManagerClientTest,
    197        IsAutomaticPasswordSavingEnabledDefaultBehaviourTest) {
    198   EXPECT_FALSE(GetClient()->IsAutomaticPasswordSavingEnabled());
    199 }
    200 
    201 TEST_F(ChromePasswordManagerClientTest,
    202        IsAutomaticPasswordSavingEnabledWhenFlagIsSetTest) {
    203   CommandLine::ForCurrentProcess()->AppendSwitch(
    204       password_manager::switches::kEnableAutomaticPasswordSaving);
    205   if (chrome::VersionInfo::GetChannel() == chrome::VersionInfo::CHANNEL_UNKNOWN)
    206     EXPECT_TRUE(GetClient()->IsAutomaticPasswordSavingEnabled());
    207   else
    208     EXPECT_FALSE(GetClient()->IsAutomaticPasswordSavingEnabled());
    209 }
    210 
    211 TEST_F(ChromePasswordManagerClientTest, LogToAReceiver) {
    212   ChromePasswordManagerClient* client = GetClient();
    213   service_->RegisterReceiver(&receiver_);
    214   EXPECT_TRUE(client->IsLoggingActive());
    215 
    216   EXPECT_CALL(receiver_, LogSavePasswordProgress(kTestText)).Times(1);
    217   client->LogSavePasswordProgress(kTestText);
    218 
    219   service_->UnregisterReceiver(&receiver_);
    220   EXPECT_FALSE(client->IsLoggingActive());
    221 }
    222 
    223 TEST_F(ChromePasswordManagerClientTest, ShouldFilterAutofillResult_Reauth) {
    224   // Make client disallow only reauth requests.
    225   CommandLine* command_line = CommandLine::ForCurrentProcess();
    226   command_line->AppendSwitch(
    227       password_manager::switches::kDisallowAutofillSyncCredentialForReauth);
    228   scoped_ptr<TestChromePasswordManagerClient> client(
    229       new TestChromePasswordManagerClient(web_contents()));
    230   autofill::PasswordForm form;
    231 
    232   client->set_is_sync_account_credential(false);
    233   NavigateAndCommit(
    234       GURL("https://accounts.google.com/login?rart=123&continue=blah"));
    235   EXPECT_FALSE(client->ShouldFilterAutofillResult(form));
    236 
    237   client->set_is_sync_account_credential(true);
    238   NavigateAndCommit(
    239       GURL("https://accounts.google.com/login?rart=123&continue=blah"));
    240   EXPECT_TRUE(client->ShouldFilterAutofillResult(form));
    241 
    242   // This counts as a reauth url, though a valid URL should have a value for
    243   // "rart"
    244   NavigateAndCommit(GURL("https://accounts.google.com/addlogin?rart"));
    245   EXPECT_TRUE(client->ShouldFilterAutofillResult(form));
    246 
    247   NavigateAndCommit(GURL("https://accounts.google.com/login?param=123"));
    248   EXPECT_FALSE(client->ShouldFilterAutofillResult(form));
    249 
    250   NavigateAndCommit(GURL("https://site.com/login?rart=678"));
    251   EXPECT_FALSE(client->ShouldFilterAutofillResult(form));
    252 }
    253 
    254 TEST_F(ChromePasswordManagerClientTest, ShouldFilterAutofillResult) {
    255   // Normally the client should allow any credentials through, even if they
    256   // are the sync credential.
    257   scoped_ptr<TestChromePasswordManagerClient> client(
    258       new TestChromePasswordManagerClient(web_contents()));
    259   autofill::PasswordForm form;
    260   client->set_is_sync_account_credential(true);
    261   NavigateAndCommit(GURL("https://accounts.google.com/Login"));
    262   EXPECT_FALSE(client->ShouldFilterAutofillResult(form));
    263 
    264   // Adding disallow switch should cause sync credential to be filtered.
    265   CommandLine* command_line = CommandLine::ForCurrentProcess();
    266   command_line->AppendSwitch(
    267       password_manager::switches::kDisallowAutofillSyncCredential);
    268   client.reset(new TestChromePasswordManagerClient(web_contents()));
    269   client->set_is_sync_account_credential(true);
    270   NavigateAndCommit(GURL("https://accounts.google.com/Login"));
    271   EXPECT_TRUE(client->ShouldFilterAutofillResult(form));
    272 }
    273 
    274 TEST_F(ChromePasswordManagerClientTest,
    275        IsPasswordManagerEnabledForCurrentPage) {
    276   ChromePasswordManagerClient* client = GetClient();
    277   NavigateAndCommit(
    278       GURL("https://accounts.google.com/ServiceLogin?continue="
    279            "https://passwords.google.com/settings&rart=123"));
    280   EXPECT_FALSE(client->IsPasswordManagerEnabledForCurrentPage());
    281 
    282   // Password site is inaccesible via HTTP, but because of HSTS the following
    283   // link should still continue to https://passwords.google.com.
    284   NavigateAndCommit(
    285       GURL("https://accounts.google.com/ServiceLogin?continue="
    286            "http://passwords.google.com/settings&rart=123"));
    287   EXPECT_FALSE(client->IsPasswordManagerEnabledForCurrentPage());
    288 
    289   // Specifying default port still passes.
    290   NavigateAndCommit(
    291       GURL("https://accounts.google.com/ServiceLogin?continue="
    292            "https://passwords.google.com:443/settings&rart=123"));
    293   EXPECT_FALSE(client->IsPasswordManagerEnabledForCurrentPage());
    294 
    295   // Encoded URL is considered the same.
    296   NavigateAndCommit(
    297       GURL("https://accounts.google.com/ServiceLogin?continue="
    298            "https://passwords.%67oogle.com/settings&rart=123"));
    299   EXPECT_FALSE(client->IsPasswordManagerEnabledForCurrentPage());
    300 
    301   // Make sure testing sites are disabled as well.
    302   NavigateAndCommit(
    303       GURL("https://accounts.google.com/Login?continue="
    304            "https://passwords-ac-testing.corp.google.com/settings&rart=456"));
    305   EXPECT_FALSE(client->IsPasswordManagerEnabledForCurrentPage());
    306 
    307   // Fully qualified domain name is considered a different hostname by GURL.
    308   // Ideally this would not be the case, but this quirk can be avoided by
    309   // verification on the server. This test is simply documentation of this
    310   // behavior.
    311   NavigateAndCommit(
    312       GURL("https://accounts.google.com/ServiceLogin?continue="
    313            "https://passwords.google.com./settings&rart=123"));
    314   EXPECT_TRUE(client->IsPasswordManagerEnabledForCurrentPage());
    315 
    316   // Not a transactional reauth page.
    317   NavigateAndCommit(
    318       GURL("https://accounts.google.com/ServiceLogin?continue="
    319            "https://passwords.google.com/settings"));
    320   EXPECT_TRUE(client->IsPasswordManagerEnabledForCurrentPage());
    321 
    322   // Should be enabled for other transactional reauth pages.
    323   NavigateAndCommit(
    324       GURL("https://accounts.google.com/ServiceLogin?continue="
    325            "https://mail.google.com&rart=234"));
    326   EXPECT_TRUE(client->IsPasswordManagerEnabledForCurrentPage());
    327 
    328   // Reauth pages are only on accounts.google.com
    329   NavigateAndCommit(
    330       GURL("https://other.site.com/ServiceLogin?continue="
    331            "https://passwords.google.com&rart=234"));
    332   EXPECT_TRUE(client->IsPasswordManagerEnabledForCurrentPage());
    333 }
    334 
    335 TEST_F(ChromePasswordManagerClientTest, CredentialManagerOnNotifyFailedSignIn) {
    336   scoped_ptr<TestChromePasswordManagerClient> client(
    337       new TestChromePasswordManagerClient(web_contents()));
    338 
    339   password_manager::CredentialInfo info(base::ASCIIToUTF16("id"),
    340                                         base::ASCIIToUTF16("name"),
    341                                         GURL("https://example.com/image.png"));
    342   client->OnNotifyFailedSignIn(kRequestId, info);
    343 
    344   const uint32 kMsgID = CredentialManagerMsg_AcknowledgeFailedSignIn::ID;
    345   const IPC::Message* message =
    346       process()->sink().GetFirstMessageMatching(kMsgID);
    347   EXPECT_TRUE(message);
    348   process()->sink().ClearMessages();
    349 }
    350 
    351 TEST_F(ChromePasswordManagerClientTest, CredentialManagerOnNotifySignedIn) {
    352   scoped_ptr<TestChromePasswordManagerClient> client(
    353       new TestChromePasswordManagerClient(web_contents()));
    354 
    355   password_manager::CredentialInfo info(base::ASCIIToUTF16("id"),
    356                                         base::ASCIIToUTF16("name"),
    357                                         GURL("https://example.com/image.png"));
    358   client->OnNotifySignedIn(kRequestId, info);
    359 
    360   const uint32 kMsgID = CredentialManagerMsg_AcknowledgeSignedIn::ID;
    361   const IPC::Message* message =
    362       process()->sink().GetFirstMessageMatching(kMsgID);
    363   EXPECT_TRUE(message);
    364   process()->sink().ClearMessages();
    365 }
    366 
    367 TEST_F(ChromePasswordManagerClientTest, CredentialManagerOnNotifySignedOut) {
    368   scoped_ptr<TestChromePasswordManagerClient> client(
    369       new TestChromePasswordManagerClient(web_contents()));
    370 
    371   client->OnNotifySignedOut(kRequestId);
    372 
    373   const uint32 kMsgID = CredentialManagerMsg_AcknowledgeSignedOut::ID;
    374   const IPC::Message* message =
    375       process()->sink().GetFirstMessageMatching(kMsgID);
    376   EXPECT_TRUE(message);
    377   process()->sink().ClearMessages();
    378 }
    379 
    380 TEST_F(ChromePasswordManagerClientTest, CredentialManagerOnRequestCredential) {
    381   scoped_ptr<TestChromePasswordManagerClient> client(
    382       new TestChromePasswordManagerClient(web_contents()));
    383 
    384   std::vector<GURL> federations;
    385   client->OnRequestCredential(kRequestId, false, federations);
    386 
    387   const uint32 kMsgID = CredentialManagerMsg_SendCredential::ID;
    388   const IPC::Message* message =
    389       process()->sink().GetFirstMessageMatching(kMsgID);
    390   EXPECT_TRUE(message);
    391   process()->sink().ClearMessages();
    392 }
    393