diff options
author | stuartmorgan@chromium.org <stuartmorgan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-23 18:56:34 +0000 |
---|---|---|
committer | stuartmorgan@chromium.org <stuartmorgan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-23 18:56:34 +0000 |
commit | 12eb8e78f183c10e08df3dbb080c09669df94424 (patch) | |
tree | 1bac8d46beafd943662d147145ad3afcd4a98115 /chrome/browser/keychain_mock_mac.cc | |
parent | d7e5b443612b102a8d2adf5717bc571136e788dd (diff) | |
download | chromium_src-12eb8e78f183c10e08df3dbb080c09669df94424.zip chromium_src-12eb8e78f183c10e08df3dbb080c09669df94424.tar.gz chromium_src-12eb8e78f183c10e08df3dbb080c09669df94424.tar.bz2 |
Move MockKeychain into its own file.
The unit test file has become very unwieldy, and I no longer believe that the
Keychain mock is temporary code that should be replaced with GMock (since the
dummy implementation makes certain tests much easier).
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/146041
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@19041 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/keychain_mock_mac.cc')
-rw-r--r-- | chrome/browser/keychain_mock_mac.cc | 408 |
1 files changed, 408 insertions, 0 deletions
diff --git a/chrome/browser/keychain_mock_mac.cc b/chrome/browser/keychain_mock_mac.cc new file mode 100644 index 0000000..858fdb6 --- /dev/null +++ b/chrome/browser/keychain_mock_mac.cc @@ -0,0 +1,408 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/logging.h" +#include "base/time.h" +#include "chrome/browser/keychain_mock_mac.h" + +MockKeychain::MockKeychain() + : search_copy_count_(0), keychain_item_copy_count_(0), + attribute_data_copy_count_(0) { + UInt32 tags[] = { kSecAccountItemAttr, + kSecServerItemAttr, + kSecPortItemAttr, + kSecPathItemAttr, + kSecProtocolItemAttr, + kSecAuthenticationTypeItemAttr, + kSecSecurityDomainItemAttr, + kSecCreationDateItemAttr, + kSecNegativeItemAttr }; + + // Create the test keychain data to return from ItemCopyAttributesAndData, + // and set up everything that's consistent across all the items. + item_capacity_ = 9; + keychain_attr_list_ = static_cast<SecKeychainAttributeList*>( + calloc(item_capacity_, sizeof(SecKeychainAttributeList))); + keychain_data_ = static_cast<KeychainPasswordData*>( + calloc(item_capacity_, sizeof(KeychainPasswordData))); + for (unsigned int i = 0; i < item_capacity_; ++i) { + keychain_attr_list_[i].count = arraysize(tags); + keychain_attr_list_[i].attr = static_cast<SecKeychainAttribute*>( + calloc(keychain_attr_list_[i].count, sizeof(SecKeychainAttribute))); + for (unsigned int j = 0; j < keychain_attr_list_[i].count; ++j) { + keychain_attr_list_[i].attr[j].tag = tags[j]; + size_t data_size = 0; + switch (tags[j]) { + case kSecPortItemAttr: + data_size = sizeof(UInt32); + break; + case kSecProtocolItemAttr: + data_size = sizeof(SecProtocolType); + break; + case kSecAuthenticationTypeItemAttr: + data_size = sizeof(SecAuthenticationType); + break; + case kSecNegativeItemAttr: + data_size = sizeof(Boolean); + break; + } + if (data_size > 0) { + keychain_attr_list_[i].attr[j].length = data_size; + keychain_attr_list_[i].attr[j].data = calloc(1, data_size); + } + } + } + + // Save one slot for use by AddInternetPassword. + unsigned int available_slots = item_capacity_ - 1; + item_count_ = 0; + + // Basic HTML form. + CHECK(item_count_ < available_slots); + SetTestDataString(item_count_, kSecAccountItemAttr, "joe_user"); + SetTestDataString(item_count_, kSecServerItemAttr, "some.domain.com"); + SetTestDataProtocol(item_count_, kSecProtocolTypeHTTP); + SetTestDataAuthType(item_count_, kSecAuthenticationTypeHTMLForm); + SetTestDataString(item_count_, kSecCreationDateItemAttr, "20020601171500Z"); + SetTestDataPasswordString(item_count_, "sekrit"); + ++item_count_; + + // HTML form with path. + CHECK(item_count_ < available_slots); + SetTestDataString(item_count_, kSecAccountItemAttr, "joe_user"); + SetTestDataString(item_count_, kSecServerItemAttr, "some.domain.com"); + SetTestDataString(item_count_, kSecPathItemAttr, "/insecure.html"); + SetTestDataProtocol(item_count_, kSecProtocolTypeHTTP); + SetTestDataAuthType(item_count_, kSecAuthenticationTypeHTMLForm); + SetTestDataString(item_count_, kSecCreationDateItemAttr, "19991231235959Z"); + SetTestDataPasswordString(item_count_, "sekrit"); + ++item_count_; + + // Secure HTML form with path. + CHECK(item_count_ < available_slots); + SetTestDataString(item_count_, kSecAccountItemAttr, "secure_user"); + SetTestDataString(item_count_, kSecServerItemAttr, "some.domain.com"); + SetTestDataString(item_count_, kSecPathItemAttr, "/secure.html"); + SetTestDataProtocol(item_count_, kSecProtocolTypeHTTPS); + SetTestDataAuthType(item_count_, kSecAuthenticationTypeHTMLForm); + SetTestDataString(item_count_, kSecCreationDateItemAttr, "20100908070605Z"); + SetTestDataPasswordString(item_count_, "password"); + ++item_count_; + + // True negative item. + CHECK(item_count_ < available_slots); + SetTestDataString(item_count_, kSecServerItemAttr, "dont.remember.com"); + SetTestDataProtocol(item_count_, kSecProtocolTypeHTTP); + SetTestDataAuthType(item_count_, kSecAuthenticationTypeHTMLForm); + SetTestDataString(item_count_, kSecCreationDateItemAttr, "20000101000000Z"); + SetTestDataNegativeItem(item_count_, true); + ++item_count_; + + // De-facto negative item, type one. + CHECK(item_count_ < available_slots); + SetTestDataString(item_count_, kSecAccountItemAttr, "Password Not Stored"); + SetTestDataString(item_count_, kSecServerItemAttr, "dont.remember.com"); + SetTestDataProtocol(item_count_, kSecProtocolTypeHTTP); + SetTestDataAuthType(item_count_, kSecAuthenticationTypeHTMLForm); + SetTestDataString(item_count_, kSecCreationDateItemAttr, "20000101000000Z"); + SetTestDataPasswordString(item_count_, ""); + ++item_count_; + + // De-facto negative item, type two. + CHECK(item_count_ < available_slots); + SetTestDataString(item_count_, kSecServerItemAttr, "dont.remember.com"); + SetTestDataProtocol(item_count_, kSecProtocolTypeHTTPS); + SetTestDataAuthType(item_count_, kSecAuthenticationTypeHTMLForm); + SetTestDataString(item_count_, kSecCreationDateItemAttr, "20000101000000Z"); + SetTestDataPasswordString(item_count_, " "); + ++item_count_; + + // HTTP auth basic, with port and path. + CHECK(item_count_ < available_slots); + SetTestDataString(item_count_, kSecAccountItemAttr, "basic_auth_user"); + SetTestDataString(item_count_, kSecServerItemAttr, "some.domain.com"); + SetTestDataString(item_count_, kSecSecurityDomainItemAttr, "low_security"); + SetTestDataString(item_count_, kSecPathItemAttr, "/insecure.html"); + SetTestDataProtocol(item_count_, kSecProtocolTypeHTTP); + SetTestDataPort(item_count_, 4567); + SetTestDataAuthType(item_count_, kSecAuthenticationTypeHTTPBasic); + SetTestDataString(item_count_, kSecCreationDateItemAttr, "19980330100000Z"); + SetTestDataPasswordString(item_count_, "basic"); + ++item_count_; + + // HTTP auth digest, secure. + CHECK(item_count_ < available_slots); + SetTestDataString(item_count_, kSecAccountItemAttr, "digest_auth_user"); + SetTestDataString(item_count_, kSecServerItemAttr, "some.domain.com"); + SetTestDataString(item_count_, kSecSecurityDomainItemAttr, "high_security"); + SetTestDataProtocol(item_count_, kSecProtocolTypeHTTPS); + SetTestDataAuthType(item_count_, kSecAuthenticationTypeHTTPDigest); + SetTestDataString(item_count_, kSecCreationDateItemAttr, "19980330100000Z"); + SetTestDataPasswordString(item_count_, "digest"); + ++item_count_; +} + +MockKeychain::~MockKeychain() { + for (unsigned int i = 0; i < item_capacity_; ++i) { + for (unsigned int j = 0; j < keychain_attr_list_[i].count; ++j) { + if (keychain_attr_list_[i].attr[j].data) { + free(keychain_attr_list_[i].attr[j].data); + } + } + free(keychain_attr_list_[i].attr); + if (keychain_data_[i].data) { + free(keychain_data_[i].data); + } + } + free(keychain_attr_list_); + free(keychain_data_); +} + +int MockKeychain::IndexForTag(const SecKeychainAttributeList& attribute_list, + UInt32 tag) { + for (unsigned int i = 0; i < attribute_list.count; ++i) { + if (attribute_list.attr[i].tag == tag) { + return i; + } + } + DCHECK(false); + return -1; +} + +void MockKeychain::SetTestDataBytes(int item, UInt32 tag, const void* data, + size_t length) const { + int attribute_index = IndexForTag(keychain_attr_list_[item], tag); + keychain_attr_list_[item].attr[attribute_index].length = length; + if (length > 0) { + if (keychain_attr_list_[item].attr[attribute_index].data) { + free(keychain_attr_list_[item].attr[attribute_index].data); + } + keychain_attr_list_[item].attr[attribute_index].data = malloc(length); + CHECK(keychain_attr_list_[item].attr[attribute_index].data); + memcpy(keychain_attr_list_[item].attr[attribute_index].data, data, length); + } else { + keychain_attr_list_[item].attr[attribute_index].data = NULL; + } +} + +void MockKeychain::SetTestDataString(int item, UInt32 tag, + const char* value) const { + SetTestDataBytes(item, tag, value, value ? strlen(value) : 0); +} + +void MockKeychain::SetTestDataPort(int item, UInt32 value) const { + int attribute_index = IndexForTag(keychain_attr_list_[item], + kSecPortItemAttr); + void* data = keychain_attr_list_[item].attr[attribute_index].data; + *(static_cast<UInt32*>(data)) = value; +} + +void MockKeychain::SetTestDataProtocol(int item, SecProtocolType value) const { + int attribute_index = IndexForTag(keychain_attr_list_[item], + kSecProtocolItemAttr); + void* data = keychain_attr_list_[item].attr[attribute_index].data; + *(static_cast<SecProtocolType*>(data)) = value; +} + +void MockKeychain::SetTestDataAuthType(int item, + SecAuthenticationType value) const { + int attribute_index = IndexForTag(keychain_attr_list_[item], + kSecAuthenticationTypeItemAttr); + void* data = keychain_attr_list_[item].attr[attribute_index].data; + *(static_cast<SecAuthenticationType*>(data)) = value; +} + +void MockKeychain::SetTestDataNegativeItem(int item, Boolean value) const { + int attribute_index = IndexForTag(keychain_attr_list_[item], + kSecNegativeItemAttr); + void* data = keychain_attr_list_[item].attr[attribute_index].data; + *(static_cast<Boolean*>(data)) = value; +} + +void MockKeychain::SetTestDataPasswordBytes(int item, const void* data, + size_t length) const { + keychain_data_[item].length = length; + if (length > 0) { + if (keychain_data_[item].data) { + free(keychain_data_[item].data); + } + keychain_data_[item].data = malloc(length); + memcpy(keychain_data_[item].data, data, length); + } else { + keychain_data_[item].data = NULL; + } +} + +void MockKeychain::SetTestDataPasswordString(int item, + const char* value) const { + SetTestDataPasswordBytes(item, value, value ? strlen(value) : 0); +} + +OSStatus MockKeychain::ItemCopyAttributesAndData( + SecKeychainItemRef itemRef, SecKeychainAttributeInfo *info, + SecItemClass *itemClass, SecKeychainAttributeList **attrList, + UInt32 *length, void **outData) const { + DCHECK(itemRef); + unsigned int item_index = reinterpret_cast<unsigned int>(itemRef) - 1; + if (item_index >= item_count_) { + return errSecInvalidItemRef; + } + + DCHECK(!itemClass); // itemClass not implemented in the Mock. + if (attrList) { + *attrList = &(keychain_attr_list_[item_index]); + } + if (outData) { + *outData = keychain_data_[item_index].data; + DCHECK(length); + *length = keychain_data_[item_index].length; + } + + ++attribute_data_copy_count_; + return noErr; +} + +OSStatus MockKeychain::ItemModifyAttributesAndData( + SecKeychainItemRef itemRef, const SecKeychainAttributeList *attrList, + UInt32 length, const void *data) const { + DCHECK(itemRef); + const char* fail_trigger = "fail_me"; + if (length == strlen(fail_trigger) && + memcmp(data, fail_trigger, length) == 0) { + return errSecAuthFailed; + } + + unsigned int item_index = reinterpret_cast<unsigned int>(itemRef) - 1; + if (item_index >= item_count_) { + return errSecInvalidItemRef; + } + + if (attrList) { + NOTIMPLEMENTED(); + } + if (data) { + SetTestDataPasswordBytes(item_index, data, length); + } + return noErr; +} + +OSStatus MockKeychain::ItemFreeAttributesAndData( + SecKeychainAttributeList *attrList, + void *data) const { + --attribute_data_copy_count_; + return noErr; +} + +OSStatus MockKeychain::SearchCreateFromAttributes( + CFTypeRef keychainOrArray, SecItemClass itemClass, + const SecKeychainAttributeList *attrList, + SecKeychainSearchRef *searchRef) const { + // Figure out which of our mock items matches, and set up the array we'll use + // to generate results out of SearchCopyNext. + remaining_search_results_.clear(); + for (unsigned int mock_item = 0; mock_item < item_count_; ++mock_item) { + bool mock_item_matches = true; + for (UInt32 search_attr = 0; search_attr < attrList->count; ++search_attr) { + int mock_attr = IndexForTag(keychain_attr_list_[mock_item], + attrList->attr[search_attr].tag); + SecKeychainAttribute* mock_attribute = + &(keychain_attr_list_[mock_item].attr[mock_attr]); + if (mock_attribute->length != attrList->attr[search_attr].length || + memcmp(mock_attribute->data, attrList->attr[search_attr].data, + attrList->attr[search_attr].length) != 0) { + mock_item_matches = false; + break; + } + } + if (mock_item_matches) { + remaining_search_results_.push_back(mock_item); + } + } + + DCHECK(searchRef); + *searchRef = reinterpret_cast<SecKeychainSearchRef>(kDummySearchRef); + ++search_copy_count_; + return noErr; +} + +OSStatus MockKeychain::AddInternetPassword( + SecKeychainRef keychain, + UInt32 serverNameLength, const char *serverName, + UInt32 securityDomainLength, const char *securityDomain, + UInt32 accountNameLength, const char *accountName, + UInt32 pathLength, const char *path, + UInt16 port, SecProtocolType protocol, + SecAuthenticationType authenticationType, + UInt32 passwordLength, const void *passwordData, + SecKeychainItemRef *itemRef) const { + + // Check for the magic duplicate item trigger. + if (strcmp(serverName, "some.domain.com") == 0) { + return errSecDuplicateItem; + } + + // Use empty slots until they run out, then just keep replacing the last item. + int target_item = (item_count_ == item_capacity_) ? item_capacity_ - 1 + : item_count_++; + + SetTestDataBytes(target_item, kSecServerItemAttr, serverName, + serverNameLength); + SetTestDataBytes(target_item, kSecSecurityDomainItemAttr, securityDomain, + securityDomainLength); + SetTestDataBytes(target_item, kSecAccountItemAttr, accountName, + accountNameLength); + SetTestDataBytes(target_item, kSecPathItemAttr, path, pathLength); + SetTestDataPort(target_item, port); + SetTestDataProtocol(target_item, protocol); + SetTestDataAuthType(target_item, authenticationType); + SetTestDataPasswordBytes(target_item, passwordData, passwordLength); + base::Time::Exploded exploded_time; + base::Time::Now().UTCExplode(&exploded_time); + char time_string[128]; + snprintf(time_string, sizeof(time_string), "%04d%02d%02d%02d%02d%02dZ", + exploded_time.year, exploded_time.month, exploded_time.day_of_month, + exploded_time.hour, exploded_time.minute, exploded_time.second); + SetTestDataString(target_item, kSecCreationDateItemAttr, time_string); + + if (itemRef) { + *itemRef = reinterpret_cast<SecKeychainItemRef>(target_item + 1); + } + return noErr; +} + +OSStatus MockKeychain::SearchCopyNext(SecKeychainSearchRef searchRef, + SecKeychainItemRef *itemRef) const { + if (remaining_search_results_.empty()) { + return errSecItemNotFound; + } + unsigned int index = remaining_search_results_.front(); + remaining_search_results_.erase(remaining_search_results_.begin()); + *itemRef = reinterpret_cast<SecKeychainItemRef>(index + 1); + ++keychain_item_copy_count_; + return noErr; +} + +void MockKeychain::Free(CFTypeRef ref) const { + if (!ref) { + return; + } + + if (reinterpret_cast<int>(ref) == kDummySearchRef) { + --search_copy_count_; + } else { + --keychain_item_copy_count_; + } +} + +int MockKeychain::UnfreedSearchCount() const { + return search_copy_count_; +} + +int MockKeychain::UnfreedKeychainItemCount() const { + return keychain_item_copy_count_; +} + +int MockKeychain::UnfreedAttributeDataCount() const { + return attribute_data_copy_count_; +} |