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

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

Issue 1375883002: Support Android username-only credentials. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: comments Created 5 years, 2 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
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/password_manager/password_store_mac.h" 5 #include "chrome/browser/password_manager/password_store_mac.h"
6 #include "chrome/browser/password_manager/password_store_mac_internal.h" 6 #include "chrome/browser/password_manager/password_store_mac_internal.h"
7 7
8 #include <CoreServices/CoreServices.h> 8 #include <CoreServices/CoreServices.h>
9 #include <set> 9 #include <set>
10 #include <string> 10 #include <string>
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after
231 mover(scoped_ptr<autofill::PasswordForm>(form_ptr)); 231 mover(scoped_ptr<autofill::PasswordForm>(form_ptr));
232 } 232 }
233 // We moved the ownership of every form out of |forms|. For performance 233 // We moved the ownership of every form out of |forms|. For performance
234 // reasons, we can just weak_clear it, instead of nullptr-ing the respective 234 // reasons, we can just weak_clear it, instead of nullptr-ing the respective
235 // elements and letting the vector's destructor to go through the list once 235 // elements and letting the vector's destructor to go through the list once
236 // more. This was tested on a benchmark, and seemed to make a difference on 236 // more. This was tested on a benchmark, and seemed to make a difference on
237 // Mac. 237 // Mac.
238 forms->weak_clear(); 238 forms->weak_clear();
239 } 239 }
240 240
241 // True if the form has no password to be stored in Keychain.
242 bool IsLoginDatabaseOnlyForm(const autofill::PasswordForm& form) {
243 return form.blacklisted_by_user || !form.federation_url.is_empty() ||
244 form.scheme == autofill::PasswordForm::SCHEME_USERNAME_ONLY;
245 }
246
241 } // namespace 247 } // namespace
242 248
243 #pragma mark - 249 #pragma mark -
244 250
245 // TODO(stuartmorgan): Convert most of this to private helpers in 251 // TODO(stuartmorgan): Convert most of this to private helpers in
246 // MacKeychainPasswordFormAdapter once it has sufficient higher-level public 252 // MacKeychainPasswordFormAdapter once it has sufficient higher-level public
247 // methods to provide test coverage. 253 // methods to provide test coverage.
248 namespace internal_keychain_helpers { 254 namespace internal_keychain_helpers {
249 255
250 // Returns a URL built from the given components. To create a URL without a 256 // Returns a URL built from the given components. To create a URL without a
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after
463 break; 469 break;
464 } 470 }
465 } 471 }
466 keychain.ItemFreeAttributesAndData(attr_list, nullptr); 472 keychain.ItemFreeAttributesAndData(attr_list, nullptr);
467 return creator_code && creator_code == base::mac::CreatorCodeForApplication(); 473 return creator_code && creator_code == base::mac::CreatorCodeForApplication();
468 } 474 }
469 475
470 bool FormsMatchForMerge(const PasswordForm& form_a, 476 bool FormsMatchForMerge(const PasswordForm& form_a,
471 const PasswordForm& form_b, 477 const PasswordForm& form_b,
472 FormMatchStrictness strictness) { 478 FormMatchStrictness strictness) {
473 // We never merge blacklist entries between our store and the Keychain, 479 if (IsLoginDatabaseOnlyForm(form_a) || IsLoginDatabaseOnlyForm(form_b))
474 // and federated logins should not be stored in the Keychain at all.
475 if (form_a.blacklisted_by_user || form_b.blacklisted_by_user ||
476 !form_a.federation_url.is_empty() || !form_b.federation_url.is_empty()) {
477 return false; 480 return false;
478 } 481
479 bool equal_realm = form_a.signon_realm == form_b.signon_realm; 482 bool equal_realm = form_a.signon_realm == form_b.signon_realm;
480 if (strictness == FUZZY_FORM_MATCH) { 483 if (strictness == FUZZY_FORM_MATCH) {
481 equal_realm |= form_a.is_public_suffix_match; 484 equal_realm |= form_a.is_public_suffix_match;
482 } 485 }
483 return form_a.scheme == form_b.scheme && equal_realm && 486 return form_a.scheme == form_b.scheme && equal_realm &&
484 form_a.username_value == form_b.username_value; 487 form_a.username_value == form_b.username_value;
485 } 488 }
486 489
487 // Moves entries from |forms| that represent either blacklisted or federated 490 // Moves entries from |forms| that represent either blacklisted or federated
488 // logins into |extracted|. These two types are stored only in the LoginDatabase 491 // logins into |extracted|. These two types are stored only in the LoginDatabase
489 // and do not have corresponding Keychain entries. 492 // and do not have corresponding Keychain entries.
490 void ExtractNonKeychainForms(ScopedVector<autofill::PasswordForm>* forms, 493 void ExtractNonKeychainForms(ScopedVector<autofill::PasswordForm>* forms,
491 ScopedVector<autofill::PasswordForm>* extracted) { 494 ScopedVector<autofill::PasswordForm>* extracted) {
492 extracted->reserve(extracted->size() + forms->size()); 495 extracted->reserve(extracted->size() + forms->size());
493 ScopedVector<autofill::PasswordForm> remaining; 496 ScopedVector<autofill::PasswordForm> remaining;
494 MoveAllFormsOut( 497 MoveAllFormsOut(
495 forms, [&remaining, extracted](scoped_ptr<autofill::PasswordForm> form) { 498 forms, [&remaining, extracted](scoped_ptr<autofill::PasswordForm> form) {
496 if (form->blacklisted_by_user || !form->federation_url.is_empty()) 499 if (IsLoginDatabaseOnlyForm(*form))
497 extracted->push_back(form.Pass()); 500 extracted->push_back(form.Pass());
498 else 501 else
499 remaining.push_back(form.Pass()); 502 remaining.push_back(form.Pass());
500 }); 503 });
501 forms->swap(remaining); 504 forms->swap(remaining);
502 } 505 }
503 506
504 // Takes |keychain_forms| and |database_forms| and moves the following 2 types 507 // Takes |keychain_forms| and |database_forms| and moves the following 2 types
505 // of forms to |merged_forms|: 508 // of forms to |merged_forms|:
506 // (1) |database_forms| that by principle never have a corresponding Keychain 509 // (1) |database_forms| that by principle never have a corresponding Keychain
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after
714 SecKeychainItemRef keychain_item = KeychainItemForForm(query_form); 717 SecKeychainItemRef keychain_item = KeychainItemForForm(query_form);
715 if (keychain_item) { 718 if (keychain_item) {
716 keychain_->Free(keychain_item); 719 keychain_->Free(keychain_item);
717 return true; 720 return true;
718 } 721 }
719 return false; 722 return false;
720 } 723 }
721 724
722 bool MacKeychainPasswordFormAdapter::HasPasswordsMergeableWithForm( 725 bool MacKeychainPasswordFormAdapter::HasPasswordsMergeableWithForm(
723 const PasswordForm& query_form) { 726 const PasswordForm& query_form) {
724 if (!query_form.federation_url.is_empty()) 727 if (IsLoginDatabaseOnlyForm(query_form))
725 return false; 728 return false;
726 std::string username = base::UTF16ToUTF8(query_form.username_value); 729 std::string username = base::UTF16ToUTF8(query_form.username_value);
727 std::vector<SecKeychainItemRef> matches = 730 std::vector<SecKeychainItemRef> matches =
728 MatchingKeychainItems(query_form.signon_realm, query_form.scheme, 731 MatchingKeychainItems(query_form.signon_realm, query_form.scheme,
729 NULL, username.c_str()); 732 NULL, username.c_str());
730 for (std::vector<SecKeychainItemRef>::iterator i = matches.begin(); 733 for (std::vector<SecKeychainItemRef>::iterator i = matches.begin();
731 i != matches.end(); ++i) { 734 i != matches.end(); ++i) {
732 keychain_->Free(*i); 735 keychain_->Free(*i);
733 } 736 }
734 737
(...skipping 26 matching lines...) Expand all
761 } 764 }
762 765
763 ScopedVector<autofill::PasswordForm> 766 ScopedVector<autofill::PasswordForm>
764 MacKeychainPasswordFormAdapter::GetAllPasswordFormPasswords() { 767 MacKeychainPasswordFormAdapter::GetAllPasswordFormPasswords() {
765 std::vector<SecKeychainItemRef> items = GetAllPasswordFormKeychainItems(); 768 std::vector<SecKeychainItemRef> items = GetAllPasswordFormKeychainItems();
766 return ConvertKeychainItemsToForms(&items); 769 return ConvertKeychainItemsToForms(&items);
767 } 770 }
768 771
769 bool MacKeychainPasswordFormAdapter::AddPassword(const PasswordForm& form) { 772 bool MacKeychainPasswordFormAdapter::AddPassword(const PasswordForm& form) {
770 // We should never be trying to store a blacklist in the keychain. 773 // We should never be trying to store a blacklist in the keychain.
771 DCHECK(!form.blacklisted_by_user); 774 DCHECK(!IsLoginDatabaseOnlyForm(form));
772 775
773 std::string server; 776 std::string server;
774 std::string security_domain; 777 std::string security_domain;
775 UInt32 port; 778 UInt32 port;
776 bool is_secure; 779 bool is_secure;
777 if (!internal_keychain_helpers::ExtractSignonRealmComponents( 780 if (!internal_keychain_helpers::ExtractSignonRealmComponents(
778 form.signon_realm, &server, &port, &is_secure, &security_domain)) { 781 form.signon_realm, &server, &port, &is_secure, &security_domain)) {
779 return false; 782 return false;
780 } 783 }
781 std::string path; 784 std::string path;
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
841 } 844 }
842 items->clear(); 845 items->clear();
843 return forms.Pass(); 846 return forms.Pass();
844 } 847 }
845 848
846 SecKeychainItemRef MacKeychainPasswordFormAdapter::KeychainItemForForm( 849 SecKeychainItemRef MacKeychainPasswordFormAdapter::KeychainItemForForm(
847 const PasswordForm& form) { 850 const PasswordForm& form) {
848 // We don't store blacklist entries in the keychain, so the answer to "what 851 // We don't store blacklist entries in the keychain, so the answer to "what
849 // Keychain item goes with this form" is always "nothing" for blacklists. 852 // Keychain item goes with this form" is always "nothing" for blacklists.
850 // Same goes for federated logins. 853 // Same goes for federated logins.
851 if (form.blacklisted_by_user || !form.federation_url.is_empty()) { 854 if (IsLoginDatabaseOnlyForm(form))
852 return NULL; 855 return NULL;
853 }
854 856
855 std::string path; 857 std::string path;
856 // Path doesn't make sense for Android app credentials. 858 // Path doesn't make sense for Android app credentials.
857 if (!password_manager::IsValidAndroidFacetURI(form.signon_realm)) 859 if (!password_manager::IsValidAndroidFacetURI(form.signon_realm))
858 path = form.origin.path(); 860 path = form.origin.path();
859 std::string username = base::UTF16ToUTF8(form.username_value); 861 std::string username = base::UTF16ToUTF8(form.username_value);
860 std::vector<SecKeychainItemRef> matches = MatchingKeychainItems( 862 std::vector<SecKeychainItemRef> matches = MatchingKeychainItems(
861 form.signon_realm, form.scheme, path.c_str(), username.c_str()); 863 form.signon_realm, form.scheme, path.c_str(), username.c_str());
862 864
863 if (matches.empty()) { 865 if (matches.empty()) {
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
909 } 911 }
910 912
911 // Returns the Keychain SecAuthenticationType type corresponding to |scheme|. 913 // Returns the Keychain SecAuthenticationType type corresponding to |scheme|.
912 SecAuthenticationType MacKeychainPasswordFormAdapter::AuthTypeForScheme( 914 SecAuthenticationType MacKeychainPasswordFormAdapter::AuthTypeForScheme(
913 PasswordForm::Scheme scheme) { 915 PasswordForm::Scheme scheme) {
914 switch (scheme) { 916 switch (scheme) {
915 case PasswordForm::SCHEME_HTML: return kSecAuthenticationTypeHTMLForm; 917 case PasswordForm::SCHEME_HTML: return kSecAuthenticationTypeHTMLForm;
916 case PasswordForm::SCHEME_BASIC: return kSecAuthenticationTypeHTTPBasic; 918 case PasswordForm::SCHEME_BASIC: return kSecAuthenticationTypeHTTPBasic;
917 case PasswordForm::SCHEME_DIGEST: return kSecAuthenticationTypeHTTPDigest; 919 case PasswordForm::SCHEME_DIGEST: return kSecAuthenticationTypeHTTPDigest;
918 case PasswordForm::SCHEME_OTHER: return kSecAuthenticationTypeDefault; 920 case PasswordForm::SCHEME_OTHER: return kSecAuthenticationTypeDefault;
921 case PasswordForm::SCHEME_USERNAME_ONLY:
922 NOTREACHED();
923 break;
919 } 924 }
920 NOTREACHED(); 925 NOTREACHED();
921 return kSecAuthenticationTypeDefault; 926 return kSecAuthenticationTypeDefault;
922 } 927 }
923 928
924 bool MacKeychainPasswordFormAdapter::SetKeychainItemPassword( 929 bool MacKeychainPasswordFormAdapter::SetKeychainItemPassword(
925 const SecKeychainItemRef& keychain_item, const std::string& password) { 930 const SecKeychainItemRef& keychain_item, const std::string& password) {
926 OSStatus result = keychain_->ItemModifyAttributesAndData(keychain_item, NULL, 931 OSStatus result = keychain_->ItemModifyAttributesAndData(keychain_item, NULL,
927 password.size(), 932 password.size(),
928 password.c_str()); 933 password.c_str());
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after
1175 } 1180 }
1176 1181
1177 // Let's gather all signon realms we want to match with keychain entries. 1182 // Let's gather all signon realms we want to match with keychain entries.
1178 std::set<std::string> realm_set; 1183 std::set<std::string> realm_set;
1179 realm_set.insert(form.signon_realm); 1184 realm_set.insert(form.signon_realm);
1180 for (const autofill::PasswordForm* db_form : database_forms) { 1185 for (const autofill::PasswordForm* db_form : database_forms) {
1181 // TODO(vabr): We should not be getting different schemes here. 1186 // TODO(vabr): We should not be getting different schemes here.
1182 // http://crbug.com/340112 1187 // http://crbug.com/340112
1183 if (form.scheme != db_form->scheme) 1188 if (form.scheme != db_form->scheme)
1184 continue; // Forms with different schemes never match. 1189 continue; // Forms with different schemes never match.
1185 if (db_form->is_public_suffix_match) 1190 if (db_form->is_public_suffix_match)
engedy 2015/10/13 12:11:33 We need to take |is_affiliation_based_match| into
vasilii 2015/10/13 18:05:26 That's unrelated to the current CL. Please follow
1186 realm_set.insert(db_form->signon_realm); 1191 realm_set.insert(db_form->signon_realm);
1187 } 1192 }
1188 ScopedVector<autofill::PasswordForm> keychain_forms; 1193 ScopedVector<autofill::PasswordForm> keychain_forms;
1189 for (std::set<std::string>::const_iterator realm = realm_set.begin(); 1194 for (std::set<std::string>::const_iterator realm = realm_set.begin();
1190 realm != realm_set.end(); ++realm) { 1195 realm != realm_set.end(); ++realm) {
1191 MacKeychainPasswordFormAdapter keychain_adapter(keychain_.get()); 1196 MacKeychainPasswordFormAdapter keychain_adapter(keychain_.get());
1192 ScopedVector<autofill::PasswordForm> temp_keychain_forms = 1197 ScopedVector<autofill::PasswordForm> temp_keychain_forms =
1193 keychain_adapter.PasswordsFillingForm(*realm, form.scheme); 1198 keychain_adapter.PasswordsFillingForm(*realm, form.scheme);
1194 AppendSecondToFirst(&keychain_forms, &temp_keychain_forms); 1199 AppendSecondToFirst(&keychain_forms, &temp_keychain_forms);
1195 } 1200 }
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
1254 1259
1255 scoped_ptr<password_manager::InteractionsStats> 1260 scoped_ptr<password_manager::InteractionsStats>
1256 PasswordStoreMac::GetSiteStatsImpl(const GURL& origin_domain) { 1261 PasswordStoreMac::GetSiteStatsImpl(const GURL& origin_domain) {
1257 DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread()); 1262 DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread());
1258 return login_metadata_db_ 1263 return login_metadata_db_
1259 ? login_metadata_db_->stats_table().GetRow(origin_domain) 1264 ? login_metadata_db_->stats_table().GetRow(origin_domain)
1260 : scoped_ptr<password_manager::InteractionsStats>(); 1265 : scoped_ptr<password_manager::InteractionsStats>();
1261 } 1266 }
1262 1267
1263 bool PasswordStoreMac::AddToKeychainIfNecessary(const PasswordForm& form) { 1268 bool PasswordStoreMac::AddToKeychainIfNecessary(const PasswordForm& form) {
1264 if (form.blacklisted_by_user || !form.federation_url.is_empty()) 1269 if (IsLoginDatabaseOnlyForm(form))
1265 return true; 1270 return true;
1266 MacKeychainPasswordFormAdapter keychainAdapter(keychain_.get()); 1271 MacKeychainPasswordFormAdapter keychainAdapter(keychain_.get());
1267 return keychainAdapter.AddPassword(form); 1272 return keychainAdapter.AddPassword(form);
1268 } 1273 }
1269 1274
1270 bool PasswordStoreMac::DatabaseHasFormMatchingKeychainForm( 1275 bool PasswordStoreMac::DatabaseHasFormMatchingKeychainForm(
1271 const autofill::PasswordForm& form) { 1276 const autofill::PasswordForm& form) {
1272 DCHECK(login_metadata_db_); 1277 DCHECK(login_metadata_db_);
1273 bool has_match = false; 1278 bool has_match = false;
1274 ScopedVector<autofill::PasswordForm> database_forms; 1279 ScopedVector<autofill::PasswordForm> database_forms;
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
1323 ScopedVector<PasswordForm> forms_with_keychain_entry; 1328 ScopedVector<PasswordForm> forms_with_keychain_entry;
1324 internal_keychain_helpers::GetPasswordsForForms(*keychain_, &database_forms, 1329 internal_keychain_helpers::GetPasswordsForForms(*keychain_, &database_forms,
1325 &forms_with_keychain_entry); 1330 &forms_with_keychain_entry);
1326 1331
1327 // Clean up any orphaned database entries. 1332 // Clean up any orphaned database entries.
1328 RemoveDatabaseForms(&database_forms); 1333 RemoveDatabaseForms(&database_forms);
1329 1334
1330 // Move the orphaned DB forms to the output parameter. 1335 // Move the orphaned DB forms to the output parameter.
1331 AppendSecondToFirst(orphaned_forms, &database_forms); 1336 AppendSecondToFirst(orphaned_forms, &database_forms);
1332 } 1337 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698