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

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

Issue 2909283002: Delete PasswordStoreMac and SimplePasswordStoreMac. (Closed)
Patch Set: test Created 3 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 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
deleted file mode 100644
index 25a1db966da81e72e11512d3eed42bbf675827c3..0000000000000000000000000000000000000000
--- a/chrome/browser/password_manager/password_store_mac.cc
+++ /dev/null
@@ -1,1395 +0,0 @@
-// Copyright (c) 2012 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 "chrome/browser/password_manager/password_store_mac.h"
-
-#include <CoreServices/CoreServices.h>
-#include <stddef.h>
-#include <algorithm>
-#include <iterator>
-#include <set>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/callback.h"
-#include "base/logging.h"
-#include "base/mac/foundation_util.h"
-#include "base/mac/mac_logging.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/mac/security_wrappers.h"
-#include "chrome/browser/password_manager/password_store_mac_internal.h"
-#include "components/os_crypt/os_crypt.h"
-#include "components/password_manager/core/browser/affiliation_utils.h"
-#include "components/password_manager/core/browser/login_database.h"
-#include "components/password_manager/core/browser/password_manager_util.h"
-#include "components/password_manager/core/browser/password_store_change.h"
-#include "content/public/browser/browser_thread.h"
-#include "crypto/apple_keychain.h"
-#include "url/origin.h"
-
-using autofill::PasswordForm;
-using crypto::AppleKeychain;
-using password_manager::PasswordStoreChange;
-using password_manager::PasswordStoreChangeList;
-
-namespace {
-
-// Utility class to handle the details of constructing and running a keychain
-// search from a set of attributes.
-class KeychainSearch {
- public:
- explicit KeychainSearch(const AppleKeychain& keychain);
- ~KeychainSearch();
-
- // Sets up a keychain search based on an non "null" (NULL for char*,
- // The appropriate "Any" entry for other types) arguments.
- //
- // IMPORTANT: Any parameters passed in *must* remain valid for as long as the
- // KeychainSearch object, since the search uses them by reference.
- void Init(const char* server,
- const UInt32* port,
- const SecProtocolType* protocol,
- const SecAuthenticationType* auth_type,
- const char* security_domain,
- const char* path,
- const char* username,
- const OSType* creator);
-
- // Fills |items| with all Keychain items that match the Init'd search.
- // If the search fails for any reason, |items| will be unchanged.
- void FindMatchingItems(std::vector<SecKeychainItemRef>* matches);
-
- private:
- const AppleKeychain* keychain_;
- SecKeychainAttributeList search_attributes_;
- SecKeychainSearchRef search_ref_;
-};
-
-KeychainSearch::KeychainSearch(const AppleKeychain& keychain)
- : keychain_(&keychain), search_ref_(NULL) {
- search_attributes_.count = 0;
- search_attributes_.attr = NULL;
-}
-
-KeychainSearch::~KeychainSearch() {
- if (search_attributes_.attr) {
- free(search_attributes_.attr);
- }
-}
-
-void KeychainSearch::Init(const char* server,
- const UInt32* port,
- const SecProtocolType* protocol,
- const SecAuthenticationType* auth_type,
- const char* security_domain,
- const char* path,
- const char* username,
- const OSType* creator) {
- // Allocate enough to hold everything we might use.
- const unsigned int kMaxEntryCount = 8;
- search_attributes_.attr =
- static_cast<SecKeychainAttribute*>(calloc(kMaxEntryCount,
- sizeof(SecKeychainAttribute)));
- unsigned int entries = 0;
- // We only use search_attributes_ with SearchCreateFromAttributes, which takes
- // a "const SecKeychainAttributeList *", so we trust that they won't try
- // to modify the list, and that casting away const-ness is thus safe.
- if (server != NULL) {
- DCHECK_LT(entries, kMaxEntryCount);
- search_attributes_.attr[entries].tag = kSecServerItemAttr;
- search_attributes_.attr[entries].length = strlen(server);
- search_attributes_.attr[entries].data =
- const_cast<void*>(static_cast<const void*>(server));
- ++entries;
- }
- if (port != NULL && *port != kAnyPort) {
- DCHECK_LE(entries, kMaxEntryCount);
- search_attributes_.attr[entries].tag = kSecPortItemAttr;
- search_attributes_.attr[entries].length = sizeof(*port);
- search_attributes_.attr[entries].data =
- const_cast<void*>(static_cast<const void*>(port));
- ++entries;
- }
- if (protocol != NULL && *protocol != kSecProtocolTypeAny) {
- DCHECK_LE(entries, kMaxEntryCount);
- search_attributes_.attr[entries].tag = kSecProtocolItemAttr;
- search_attributes_.attr[entries].length = sizeof(*protocol);
- search_attributes_.attr[entries].data =
- const_cast<void*>(static_cast<const void*>(protocol));
- ++entries;
- }
- if (auth_type != NULL && *auth_type != kSecAuthenticationTypeAny) {
- DCHECK_LE(entries, kMaxEntryCount);
- search_attributes_.attr[entries].tag = kSecAuthenticationTypeItemAttr;
- search_attributes_.attr[entries].length = sizeof(*auth_type);
- search_attributes_.attr[entries].data =
- const_cast<void*>(static_cast<const void*>(auth_type));
- ++entries;
- }
- if (security_domain != NULL && strlen(security_domain) > 0) {
- DCHECK_LE(entries, kMaxEntryCount);
- search_attributes_.attr[entries].tag = kSecSecurityDomainItemAttr;
- search_attributes_.attr[entries].length = strlen(security_domain);
- search_attributes_.attr[entries].data =
- const_cast<void*>(static_cast<const void*>(security_domain));
- ++entries;
- }
- if (path != NULL && strlen(path) > 0 && strcmp(path, "/") != 0) {
- DCHECK_LE(entries, kMaxEntryCount);
- search_attributes_.attr[entries].tag = kSecPathItemAttr;
- search_attributes_.attr[entries].length = strlen(path);
- search_attributes_.attr[entries].data =
- const_cast<void*>(static_cast<const void*>(path));
- ++entries;
- }
- if (username != NULL) {
- DCHECK_LE(entries, kMaxEntryCount);
- search_attributes_.attr[entries].tag = kSecAccountItemAttr;
- search_attributes_.attr[entries].length = strlen(username);
- search_attributes_.attr[entries].data =
- const_cast<void*>(static_cast<const void*>(username));
- ++entries;
- }
- if (creator != NULL) {
- DCHECK_LE(entries, kMaxEntryCount);
- search_attributes_.attr[entries].tag = kSecCreatorItemAttr;
- search_attributes_.attr[entries].length = sizeof(*creator);
- search_attributes_.attr[entries].data =
- const_cast<void*>(static_cast<const void*>(creator));
- ++entries;
- }
- search_attributes_.count = entries;
-}
-
-void KeychainSearch::FindMatchingItems(std::vector<SecKeychainItemRef>* items) {
- OSStatus result = keychain_->SearchCreateFromAttributes(
- NULL, kSecInternetPasswordItemClass, &search_attributes_, &search_ref_);
-
- if (result != noErr) {
- OSSTATUS_LOG(ERROR, result) << "Keychain lookup failed";
- return;
- }
-
- SecKeychainItemRef keychain_item;
- while (keychain_->SearchCopyNext(search_ref_, &keychain_item) == noErr) {
- // Consumer is responsible for freeing the items.
- items->push_back(keychain_item);
- }
-
- keychain_->Free(search_ref_);
- search_ref_ = NULL;
-}
-
-PasswordStoreChangeList FormsToRemoveChangeList(
- const std::vector<std::unique_ptr<PasswordForm>>& forms) {
- PasswordStoreChangeList changes;
- for (const auto& form : forms) {
- changes.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE, *form));
- }
- return changes;
-}
-
-// Moves the content of |second| to the end of |first|.
-void AppendSecondToFirst(std::vector<std::unique_ptr<PasswordForm>>* first,
- std::vector<std::unique_ptr<PasswordForm>>* second) {
- first->reserve(first->size() + second->size());
- std::move(second->begin(), second->end(), std::back_inserter(*first));
- second->clear();
-}
-
-// Returns the best match for |base_form| from |keychain_forms|, or nullptr if
-// there is no suitable match.
-const PasswordForm* BestKeychainFormForForm(
- const PasswordForm& base_form,
- const std::vector<std::unique_ptr<PasswordForm>>& keychain_forms) {
- const PasswordForm* partial_match = nullptr;
- for (const auto& keychain_form : keychain_forms) {
- // TODO(stuartmorgan): We should really be scoring path matches and picking
- // the best, rather than just checking exact-or-not (although in practice
- // keychain items with paths probably came from us).
- if (internal_keychain_helpers::FormsMatchForMerge(
- base_form, *keychain_form,
- internal_keychain_helpers::FUZZY_FORM_MATCH)) {
- if (base_form.origin == keychain_form->origin) {
- return keychain_form.get();
- } else if (!partial_match) {
- partial_match = keychain_form.get();
- }
- }
- }
- return partial_match;
-}
-
-// True if the form has no password to be stored in Keychain.
-bool IsLoginDatabaseOnlyForm(const PasswordForm& form) {
- return form.blacklisted_by_user || !form.federation_origin.unique() ||
- form.scheme == PasswordForm::SCHEME_USERNAME_ONLY;
-}
-
-} // namespace
-
-#pragma mark -
-
-// TODO(stuartmorgan): Convert most of this to private helpers in
-// MacKeychainPasswordFormAdapter once it has sufficient higher-level public
-// methods to provide test coverage.
-namespace internal_keychain_helpers {
-
-// Returns a URL built from the given components. To create a URL without a
-// port, pass kAnyPort for the |port| parameter.
-GURL URLFromComponents(bool is_secure, const std::string& host, int port,
- const std::string& path) {
- GURL::Replacements url_components;
- std::string scheme(is_secure ? "https" : "http");
- url_components.SetSchemeStr(scheme);
- url_components.SetHostStr(host);
- std::string port_string; // Must remain in scope until after we do replacing.
- if (port != kAnyPort) {
- std::ostringstream port_stringstream;
- port_stringstream << port;
- port_string = port_stringstream.str();
- url_components.SetPortStr(port_string);
- }
- url_components.SetPathStr(path);
-
- GURL url("http://dummy.com"); // ReplaceComponents needs a valid URL.
- return url.ReplaceComponents(url_components);
-}
-
-// Converts a Keychain time string to a Time object, returning true if
-// time_string_bytes was parsable.
-bool TimeFromKeychainTimeString(const char* time_string_bytes,
- unsigned int byte_length,
- base::Time* time) {
- DCHECK(time);
-
- char* time_string = static_cast<char*>(malloc(byte_length + 1));
- memcpy(time_string, time_string_bytes, byte_length);
- time_string[byte_length] = '\0';
- base::Time::Exploded exploded_time;
- bzero(&exploded_time, sizeof(exploded_time));
- // The time string is of the form "yyyyMMddHHmmss'Z", in UTC time.
- int assignments = sscanf(time_string, "%4d%2d%2d%2d%2d%2dZ",
- &exploded_time.year, &exploded_time.month,
- &exploded_time.day_of_month, &exploded_time.hour,
- &exploded_time.minute, &exploded_time.second);
- free(time_string);
-
- return assignments == 6 && base::Time::FromUTCExploded(exploded_time, time);
-}
-
-// Returns the PasswordForm Scheme corresponding to |auth_type|.
-PasswordForm::Scheme SchemeForAuthType(SecAuthenticationType auth_type) {
- switch (auth_type) {
- case kSecAuthenticationTypeHTMLForm: return PasswordForm::SCHEME_HTML;
- case kSecAuthenticationTypeHTTPBasic: return PasswordForm::SCHEME_BASIC;
- case kSecAuthenticationTypeHTTPDigest: return PasswordForm::SCHEME_DIGEST;
- default: return PasswordForm::SCHEME_OTHER;
- }
-}
-
-bool FillPasswordFormFromKeychainItem(const AppleKeychain& keychain,
- SecKeychainItemRef keychain_item,
- PasswordForm* form,
- bool extract_password_data) {
- DCHECK(form);
-
- SecKeychainAttributeInfo attrInfo;
- UInt32 tags[] = { kSecAccountItemAttr,
- kSecServerItemAttr,
- kSecPortItemAttr,
- kSecPathItemAttr,
- kSecProtocolItemAttr,
- kSecAuthenticationTypeItemAttr,
- kSecSecurityDomainItemAttr,
- kSecCreationDateItemAttr,
- kSecNegativeItemAttr };
- attrInfo.count = arraysize(tags);
- attrInfo.tag = tags;
- attrInfo.format = NULL;
-
- SecKeychainAttributeList* attrList;
- UInt32 password_length;
-
- // 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_ref);
-
- if (result != noErr) {
- // We don't log errSecAuthFailed because that just means that the user
- // chose not to allow us access to the item.
- if (result != errSecAuthFailed) {
- OSSTATUS_LOG(ERROR, result) << "Keychain data load failed";
- }
- return false;
- }
-
- if (extract_password_data) {
- base::UTF8ToUTF16(static_cast<const char *>(password_data), password_length,
- &(form->password_value));
- }
-
- int port = kAnyPort;
- std::string server;
- std::string security_domain;
- std::string path;
- bool is_secure = false;
- for (unsigned int i = 0; i < attrList->count; i++) {
- SecKeychainAttribute attr = attrList->attr[i];
- if (!attr.data) {
- continue;
- }
- switch (attr.tag) {
- case kSecAccountItemAttr:
- base::UTF8ToUTF16(static_cast<const char *>(attr.data), attr.length,
- &(form->username_value));
- break;
- case kSecServerItemAttr:
- server.assign(static_cast<const char *>(attr.data), attr.length);
- break;
- case kSecPortItemAttr:
- port = *(static_cast<UInt32*>(attr.data));
- break;
- case kSecPathItemAttr:
- path.assign(static_cast<const char *>(attr.data), attr.length);
- break;
- case kSecProtocolItemAttr:
- {
- SecProtocolType protocol = *(static_cast<SecProtocolType*>(attr.data));
- // TODO(stuartmorgan): Handle proxy types
- is_secure = (protocol == kSecProtocolTypeHTTPS);
- break;
- }
- case kSecAuthenticationTypeItemAttr:
- {
- SecAuthenticationType auth_type =
- *(static_cast<SecAuthenticationType*>(attr.data));
- form->scheme = SchemeForAuthType(auth_type);
- break;
- }
- case kSecSecurityDomainItemAttr:
- security_domain.assign(static_cast<const char *>(attr.data),
- attr.length);
- break;
- case kSecCreationDateItemAttr:
- // The only way to get a date out of Keychain is as a string. Really.
- // (The docs claim it's an int, but the header is correct.)
- TimeFromKeychainTimeString(static_cast<char*>(attr.data), attr.length,
- &form->date_created);
- break;
- case kSecNegativeItemAttr:
- Boolean negative_item = *(static_cast<Boolean*>(attr.data));
- if (negative_item) {
- form->blacklisted_by_user = true;
- }
- break;
- }
- }
- keychain.ItemFreeAttributesAndData(attrList, password_data);
-
- // 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 (extract_password_data && (form->password_value.empty() ||
- base::EqualsASCII(form->password_value, " "))) {
- form->blacklisted_by_user = true;
- }
-
- // Android facet URLs aren't parsed correctly by GURL and need to be handled
- // separately.
- if (password_manager::IsValidAndroidFacetURI(server)) {
- form->signon_realm = server;
- form->origin = GURL();
- } else {
- form->origin = URLFromComponents(is_secure, server, port, path);
- // TODO(stuartmorgan): Handle proxies, which need a different signon_realm
- // format.
- form->signon_realm = form->origin.GetOrigin().spec();
- if (form->scheme != PasswordForm::SCHEME_HTML) {
- form->signon_realm.append(security_domain);
- }
- }
- return true;
-}
-
-bool HasChromeCreatorCode(const AppleKeychain& keychain,
- SecKeychainItemRef keychain_item) {
- SecKeychainAttributeInfo attr_info;
- UInt32 tags[] = {kSecCreatorItemAttr};
- attr_info.count = arraysize(tags);
- attr_info.tag = tags;
- attr_info.format = nullptr;
-
- SecKeychainAttributeList* attr_list;
- UInt32 password_length;
- OSStatus result = keychain.ItemCopyAttributesAndData(
- keychain_item, &attr_info, nullptr, &attr_list,
- &password_length, nullptr);
- if (result != noErr)
- return false;
- OSType creator_code = 0;
- for (unsigned int i = 0; i < attr_list->count; i++) {
- SecKeychainAttribute attr = attr_list->attr[i];
- if (!attr.data) {
- continue;
- }
- if (attr.tag == kSecCreatorItemAttr) {
- creator_code = *(static_cast<FourCharCode*>(attr.data));
- break;
- }
- }
- keychain.ItemFreeAttributesAndData(attr_list, nullptr);
- return creator_code && creator_code == base::mac::CreatorCodeForApplication();
-}
-
-bool FormsMatchForMerge(const PasswordForm& form_a,
- const PasswordForm& form_b,
- FormMatchStrictness strictness) {
- if (IsLoginDatabaseOnlyForm(form_a) || IsLoginDatabaseOnlyForm(form_b))
- return false;
-
- bool equal_realm = form_a.signon_realm == form_b.signon_realm;
- if (strictness == FUZZY_FORM_MATCH) {
- equal_realm |= form_a.is_public_suffix_match;
- }
- return form_a.scheme == form_b.scheme && equal_realm &&
- form_a.username_value == form_b.username_value;
-}
-
-// Moves entries from |forms| that represent either blacklisted or federated
-// logins into |extracted|. These two types are stored only in the LoginDatabase
-// and do not have corresponding Keychain entries.
-void ExtractNonKeychainForms(
- std::vector<std::unique_ptr<PasswordForm>>* forms,
- std::vector<std::unique_ptr<PasswordForm>>* extracted) {
- extracted->reserve(extracted->size() + forms->size());
-
- std::vector<std::unique_ptr<PasswordForm>> remaining;
- remaining.reserve(forms->size());
-
- for (std::unique_ptr<PasswordForm>& form : *forms) {
- if (IsLoginDatabaseOnlyForm(*form))
- extracted->push_back(std::move(form));
- else
- remaining.push_back(std::move(form));
- }
- forms->swap(remaining);
-}
-
-// Takes |keychain_forms| and |database_forms| and moves the following 2 types
-// of forms to |merged_forms|:
-// (1) |database_forms| that by principle never have a corresponding Keychain
-// entry (viz., blacklisted and federated logins),
-// (2) |database_forms| which should have and do have a corresponding entry in
-// |keychain_forms|.
-// The database forms of type (2) have their password value updated from the
-// corresponding keychain form, and all the keychain forms corresponding to some
-// database form are removed from |keychain_forms| and deleted.
-void MergePasswordForms(
- std::vector<std::unique_ptr<PasswordForm>>* keychain_forms,
- std::vector<std::unique_ptr<PasswordForm>>* database_forms,
- std::vector<std::unique_ptr<PasswordForm>>* merged_forms) {
- // Pull out the database blacklist items and federated logins, since they are
- // used as-is rather than being merged with keychain forms.
- ExtractNonKeychainForms(database_forms, merged_forms);
-
- // Merge the normal entries.
- std::vector<std::unique_ptr<PasswordForm>> unused_database_forms;
- unused_database_forms.reserve(database_forms->size());
- std::set<const PasswordForm*> used_keychain_forms;
- // Move all database forms to either |merged_forms| or
- // |unused_database_forms|, based on whether they have a match in the keychain
- // forms or not. If there is a match, add its password to the DB form and
- // mark the keychain form as used.
- for (std::unique_ptr<PasswordForm>& db_form : *database_forms) {
- const PasswordForm* best_match =
- BestKeychainFormForForm(*db_form, *keychain_forms);
- if (best_match) {
- used_keychain_forms.insert(best_match);
- db_form->password_value = best_match->password_value;
- merged_forms->push_back(std::move(db_form));
- } else {
- unused_database_forms.push_back(std::move(db_form));
- }
- }
- database_forms->swap(unused_database_forms);
-
- // Clear out all the Keychain entries we used.
- std::vector<std::unique_ptr<PasswordForm>> unused_keychain_forms;
- unused_keychain_forms.reserve(keychain_forms->size());
- for (std::unique_ptr<PasswordForm>& keychain_form : *keychain_forms) {
- if (!base::ContainsKey(used_keychain_forms, keychain_form.get())) {
- unused_keychain_forms.push_back(std::move(keychain_form));
- }
- }
- keychain_forms->swap(unused_keychain_forms);
-}
-
-std::vector<ItemFormPair> ExtractAllKeychainItemAttributesIntoPasswordForms(
- std::vector<SecKeychainItemRef>* keychain_items,
- const AppleKeychain& keychain) {
- DCHECK(keychain_items);
- MacKeychainPasswordFormAdapter keychain_adapter(&keychain);
- *keychain_items = keychain_adapter.GetAllPasswordFormKeychainItems();
- std::vector<ItemFormPair> item_form_pairs;
- for (auto* keychain_item : *keychain_items) {
- std::unique_ptr<PasswordForm> form_without_password =
- base::MakeUnique<PasswordForm>();
- internal_keychain_helpers::FillPasswordFormFromKeychainItem(
- keychain, keychain_item, form_without_password.get(),
- false); // Load password attributes, but not password data.
- item_form_pairs.push_back(
- std::make_pair(keychain_item, std::move(form_without_password)));
- }
- return item_form_pairs;
-}
-
-void GetPasswordsForForms(
- const AppleKeychain& keychain,
- std::vector<std::unique_ptr<PasswordForm>>* database_forms,
- std::vector<std::unique_ptr<PasswordForm>>* passwords) {
- // 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<ItemFormPair> item_form_pairs =
- ExtractAllKeychainItemAttributesIntoPasswordForms(&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.
- std::vector<std::unique_ptr<PasswordForm>> unused_db_forms;
- unused_db_forms.reserve(database_forms->size());
- // Move database forms with a password stored in |keychain| to |passwords|,
- // including the password. The rest is moved to |unused_db_forms|.
- for (std::unique_ptr<PasswordForm>& db_form : *database_forms) {
- std::vector<std::unique_ptr<PasswordForm>> keychain_matches =
- ExtractPasswordsMergeableWithForm(keychain, item_form_pairs, *db_form);
-
- std::vector<std::unique_ptr<PasswordForm>> db_form_container;
- db_form_container.push_back(std::move(db_form));
- MergePasswordForms(&keychain_matches, &db_form_container, passwords);
- AppendSecondToFirst(&unused_db_forms, &db_form_container);
- }
- database_forms->swap(unused_db_forms);
-
- for (SecKeychainItemRef item : keychain_items) {
- keychain.Free(item);
- }
-}
-
-// TODO(stuartmorgan): signon_realm for proxies is not yet supported.
-bool ExtractSignonRealmComponents(const std::string& signon_realm,
- std::string* server,
- UInt32* port,
- bool* is_secure,
- std::string* security_domain) {
- // GURL does not parse Android facet URIs correctly.
- if (password_manager::IsValidAndroidFacetURI(signon_realm)) {
- if (server)
- *server = signon_realm;
- if (is_secure)
- *is_secure = true;
- if (port)
- *port = 0;
- if (security_domain)
- security_domain->clear();
- return true;
- }
-
- // The signon_realm will be the Origin portion of a URL for an HTML form,
- // and the same but with the security domain as a path for HTTP auth.
- GURL realm_as_url(signon_realm);
- if (!realm_as_url.is_valid()) {
- return false;
- }
-
- if (server)
- *server = realm_as_url.host();
- if (is_secure)
- *is_secure = realm_as_url.SchemeIsCryptographic();
- if (port)
- *port = realm_as_url.has_port() ? atoi(realm_as_url.port().c_str()) : 0;
- if (security_domain) {
- // Strip the leading '/' off of the path to get the security domain.
- if (realm_as_url.path().length() > 0)
- *security_domain = realm_as_url.path().substr(1);
- else
- security_domain->clear();
- }
- return true;
-}
-
-bool FormIsValidAndMatchesOtherForm(const PasswordForm& query_form,
- const PasswordForm& other_form) {
- std::string server;
- std::string security_domain;
- UInt32 port;
- bool is_secure;
- if (!ExtractSignonRealmComponents(query_form.signon_realm, &server, &port,
- &is_secure, &security_domain)) {
- return false;
- }
- return FormsMatchForMerge(query_form, other_form, STRICT_FORM_MATCH);
-}
-
-std::vector<std::unique_ptr<PasswordForm>> ExtractPasswordsMergeableWithForm(
- const AppleKeychain& keychain,
- const std::vector<ItemFormPair>& item_form_pairs,
- const PasswordForm& query_form) {
- std::vector<std::unique_ptr<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.
- auto form_with_password = base::MakeUnique<PasswordForm>();
- FillPasswordFormFromKeychainItem(
- keychain, i->first, form_with_password.get(),
- true); // Load password attributes and data.
- // Do not include blacklisted items found in the keychain.
- if (!form_with_password->blacklisted_by_user)
- matches.push_back(std::move(form_with_password));
- }
- }
- return matches;
-}
-
-} // namespace internal_keychain_helpers
-
-#pragma mark -
-
-MacKeychainPasswordFormAdapter::MacKeychainPasswordFormAdapter(
- const AppleKeychain* keychain)
- : keychain_(keychain), finds_only_owned_(false) {
-}
-
-std::vector<std::unique_ptr<PasswordForm>>
-MacKeychainPasswordFormAdapter::PasswordsFillingForm(
- const std::string& signon_realm,
- PasswordForm::Scheme scheme) {
- std::vector<SecKeychainItemRef> keychain_items =
- MatchingKeychainItems(signon_realm, scheme, NULL, NULL);
- return ConvertKeychainItemsToForms(&keychain_items);
-}
-
-bool MacKeychainPasswordFormAdapter::HasPasswordExactlyMatchingForm(
- const PasswordForm& query_form) {
- SecKeychainItemRef keychain_item = KeychainItemForForm(query_form);
- if (keychain_item) {
- keychain_->Free(keychain_item);
- return true;
- }
- return false;
-}
-
-bool MacKeychainPasswordFormAdapter::HasPasswordsMergeableWithForm(
- const PasswordForm& query_form) {
- if (IsLoginDatabaseOnlyForm(query_form))
- return false;
- std::string username = base::UTF16ToUTF8(query_form.username_value);
- std::vector<SecKeychainItemRef> matches =
- MatchingKeychainItems(query_form.signon_realm, query_form.scheme,
- NULL, username.c_str());
- for (SecKeychainItemRef item : matches)
- keychain_->Free(item);
-
- return !matches.empty();
-}
-
-std::vector<SecKeychainItemRef>
- MacKeychainPasswordFormAdapter::GetAllPasswordFormKeychainItems() {
- SecAuthenticationType supported_auth_types[] = {
- kSecAuthenticationTypeHTMLForm,
- kSecAuthenticationTypeHTTPBasic,
- kSecAuthenticationTypeHTTPDigest,
- };
-
- std::vector<SecKeychainItemRef> matches;
- for (unsigned int i = 0; i < arraysize(supported_auth_types); ++i) {
- KeychainSearch keychain_search(*keychain_);
- OSType creator = CreatorCodeForSearch();
- keychain_search.Init(NULL,
- NULL,
- NULL,
- &supported_auth_types[i],
- NULL,
- NULL,
- NULL,
- creator ? &creator : NULL);
- keychain_search.FindMatchingItems(&matches);
- }
- return matches;
-}
-
-std::vector<std::unique_ptr<PasswordForm>>
-MacKeychainPasswordFormAdapter::GetAllPasswordFormPasswords() {
- std::vector<SecKeychainItemRef> items = GetAllPasswordFormKeychainItems();
- return ConvertKeychainItemsToForms(&items);
-}
-
-bool MacKeychainPasswordFormAdapter::AddPassword(const PasswordForm& form) {
- // We should never be trying to store a blacklist in the keychain.
- DCHECK(!IsLoginDatabaseOnlyForm(form));
-
- std::string server;
- std::string security_domain;
- UInt32 port;
- bool is_secure;
- if (!internal_keychain_helpers::ExtractSignonRealmComponents(
- form.signon_realm, &server, &port, &is_secure, &security_domain)) {
- return false;
- }
- std::string path;
- // Path doesn't make sense for Android app credentials.
- if (!password_manager::IsValidAndroidFacetURI(form.signon_realm))
- path = form.origin.path();
- std::string username = base::UTF16ToUTF8(form.username_value);
- std::string password = base::UTF16ToUTF8(form.password_value);
- SecProtocolType protocol = is_secure ? kSecProtocolTypeHTTPS
- : kSecProtocolTypeHTTP;
- SecKeychainItemRef new_item = NULL;
- OSStatus result = keychain_->AddInternetPassword(
- NULL, server.size(), server.c_str(),
- security_domain.size(), security_domain.c_str(),
- username.size(), username.c_str(),
- path.size(), path.c_str(),
- port, protocol, AuthTypeForScheme(form.scheme),
- password.size(), password.c_str(), &new_item);
-
- if (result == noErr) {
- SetKeychainItemCreatorCode(new_item,
- base::mac::CreatorCodeForApplication());
- keychain_->Free(new_item);
- } else if (result == errSecDuplicateItem) {
- // If we collide with an existing item, find and update it instead.
- SecKeychainItemRef existing_item = KeychainItemForForm(form);
- if (!existing_item) {
- return false;
- }
- bool changed = SetKeychainItemPassword(existing_item, password);
- keychain_->Free(existing_item);
- return changed;
- }
-
- return result == noErr;
-}
-
-bool MacKeychainPasswordFormAdapter::RemovePassword(const PasswordForm& form) {
- SecKeychainItemRef keychain_item = KeychainItemForForm(form);
- if (keychain_item == NULL)
- return false;
- OSStatus result = keychain_->ItemDelete(keychain_item);
- keychain_->Free(keychain_item);
- return result == noErr;
-}
-
-void MacKeychainPasswordFormAdapter::SetFindsOnlyOwnedItems(
- bool finds_only_owned) {
- finds_only_owned_ = finds_only_owned;
-}
-
-std::vector<std::unique_ptr<PasswordForm>>
-MacKeychainPasswordFormAdapter::ConvertKeychainItemsToForms(
- std::vector<SecKeychainItemRef>* items) {
- std::vector<std::unique_ptr<PasswordForm>> forms;
- for (SecKeychainItemRef item : *items) {
- auto form = base::MakeUnique<PasswordForm>();
- if (internal_keychain_helpers::FillPasswordFormFromKeychainItem(
- *keychain_, item, form.get(), true)) {
- forms.push_back(std::move(form));
- }
- keychain_->Free(item);
- }
- items->clear();
- return forms;
-}
-
-SecKeychainItemRef MacKeychainPasswordFormAdapter::KeychainItemForForm(
- const PasswordForm& form) {
- // We don't store blacklist entries in the keychain, so the answer to "what
- // Keychain item goes with this form" is always "nothing" for blacklists.
- // Same goes for federated logins.
- if (IsLoginDatabaseOnlyForm(form))
- return NULL;
-
- std::string path;
- // Path doesn't make sense for Android app credentials.
- if (!password_manager::IsValidAndroidFacetURI(form.signon_realm))
- path = form.origin.path();
- std::string username = base::UTF16ToUTF8(form.username_value);
- std::vector<SecKeychainItemRef> matches = MatchingKeychainItems(
- form.signon_realm, form.scheme, path.c_str(), username.c_str());
-
- if (matches.empty()) {
- return NULL;
- }
-
- // Free all items after the first, since we won't be returning them.
- for (auto i = matches.begin() + 1; i != matches.end(); ++i)
- keychain_->Free(*i);
-
- return matches[0];
-}
-
-std::vector<SecKeychainItemRef>
-MacKeychainPasswordFormAdapter::MatchingKeychainItems(
- const std::string& signon_realm,
- PasswordForm::Scheme scheme,
- const char* path,
- const char* username) {
- std::vector<SecKeychainItemRef> matches;
-
- std::string server;
- std::string security_domain;
- UInt32 port;
- bool is_secure;
- if (!internal_keychain_helpers::ExtractSignonRealmComponents(
- signon_realm, &server, &port, &is_secure, &security_domain)) {
- // TODO(stuartmorgan): Proxies will currently fail here, since their
- // signon_realm is not a URL. We need to detect the proxy case and handle
- // it specially.
- return matches;
- }
- SecProtocolType protocol = is_secure ? kSecProtocolTypeHTTPS
- : kSecProtocolTypeHTTP;
- SecAuthenticationType auth_type = AuthTypeForScheme(scheme);
- const char* auth_domain = (scheme == PasswordForm::SCHEME_HTML) ?
- NULL : security_domain.c_str();
- OSType creator = CreatorCodeForSearch();
- KeychainSearch keychain_search(*keychain_);
- keychain_search.Init(server.c_str(),
- &port,
- &protocol,
- &auth_type,
- auth_domain,
- path,
- username,
- creator ? &creator : NULL);
- keychain_search.FindMatchingItems(&matches);
- return matches;
-}
-
-// Returns the Keychain SecAuthenticationType type corresponding to |scheme|.
-SecAuthenticationType MacKeychainPasswordFormAdapter::AuthTypeForScheme(
- PasswordForm::Scheme scheme) {
- switch (scheme) {
- case PasswordForm::SCHEME_HTML: return kSecAuthenticationTypeHTMLForm;
- case PasswordForm::SCHEME_BASIC: return kSecAuthenticationTypeHTTPBasic;
- case PasswordForm::SCHEME_DIGEST: return kSecAuthenticationTypeHTTPDigest;
- case PasswordForm::SCHEME_OTHER: return kSecAuthenticationTypeDefault;
- case PasswordForm::SCHEME_USERNAME_ONLY:
- NOTREACHED();
- break;
- }
- NOTREACHED();
- return kSecAuthenticationTypeDefault;
-}
-
-bool MacKeychainPasswordFormAdapter::SetKeychainItemPassword(
- SecKeychainItemRef keychain_item,
- const std::string& password) {
- OSStatus result = keychain_->ItemModifyAttributesAndData(keychain_item, NULL,
- password.size(),
- password.c_str());
- return result == noErr;
-}
-
-bool MacKeychainPasswordFormAdapter::SetKeychainItemCreatorCode(
- SecKeychainItemRef keychain_item,
- OSType creator_code) {
- SecKeychainAttribute attr = { kSecCreatorItemAttr, sizeof(creator_code),
- &creator_code };
- SecKeychainAttributeList attrList = { 1, &attr };
- OSStatus result = keychain_->ItemModifyAttributesAndData(keychain_item,
- &attrList, 0, NULL);
- return result == noErr;
-}
-
-OSType MacKeychainPasswordFormAdapter::CreatorCodeForSearch() {
- return finds_only_owned_ ? base::mac::CreatorCodeForApplication() : 0;
-}
-
-#pragma mark -
-
-PasswordStoreMac::PasswordStoreMac(
- scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
- scoped_refptr<base::SingleThreadTaskRunner> db_thread_runner,
- std::unique_ptr<AppleKeychain> keychain)
- : password_manager::PasswordStore(main_thread_runner, db_thread_runner),
- keychain_(std::move(keychain)),
- login_metadata_db_(nullptr) {
- DCHECK(keychain_);
-}
-
-PasswordStoreMac::~PasswordStoreMac() {}
-
-void PasswordStoreMac::InitWithTaskRunner(
- scoped_refptr<base::SingleThreadTaskRunner> background_task_runner) {
- db_thread_runner_ = background_task_runner;
- DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
-}
-
-// static
-PasswordStoreMac::MigrationResult PasswordStoreMac::ImportFromKeychain(
- password_manager::LoginDatabase* login_db,
- crypto::AppleKeychain* keychain) {
- std::vector<std::unique_ptr<PasswordForm>> database_forms;
- if (!login_db->GetAutofillableLogins(&database_forms))
- return LOGIN_DB_FAILURE;
-
- std::vector<std::unique_ptr<PasswordForm>> uninteresting_forms;
- internal_keychain_helpers::ExtractNonKeychainForms(&database_forms,
- &uninteresting_forms);
- // If there are no passwords to lookup in the Keychain then we're done.
- if (database_forms.empty())
- return MIGRATION_OK;
-
- // Make sure that the encryption key is retrieved from the Keychain so the
- // encryption can be done.
- std::string ciphertext;
- if (!OSCrypt::EncryptString("test", &ciphertext))
- return ENCRYPTOR_FAILURE;
-
- // Mute the Keychain.
- chrome::ScopedSecKeychainSetUserInteractionAllowed user_interaction_allowed(
- false);
-
- // Retrieve the passwords.
- // Get all the password attributes first.
- std::vector<SecKeychainItemRef> keychain_items;
- std::vector<internal_keychain_helpers::ItemFormPair> item_form_pairs =
- internal_keychain_helpers::
- ExtractAllKeychainItemAttributesIntoPasswordForms(&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.
- size_t unmerged_forms_count = 0;
- login_db->set_clear_password_values(false);
- for (const auto& form : database_forms) {
- std::vector<std::unique_ptr<PasswordForm>> keychain_matches =
- internal_keychain_helpers::ExtractPasswordsMergeableWithForm(
- *keychain, item_form_pairs, *form);
-
- const PasswordForm* best_match =
- BestKeychainFormForForm(*form, keychain_matches);
- if (best_match) {
- form->password_value = best_match->password_value;
- PasswordStoreChangeList change = login_db->UpdateLogin(*form);
- DCHECK_EQ(1u, change.size());
- } else {
- unmerged_forms_count++;
- bool removed = login_db->RemoveLogin(*form);
- DCHECK(removed);
- }
- }
- for (SecKeychainItemRef item : keychain_items)
- keychain->Free(item);
-
- if (unmerged_forms_count) {
- UMA_HISTOGRAM_COUNTS(
- "PasswordManager.KeychainMigration.NumPasswordsOnFailure",
- database_forms.size());
- UMA_HISTOGRAM_COUNTS("PasswordManager.KeychainMigration.NumFailedPasswords",
- unmerged_forms_count);
- return MIGRATION_PARTIAL;
- }
- return MIGRATION_OK;
-}
-
-// static
-void PasswordStoreMac::CleanUpKeychain(
- crypto::AppleKeychain* keychain,
- const std::vector<std::unique_ptr<PasswordForm>>& forms) {
- MacKeychainPasswordFormAdapter keychain_adapter(keychain);
- keychain_adapter.SetFindsOnlyOwnedItems(true);
- for (const auto& form : forms)
- keychain_adapter.RemovePassword(*form);
-}
-
-void PasswordStoreMac::set_login_metadata_db(
- password_manager::LoginDatabase* login_db) {
- login_metadata_db_ = login_db;
- if (login_metadata_db_)
- login_metadata_db_->set_clear_password_values(true);
-}
-
-bool PasswordStoreMac::Init(
- const syncer::SyncableService::StartSyncFlare& flare,
- PrefService* prefs) {
- // The class should be used inside PasswordStoreProxyMac only.
- NOTREACHED();
- return true;
-}
-
-void PasswordStoreMac::ReportMetricsImpl(const std::string& sync_username,
- bool custom_passphrase_sync_enabled) {
- if (!login_metadata_db_)
- return;
- login_metadata_db_->ReportMetrics(sync_username,
- custom_passphrase_sync_enabled);
-}
-
-PasswordStoreChangeList PasswordStoreMac::AddLoginImpl(
- const PasswordForm& form) {
- DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
- if (login_metadata_db_ && AddToKeychainIfNecessary(form))
- return login_metadata_db_->AddLogin(form);
- return PasswordStoreChangeList();
-}
-
-PasswordStoreChangeList PasswordStoreMac::UpdateLoginImpl(
- const PasswordForm& form) {
- DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
- if (!login_metadata_db_)
- return PasswordStoreChangeList();
-
- PasswordStoreChangeList changes = login_metadata_db_->UpdateLogin(form);
-
- MacKeychainPasswordFormAdapter keychain_adapter(keychain_.get());
- if (changes.empty() &&
- !keychain_adapter.HasPasswordsMergeableWithForm(form)) {
- // If the password isn't in either the DB or the keychain, then it must have
- // been deleted after autofill happened, and should not be re-added.
- return changes;
- }
-
- // The keychain add will update if there is a collision and add if there
- // isn't, which is the behavior we want, so there's no separate update call.
- if (AddToKeychainIfNecessary(form) && changes.empty()) {
- changes = login_metadata_db_->AddLogin(form);
- }
- return changes;
-}
-
-PasswordStoreChangeList PasswordStoreMac::RemoveLoginImpl(
- const PasswordForm& form) {
- DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
- PasswordStoreChangeList changes;
- if (login_metadata_db_ && login_metadata_db_->RemoveLogin(form)) {
- // See if we own a Keychain item associated with this item. We can do an
- // exact search rather than messing around with trying to do fuzzy matching
- // because passwords that we created will always have an exact-match
- // database entry.
- // (If a user does lose their profile but not their keychain we'll treat the
- // entries we find like other imported entries anyway, so it's reasonable to
- // handle deletes on them the way we would for an imported item.)
- MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_.get());
- owned_keychain_adapter.SetFindsOnlyOwnedItems(true);
- if (owned_keychain_adapter.HasPasswordExactlyMatchingForm(form)) {
- // If we don't have other forms using it (i.e., a form differing only by
- // the names of the form elements), delete the keychain entry.
- if (!DatabaseHasFormMatchingKeychainForm(form)) {
- owned_keychain_adapter.RemovePassword(form);
- }
- }
-
- changes.push_back(PasswordStoreChange(PasswordStoreChange::REMOVE, form));
- }
- return changes;
-}
-
-PasswordStoreChangeList PasswordStoreMac::RemoveLoginsByURLAndTimeImpl(
- const base::Callback<bool(const GURL&)>& url_filter,
- base::Time delete_begin,
- base::Time delete_end) {
- PasswordStoreChangeList changes;
- std::vector<std::unique_ptr<PasswordForm>> forms_to_consider;
- std::vector<std::unique_ptr<PasswordForm>> forms_to_remove;
- if (login_metadata_db_ &&
- login_metadata_db_->GetLoginsCreatedBetween(delete_begin, delete_end,
- &forms_to_consider)) {
- for (std::unique_ptr<PasswordForm>& form_to_consider : forms_to_consider) {
- if (url_filter.Run(form_to_consider->origin) &&
- login_metadata_db_->RemoveLogin(*form_to_consider))
- forms_to_remove.push_back(std::move(form_to_consider));
- }
- if (!forms_to_remove.empty()) {
- RemoveKeychainForms(forms_to_remove);
- CleanOrphanedForms(&forms_to_remove); // Add the orphaned forms.
- changes = FormsToRemoveChangeList(forms_to_remove);
- LogStatsForBulkDeletion(changes.size());
- }
- }
- return changes;
-}
-
-PasswordStoreChangeList PasswordStoreMac::RemoveLoginsCreatedBetweenImpl(
- base::Time delete_begin,
- base::Time delete_end) {
- PasswordStoreChangeList changes;
- std::vector<std::unique_ptr<PasswordForm>> forms_to_remove;
- if (login_metadata_db_ &&
- login_metadata_db_->GetLoginsCreatedBetween(delete_begin, delete_end,
- &forms_to_remove) &&
- login_metadata_db_->RemoveLoginsCreatedBetween(delete_begin,
- delete_end)) {
- RemoveKeychainForms(forms_to_remove);
- CleanOrphanedForms(&forms_to_remove); // Add the orphaned forms.
- changes = FormsToRemoveChangeList(forms_to_remove);
- LogStatsForBulkDeletion(changes.size());
- }
- return changes;
-}
-
-PasswordStoreChangeList PasswordStoreMac::RemoveLoginsSyncedBetweenImpl(
- base::Time delete_begin,
- base::Time delete_end) {
- PasswordStoreChangeList changes;
- std::vector<std::unique_ptr<PasswordForm>> forms_to_remove;
- if (login_metadata_db_ &&
- login_metadata_db_->GetLoginsSyncedBetween(delete_begin, delete_end,
- &forms_to_remove) &&
- login_metadata_db_->RemoveLoginsSyncedBetween(delete_begin, delete_end)) {
- RemoveKeychainForms(forms_to_remove);
- CleanOrphanedForms(&forms_to_remove); // Add the orphaned forms_to_remove.
- changes = FormsToRemoveChangeList(forms_to_remove);
- LogStatsForBulkDeletionDuringRollback(changes.size());
- }
- return changes;
-}
-
-PasswordStoreChangeList PasswordStoreMac::DisableAutoSignInForOriginsImpl(
- const base::Callback<bool(const GURL&)>& origin_filter) {
- std::vector<std::unique_ptr<PasswordForm>> forms;
- PasswordStoreChangeList changes;
- if (!login_metadata_db_ ||
- !login_metadata_db_->GetAutoSignInLogins(&forms)) {
- return changes;
- }
-
- std::set<GURL> origins_to_update;
- for (const auto& form : forms) {
- if (origin_filter.Run(form->origin))
- origins_to_update.insert(form->origin);
- }
-
- std::set<GURL> origins_updated;
- for (const GURL& origin : origins_to_update) {
- if (login_metadata_db_->DisableAutoSignInForOrigin(origin))
- origins_updated.insert(origin);
- }
-
- for (const auto& form : forms) {
- if (origins_updated.count(form->origin)) {
- changes.push_back(
- PasswordStoreChange(PasswordStoreChange::UPDATE, *form));
- }
- }
-
- return changes;
-}
-
-bool PasswordStoreMac::RemoveStatisticsByOriginAndTimeImpl(
- const base::Callback<bool(const GURL&)>& origin_filter,
- base::Time delete_begin,
- base::Time delete_end) {
- return login_metadata_db_ &&
- login_metadata_db_->stats_table().RemoveStatsByOriginAndTime(
- origin_filter, delete_begin, delete_end);
-}
-
-std::vector<std::unique_ptr<PasswordForm>> PasswordStoreMac::FillMatchingLogins(
- const FormDigest& form) {
- chrome::ScopedSecKeychainSetUserInteractionAllowed user_interaction_allowed(
- false);
-
- std::vector<std::unique_ptr<PasswordForm>> database_forms;
- if (!login_metadata_db_ ||
- !login_metadata_db_->GetLogins(form, &database_forms)) {
- return std::vector<std::unique_ptr<PasswordForm>>();
- }
-
- // Let's gather all signon realms we want to match with keychain entries.
- std::set<std::string> realm_set;
- realm_set.insert(form.signon_realm);
- for (const std::unique_ptr<PasswordForm>& db_form : database_forms) {
- // TODO(vabr): We should not be getting different schemes here.
- // http://crbug.com/340112
- if (form.scheme != db_form->scheme)
- continue; // Forms with different schemes never match.
- if (db_form->is_public_suffix_match || db_form->is_affiliation_based_match)
- realm_set.insert(db_form->signon_realm);
- }
- std::vector<std::unique_ptr<PasswordForm>> keychain_forms;
- for (std::set<std::string>::const_iterator realm = realm_set.begin();
- realm != realm_set.end(); ++realm) {
- MacKeychainPasswordFormAdapter keychain_adapter(keychain_.get());
- std::vector<std::unique_ptr<PasswordForm>> temp_keychain_forms =
- keychain_adapter.PasswordsFillingForm(*realm, form.scheme);
- AppendSecondToFirst(&keychain_forms, &temp_keychain_forms);
- }
-
- std::vector<std::unique_ptr<PasswordForm>> matched_forms;
- internal_keychain_helpers::MergePasswordForms(
- &keychain_forms, &database_forms, &matched_forms);
-
- // Strip any blacklist entries out of the unused Keychain array, then take
- // all the entries that are left (which we can use as imported passwords).
- std::vector<std::unique_ptr<PasswordForm>> keychain_blacklist_forms;
- internal_keychain_helpers::ExtractNonKeychainForms(&keychain_forms,
- &keychain_blacklist_forms);
- AppendSecondToFirst(&matched_forms, &keychain_forms);
-
- if (!database_forms.empty()) {
- RemoveDatabaseForms(&database_forms);
- NotifyLoginsChanged(FormsToRemoveChangeList(database_forms));
- }
-
- return matched_forms;
-}
-
-std::vector<std::unique_ptr<autofill::PasswordForm>>
-PasswordStoreMac::FillLoginsForSameOrganizationName(
- const std::string& signon_realm) {
- // Not implemented.
- return std::vector<std::unique_ptr<autofill::PasswordForm>>();
-}
-
-bool PasswordStoreMac::FillAutofillableLogins(
- std::vector<std::unique_ptr<PasswordForm>>* forms) {
- DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
- forms->clear();
-
- std::vector<std::unique_ptr<PasswordForm>> database_forms;
- if (!login_metadata_db_ ||
- !login_metadata_db_->GetAutofillableLogins(&database_forms))
- return false;
-
- internal_keychain_helpers::GetPasswordsForForms(*keychain_, &database_forms,
- forms);
-
- if (!database_forms.empty()) {
- RemoveDatabaseForms(&database_forms);
- NotifyLoginsChanged(FormsToRemoveChangeList(database_forms));
- }
-
- return true;
-}
-
-bool PasswordStoreMac::FillBlacklistLogins(
- std::vector<std::unique_ptr<PasswordForm>>* forms) {
- DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
- return login_metadata_db_ && login_metadata_db_->GetBlacklistLogins(forms);
-}
-
-void PasswordStoreMac::AddSiteStatsImpl(
- const password_manager::InteractionsStats& stats) {
- DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
- if (login_metadata_db_)
- login_metadata_db_->stats_table().AddRow(stats);
-}
-
-void PasswordStoreMac::RemoveSiteStatsImpl(const GURL& origin_domain) {
- DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
- if (login_metadata_db_)
- login_metadata_db_->stats_table().RemoveRow(origin_domain);
-}
-
-std::vector<password_manager::InteractionsStats>
-PasswordStoreMac::GetAllSiteStatsImpl() {
- DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
- return login_metadata_db_
- ? login_metadata_db_->stats_table().GetAllRows()
- : std::vector<password_manager::InteractionsStats>();
-}
-
-std::vector<password_manager::InteractionsStats>
-PasswordStoreMac::GetSiteStatsImpl(const GURL& origin_domain) {
- DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
- return login_metadata_db_
- ? login_metadata_db_->stats_table().GetRows(origin_domain)
- : std::vector<password_manager::InteractionsStats>();
-}
-
-bool PasswordStoreMac::AddToKeychainIfNecessary(const PasswordForm& form) {
- if (IsLoginDatabaseOnlyForm(form))
- return true;
- MacKeychainPasswordFormAdapter keychainAdapter(keychain_.get());
- return keychainAdapter.AddPassword(form);
-}
-
-bool PasswordStoreMac::DatabaseHasFormMatchingKeychainForm(
- const PasswordForm& form) {
- DCHECK(login_metadata_db_);
- bool has_match = false;
- std::vector<std::unique_ptr<PasswordForm>> database_forms;
- if (!login_metadata_db_->GetLogins(
- password_manager::PasswordStore::FormDigest(form), &database_forms))
- return false;
- for (const auto& db_form : database_forms) {
- // Below we filter out fuzzy matched forms because we are only interested
- // in exact ones.
- if (!db_form->is_public_suffix_match &&
- internal_keychain_helpers::FormsMatchForMerge(
- form, *db_form, internal_keychain_helpers::STRICT_FORM_MATCH) &&
- db_form->origin == form.origin) {
- has_match = true;
- break;
- }
- }
- return has_match;
-}
-
-void PasswordStoreMac::RemoveDatabaseForms(
- std::vector<std::unique_ptr<PasswordForm>>* forms) {
- DCHECK(login_metadata_db_);
- std::vector<std::unique_ptr<PasswordForm>> removed_forms;
- for (std::unique_ptr<PasswordForm>& form : *forms) {
- if (login_metadata_db_->RemoveLogin(*form))
- removed_forms.push_back(std::move(form));
- }
- removed_forms.swap(*forms);
-}
-
-void PasswordStoreMac::RemoveKeychainForms(
- const std::vector<std::unique_ptr<PasswordForm>>& forms) {
- MacKeychainPasswordFormAdapter owned_keychain_adapter(keychain_.get());
- owned_keychain_adapter.SetFindsOnlyOwnedItems(true);
- for (const auto& form : forms) {
- owned_keychain_adapter.RemovePassword(*form);
- }
-}
-
-void PasswordStoreMac::CleanOrphanedForms(
- std::vector<std::unique_ptr<PasswordForm>>* orphaned_forms) {
- DCHECK(orphaned_forms);
- DCHECK(login_metadata_db_);
-
- std::vector<std::unique_ptr<PasswordForm>> database_forms;
- if (!login_metadata_db_->GetAutofillableLogins(&database_forms))
- return;
-
- // Filter forms with corresponding Keychain entry out of |database_forms|.
- std::vector<std::unique_ptr<PasswordForm>> forms_with_keychain_entry;
- internal_keychain_helpers::GetPasswordsForForms(*keychain_, &database_forms,
- &forms_with_keychain_entry);
-
- // Clean up any orphaned database entries.
- RemoveDatabaseForms(&database_forms);
-
- // Move the orphaned DB forms to the output parameter.
- AppendSecondToFirst(orphaned_forms, &database_forms);
-}
« no previous file with comments | « chrome/browser/password_manager/password_store_mac.h ('k') | chrome/browser/password_manager/password_store_mac_internal.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698