OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "testing/gmock/include/gmock/gmock.h" | 5 #include "testing/gmock/include/gmock/gmock.h" |
6 #include "testing/gtest/include/gtest/gtest.h" | 6 #include "testing/gtest/include/gtest/gtest.h" |
7 | 7 |
8 #include "base/basictypes.h" | 8 #include "base/basictypes.h" |
9 #include "base/file_util.h" | 9 #include "base/file_util.h" |
10 #include "base/path_service.h" | 10 #include "base/path_service.h" |
11 #include "base/scoped_temp_dir.h" | 11 #include "base/scoped_temp_dir.h" |
12 #include "base/stl_util.h" | 12 #include "base/stl_util.h" |
13 #include "base/string_util.h" | 13 #include "base/string_util.h" |
14 #include "base/utf_string_conversions.h" | 14 #include "base/utf_string_conversions.h" |
15 #include "chrome/browser/password_manager/password_store_consumer.h" | 15 #include "chrome/browser/password_manager/password_store_consumer.h" |
16 #include "chrome/browser/password_manager/password_store_mac.h" | 16 #include "chrome/browser/password_manager/password_store_mac.h" |
17 #include "chrome/browser/password_manager/password_store_mac_internal.h" | 17 #include "chrome/browser/password_manager/password_store_mac_internal.h" |
18 #include "chrome/common/chrome_paths.h" | 18 #include "chrome/common/chrome_paths.h" |
19 #include "content/public/test/test_browser_thread.h" | 19 #include "content/public/test/test_browser_thread.h" |
20 #include "crypto/mock_keychain_mac.h" | 20 #include "crypto/mock_apple_keychain.h" |
21 | 21 |
22 using content::BrowserThread; | 22 using content::BrowserThread; |
23 using crypto::MockKeychain; | 23 using crypto::MockAppleKeychain; |
24 using webkit::forms::PasswordForm; | 24 using webkit::forms::PasswordForm; |
25 using testing::_; | 25 using testing::_; |
26 using testing::DoAll; | 26 using testing::DoAll; |
27 using testing::WithArg; | 27 using testing::WithArg; |
28 | 28 |
29 namespace { | 29 namespace { |
30 | 30 |
31 class MockPasswordStoreConsumer : public PasswordStoreConsumer { | 31 class MockPasswordStoreConsumer : public PasswordStoreConsumer { |
32 public: | 32 public: |
33 MOCK_METHOD2(OnPasswordStoreRequestDone, | 33 MOCK_METHOD2(OnPasswordStoreRequestDone, |
(...skipping 10 matching lines...) Expand all Loading... |
44 MessageLoop::current()->Quit(); | 44 MessageLoop::current()->Quit(); |
45 } | 45 } |
46 | 46 |
47 } // namespace | 47 } // namespace |
48 | 48 |
49 #pragma mark - | 49 #pragma mark - |
50 | 50 |
51 class PasswordStoreMacInternalsTest : public testing::Test { | 51 class PasswordStoreMacInternalsTest : public testing::Test { |
52 public: | 52 public: |
53 virtual void SetUp() { | 53 virtual void SetUp() { |
54 MockKeychain::KeychainTestData test_data[] = { | 54 MockAppleKeychain::KeychainTestData test_data[] = { |
55 // Basic HTML form. | 55 // Basic HTML form. |
56 { kSecAuthenticationTypeHTMLForm, "some.domain.com", | 56 { kSecAuthenticationTypeHTMLForm, "some.domain.com", |
57 kSecProtocolTypeHTTP, NULL, 0, NULL, "20020601171500Z", | 57 kSecProtocolTypeHTTP, NULL, 0, NULL, "20020601171500Z", |
58 "joe_user", "sekrit", false }, | 58 "joe_user", "sekrit", false }, |
59 // HTML form with path. | 59 // HTML form with path. |
60 { kSecAuthenticationTypeHTMLForm, "some.domain.com", | 60 { kSecAuthenticationTypeHTMLForm, "some.domain.com", |
61 kSecProtocolTypeHTTP, "/insecure.html", 0, NULL, "19991231235959Z", | 61 kSecProtocolTypeHTTP, "/insecure.html", 0, NULL, "19991231235959Z", |
62 "joe_user", "sekrit", false }, | 62 "joe_user", "sekrit", false }, |
63 // Secure HTML form with path. | 63 // Secure HTML form with path. |
64 { kSecAuthenticationTypeHTMLForm, "some.domain.com", | 64 { kSecAuthenticationTypeHTMLForm, "some.domain.com", |
(...skipping 19 matching lines...) Expand all Loading... |
84 // HTTP auth digest, secure. | 84 // HTTP auth digest, secure. |
85 { kSecAuthenticationTypeHTTPDigest, "some.domain.com", | 85 { kSecAuthenticationTypeHTTPDigest, "some.domain.com", |
86 kSecProtocolTypeHTTPS, NULL, 0, "high_security", "19980330100000Z", | 86 kSecProtocolTypeHTTPS, NULL, 0, "high_security", "19980330100000Z", |
87 "digest_auth_user", "digest", false }, | 87 "digest_auth_user", "digest", false }, |
88 // An FTP password with an invalid date, for edge-case testing. | 88 // An FTP password with an invalid date, for edge-case testing. |
89 { kSecAuthenticationTypeDefault, "a.server.com", | 89 { kSecAuthenticationTypeDefault, "a.server.com", |
90 kSecProtocolTypeFTP, NULL, 0, NULL, "20010203040", | 90 kSecProtocolTypeFTP, NULL, 0, NULL, "20010203040", |
91 "abc", "123", false }, | 91 "abc", "123", false }, |
92 }; | 92 }; |
93 | 93 |
94 keychain_ = new MockKeychain(); | 94 keychain_ = new MockAppleKeychain(); |
95 | 95 |
96 for (unsigned int i = 0; i < arraysize(test_data); ++i) { | 96 for (unsigned int i = 0; i < arraysize(test_data); ++i) { |
97 keychain_->AddTestItem(test_data[i]); | 97 keychain_->AddTestItem(test_data[i]); |
98 } | 98 } |
99 } | 99 } |
100 | 100 |
101 virtual void TearDown() { | 101 virtual void TearDown() { |
102 ExpectCreatesAndFreesBalanced(); | 102 ExpectCreatesAndFreesBalanced(); |
103 ExpectCreatorCodesSet(); | 103 ExpectCreatorCodesSet(); |
104 delete keychain_; | 104 delete keychain_; |
105 } | 105 } |
106 | 106 |
107 protected: | 107 protected: |
108 // Causes a test failure unless everything returned from keychain_'s | 108 // Causes a test failure unless everything returned from keychain_'s |
109 // ItemCopyAttributesAndData, SearchCreateFromAttributes, and SearchCopyNext | 109 // ItemCopyAttributesAndData, SearchCreateFromAttributes, and SearchCopyNext |
110 // was correctly freed. | 110 // was correctly freed. |
111 void ExpectCreatesAndFreesBalanced() { | 111 void ExpectCreatesAndFreesBalanced() { |
112 EXPECT_EQ(0, keychain_->UnfreedSearchCount()); | 112 EXPECT_EQ(0, keychain_->UnfreedSearchCount()); |
113 EXPECT_EQ(0, keychain_->UnfreedKeychainItemCount()); | 113 EXPECT_EQ(0, keychain_->UnfreedKeychainItemCount()); |
114 EXPECT_EQ(0, keychain_->UnfreedAttributeDataCount()); | 114 EXPECT_EQ(0, keychain_->UnfreedAttributeDataCount()); |
115 } | 115 } |
116 | 116 |
117 // Causes a test failure unless any Keychain items added during the test have | 117 // Causes a test failure unless any Keychain items added during the test have |
118 // their creator code set. | 118 // their creator code set. |
119 void ExpectCreatorCodesSet() { | 119 void ExpectCreatorCodesSet() { |
120 EXPECT_TRUE(keychain_->CreatorCodesSetForAddedItems()); | 120 EXPECT_TRUE(keychain_->CreatorCodesSetForAddedItems()); |
121 } | 121 } |
122 | 122 |
123 MockKeychain* keychain_; | 123 MockAppleKeychain* keychain_; |
124 }; | 124 }; |
125 | 125 |
126 #pragma mark - | 126 #pragma mark - |
127 | 127 |
128 // Struct used for creation of PasswordForms from static arrays of data. | 128 // Struct used for creation of PasswordForms from static arrays of data. |
129 struct PasswordFormData { | 129 struct PasswordFormData { |
130 const PasswordForm::Scheme scheme; | 130 const PasswordForm::Scheme scheme; |
131 const char* signon_realm; | 131 const char* signon_realm; |
132 const char* origin; | 132 const char* origin; |
133 const char* action; | 133 const char* action; |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
267 "https://some.domain.com/", L"digest_auth_user", L"digest", true, | 267 "https://some.domain.com/", L"digest_auth_user", L"digest", true, |
268 1998, 3, 30, 10, 0, 0 }, | 268 1998, 3, 30, 10, 0, 0 }, |
269 // This one gives us an invalid date, which we will treat as a "NULL" date | 269 // This one gives us an invalid date, which we will treat as a "NULL" date |
270 // which is 1601. | 270 // which is 1601. |
271 { PasswordForm::SCHEME_OTHER, "http://a.server.com/", | 271 { PasswordForm::SCHEME_OTHER, "http://a.server.com/", |
272 "http://a.server.com/", L"abc", L"123", false, | 272 "http://a.server.com/", L"abc", L"123", false, |
273 1601, 1, 1, 0, 0, 0 }, | 273 1601, 1, 1, 0, 0, 0 }, |
274 }; | 274 }; |
275 | 275 |
276 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(expected); ++i) { | 276 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(expected); ++i) { |
277 // Create our fake KeychainItemRef; see MockKeychain docs. | 277 // Create our fake KeychainItemRef; see MockAppleKeychain docs. |
278 SecKeychainItemRef keychain_item = | 278 SecKeychainItemRef keychain_item = |
279 reinterpret_cast<SecKeychainItemRef>(i + 1); | 279 reinterpret_cast<SecKeychainItemRef>(i + 1); |
280 PasswordForm form; | 280 PasswordForm form; |
281 bool parsed = internal_keychain_helpers::FillPasswordFormFromKeychainItem( | 281 bool parsed = internal_keychain_helpers::FillPasswordFormFromKeychainItem( |
282 *keychain_, keychain_item, &form); | 282 *keychain_, keychain_item, &form); |
283 | 283 |
284 EXPECT_TRUE(parsed) << "In iteration " << i; | 284 EXPECT_TRUE(parsed) << "In iteration " << i; |
285 | 285 |
286 EXPECT_EQ(expected[i].scheme, form.scheme) << "In iteration " << i; | 286 EXPECT_EQ(expected[i].scheme, form.scheme) << "In iteration " << i; |
287 EXPECT_EQ(GURL(expected[i].origin), form.origin) << "In iteration " << i; | 287 EXPECT_EQ(GURL(expected[i].origin), form.origin) << "In iteration " << i; |
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
507 "http://a.site.com:2222/", NULL, NULL, NULL, NULL, | 507 "http://a.site.com:2222/", NULL, NULL, NULL, NULL, |
508 L"username", L"password", false, false, 0 }, true }, | 508 L"username", L"password", false, false, 0 }, true }, |
509 { { PasswordForm::SCHEME_DIGEST, "https://digest.site.com/differentrealm", | 509 { { PasswordForm::SCHEME_DIGEST, "https://digest.site.com/differentrealm", |
510 "https://digest.site.com/secure.html", NULL, NULL, NULL, NULL, | 510 "https://digest.site.com/secure.html", NULL, NULL, NULL, NULL, |
511 L"testname", L"testpass", false, false, 0 }, true }, | 511 L"testname", L"testpass", false, false, 0 }, true }, |
512 // Make sure that garbage forms are rejected. | 512 // Make sure that garbage forms are rejected. |
513 { { PasswordForm::SCHEME_HTML, "gobbledygook", | 513 { { PasswordForm::SCHEME_HTML, "gobbledygook", |
514 "gobbledygook", NULL, NULL, NULL, NULL, | 514 "gobbledygook", NULL, NULL, NULL, NULL, |
515 L"anonymous", L"knock-knock", false, false, 0 }, false }, | 515 L"anonymous", L"knock-knock", false, false, 0 }, false }, |
516 // Test that failing to update a duplicate (forced using the magic failure | 516 // Test that failing to update a duplicate (forced using the magic failure |
517 // password; see MockKeychain::ItemModifyAttributesAndData) is reported. | 517 // password; see MockAppleKeychain::ItemModifyAttributesAndData) is |
| 518 // reported. |
518 { { PasswordForm::SCHEME_HTML, "http://some.domain.com", | 519 { { PasswordForm::SCHEME_HTML, "http://some.domain.com", |
519 "http://some.domain.com/insecure.html", NULL, NULL, NULL, NULL, | 520 "http://some.domain.com/insecure.html", NULL, NULL, NULL, NULL, |
520 L"joe_user", L"fail_me", false, false, 0 }, false }, | 521 L"joe_user", L"fail_me", false, false, 0 }, false }, |
521 }; | 522 }; |
522 | 523 |
523 MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_); | 524 MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_); |
524 owned_keychain_adapter.SetFindsOnlyOwnedItems(true); | 525 owned_keychain_adapter.SetFindsOnlyOwnedItems(true); |
525 | 526 |
526 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(test_data); ++i) { | 527 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(test_data); ++i) { |
527 scoped_ptr<PasswordForm> in_form( | 528 scoped_ptr<PasswordForm> in_form( |
(...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
899 class PasswordStoreMacTest : public testing::Test { | 900 class PasswordStoreMacTest : public testing::Test { |
900 public: | 901 public: |
901 PasswordStoreMacTest() : ui_thread_(BrowserThread::UI, &message_loop_) {} | 902 PasswordStoreMacTest() : ui_thread_(BrowserThread::UI, &message_loop_) {} |
902 | 903 |
903 virtual void SetUp() { | 904 virtual void SetUp() { |
904 login_db_ = new LoginDatabase(); | 905 login_db_ = new LoginDatabase(); |
905 ASSERT_TRUE(db_dir_.CreateUniqueTempDir()); | 906 ASSERT_TRUE(db_dir_.CreateUniqueTempDir()); |
906 FilePath db_file = db_dir_.path().AppendASCII("login.db"); | 907 FilePath db_file = db_dir_.path().AppendASCII("login.db"); |
907 ASSERT_TRUE(login_db_->Init(db_file)); | 908 ASSERT_TRUE(login_db_->Init(db_file)); |
908 | 909 |
909 keychain_ = new MockKeychain(); | 910 keychain_ = new MockAppleKeychain(); |
910 | 911 |
911 store_ = new PasswordStoreMac(keychain_, login_db_); | 912 store_ = new PasswordStoreMac(keychain_, login_db_); |
912 ASSERT_TRUE(store_->Init()); | 913 ASSERT_TRUE(store_->Init()); |
913 } | 914 } |
914 | 915 |
915 virtual void TearDown() { | 916 virtual void TearDown() { |
916 store_->ShutdownOnUIThread(); | 917 store_->ShutdownOnUIThread(); |
917 MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure()); | 918 MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure()); |
918 MessageLoop::current()->Run(); | 919 MessageLoop::current()->Run(); |
919 } | 920 } |
920 | 921 |
921 protected: | 922 protected: |
922 MessageLoopForUI message_loop_; | 923 MessageLoopForUI message_loop_; |
923 content::TestBrowserThread ui_thread_; | 924 content::TestBrowserThread ui_thread_; |
924 | 925 |
925 MockKeychain* keychain_; // Owned by store_. | 926 MockAppleKeychain* keychain_; // Owned by store_. |
926 LoginDatabase* login_db_; // Owned by store_. | 927 LoginDatabase* login_db_; // Owned by store_. |
927 scoped_refptr<PasswordStoreMac> store_; | 928 scoped_refptr<PasswordStoreMac> store_; |
928 ScopedTempDir db_dir_; | 929 ScopedTempDir db_dir_; |
929 }; | 930 }; |
930 | 931 |
931 TEST_F(PasswordStoreMacTest, TestStoreUpdate) { | 932 TEST_F(PasswordStoreMacTest, TestStoreUpdate) { |
932 // Insert a password into both the database and the keychain. | 933 // Insert a password into both the database and the keychain. |
933 // This is done manually, rather than through store_->AddLogin, because the | 934 // This is done manually, rather than through store_->AddLogin, because the |
934 // Mock Keychain isn't smart enough to be able to support update generically, | 935 // Mock Keychain isn't smart enough to be able to support update generically, |
935 // so some.domain.com triggers special handling to test it that make inserting | 936 // so some.domain.com triggers special handling to test it that make inserting |
936 // fail. | 937 // fail. |
937 PasswordFormData joint_data = { | 938 PasswordFormData joint_data = { |
938 PasswordForm::SCHEME_HTML, "http://some.domain.com/", | 939 PasswordForm::SCHEME_HTML, "http://some.domain.com/", |
939 "http://some.domain.com/insecure.html", "login.cgi", | 940 "http://some.domain.com/insecure.html", "login.cgi", |
940 L"username", L"password", L"submit", L"joe_user", L"sekrit", true, false, 1 | 941 L"username", L"password", L"submit", L"joe_user", L"sekrit", true, false, 1 |
941 }; | 942 }; |
942 scoped_ptr<PasswordForm> joint_form(CreatePasswordFormFromData(joint_data)); | 943 scoped_ptr<PasswordForm> joint_form(CreatePasswordFormFromData(joint_data)); |
943 login_db_->AddLogin(*joint_form); | 944 login_db_->AddLogin(*joint_form); |
944 MockKeychain::KeychainTestData joint_keychain_data = { | 945 MockAppleKeychain::KeychainTestData joint_keychain_data = { |
945 kSecAuthenticationTypeHTMLForm, "some.domain.com", | 946 kSecAuthenticationTypeHTMLForm, "some.domain.com", |
946 kSecProtocolTypeHTTP, "/insecure.html", 0, NULL, "20020601171500Z", | 947 kSecProtocolTypeHTTP, "/insecure.html", 0, NULL, "20020601171500Z", |
947 "joe_user", "sekrit", false }; | 948 "joe_user", "sekrit", false }; |
948 keychain_->AddTestItem(joint_keychain_data); | 949 keychain_->AddTestItem(joint_keychain_data); |
949 | 950 |
950 // Insert a password into the keychain only. | 951 // Insert a password into the keychain only. |
951 MockKeychain::KeychainTestData keychain_only_data = { | 952 MockAppleKeychain::KeychainTestData keychain_only_data = { |
952 kSecAuthenticationTypeHTMLForm, "keychain.only.com", | 953 kSecAuthenticationTypeHTMLForm, "keychain.only.com", |
953 kSecProtocolTypeHTTP, NULL, 0, NULL, "20020601171500Z", | 954 kSecProtocolTypeHTTP, NULL, 0, NULL, "20020601171500Z", |
954 "keychain", "only", false | 955 "keychain", "only", false |
955 }; | 956 }; |
956 keychain_->AddTestItem(keychain_only_data); | 957 keychain_->AddTestItem(keychain_only_data); |
957 | 958 |
958 struct UpdateData { | 959 struct UpdateData { |
959 PasswordFormData form_data; | 960 PasswordFormData form_data; |
960 const char* password; // NULL indicates no entry should be present. | 961 const char* password; // NULL indicates no entry should be present. |
961 }; | 962 }; |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1018 EXPECT_EQ(0U, matching_items.size()) << "iteration " << i; | 1019 EXPECT_EQ(0U, matching_items.size()) << "iteration " << i; |
1019 } | 1020 } |
1020 STLDeleteElements(&matching_items); | 1021 STLDeleteElements(&matching_items); |
1021 | 1022 |
1022 login_db_->GetLogins(*query_form, &matching_items); | 1023 login_db_->GetLogins(*query_form, &matching_items); |
1023 EXPECT_EQ(updates[i].password ? 1U : 0U, matching_items.size()) | 1024 EXPECT_EQ(updates[i].password ? 1U : 0U, matching_items.size()) |
1024 << "iteration " << i; | 1025 << "iteration " << i; |
1025 STLDeleteElements(&matching_items); | 1026 STLDeleteElements(&matching_items); |
1026 } | 1027 } |
1027 } | 1028 } |
OLD | NEW |