Index: chrome/browser/password_manager/password_store_mac.cc |
=================================================================== |
--- chrome/browser/password_manager/password_store_mac.cc (revision 19855) |
+++ chrome/browser/password_manager/password_store_mac.cc (working copy) |
@@ -143,7 +143,7 @@ |
SecKeychainItemRef keychain_item; |
while (keychain_->SearchCopyNext(search_ref_, &keychain_item) == noErr) { |
- // Consumer is responsible for deleting the forms when they are done. |
+ // Consumer is responsible for freeing the items. |
items->push_back(keychain_item); |
} |
@@ -158,37 +158,6 @@ |
// methods to provide test coverage. |
namespace internal_keychain_helpers { |
-// Takes a PasswordForm's signon_realm and parses it into its component parts, |
-// which are returned though the appropriate out parameters. |
-// Returns true if it can be successfully parsed, in which case all out params |
-// that are non-NULL will be set. If there is no port, port will be 0. |
-// If the return value is false, the state of the our params is undefined. |
-// |
-// TODO(stuartmorgan): signon_realm for proxies is not yet supported. |
-bool ExtractSignonRealmComponents(const std::string& signon_realm, |
- std::string* server, int* port, |
- bool* is_secure, |
- std::string* security_domain) { |
- // 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.SchemeIsSecure(); |
- 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. |
- *security_domain = realm_as_url.path().substr(1); |
- } |
- return true; |
-} |
- |
// 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, |
@@ -237,18 +206,6 @@ |
return false; |
} |
-// Returns the Keychain SecAuthenticationType type corresponding to |scheme|. |
-SecAuthenticationType 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; |
- } |
- NOTREACHED(); |
- return kSecAuthenticationTypeDefault; |
-} |
- |
// Returns the PasswordForm Scheme corresponding to |auth_type|. |
PasswordForm::Scheme SchemeForAuthType(SecAuthenticationType auth_type) { |
switch (auth_type) { |
@@ -259,53 +216,6 @@ |
} |
} |
-SecKeychainItemRef MatchingKeychainItem(const MacKeychain& keychain, |
- 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. |
- if (form.blacklisted_by_user) { |
- return NULL; |
- } |
- |
- // Construct a keychain search based on all the unique attributes. |
- std::string server; |
- std::string security_domain; |
- int port; |
- bool is_secure; |
- if (!ExtractSignonRealmComponents(form.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 NULL; |
- } |
- |
- SecProtocolType protocol = is_secure ? kSecProtocolTypeHTTPS |
- : kSecProtocolTypeHTTP; |
- SecAuthenticationType auth_type = AuthTypeForScheme(form.scheme); |
- std::string path = form.origin.path(); |
- std::string username = WideToUTF8(form.username_value); |
- |
- KeychainSearch keychain_search(keychain); |
- keychain_search.Init(server.c_str(), port, protocol, auth_type, |
- (form.scheme == PasswordForm::SCHEME_HTML) ? |
- NULL : security_domain.c_str(), |
- path.c_str(), username.c_str()); |
- |
- std::vector<SecKeychainItemRef> matches; |
- keychain_search.FindMatchingItems(&matches); |
- |
- if (matches.size() == 0) { |
- return NULL; |
- } |
- // Free all items after the first, since we won't be returning them. |
- for (std::vector<SecKeychainItemRef>::iterator i = matches.begin() + 1; |
- i != matches.end(); ++i) { |
- keychain.Free(*i); |
- } |
- return matches[0]; |
-} |
- |
bool FillPasswordFormFromKeychainItem(const MacKeychain& keychain, |
const SecKeychainItemRef& keychain_item, |
PasswordForm* form) { |
@@ -510,13 +420,11 @@ |
MacKeychain* keychain) : keychain_(keychain) { |
} |
-// Returns PasswordForms for each keychain entry matching |form|. |
-// Caller is responsible for deleting the returned forms. |
std::vector<PasswordForm*> |
MacKeychainPasswordFormAdapter::PasswordsMatchingForm( |
const PasswordForm& query_form) { |
std::vector<SecKeychainItemRef> keychain_items = |
- MatchingKeychainItems(query_form.signon_realm, query_form.scheme); |
+ KeychainItemsForFillingForm(query_form); |
std::vector<PasswordForm*> keychain_forms = |
CreateFormsFromKeychainItems(keychain_items); |
@@ -527,13 +435,27 @@ |
return keychain_forms; |
} |
+PasswordForm* MacKeychainPasswordFormAdapter::PasswordExactlyMatchingForm( |
+ const PasswordForm& query_form) { |
+ SecKeychainItemRef keychain_item = KeychainItemForForm(query_form); |
+ if (keychain_item) { |
+ PasswordForm* form = new PasswordForm(); |
+ internal_keychain_helpers::FillPasswordFormFromKeychainItem(*keychain_, |
+ keychain_item, |
+ form); |
+ keychain_->Free(keychain_item); |
+ return form; |
+ } |
+ return NULL; |
+} |
+ |
bool MacKeychainPasswordFormAdapter::AddLogin(const PasswordForm& form) { |
std::string server; |
std::string security_domain; |
int port; |
bool is_secure; |
- if (!internal_keychain_helpers::ExtractSignonRealmComponents( |
- form.signon_realm, &server, &port, &is_secure, &security_domain)) { |
+ if (!ExtractSignonRealmComponents(form.signon_realm, &server, &port, |
+ &is_secure, &security_domain)) { |
return false; |
} |
std::string username = WideToUTF8(form.username_value); |
@@ -547,7 +469,7 @@ |
security_domain.size(), security_domain.c_str(), |
username.size(), username.c_str(), |
path.size(), path.c_str(), |
- port, protocol, internal_keychain_helpers::AuthTypeForScheme(form.scheme), |
+ port, protocol, AuthTypeForScheme(form.scheme), |
password.size(), password.c_str(), &new_item); |
if (result == noErr) { |
@@ -555,8 +477,7 @@ |
keychain_->Free(new_item); |
} else if (result == errSecDuplicateItem) { |
// If we collide with an existing item, find and update it instead. |
- SecKeychainItemRef existing_item = |
- internal_keychain_helpers::MatchingKeychainItem(*keychain_, form); |
+ SecKeychainItemRef existing_item = KeychainItemForForm(form); |
if (!existing_item) { |
return false; |
} |
@@ -583,40 +504,104 @@ |
return keychain_forms; |
} |
-// Searches |keychain| for all items usable for the given signon_realm, and |
-// returns them. The caller is responsible for calling keychain->Free |
-// on each of them when it is finished with them. |
std::vector<SecKeychainItemRef> |
+ MacKeychainPasswordFormAdapter::KeychainItemsForFillingForm( |
+ const PasswordForm& form) { |
+ return MatchingKeychainItems(form.signon_realm, form.scheme, NULL, NULL); |
+} |
+ |
+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. |
+ if (form.blacklisted_by_user) { |
+ return NULL; |
+ } |
+ |
+ std::string path = form.origin.path(); |
+ std::string username = WideToUTF8(form.username_value); |
+ std::vector<SecKeychainItemRef> matches = MatchingKeychainItems( |
+ form.signon_realm, form.scheme, path.c_str(), username.c_str()); |
+ |
+ if (matches.size() == 0) { |
+ return NULL; |
+ } |
+ // Free all items after the first, since we won't be returning them. |
+ for (std::vector<SecKeychainItemRef>::iterator 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 std::string& signon_realm, |
+ webkit_glue::PasswordForm::Scheme scheme, |
+ const char* path, const char* username) { |
std::vector<SecKeychainItemRef> matches; |
- // Construct a keychain search based on the signon_realm and scheme. |
+ |
std::string server; |
std::string security_domain; |
int port; |
bool is_secure; |
- if (!internal_keychain_helpers::ExtractSignonRealmComponents( |
- signon_realm, &server, &port, &is_secure, &security_domain)) { |
+ if (!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 = |
- internal_keychain_helpers::AuthTypeForScheme(scheme); |
+ SecAuthenticationType auth_type = AuthTypeForScheme(scheme); |
+ const char* auth_domain = (scheme == PasswordForm::SCHEME_HTML) ? |
+ NULL : security_domain.c_str(); |
KeychainSearch keychain_search(*keychain_); |
keychain_search.Init(server.c_str(), port, protocol, auth_type, |
- (scheme == PasswordForm::SCHEME_HTML) ? |
- NULL : security_domain.c_str(), |
- NULL, NULL); |
+ auth_domain, path, username); |
keychain_search.FindMatchingItems(&matches); |
return matches; |
} |
+// TODO(stuartmorgan): signon_realm for proxies is not yet supported. |
+bool MacKeychainPasswordFormAdapter::ExtractSignonRealmComponents( |
+ const std::string& signon_realm, std::string* server, int* port, |
+ bool* is_secure, std::string* security_domain) { |
+ // 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.SchemeIsSecure(); |
+ 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. |
+ *security_domain = realm_as_url.path().substr(1); |
+ } |
+ return true; |
+} |
+ |
+// 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; |
+ } |
+ NOTREACHED(); |
+ return kSecAuthenticationTypeDefault; |
+} |
+ |
bool MacKeychainPasswordFormAdapter::SetKeychainItemPassword( |
const SecKeychainItemRef& keychain_item, const std::string& password) { |
OSStatus result = keychain_->ItemModifyAttributesAndData(keychain_item, NULL, |