OLD | NEW |
---|---|
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 Loading... | |
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 IsDBOnlyForm(const autofill::PasswordForm& form) { | |
engedy
2015/10/08 17:31:00
nit: IsLoginDatabaseOnlyForm
vasilii
2015/10/12 15:12:48
Done.
| |
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 Loading... | |
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 // We never merge blacklist entries between our store and the Keychain, |
vabr (Chromium)
2015/10/09 07:53:09
nit: This comment is slightly out of date. And giv
vasilii
2015/10/12 15:12:48
Done.
| |
474 // and federated logins should not be stored in the Keychain at all. | 480 // and federated logins should not be stored in the Keychain at all. |
475 if (form_a.blacklisted_by_user || form_b.blacklisted_by_user || | 481 if (IsDBOnlyForm(form_a) || IsDBOnlyForm(form_b)) |
476 !form_a.federation_url.is_empty() || !form_b.federation_url.is_empty()) { | |
477 return false; | 482 return false; |
478 } | 483 |
479 bool equal_realm = form_a.signon_realm == form_b.signon_realm; | 484 bool equal_realm = form_a.signon_realm == form_b.signon_realm; |
480 if (strictness == FUZZY_FORM_MATCH) { | 485 if (strictness == FUZZY_FORM_MATCH) { |
481 equal_realm |= (!form_a.original_signon_realm.empty()) && | 486 equal_realm |= (!form_a.original_signon_realm.empty()) && |
482 form_a.original_signon_realm == form_b.signon_realm; | 487 form_a.original_signon_realm == form_b.signon_realm; |
483 } | 488 } |
484 return form_a.scheme == form_b.scheme && equal_realm && | 489 return form_a.scheme == form_b.scheme && equal_realm && |
485 form_a.username_value == form_b.username_value; | 490 form_a.username_value == form_b.username_value; |
486 } | 491 } |
487 | 492 |
488 // Moves entries from |forms| that represent either blacklisted or federated | 493 // Moves entries from |forms| that represent either blacklisted or federated |
489 // logins into |extracted|. These two types are stored only in the LoginDatabase | 494 // logins into |extracted|. These two types are stored only in the LoginDatabase |
490 // and do not have corresponding Keychain entries. | 495 // and do not have corresponding Keychain entries. |
491 void ExtractNonKeychainForms(ScopedVector<autofill::PasswordForm>* forms, | 496 void ExtractNonKeychainForms(ScopedVector<autofill::PasswordForm>* forms, |
492 ScopedVector<autofill::PasswordForm>* extracted) { | 497 ScopedVector<autofill::PasswordForm>* extracted) { |
493 extracted->reserve(extracted->size() + forms->size()); | 498 extracted->reserve(extracted->size() + forms->size()); |
494 ScopedVector<autofill::PasswordForm> remaining; | 499 ScopedVector<autofill::PasswordForm> remaining; |
495 MoveAllFormsOut( | 500 MoveAllFormsOut( |
496 forms, [&remaining, extracted](scoped_ptr<autofill::PasswordForm> form) { | 501 forms, [&remaining, extracted](scoped_ptr<autofill::PasswordForm> form) { |
497 if (form->blacklisted_by_user || !form->federation_url.is_empty()) | 502 if (IsDBOnlyForm(*form)) |
498 extracted->push_back(form.Pass()); | 503 extracted->push_back(form.Pass()); |
499 else | 504 else |
500 remaining.push_back(form.Pass()); | 505 remaining.push_back(form.Pass()); |
501 }); | 506 }); |
502 forms->swap(remaining); | 507 forms->swap(remaining); |
503 } | 508 } |
504 | 509 |
505 // Takes |keychain_forms| and |database_forms| and moves the following 2 types | 510 // Takes |keychain_forms| and |database_forms| and moves the following 2 types |
506 // of forms to |merged_forms|: | 511 // of forms to |merged_forms|: |
507 // (1) |database_forms| that by principle never have a corresponding Keychain | 512 // (1) |database_forms| that by principle never have a corresponding Keychain |
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
715 SecKeychainItemRef keychain_item = KeychainItemForForm(query_form); | 720 SecKeychainItemRef keychain_item = KeychainItemForForm(query_form); |
716 if (keychain_item) { | 721 if (keychain_item) { |
717 keychain_->Free(keychain_item); | 722 keychain_->Free(keychain_item); |
718 return true; | 723 return true; |
719 } | 724 } |
720 return false; | 725 return false; |
721 } | 726 } |
722 | 727 |
723 bool MacKeychainPasswordFormAdapter::HasPasswordsMergeableWithForm( | 728 bool MacKeychainPasswordFormAdapter::HasPasswordsMergeableWithForm( |
724 const PasswordForm& query_form) { | 729 const PasswordForm& query_form) { |
725 if (!query_form.federation_url.is_empty()) | 730 if (IsDBOnlyForm(query_form)) |
726 return false; | 731 return false; |
727 std::string username = base::UTF16ToUTF8(query_form.username_value); | 732 std::string username = base::UTF16ToUTF8(query_form.username_value); |
728 std::vector<SecKeychainItemRef> matches = | 733 std::vector<SecKeychainItemRef> matches = |
729 MatchingKeychainItems(query_form.signon_realm, query_form.scheme, | 734 MatchingKeychainItems(query_form.signon_realm, query_form.scheme, |
730 NULL, username.c_str()); | 735 NULL, username.c_str()); |
731 for (std::vector<SecKeychainItemRef>::iterator i = matches.begin(); | 736 for (std::vector<SecKeychainItemRef>::iterator i = matches.begin(); |
732 i != matches.end(); ++i) { | 737 i != matches.end(); ++i) { |
733 keychain_->Free(*i); | 738 keychain_->Free(*i); |
734 } | 739 } |
735 | 740 |
(...skipping 26 matching lines...) Expand all Loading... | |
762 } | 767 } |
763 | 768 |
764 ScopedVector<autofill::PasswordForm> | 769 ScopedVector<autofill::PasswordForm> |
765 MacKeychainPasswordFormAdapter::GetAllPasswordFormPasswords() { | 770 MacKeychainPasswordFormAdapter::GetAllPasswordFormPasswords() { |
766 std::vector<SecKeychainItemRef> items = GetAllPasswordFormKeychainItems(); | 771 std::vector<SecKeychainItemRef> items = GetAllPasswordFormKeychainItems(); |
767 return ConvertKeychainItemsToForms(&items); | 772 return ConvertKeychainItemsToForms(&items); |
768 } | 773 } |
769 | 774 |
770 bool MacKeychainPasswordFormAdapter::AddPassword(const PasswordForm& form) { | 775 bool MacKeychainPasswordFormAdapter::AddPassword(const PasswordForm& form) { |
771 // We should never be trying to store a blacklist in the keychain. | 776 // We should never be trying to store a blacklist in the keychain. |
772 DCHECK(!form.blacklisted_by_user); | 777 DCHECK(!IsDBOnlyForm(form)); |
773 | 778 |
774 std::string server; | 779 std::string server; |
775 std::string security_domain; | 780 std::string security_domain; |
776 UInt32 port; | 781 UInt32 port; |
777 bool is_secure; | 782 bool is_secure; |
778 if (!internal_keychain_helpers::ExtractSignonRealmComponents( | 783 if (!internal_keychain_helpers::ExtractSignonRealmComponents( |
779 form.signon_realm, &server, &port, &is_secure, &security_domain)) { | 784 form.signon_realm, &server, &port, &is_secure, &security_domain)) { |
780 return false; | 785 return false; |
781 } | 786 } |
782 std::string path; | 787 std::string path; |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
842 } | 847 } |
843 items->clear(); | 848 items->clear(); |
844 return forms.Pass(); | 849 return forms.Pass(); |
845 } | 850 } |
846 | 851 |
847 SecKeychainItemRef MacKeychainPasswordFormAdapter::KeychainItemForForm( | 852 SecKeychainItemRef MacKeychainPasswordFormAdapter::KeychainItemForForm( |
848 const PasswordForm& form) { | 853 const PasswordForm& form) { |
849 // We don't store blacklist entries in the keychain, so the answer to "what | 854 // We don't store blacklist entries in the keychain, so the answer to "what |
850 // Keychain item goes with this form" is always "nothing" for blacklists. | 855 // Keychain item goes with this form" is always "nothing" for blacklists. |
851 // Same goes for federated logins. | 856 // Same goes for federated logins. |
852 if (form.blacklisted_by_user || !form.federation_url.is_empty()) { | 857 if (IsDBOnlyForm(form)) |
853 return NULL; | 858 return NULL; |
854 } | |
855 | 859 |
856 std::string path; | 860 std::string path; |
857 // Path doesn't make sense for Android app credentials. | 861 // Path doesn't make sense for Android app credentials. |
858 if (!password_manager::IsValidAndroidFacetURI(form.signon_realm)) | 862 if (!password_manager::IsValidAndroidFacetURI(form.signon_realm)) |
859 path = form.origin.path(); | 863 path = form.origin.path(); |
860 std::string username = base::UTF16ToUTF8(form.username_value); | 864 std::string username = base::UTF16ToUTF8(form.username_value); |
861 std::vector<SecKeychainItemRef> matches = MatchingKeychainItems( | 865 std::vector<SecKeychainItemRef> matches = MatchingKeychainItems( |
862 form.signon_realm, form.scheme, path.c_str(), username.c_str()); | 866 form.signon_realm, form.scheme, path.c_str(), username.c_str()); |
863 | 867 |
864 if (matches.empty()) { | 868 if (matches.empty()) { |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
910 } | 914 } |
911 | 915 |
912 // Returns the Keychain SecAuthenticationType type corresponding to |scheme|. | 916 // Returns the Keychain SecAuthenticationType type corresponding to |scheme|. |
913 SecAuthenticationType MacKeychainPasswordFormAdapter::AuthTypeForScheme( | 917 SecAuthenticationType MacKeychainPasswordFormAdapter::AuthTypeForScheme( |
914 PasswordForm::Scheme scheme) { | 918 PasswordForm::Scheme scheme) { |
915 switch (scheme) { | 919 switch (scheme) { |
916 case PasswordForm::SCHEME_HTML: return kSecAuthenticationTypeHTMLForm; | 920 case PasswordForm::SCHEME_HTML: return kSecAuthenticationTypeHTMLForm; |
917 case PasswordForm::SCHEME_BASIC: return kSecAuthenticationTypeHTTPBasic; | 921 case PasswordForm::SCHEME_BASIC: return kSecAuthenticationTypeHTTPBasic; |
918 case PasswordForm::SCHEME_DIGEST: return kSecAuthenticationTypeHTTPDigest; | 922 case PasswordForm::SCHEME_DIGEST: return kSecAuthenticationTypeHTTPDigest; |
919 case PasswordForm::SCHEME_OTHER: return kSecAuthenticationTypeDefault; | 923 case PasswordForm::SCHEME_OTHER: return kSecAuthenticationTypeDefault; |
924 case PasswordForm::SCHEME_USERNAME_ONLY: | |
925 NOTREACHED(); | |
926 break; | |
920 } | 927 } |
921 NOTREACHED(); | 928 NOTREACHED(); |
922 return kSecAuthenticationTypeDefault; | 929 return kSecAuthenticationTypeDefault; |
923 } | 930 } |
924 | 931 |
925 bool MacKeychainPasswordFormAdapter::SetKeychainItemPassword( | 932 bool MacKeychainPasswordFormAdapter::SetKeychainItemPassword( |
926 const SecKeychainItemRef& keychain_item, const std::string& password) { | 933 const SecKeychainItemRef& keychain_item, const std::string& password) { |
927 OSStatus result = keychain_->ItemModifyAttributesAndData(keychain_item, NULL, | 934 OSStatus result = keychain_->ItemModifyAttributesAndData(keychain_item, NULL, |
928 password.size(), | 935 password.size(), |
929 password.c_str()); | 936 password.c_str()); |
(...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1256 | 1263 |
1257 scoped_ptr<password_manager::InteractionsStats> | 1264 scoped_ptr<password_manager::InteractionsStats> |
1258 PasswordStoreMac::GetSiteStatsImpl(const GURL& origin_domain) { | 1265 PasswordStoreMac::GetSiteStatsImpl(const GURL& origin_domain) { |
1259 DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread()); | 1266 DCHECK(GetBackgroundTaskRunner()->BelongsToCurrentThread()); |
1260 return login_metadata_db_ | 1267 return login_metadata_db_ |
1261 ? login_metadata_db_->stats_table().GetRow(origin_domain) | 1268 ? login_metadata_db_->stats_table().GetRow(origin_domain) |
1262 : scoped_ptr<password_manager::InteractionsStats>(); | 1269 : scoped_ptr<password_manager::InteractionsStats>(); |
1263 } | 1270 } |
1264 | 1271 |
1265 bool PasswordStoreMac::AddToKeychainIfNecessary(const PasswordForm& form) { | 1272 bool PasswordStoreMac::AddToKeychainIfNecessary(const PasswordForm& form) { |
1266 if (form.blacklisted_by_user || !form.federation_url.is_empty()) | 1273 if (IsDBOnlyForm(form)) |
1267 return true; | 1274 return true; |
1268 MacKeychainPasswordFormAdapter keychainAdapter(keychain_.get()); | 1275 MacKeychainPasswordFormAdapter keychainAdapter(keychain_.get()); |
1269 return keychainAdapter.AddPassword(form); | 1276 return keychainAdapter.AddPassword(form); |
1270 } | 1277 } |
1271 | 1278 |
1272 bool PasswordStoreMac::DatabaseHasFormMatchingKeychainForm( | 1279 bool PasswordStoreMac::DatabaseHasFormMatchingKeychainForm( |
1273 const autofill::PasswordForm& form) { | 1280 const autofill::PasswordForm& form) { |
1274 DCHECK(login_metadata_db_); | 1281 DCHECK(login_metadata_db_); |
1275 bool has_match = false; | 1282 bool has_match = false; |
1276 ScopedVector<autofill::PasswordForm> database_forms; | 1283 ScopedVector<autofill::PasswordForm> database_forms; |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1325 ScopedVector<PasswordForm> forms_with_keychain_entry; | 1332 ScopedVector<PasswordForm> forms_with_keychain_entry; |
1326 internal_keychain_helpers::GetPasswordsForForms(*keychain_, &database_forms, | 1333 internal_keychain_helpers::GetPasswordsForForms(*keychain_, &database_forms, |
1327 &forms_with_keychain_entry); | 1334 &forms_with_keychain_entry); |
1328 | 1335 |
1329 // Clean up any orphaned database entries. | 1336 // Clean up any orphaned database entries. |
1330 RemoveDatabaseForms(&database_forms); | 1337 RemoveDatabaseForms(&database_forms); |
1331 | 1338 |
1332 // Move the orphaned DB forms to the output parameter. | 1339 // Move the orphaned DB forms to the output parameter. |
1333 AppendSecondToFirst(orphaned_forms, &database_forms); | 1340 AppendSecondToFirst(orphaned_forms, &database_forms); |
1334 } | 1341 } |
OLD | NEW |