Home | History | Annotate | Download | only in browser
      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 "base/basictypes.h"
      6 #include "base/bind.h"
      7 #include "base/files/scoped_temp_dir.h"
      8 #include "base/stl_util.h"
      9 #include "base/strings/string_util.h"
     10 #include "base/synchronization/waitable_event.h"
     11 #include "base/time/time.h"
     12 #include "components/password_manager/core/browser/password_form_data.h"
     13 #include "components/password_manager/core/browser/password_store_consumer.h"
     14 #include "components/password_manager/core/browser/password_store_default.h"
     15 #include "testing/gmock/include/gmock/gmock.h"
     16 #include "testing/gtest/include/gtest/gtest.h"
     17 
     18 using autofill::PasswordForm;
     19 using base::WaitableEvent;
     20 using testing::_;
     21 using testing::DoAll;
     22 using testing::WithArg;
     23 
     24 namespace password_manager {
     25 
     26 namespace {
     27 
     28 class MockPasswordStoreConsumer : public PasswordStoreConsumer {
     29  public:
     30   MOCK_METHOD1(OnGetPasswordStoreResults,
     31                void(const std::vector<PasswordForm*>&));
     32 };
     33 
     34 class StartSyncFlareMock {
     35  public:
     36   StartSyncFlareMock() {}
     37   ~StartSyncFlareMock() {}
     38 
     39   MOCK_METHOD1(StartSyncFlare, void(syncer::ModelType));
     40 };
     41 
     42 }  // namespace
     43 
     44 class PasswordStoreTest : public testing::Test {
     45  protected:
     46   virtual void SetUp() OVERRIDE {
     47     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     48     login_db_.reset(new LoginDatabase());
     49     ASSERT_TRUE(login_db_->Init(temp_dir_.path().Append(
     50         FILE_PATH_LITERAL("login_test"))));
     51   }
     52 
     53   virtual void TearDown() OVERRIDE {
     54     ASSERT_TRUE(temp_dir_.Delete());
     55   }
     56 
     57   base::MessageLoopForUI message_loop_;
     58   scoped_ptr<LoginDatabase> login_db_;
     59   base::ScopedTempDir temp_dir_;
     60 };
     61 
     62 ACTION(STLDeleteElements0) {
     63   STLDeleteContainerPointers(arg0.begin(), arg0.end());
     64 }
     65 
     66 TEST_F(PasswordStoreTest, IgnoreOldWwwGoogleLogins) {
     67   scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
     68       base::MessageLoopProxy::current(),
     69       base::MessageLoopProxy::current(),
     70       login_db_.release()));
     71   store->Init(syncer::SyncableService::StartSyncFlare(), "");
     72 
     73   const time_t cutoff = 1325376000;  // 00:00 Jan 1 2012 UTC
     74   // The passwords are all empty because PasswordStoreDefault doesn't store the
     75   // actual passwords on OS X (they're stored in the Keychain instead). We could
     76   // special-case it, but it's easier to just have empty passwords.
     77   static const PasswordFormData form_data[] = {
     78     // A form on https://www.google.com/ older than the cutoff. Will be ignored.
     79     { PasswordForm::SCHEME_HTML,
     80       "https://www.google.com",
     81       "https://www.google.com/origin",
     82       "https://www.google.com/action",
     83       L"submit_element",
     84       L"username_element",
     85       L"password_element",
     86       L"username_value_1",
     87       L"",
     88       true, true, cutoff - 1 },
     89     // A form on https://www.google.com/ older than the cutoff. Will be ignored.
     90     { PasswordForm::SCHEME_HTML,
     91       "https://www.google.com",
     92       "https://www.google.com/origin",
     93       "https://www.google.com/action",
     94       L"submit_element",
     95       L"username_element",
     96       L"password_element",
     97       L"username_value_2",
     98       L"",
     99       true, true, cutoff - 1 },
    100     // A form on https://www.google.com/ newer than the cutoff.
    101     { PasswordForm::SCHEME_HTML,
    102       "https://www.google.com",
    103       "https://www.google.com/origin",
    104       "https://www.google.com/action",
    105       L"submit_element",
    106       L"username_element",
    107       L"password_element",
    108       L"username_value_3",
    109       L"",
    110       true, true, cutoff + 1 },
    111     // A form on https://accounts.google.com/ older than the cutoff.
    112     { PasswordForm::SCHEME_HTML,
    113       "https://accounts.google.com",
    114       "https://accounts.google.com/origin",
    115       "https://accounts.google.com/action",
    116       L"submit_element",
    117       L"username_element",
    118       L"password_element",
    119       L"username_value",
    120       L"",
    121       true, true, cutoff - 1 },
    122     // A form on http://bar.example.com/ older than the cutoff.
    123     { PasswordForm::SCHEME_HTML,
    124       "http://bar.example.com",
    125       "http://bar.example.com/origin",
    126       "http://bar.example.com/action",
    127       L"submit_element",
    128       L"username_element",
    129       L"password_element",
    130       L"username_value",
    131       L"",
    132       true, false, cutoff - 1 },
    133   };
    134 
    135   // Build the forms vector and add the forms to the store.
    136   std::vector<PasswordForm*> all_forms;
    137   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(form_data); ++i) {
    138     PasswordForm* form = CreatePasswordFormFromData(form_data[i]);
    139     all_forms.push_back(form);
    140     store->AddLogin(*form);
    141   }
    142   base::MessageLoop::current()->RunUntilIdle();
    143 
    144   // We expect to get back only the "recent" www.google.com login.
    145   // Theoretically these should never actually exist since there are no longer
    146   // any login forms on www.google.com to save, but we technically allow them.
    147   // We should not get back the older saved password though.
    148   PasswordForm www_google;
    149   www_google.scheme = PasswordForm::SCHEME_HTML;
    150   www_google.signon_realm = "https://www.google.com";
    151   std::vector<PasswordForm*> www_google_expected;
    152   www_google_expected.push_back(all_forms[2]);
    153 
    154   // We should still get the accounts.google.com login even though it's older
    155   // than our cutoff - this is the new location of all Google login forms.
    156   PasswordForm accounts_google;
    157   accounts_google.scheme = PasswordForm::SCHEME_HTML;
    158   accounts_google.signon_realm = "https://accounts.google.com";
    159   std::vector<PasswordForm*> accounts_google_expected;
    160   accounts_google_expected.push_back(all_forms[3]);
    161 
    162   // Same thing for a generic saved login.
    163   PasswordForm bar_example;
    164   bar_example.scheme = PasswordForm::SCHEME_HTML;
    165   bar_example.signon_realm = "http://bar.example.com";
    166   std::vector<PasswordForm*> bar_example_expected;
    167   bar_example_expected.push_back(all_forms[4]);
    168 
    169   MockPasswordStoreConsumer consumer;
    170 
    171   // Expect the appropriate replies, as above, in reverse order than we will
    172   // issue the queries. Each retires on saturation to avoid matcher spew.
    173   EXPECT_CALL(consumer,
    174       OnGetPasswordStoreResults(ContainsAllPasswordForms(bar_example_expected)))
    175       .WillOnce(WithArg<0>(STLDeleteElements0())).RetiresOnSaturation();
    176   EXPECT_CALL(consumer,
    177       OnGetPasswordStoreResults(
    178           ContainsAllPasswordForms(accounts_google_expected)))
    179       .WillOnce(WithArg<0>(STLDeleteElements0())).RetiresOnSaturation();
    180   EXPECT_CALL(consumer,
    181       OnGetPasswordStoreResults(
    182           ContainsAllPasswordForms(www_google_expected)))
    183       .WillOnce(WithArg<0>(STLDeleteElements0())).RetiresOnSaturation();
    184 
    185   store->GetLogins(www_google, PasswordStore::ALLOW_PROMPT, &consumer);
    186   store->GetLogins(accounts_google, PasswordStore::ALLOW_PROMPT, &consumer);
    187   store->GetLogins(bar_example, PasswordStore::ALLOW_PROMPT, &consumer);
    188 
    189   base::MessageLoop::current()->RunUntilIdle();
    190 
    191   STLDeleteElements(&all_forms);
    192   store->Shutdown();
    193   base::MessageLoop::current()->RunUntilIdle();
    194 }
    195 
    196 TEST_F(PasswordStoreTest, StartSyncFlare) {
    197   scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
    198       base::MessageLoopProxy::current(),
    199       base::MessageLoopProxy::current(),
    200       login_db_.release()));
    201   StartSyncFlareMock mock;
    202   store->Init(base::Bind(&StartSyncFlareMock::StartSyncFlare,
    203                          base::Unretained(&mock)),
    204               "");
    205   {
    206     PasswordForm form;
    207     EXPECT_CALL(mock, StartSyncFlare(syncer::PASSWORDS));
    208     store->AddLogin(form);
    209     base::MessageLoop::current()->RunUntilIdle();
    210   }
    211   store->Shutdown();
    212   base::MessageLoop::current()->RunUntilIdle();
    213 }
    214 
    215 }  // namespace password_manager
    216