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

Unified Diff: chrome/browser/password_manager/password_store_mac.cc

Issue 23477015: [sync] Significantly speed up password model association on mac (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address feedback Created 7 years, 3 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/password_manager/password_store_mac.cc
diff --git a/chrome/browser/password_manager/password_store_mac.cc b/chrome/browser/password_manager/password_store_mac.cc
index 4b938c5a07a8d2b0bd6a8027f5ddbac7503f7d57..b17ab978cc8887fc070effd203ae55435c893019 100644
--- a/chrome/browser/password_manager/password_store_mac.cc
+++ b/chrome/browser/password_manager/password_store_mac.cc
@@ -8,6 +8,7 @@
#include <CoreServices/CoreServices.h>
#include <set>
#include <string>
+#include <utility>
#include <vector>
#include "base/callback.h"
@@ -236,7 +237,8 @@ PasswordForm::Scheme SchemeForAuthType(SecAuthenticationType auth_type) {
bool FillPasswordFormFromKeychainItem(const AppleKeychain& keychain,
const SecKeychainItemRef& keychain_item,
- PasswordForm* form) {
+ PasswordForm* form,
+ bool extract_password_data) {
DCHECK(form);
SecKeychainAttributeInfo attrInfo;
@@ -255,11 +257,18 @@ bool FillPasswordFormFromKeychainItem(const AppleKeychain& keychain,
SecKeychainAttributeList *attrList;
UInt32 password_length;
- void* password_data;
+
+ // If |extract_password_data| is false, do not pass in a reference to
+ // |password_data|. ItemCopyAttributesAndData will then extract only the
+ // attributes of |keychain_item| (doesn't require OS authorization), and not
+ // attempt to extract its password data (requires OS authorization).
+ void* password_data = NULL;
+ void** password_data_ref = extract_password_data ? &password_data : NULL;
+
OSStatus result = keychain.ItemCopyAttributesAndData(keychain_item, &attrInfo,
NULL, &attrList,
&password_length,
- &password_data);
+ password_data_ref);
if (result != noErr) {
// We don't log errSecAuthFailed because that just means that the user
@@ -270,8 +279,10 @@ bool FillPasswordFormFromKeychainItem(const AppleKeychain& keychain,
return false;
}
- UTF8ToUTF16(static_cast<const char *>(password_data), password_length,
- &(form->password_value));
+ if (extract_password_data) {
+ UTF8ToUTF16(static_cast<const char *>(password_data), password_length,
+ &(form->password_value));
+ }
int port = kAnyPort;
std::string server;
@@ -333,7 +344,8 @@ bool FillPasswordFormFromKeychainItem(const AppleKeychain& keychain,
// kSecNegativeItemAttr doesn't seem to actually be in widespread use. In
// practice, other browsers seem to use a "" or " " password (and a special
// user name) to indicated blacklist entries.
- if (form->password_value.empty() || EqualsASCII(form->password_value, " ")) {
+ if (extract_password_data && (form->password_value.empty() ||
+ EqualsASCII(form->password_value, " "))) {
form->blacklisted_by_user = true;
}
@@ -446,17 +458,52 @@ void MergePasswordForms(std::vector<PasswordForm*>* keychain_forms,
DeleteVectorElementsInSet(keychain_forms, used_keychain_forms);
}
+std::vector<MacKeychainPasswordFormAdapter::ItemFormPair>
+ GetAllKeychainItemAttributesAsPasswordForms(
+ std::vector<SecKeychainItemRef>* keychain_items,
+ const AppleKeychain& keychain) {
+ DCHECK(keychain_items);
+ MacKeychainPasswordFormAdapter keychain_adapter(&keychain);
+ *keychain_items = keychain_adapter.GetAllPasswordFormKeychainItems();
+ std::vector<MacKeychainPasswordFormAdapter::ItemFormPair> item_form_pairs;
+ for (std::vector<SecKeychainItemRef>::iterator i = keychain_items->begin();
+ i != keychain_items->end(); ++i) {
+ PasswordForm* form_without_password = new PasswordForm();
+ internal_keychain_helpers::FillPasswordFormFromKeychainItem(
+ keychain,
+ *i,
+ form_without_password,
+ false); // Load password attributes, but not password data.
+ item_form_pairs.push_back(std::make_pair(&(*i), form_without_password));
+ }
+ return item_form_pairs;
+}
+
std::vector<PasswordForm*> GetPasswordsForForms(
const AppleKeychain& keychain,
std::vector<PasswordForm*>* database_forms) {
+ // First load the attributes of all items in the keychain without loading
+ // their password data, and then match items in |database_forms| against them.
+ // This avoids individually searching through the keychain for passwords
+ // matching each form in |database_forms|, and results in a significant
+ // performance gain, replacing O(N) keychain search operations with a single
+ // operation that loads all keychain items, and then selective reads of only
+ // the relevant passwords. See crbug.com/263685.
+ std::vector<SecKeychainItemRef> keychain_items;
+ std::vector<MacKeychainPasswordFormAdapter::ItemFormPair> item_form_pairs =
+ GetAllKeychainItemAttributesAsPasswordForms(&keychain_items, keychain);
+
+ // Next, compare the attributes of the PasswordForms in |database_forms|
+ // against those in |item_form_pairs|, and extract password data for each
+ // matching PasswordForm using its corresponding SecKeychainItemRef.
MacKeychainPasswordFormAdapter keychain_adapter(&keychain);
-
std::vector<PasswordForm*> merged_forms;
for (std::vector<PasswordForm*>::iterator i = database_forms->begin();
i != database_forms->end();) {
std::vector<PasswordForm*> db_form_container(1, *i);
std::vector<PasswordForm*> keychain_matches =
- keychain_adapter.PasswordsMergeableWithForm(**i);
+ keychain_adapter.ExtractPasswordsMergeableWithForm(item_form_pairs,
+ **i);
MergePasswordForms(&keychain_matches, &db_form_container, &merged_forms);
if (db_form_container.empty()) {
i = database_forms->erase(i);
@@ -465,6 +512,14 @@ std::vector<PasswordForm*> GetPasswordsForForms(
}
STLDeleteElements(&keychain_matches);
}
+
+ // Clean up temporary PasswordForms and SecKeychainItemRefs.
+ STLDeleteContainerPairSecondPointers(item_form_pairs.begin(),
+ item_form_pairs.end());
+ for (std::vector<SecKeychainItemRef>::iterator i = keychain_items.begin();
+ i != keychain_items.end(); ++i) {
+ keychain.Free(*i);
+ }
return merged_forms;
}
@@ -496,15 +551,40 @@ std::vector<PasswordForm*>
return ConvertKeychainItemsToForms(&keychain_items);
}
+bool MacKeychainPasswordFormAdapter::FormIsValidAndMatchesOtherForm(
+ const PasswordForm& query_form,
+ const PasswordForm& other_form) {
+ std::string server;
+ std::string security_domain;
+ int port;
+ bool is_secure;
+ if (!ExtractSignonRealmComponents(query_form.signon_realm, &server, &port,
+ &is_secure, &security_domain)) {
+ return false;
+ }
+ return internal_keychain_helpers::FormsMatchForMerge(query_form, other_form);
+}
+
std::vector<PasswordForm*>
- MacKeychainPasswordFormAdapter::PasswordsMergeableWithForm(
+ MacKeychainPasswordFormAdapter::ExtractPasswordsMergeableWithForm(
stuartmorgan 2013/09/30 22:39:12 AFAICT this no longer operates on the keychain in
Raghu Simha 2013/10/02 02:09:50 We reference the keychain in line 580, while calli
+ const std::vector<ItemFormPair>& item_form_pairs,
const PasswordForm& query_form) {
- std::string username = UTF16ToUTF8(query_form.username_value);
- std::vector<SecKeychainItemRef> keychain_items =
- MatchingKeychainItems(query_form.signon_realm, query_form.scheme,
- NULL, username.c_str());
-
- return ConvertKeychainItemsToForms(&keychain_items);
+ std::vector<PasswordForm*> matches;
+ for (std::vector<ItemFormPair>::const_iterator i = item_form_pairs.begin();
+ i != item_form_pairs.end(); ++i) {
+ if (FormIsValidAndMatchesOtherForm(query_form, *(i->second))) {
+ // Create a new object, since the caller is responsible for deleting the
+ // returned forms.
stuartmorgan 2013/09/30 22:39:12 Feel free to use ScopedVector anywhere it makes li
Raghu Simha 2013/10/02 02:09:50 I did consider using a ScopedVector here, but ende
+ PasswordForm* form_with_password = new PasswordForm();
+ internal_keychain_helpers::FillPasswordFormFromKeychainItem(
+ *keychain_,
+ *(i->first),
+ form_with_password,
+ true); // Load password attributes and data.
+ matches.push_back(form_with_password);
+ }
+ }
+ return matches;
}
PasswordForm* MacKeychainPasswordFormAdapter::PasswordExactlyMatchingForm(
@@ -514,7 +594,8 @@ PasswordForm* MacKeychainPasswordFormAdapter::PasswordExactlyMatchingForm(
PasswordForm* form = new PasswordForm();
internal_keychain_helpers::FillPasswordFormFromKeychainItem(*keychain_,
keychain_item,
- form);
+ form,
+ true);
keychain_->Free(keychain_item);
return form;
}
@@ -535,8 +616,8 @@ bool MacKeychainPasswordFormAdapter::HasPasswordsMergeableWithForm(
return !matches.empty();
}
-std::vector<PasswordForm*>
- MacKeychainPasswordFormAdapter::GetAllPasswordFormPasswords() {
+std::vector<SecKeychainItemRef>
+ MacKeychainPasswordFormAdapter::GetAllPasswordFormKeychainItems() {
SecAuthenticationType supported_auth_types[] = {
kSecAuthenticationTypeHTMLForm,
kSecAuthenticationTypeHTTPBasic,
@@ -550,8 +631,13 @@ std::vector<PasswordForm*>
NULL, NULL, NULL, CreatorCodeForSearch());
keychain_search.FindMatchingItems(&matches);
}
+ return matches;
+}
- return ConvertKeychainItemsToForms(&matches);
+std::vector<PasswordForm*>
+ MacKeychainPasswordFormAdapter::GetAllPasswordFormPasswords() {
+ std::vector<SecKeychainItemRef> items = GetAllPasswordFormKeychainItems();
+ return ConvertKeychainItemsToForms(&items);
}
bool MacKeychainPasswordFormAdapter::AddPassword(const PasswordForm& form) {
@@ -619,8 +705,8 @@ std::vector<PasswordForm*>
for (std::vector<SecKeychainItemRef>::const_iterator i = items->begin();
i != items->end(); ++i) {
PasswordForm* form = new PasswordForm();
- if (internal_keychain_helpers::FillPasswordFormFromKeychainItem(*keychain_,
- *i, form)) {
+ if (internal_keychain_helpers::FillPasswordFormFromKeychainItem(
+ *keychain_, *i, form, true)) {
keychain_forms.push_back(form);
}
keychain_->Free(*i);

Powered by Google App Engine
This is Rietveld 408576698