Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(339)

Side by Side Diff: chrome/browser/password_manager/password_store_mac_unittest.cc

Issue 115658: First phase of Mac Keychain integration. For the overall plan, see the design... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/password_manager/password_store_mac_internal.h ('k') | chrome/chrome.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2009 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 "testing/gtest/include/gtest/gtest.h"
6
7 #include "base/basictypes.h"
8 #include "chrome/browser/password_manager/password_store_mac.h"
9 #include "chrome/browser/password_manager/password_store_mac_internal.h"
10
11 #pragma mark Mock Keychain
12
13 // TODO(stuartmorgan): Replace this with gMock. You know, once we have it.
14 // The basic idea of this mock is that it has a static array of data to use
15 // for ItemCopyAttributesAndData, and SecKeychainItemRef values are just indexes
16 // into that array (offset by 1 to prevent problems with client null-checking
17 // refs), cast to pointers.
18 class MockKeychain : public MacKeychain {
19 public:
20 MockKeychain();
21 virtual ~MockKeychain();
22 virtual OSStatus ItemCopyAttributesAndData(
23 SecKeychainItemRef itemRef, SecKeychainAttributeInfo *info,
24 SecItemClass *itemClass, SecKeychainAttributeList **attrList,
25 UInt32 *length, void **outData) const;
26 virtual OSStatus ItemFreeAttributesAndData(SecKeychainAttributeList *attrList,
27 void *data) const;
28 virtual OSStatus SearchCreateFromAttributes(
29 CFTypeRef keychainOrArray, SecItemClass itemClass,
30 const SecKeychainAttributeList *attrList,
31 SecKeychainSearchRef *searchRef) const;
32 virtual OSStatus SearchCopyNext(SecKeychainSearchRef searchRef,
33 SecKeychainItemRef *itemRef) const;
34 virtual void Free(CFTypeRef ref) const;
35
36 // Causes a test failure unless everything returned from
37 // ItemCopyAttributesAndData, SearchCreateFromAttributes, and SearchCopyNext
38 // was correctly freed.
39 void ExpectCreatesAndFreesBalanced();
40
41 private:
42 // Sets the data and length of |tag| in the item-th test item based on
43 // |value|. The null-terminator will not be included; the Keychain Services
44 // docs don't indicate whether it is or not, so clients should not assume
45 // that it will be.
46 void SetTestDataString(int item, UInt32 tag, const char* value);
47 // Sets the data of the corresponding attribute of the item-th test item to
48 // |value|. Assumes that the space has alread been allocated, and the length
49 // set.
50 void SetTestDataPort(int item, UInt32 value);
51 void SetTestDataProtocol(int item, SecProtocolType value);
52 void SetTestDataAuthType(int item, SecAuthenticationType value);
53 void SetTestDataNegativeItem(int item, Boolean value);
54 // Sets the password for the item-th test item. As with SetTestDataString,
55 // the data will not be null-terminated.
56 void SetTestDataPassword(int item, const char* value);
57
58 // Returns the index of |tag| in |attribute_list|, or -1 if it's not found.
59 static int IndexForTag(const SecKeychainAttributeList& attribute_list,
60 UInt32 tag);
61
62 static const int kDummySearchRef = 1000;
63
64 typedef struct {
65 void* data;
66 UInt32 length;
67 } KeychainPasswordData;
68
69 SecKeychainAttributeList* keychain_attr_list_;
70 KeychainPasswordData* keychain_data_;
71 unsigned int item_count_;
72
73 // Tracks the items that should be returned in subsequent calls to
74 // SearchCopyNext, based on the last call to SearchCreateFromAttributes.
75 // We can't handle multiple active searches, since we don't track the search
76 // ref we return, but we don't need to for our mocking.
77 mutable std::vector<unsigned int> remaining_search_results_;
78
79 // Track copies and releases to make sure they balance. Really these should
80 // be maps to track per item, but this should be good enough to catch
81 // real mistakes.
82 mutable int search_copy_count_;
83 mutable int keychain_item_copy_count_;
84 mutable int attribute_data_copy_count_;
85 };
86
87 MockKeychain::MockKeychain()
88 : search_copy_count_(0), keychain_item_copy_count_(0),
89 attribute_data_copy_count_(0) {
90 UInt32 tags[] = { kSecAccountItemAttr,
91 kSecServerItemAttr,
92 kSecPortItemAttr,
93 kSecPathItemAttr,
94 kSecProtocolItemAttr,
95 kSecAuthenticationTypeItemAttr,
96 kSecSecurityDomainItemAttr,
97 kSecCreationDateItemAttr,
98 kSecNegativeItemAttr };
99
100 // Create the test keychain data to return from ItemCopyAttributesAndData,
101 // and set up everything that's consistent across all the items.
102 item_count_ = 8;
103 keychain_attr_list_ = static_cast<SecKeychainAttributeList*>(
104 calloc(item_count_, sizeof(SecKeychainAttributeList)));
105 keychain_data_ = static_cast<KeychainPasswordData*>(
106 calloc(item_count_, sizeof(KeychainPasswordData)));
107 for (unsigned int i = 0; i < item_count_; ++i) {
108 keychain_attr_list_[i].count = arraysize(tags);
109 keychain_attr_list_[i].attr = static_cast<SecKeychainAttribute*>(
110 calloc(keychain_attr_list_[i].count, sizeof(SecKeychainAttribute)));
111 for (unsigned int j = 0; j < keychain_attr_list_[i].count; ++j) {
112 keychain_attr_list_[i].attr[j].tag = tags[j];
113 size_t data_size = 0;
114 switch (tags[j]) {
115 case kSecPortItemAttr:
116 data_size = sizeof(UInt32);
117 break;
118 case kSecProtocolItemAttr:
119 data_size = sizeof(SecProtocolType);
120 break;
121 case kSecAuthenticationTypeItemAttr:
122 data_size = sizeof(SecAuthenticationType);
123 break;
124 case kSecNegativeItemAttr:
125 data_size = sizeof(Boolean);
126 break;
127 }
128 if (data_size > 0) {
129 keychain_attr_list_[i].attr[j].length = data_size;
130 keychain_attr_list_[i].attr[j].data = calloc(1, data_size);
131 }
132 }
133 }
134
135 // Basic HTML form.
136 unsigned int item = 0;
137 CHECK(item < item_count_);
138 SetTestDataString(item, kSecAccountItemAttr, "joe_user");
139 SetTestDataString(item, kSecServerItemAttr, "some.domain.com");
140 SetTestDataProtocol(item, kSecProtocolTypeHTTP);
141 SetTestDataAuthType(item, kSecAuthenticationTypeHTMLForm);
142 SetTestDataString(item, kSecCreationDateItemAttr, "20020601171500Z");
143 SetTestDataPassword(item, "sekrit");
144
145 // HTML form with path.
146 ++item;
147 CHECK(item < item_count_);
148 SetTestDataString(item, kSecAccountItemAttr, "joe_user");
149 SetTestDataString(item, kSecServerItemAttr, "some.domain.com");
150 SetTestDataString(item, kSecPathItemAttr, "insecure.html");
151 SetTestDataProtocol(item, kSecProtocolTypeHTTP);
152 SetTestDataAuthType(item, kSecAuthenticationTypeHTMLForm);
153 SetTestDataString(item, kSecCreationDateItemAttr, "19991231235959Z");
154 SetTestDataPassword(item, "sekrit");
155
156 // Secure HTML form with path.
157 ++item;
158 CHECK(item < item_count_);
159 SetTestDataString(item, kSecAccountItemAttr, "secure_user");
160 SetTestDataString(item, kSecServerItemAttr, "some.domain.com");
161 SetTestDataString(item, kSecPathItemAttr, "secure.html");
162 SetTestDataProtocol(item, kSecProtocolTypeHTTPS);
163 SetTestDataAuthType(item, kSecAuthenticationTypeHTMLForm);
164 SetTestDataString(item, kSecCreationDateItemAttr, "20100908070605Z");
165 SetTestDataPassword(item, "password");
166
167 // True negative item.
168 ++item;
169 CHECK(item < item_count_);
170 SetTestDataString(item, kSecServerItemAttr, "dont.remember.com");
171 SetTestDataProtocol(item, kSecProtocolTypeHTTP);
172 SetTestDataAuthType(item, kSecAuthenticationTypeHTMLForm);
173 SetTestDataString(item, kSecCreationDateItemAttr, "20000101000000Z");
174 SetTestDataNegativeItem(item, true);
175
176 // De-facto negative item, type one.
177 ++item;
178 CHECK(item < item_count_);
179 SetTestDataString(item, kSecAccountItemAttr, "Password Not Stored");
180 SetTestDataString(item, kSecServerItemAttr, "dont.remember.com");
181 SetTestDataProtocol(item, kSecProtocolTypeHTTP);
182 SetTestDataAuthType(item, kSecAuthenticationTypeHTMLForm);
183 SetTestDataString(item, kSecCreationDateItemAttr, "20000101000000Z");
184 SetTestDataPassword(item, "");
185
186 // De-facto negative item, type two.
187 ++item;
188 CHECK(item < item_count_);
189 SetTestDataString(item, kSecServerItemAttr, "dont.remember.com");
190 SetTestDataProtocol(item, kSecProtocolTypeHTTPS);
191 SetTestDataAuthType(item, kSecAuthenticationTypeHTMLForm);
192 SetTestDataString(item, kSecCreationDateItemAttr, "20000101000000Z");
193 SetTestDataPassword(item, " ");
194
195 // HTTP auth basic, with port and path.
196 ++item;
197 CHECK(item < item_count_);
198 SetTestDataString(item, kSecAccountItemAttr, "basic_auth_user");
199 SetTestDataString(item, kSecServerItemAttr, "some.domain.com");
200 SetTestDataString(item, kSecSecurityDomainItemAttr, "low_security");
201 SetTestDataString(item, kSecPathItemAttr, "insecure.html");
202 SetTestDataProtocol(item, kSecProtocolTypeHTTP);
203 SetTestDataPort(item, 4567);
204 SetTestDataAuthType(item, kSecAuthenticationTypeHTTPBasic);
205 SetTestDataString(item, kSecCreationDateItemAttr, "19980330100000Z");
206 SetTestDataPassword(item, "basic");
207
208 // HTTP auth digest, secure.
209 ++item;
210 CHECK(item < item_count_);
211 SetTestDataString(item, kSecAccountItemAttr, "digest_auth_user");
212 SetTestDataString(item, kSecServerItemAttr, "some.domain.com");
213 SetTestDataString(item, kSecSecurityDomainItemAttr, "high_security");
214 SetTestDataProtocol(item, kSecProtocolTypeHTTPS);
215 SetTestDataAuthType(item, kSecAuthenticationTypeHTTPDigest);
216 SetTestDataString(item, kSecCreationDateItemAttr, "19980330100000Z");
217 SetTestDataPassword(item, "digest");
218 }
219
220 MockKeychain::~MockKeychain() {
221 for (unsigned int i = 0; i < item_count_; ++i) {
222 for (unsigned int j = 0; j < keychain_attr_list_[i].count; ++j) {
223 if (keychain_attr_list_[i].attr[j].data) {
224 free(keychain_attr_list_[i].attr[j].data);
225 }
226 }
227 free(keychain_attr_list_[i].attr);
228 if (keychain_data_[i].data) {
229 free(keychain_data_[i].data);
230 }
231 }
232 free(keychain_attr_list_);
233 free(keychain_data_);
234 }
235
236 void MockKeychain::ExpectCreatesAndFreesBalanced() {
237 EXPECT_EQ(0, search_copy_count_);
238 EXPECT_EQ(0, keychain_item_copy_count_);
239 EXPECT_EQ(0, attribute_data_copy_count_);
240 }
241
242 int MockKeychain::IndexForTag(const SecKeychainAttributeList& attribute_list,
243 UInt32 tag) {
244 for (unsigned int i = 0; i < attribute_list.count; ++i) {
245 if (attribute_list.attr[i].tag == tag) {
246 return i;
247 }
248 }
249 DCHECK(false);
250 return -1;
251 }
252
253 void MockKeychain::SetTestDataString(int item, UInt32 tag, const char* value) {
254 int attribute_index = IndexForTag(keychain_attr_list_[item], tag);
255 size_t data_size = strlen(value);
256 keychain_attr_list_[item].attr[attribute_index].length = data_size;
257 if (data_size > 0) {
258 keychain_attr_list_[item].attr[attribute_index].data = malloc(data_size);
259 // Use memcpy rather than str*cpy because we are deliberately omitting the
260 // null-terminator (see method declaration comment).
261 CHECK(keychain_attr_list_[item].attr[attribute_index].data);
262 memcpy(keychain_attr_list_[item].attr[attribute_index].data, value,
263 data_size);
264 } else {
265 keychain_attr_list_[item].attr[attribute_index].data = NULL;
266 }
267 }
268
269 void MockKeychain::SetTestDataPort(int item, UInt32 value) {
270 int attribute_index = IndexForTag(keychain_attr_list_[item],
271 kSecPortItemAttr);
272 void* data = keychain_attr_list_[item].attr[attribute_index].data;
273 *(static_cast<UInt32*>(data)) = value;
274 }
275
276 void MockKeychain::SetTestDataProtocol(int item, SecProtocolType value) {
277 int attribute_index = IndexForTag(keychain_attr_list_[item],
278 kSecProtocolItemAttr);
279 void* data = keychain_attr_list_[item].attr[attribute_index].data;
280 *(static_cast<SecProtocolType*>(data)) = value;
281 }
282
283 void MockKeychain::SetTestDataAuthType(int item, SecAuthenticationType value) {
284 int attribute_index = IndexForTag(keychain_attr_list_[item],
285 kSecAuthenticationTypeItemAttr);
286 void* data = keychain_attr_list_[item].attr[attribute_index].data;
287 *(static_cast<SecAuthenticationType*>(data)) = value;
288 }
289
290 void MockKeychain::SetTestDataNegativeItem(int item, Boolean value) {
291 int attribute_index = IndexForTag(keychain_attr_list_[item],
292 kSecNegativeItemAttr);
293 void* data = keychain_attr_list_[item].attr[attribute_index].data;
294 *(static_cast<Boolean*>(data)) = value;
295 }
296
297 void MockKeychain::SetTestDataPassword(int item, const char* value) {
298 size_t data_size = strlen(value);
299 keychain_data_[item].length = data_size;
300 if (data_size > 0) {
301 keychain_data_[item].data = malloc(data_size);
302 // Use memcpy rather than str*cpy because we are deliberately omitting the
303 // null-terminator (see method declaration comment).
304 memcpy(keychain_data_[item].data, value, data_size);
305 } else {
306 keychain_data_[item].data = NULL;
307 }
308 }
309
310 OSStatus MockKeychain::ItemCopyAttributesAndData(
311 SecKeychainItemRef itemRef, SecKeychainAttributeInfo *info,
312 SecItemClass *itemClass, SecKeychainAttributeList **attrList,
313 UInt32 *length, void **outData) const {
314 DCHECK(itemRef);
315 unsigned int item_index = reinterpret_cast<unsigned int>(itemRef) - 1;
316 if (item_index >= item_count_) {
317 return errSecInvalidItemRef;
318 }
319
320 DCHECK(!itemClass); // itemClass not implemented in the Mock.
321 if (attrList) {
322 *attrList = &(keychain_attr_list_[item_index]);
323 }
324 if (outData) {
325 *outData = keychain_data_[item_index].data;
326 DCHECK(length);
327 *length = keychain_data_[item_index].length;
328 }
329
330 ++attribute_data_copy_count_;
331 return noErr;
332 }
333
334 OSStatus MockKeychain::ItemFreeAttributesAndData(
335 SecKeychainAttributeList *attrList,
336 void *data) const {
337 --attribute_data_copy_count_;
338 return noErr;
339 }
340
341 OSStatus MockKeychain::SearchCreateFromAttributes(
342 CFTypeRef keychainOrArray, SecItemClass itemClass,
343 const SecKeychainAttributeList *attrList,
344 SecKeychainSearchRef *searchRef) const {
345 // Figure out which of our mock items matches, and set up the array we'll use
346 // to generate results out of SearchCopyNext.
347 remaining_search_results_.clear();
348 for (unsigned int mock_item = 0; mock_item < item_count_; ++mock_item) {
349 bool mock_item_matches = true;
350 for (UInt32 search_attr = 0; search_attr < attrList->count; ++search_attr) {
351 int mock_attr = IndexForTag(keychain_attr_list_[mock_item],
352 attrList->attr[search_attr].tag);
353 SecKeychainAttribute* mock_attribute =
354 &(keychain_attr_list_[mock_item].attr[mock_attr]);
355 if (mock_attribute->length != attrList->attr[search_attr].length ||
356 memcmp(mock_attribute->data, attrList->attr[search_attr].data,
357 attrList->attr[search_attr].length) != 0) {
358 mock_item_matches = false;
359 break;
360 }
361 }
362 if (mock_item_matches) {
363 remaining_search_results_.push_back(mock_item);
364 }
365 }
366
367 DCHECK(searchRef);
368 *searchRef = reinterpret_cast<SecKeychainSearchRef>(kDummySearchRef);
369 ++search_copy_count_;
370 return noErr;
371 }
372
373 OSStatus MockKeychain::SearchCopyNext(SecKeychainSearchRef searchRef,
374 SecKeychainItemRef *itemRef) const {
375 if (remaining_search_results_.empty()) {
376 return errSecItemNotFound;
377 }
378 unsigned int index = remaining_search_results_.front();
379 remaining_search_results_.erase(remaining_search_results_.begin());
380 *itemRef = reinterpret_cast<SecKeychainItemRef>(index + 1);
381 ++keychain_item_copy_count_;
382 return noErr;
383 }
384
385 void MockKeychain::Free(CFTypeRef ref) const {
386 if (!ref) {
387 return;
388 }
389
390 if (reinterpret_cast<int>(ref) == kDummySearchRef) {
391 --search_copy_count_;
392 } else {
393 --keychain_item_copy_count_;
394 }
395 }
396
397 #pragma mark Unit Tests
398 ////////////////////////////////////////////////////////////////////////////////
399
400 TEST(PasswordStoreMacTest, TestSignonRealmParsing) {
401 typedef struct {
402 const char* signon_realm;
403 const bool expected_parsed;
404 const char* expected_server;
405 const bool expected_is_secure;
406 const int expected_port;
407 const char* expected_security_domain;
408 } TestData;
409
410 TestData test_data[] = {
411 // HTML form signon realms.
412 { "http://www.domain.com/",
413 true, "www.domain.com", false, 0, "" },
414 { "https://foo.org:9999/",
415 true, "foo.org", true, 9999, "" },
416 // HTTP auth signon realms.
417 { "http://httpauth.com:8080/lowsecurity",
418 true, "httpauth.com", false, 8080, "lowsecurity" },
419 { "https://httpauth.com/highsecurity",
420 true, "httpauth.com", true, 0 , "highsecurity" },
421 // Bogus realms
422 { "blahblahblah",
423 false, false, "", 0, "" },
424 { "foo/bar/baz",
425 false, false, "", 0, "" },
426 };
427
428 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(test_data); ++i) {
429 std::string server;
430 std::string security_domain;
431 bool is_secure = false;
432 int port = -1;
433 bool parsed = internal_keychain_helpers::ExtractSignonRealmComponents(
434 std::string(test_data[i].signon_realm), &server, &port, &is_secure,
435 &security_domain);
436 EXPECT_EQ(test_data[i].expected_parsed, parsed) << "In iteration " << i;
437
438 if (!parsed) {
439 continue; // If parse failed, out params are undefined.
440 }
441 EXPECT_EQ(std::string(test_data[i].expected_server), server)
442 << "In iteration " << i;
443 EXPECT_EQ(std::string(test_data[i].expected_security_domain),
444 security_domain)
445 << "In iteration " << i;
446 EXPECT_EQ(test_data[i].expected_is_secure, is_secure)
447 << "In iteration " << i;
448 EXPECT_EQ(test_data[i].expected_port, port) << "In iteration " << i;
449 }
450
451 // NULLs are allowed for out params.
452 bool parsed = internal_keychain_helpers::ExtractSignonRealmComponents(
453 std::string("http://foo.bar.com:1234/baz"), NULL, NULL, NULL, NULL);
454 EXPECT_TRUE(parsed);
455 }
456
457 TEST(PasswordStoreMacTest, TestURLConstruction) {
458 std::string host("exampledomain.com");
459 std::string path("/path/to/page.html");
460
461 GURL full_url = internal_keychain_helpers::URLFromComponents(false, host,
462 1234, path);
463 EXPECT_TRUE(full_url.is_valid());
464 EXPECT_EQ(GURL("http://exampledomain.com:1234/path/to/page.html"), full_url);
465
466 GURL simple_secure_url = internal_keychain_helpers::URLFromComponents(
467 true, host, 0, std::string(""));
468 EXPECT_TRUE(simple_secure_url.is_valid());
469 EXPECT_EQ(GURL("https://exampledomain.com/"), simple_secure_url);
470 }
471
472 TEST(PasswordStoreMacTest, TestKeychainTime) {
473 typedef struct {
474 const char* time_string;
475 const bool expected_parsed;
476 const int expected_year;
477 const int expected_month;
478 const int expected_day;
479 const int expected_hour;
480 const int expected_minute;
481 const int expected_second;
482 } TestData;
483
484 TestData test_data[] = {
485 // HTML form signon realms.
486 { "19980330100000Z", true, 1998, 3, 30, 10, 0, 0 },
487 { "19991231235959Z", true, 1999, 12, 31, 23, 59, 59 },
488 { "20000101000000Z", true, 2000, 1, 1, 0, 0, 0 },
489 { "20011112012843Z", true, 2001, 11, 12, 1, 28, 43 },
490 { "20020601171530Z", true, 2002, 6, 1, 17, 15, 30 },
491 { "20100908070605Z", true, 2010, 9, 8, 7, 6, 5 },
492 { "20010203040", false, 0, 0, 0, 0, 0, 0 },
493 };
494
495 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(test_data); ++i) {
496 base::Time time;
497 bool parsed = internal_keychain_helpers::TimeFromKeychainTimeString(
498 test_data[i].time_string, strlen(test_data[i].time_string), &time);
499 EXPECT_EQ(test_data[i].expected_parsed, parsed) << "In iteration " << i;
500 if (!parsed) {
501 continue;
502 }
503
504 base::Time::Exploded exploded_time;
505 time.UTCExplode(&exploded_time);
506 EXPECT_EQ(test_data[i].expected_year, exploded_time.year)
507 << "In iteration " << i;
508 EXPECT_EQ(test_data[i].expected_month, exploded_time.month)
509 << "In iteration " << i;
510 EXPECT_EQ(test_data[i].expected_day, exploded_time.day_of_month)
511 << "In iteration " << i;
512 EXPECT_EQ(test_data[i].expected_hour, exploded_time.hour)
513 << "In iteration " << i;
514 EXPECT_EQ(test_data[i].expected_minute, exploded_time.minute)
515 << "In iteration " << i;
516 EXPECT_EQ(test_data[i].expected_second, exploded_time.second)
517 << "In iteration " << i;
518 }
519 }
520
521 TEST(PasswordStoreMacTest, TestAuthTypeSchemeTranslation) {
522 // Our defined types should round-trip correctly.
523 SecAuthenticationType auth_types[] = { kSecAuthenticationTypeHTMLForm,
524 kSecAuthenticationTypeHTTPBasic,
525 kSecAuthenticationTypeHTTPDigest };
526 const int auth_count = sizeof(auth_types) / sizeof(SecAuthenticationType);
527 for (int i = 0; i < auth_count; ++i) {
528 SecAuthenticationType round_tripped_auth_type =
529 internal_keychain_helpers::AuthTypeForScheme(
530 internal_keychain_helpers::SchemeForAuthType(auth_types[i]));
531 EXPECT_EQ(auth_types[i], round_tripped_auth_type);
532 }
533 // Anything else should become SCHEME_OTHER and come back as Default.
534 PasswordForm::Scheme scheme_for_other_auth_type =
535 internal_keychain_helpers::SchemeForAuthType(kSecAuthenticationTypeNTLM);
536 SecAuthenticationType round_tripped_other_auth_type =
537 internal_keychain_helpers::AuthTypeForScheme(scheme_for_other_auth_type);
538 EXPECT_EQ(PasswordForm::SCHEME_OTHER, scheme_for_other_auth_type);
539 EXPECT_EQ(kSecAuthenticationTypeDefault, round_tripped_other_auth_type);
540 }
541
542 TEST(PasswordStoreMacTest, TestKeychainToFormTranslation) {
543 typedef struct {
544 const PasswordForm::Scheme scheme;
545 const char* signon_realm;
546 const char* origin;
547 const wchar_t* username; // Set to NULL to check for a blacklist entry.
548 const wchar_t* password;
549 const bool ssl_valid;
550 const int creation_year;
551 const int creation_month;
552 const int creation_day;
553 const int creation_hour;
554 const int creation_minute;
555 const int creation_second;
556 } TestExpectations;
557
558 TestExpectations expected[] = {
559 { PasswordForm::SCHEME_HTML, "http://some.domain.com/",
560 "http://some.domain.com/", L"joe_user", L"sekrit", false,
561 2002, 6, 1, 17, 15, 0 },
562 { PasswordForm::SCHEME_HTML, "http://some.domain.com/",
563 "http://some.domain.com/insecure.html", L"joe_user", L"sekrit", false,
564 1999, 12, 31, 23, 59, 59 },
565 { PasswordForm::SCHEME_HTML, "https://some.domain.com/",
566 "https://some.domain.com/secure.html", L"secure_user", L"password", true,
567 2010, 9, 8, 7, 6, 5 },
568 { PasswordForm::SCHEME_HTML, "http://dont.remember.com/",
569 "http://dont.remember.com/", NULL, NULL, false,
570 2000, 1, 1, 0, 0, 0 },
571 { PasswordForm::SCHEME_HTML, "http://dont.remember.com/",
572 "http://dont.remember.com/", NULL, NULL, false,
573 2000, 1, 1, 0, 0, 0 },
574 { PasswordForm::SCHEME_HTML, "https://dont.remember.com/",
575 "https://dont.remember.com/", NULL, NULL, true,
576 2000, 1, 1, 0, 0, 0 },
577 { PasswordForm::SCHEME_BASIC, "http://some.domain.com:4567/low_security",
578 "http://some.domain.com:4567/insecure.html", L"basic_auth_user", L"basic",
579 false, 1998, 03, 30, 10, 00, 00 },
580 { PasswordForm::SCHEME_DIGEST, "https://some.domain.com/high_security",
581 "https://some.domain.com/", L"digest_auth_user", L"digest", true,
582 1998, 3, 30, 10, 0, 0 },
583 };
584
585 MockKeychain mock_keychain;
586
587 for (unsigned int i = 0; i < ARRAYSIZE_UNSAFE(expected); ++i) {
588 // Create our fake KeychainItemRef; see MockKeychain docs.
589 SecKeychainItemRef keychain_item =
590 reinterpret_cast<SecKeychainItemRef>(i + 1);
591 PasswordForm form;
592 bool parsed = internal_keychain_helpers::FillPasswordFormFromKeychainItem(
593 mock_keychain, keychain_item, &form);
594
595 EXPECT_TRUE(parsed) << "In iteration " << i;
596 mock_keychain.ExpectCreatesAndFreesBalanced();
597
598 EXPECT_EQ(expected[i].scheme, form.scheme) << "In iteration " << i;
599 EXPECT_EQ(GURL(expected[i].origin), form.origin) << "In iteration " << i;
600 EXPECT_EQ(expected[i].ssl_valid, form.ssl_valid) << "In iteration " << i;
601 EXPECT_EQ(std::string(expected[i].signon_realm), form.signon_realm)
602 << "In iteration " << i;
603 if (expected[i].username) {
604 EXPECT_EQ(std::wstring(expected[i].username), form.username_value)
605 << "In iteration " << i;
606 EXPECT_EQ(std::wstring(expected[i].password), form.password_value)
607 << "In iteration " << i;
608 EXPECT_FALSE(form.blacklisted_by_user) << "In iteration " << i;
609 } else {
610 EXPECT_TRUE(form.blacklisted_by_user) << "In iteration " << i;
611 }
612 base::Time::Exploded exploded_time;
613 form.date_created.UTCExplode(&exploded_time);
614 EXPECT_EQ(expected[i].creation_year, exploded_time.year)
615 << "In iteration " << i;
616 EXPECT_EQ(expected[i].creation_month, exploded_time.month)
617 << "In iteration " << i;
618 EXPECT_EQ(expected[i].creation_day, exploded_time.day_of_month)
619 << "In iteration " << i;
620 EXPECT_EQ(expected[i].creation_hour, exploded_time.hour)
621 << "In iteration " << i;
622 EXPECT_EQ(expected[i].creation_minute, exploded_time.minute)
623 << "In iteration " << i;
624 EXPECT_EQ(expected[i].creation_second, exploded_time.second)
625 << "In iteration " << i;
626 }
627
628 {
629 // Use an invalid ref, to make sure errors are reported.
630 SecKeychainItemRef keychain_item = reinterpret_cast<SecKeychainItemRef>(99);
631 PasswordForm form;
632 bool parsed = internal_keychain_helpers::FillPasswordFormFromKeychainItem(
633 mock_keychain, keychain_item, &form);
634 mock_keychain.ExpectCreatesAndFreesBalanced();
635 EXPECT_FALSE(parsed);
636 }
637 }
638
639 static void FreeKeychainItems(const MacKeychain& keychain,
640 std::vector<SecKeychainItemRef>* items) {
641 for (std::vector<SecKeychainItemRef>::iterator i = items->begin();
642 i != items->end(); ++i) {
643 keychain.Free(*i);
644 }
645 items->clear();
646 }
647
648 TEST(PasswordStoreMacTest, TestKeychainSearch) {
649 MockKeychain mock_keychain;
650
651 { // An HTML form we've seen.
652 std::vector<SecKeychainItemRef> matching_items;
653 internal_keychain_helpers::FindMatchingKeychainItems(
654 mock_keychain, std::string("http://some.domain.com/"),
655 PasswordForm::SCHEME_HTML, &matching_items);
656 EXPECT_EQ(static_cast<size_t>(2), matching_items.size());
657 FreeKeychainItems(mock_keychain, &matching_items);
658 mock_keychain.ExpectCreatesAndFreesBalanced();
659 }
660
661 { // An HTML form we haven't seen
662 std::vector<SecKeychainItemRef> matching_items;
663 internal_keychain_helpers::FindMatchingKeychainItems(
664 mock_keychain, std::string("http://www.unseendomain.com/"),
665 PasswordForm::SCHEME_HTML, &matching_items);
666 EXPECT_EQ(static_cast<size_t>(0), matching_items.size());
667 FreeKeychainItems(mock_keychain, &matching_items);
668 mock_keychain.ExpectCreatesAndFreesBalanced();
669 }
670
671 { // Basic auth that should match.
672 std::vector<SecKeychainItemRef> matching_items;
673 internal_keychain_helpers::FindMatchingKeychainItems(
674 mock_keychain, std::string("http://some.domain.com:4567/low_security"),
675 PasswordForm::SCHEME_BASIC, &matching_items);
676 EXPECT_EQ(static_cast<size_t>(1), matching_items.size());
677 FreeKeychainItems(mock_keychain, &matching_items);
678 mock_keychain.ExpectCreatesAndFreesBalanced();
679 }
680
681 { // Basic auth with the wrong port.
682 std::vector<SecKeychainItemRef> matching_items;
683 internal_keychain_helpers::FindMatchingKeychainItems(
684 mock_keychain, std::string("http://some.domain.com:1111/low_security"),
685 PasswordForm::SCHEME_BASIC, &matching_items);
686 EXPECT_EQ(static_cast<size_t>(0), matching_items.size());
687 FreeKeychainItems(mock_keychain, &matching_items);
688 mock_keychain.ExpectCreatesAndFreesBalanced();
689 }
690
691 { // Digest auth we've saved under https, visited with http.
692 std::vector<SecKeychainItemRef> matching_items;
693 internal_keychain_helpers::FindMatchingKeychainItems(
694 mock_keychain, std::string("http://some.domain.com/high_security"),
695 PasswordForm::SCHEME_DIGEST, &matching_items);
696 EXPECT_EQ(static_cast<size_t>(0), matching_items.size());
697 FreeKeychainItems(mock_keychain, &matching_items);
698 mock_keychain.ExpectCreatesAndFreesBalanced();
699 }
700
701 { // Digest auth that should match.
702 std::vector<SecKeychainItemRef> matching_items;
703 internal_keychain_helpers::FindMatchingKeychainItems(
704 mock_keychain, std::string("https://some.domain.com/high_security"),
705 PasswordForm::SCHEME_DIGEST, &matching_items);
706 EXPECT_EQ(static_cast<size_t>(1), matching_items.size());
707 FreeKeychainItems(mock_keychain, &matching_items);
708 mock_keychain.ExpectCreatesAndFreesBalanced();
709 }
710 }
OLDNEW
« no previous file with comments | « chrome/browser/password_manager/password_store_mac_internal.h ('k') | chrome/chrome.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698