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