// 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. #ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_FORM_MANAGER_H_ #define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_FORM_MANAGER_H_ #include <string> #include <vector> #include "build/build_config.h" #include "base/stl_util.h" #include "components/autofill/core/common/password_form.h" #include "components/password_manager/core/browser/password_manager_driver.h" #include "components/password_manager/core/browser/password_store.h" #include "components/password_manager/core/browser/password_store_consumer.h" namespace content { class WebContents; } // namespace content class PasswordManager; class PasswordManagerClient; // Per-password-form-{on-page, dialog} class responsible for interactions // between a given form, the per-tab PasswordManager, and the PasswordStore. class PasswordFormManager : public PasswordStoreConsumer { public: // |password_manager| owns this object // |form_on_page| is the form that may be submitted and could need login data. // |ssl_valid| represents the security of the page containing observed_form, // used to filter login results from database. PasswordFormManager(PasswordManager* password_manager, PasswordManagerClient* client, PasswordManagerDriver* driver, const autofill::PasswordForm& observed_form, bool ssl_valid); virtual ~PasswordFormManager(); enum ActionMatch { ACTION_MATCH_REQUIRED, ACTION_MATCH_NOT_REQUIRED }; enum OtherPossibleUsernamesAction { ALLOW_OTHER_POSSIBLE_USERNAMES, IGNORE_OTHER_POSSIBLE_USERNAMES }; // Compare basic data of observed_form_ with argument. Only check the action // URL when action match is required. bool DoesManage(const autofill::PasswordForm& form, ActionMatch action_match) const; // Retrieves potential matching logins from the database. // |prompt_policy| indicates whether it's permissible to prompt the user to // authorize access to locked passwords. This argument is only used on // platforms that support prompting the user for access (such as Mac OS). void FetchMatchingLoginsFromPasswordStore( PasswordStore::AuthorizationPromptPolicy prompt_policy); // Simple state-check to verify whether this object as received a callback // from the PasswordStore and completed its matching phase. Note that the // callback in question occurs on the same (and only) main thread from which // instances of this class are ever used, but it is required since it is // conceivable that a user (or ui test) could attempt to submit a login // prompt before the callback has occured, which would InvokeLater a call to // PasswordManager::ProvisionallySave, which would interact with this object // before the db has had time to answer with matching password entries. // This is intended to be a one-time check; if the return value is false the // expectation is caller will give up. This clearly won't work if you put it // in a loop and wait for matching to complete; you're (supposed to be) on // the same thread! bool HasCompletedMatching(); // Determines if the user opted to 'never remember' passwords for this form. bool IsBlacklisted(); // Used by PasswordManager to determine whether or not to display // a SavePasswordBar when given the green light to save the PasswordForm // managed by this. bool IsNewLogin(); // Returns true if the current pending credentials were found using // origin matching of the public suffix, instead of the signon realm of the // form. bool IsPendingCredentialsPublicSuffixMatch(); // Checks if the form is a valid password form. Forms which lack either // login or password field are not considered valid. bool HasValidPasswordForm(); // These functions are used to determine if this form has had it's password // auto generated by the browser. bool HasGeneratedPassword(); void SetHasGeneratedPassword(); // Determines if we need to autofill given the results of the query. // Takes ownership of the elements in |result|. void OnRequestDone(const std::vector<autofill::PasswordForm*>& result); virtual void OnGetPasswordStoreResults( const std::vector<autofill::PasswordForm*>& results) OVERRIDE; // A user opted to 'never remember' passwords for this form. // Blacklist it so that from now on when it is seen we ignore it. // TODO: Make this private once we switch to the new UI. void PermanentlyBlacklist(); // Sets whether the password form should use additional password // authentication if available before being used for autofill. void SetUseAdditionalPasswordAuthentication( bool use_additional_authentication); // If the user has submitted observed_form_, provisionally hold on to // the submitted credentials until we are told by PasswordManager whether // or not the login was successful. |action| describes how we deal with // possible usernames. If |action| is ALLOW_OTHER_POSSIBLE_USERNAMES we will // treat a possible usernames match as a sign that our original heuristics // were wrong and that the user selected the correct username from the // Autofill UI. void ProvisionallySave(const autofill::PasswordForm& credentials, OtherPossibleUsernamesAction action); // Handles save-as-new or update of the form managed by this manager. // Note the basic data of updated_credentials must match that of // observed_form_ (e.g DoesManage(pending_credentials_) == true). // TODO: Make this private once we switch to the new UI. void Save(); // Call these if/when we know the form submission worked or failed. // These routines are used to update internal statistics ("ActionsTaken"). void SubmitPassed(); void SubmitFailed(); // Returns the username associated with the credentials. const base::string16& associated_username() const { return pending_credentials_.username_value; } // Returns the pending credentials. const autofill::PasswordForm pending_credentials() const { return pending_credentials_; } // Returns the best matches. const autofill::PasswordFormMap best_matches() const { return best_matches_; } // Returns the realm URL for the form managed my this manager. const std::string& realm() const { return pending_credentials_.signon_realm; } private: friend class PasswordFormManagerTest; // ManagerAction - What does the manager do with this form? Either it // fills it, or it doesn't. If it doesn't fill it, that's either // because it has no match, or it is blacklisted, or it is disabled // via the AUTOCOMPLETE=off attribute. Note that if we don't have // an exact match, we still provide candidates that the user may // end up choosing. enum ManagerAction { kManagerActionNone = 0, kManagerActionAutofilled, kManagerActionBlacklisted, kManagerActionMax }; // UserAction - What does the user do with this form? If he or she // does nothing (either by accepting what the password manager did, or // by simply (not typing anything at all), you get None. If there were // multiple choices and the user selects one other than the default, // you get Choose, if user selects an entry from matching against the Public // Suffix List you get ChoosePslMatch, if the user types in a new value // for just the password you get OverridePassword, and if the user types in a // new value for the username and password you get // OverrideUsernameAndPassword. enum UserAction { kUserActionNone = 0, kUserActionChoose, kUserActionChoosePslMatch, kUserActionOverridePassword, kUserActionOverrideUsernameAndPassword, kUserActionMax }; // Result - What happens to the form? enum SubmitResult { kSubmitResultNotSubmitted = 0, kSubmitResultFailed, kSubmitResultPassed, kSubmitResultMax }; // The maximum number of combinations of the three preceding enums. // This is used when recording the actions taken by the form in UMA. static const int kMaxNumActionsTaken = kManagerActionMax * kUserActionMax * kSubmitResultMax; // Helper for OnGetPasswordStoreResults to determine whether or not // the given result form is worth scoring. bool IgnoreResult(const autofill::PasswordForm& form) const; // Helper for Save in the case that best_matches.size() == 0, meaning // we have no prior record of this form/username/password and the user // has opted to 'Save Password'. If |reset_preferred_login| is set, // the previously preferred login from |best_matches_| will be reset. void SaveAsNewLogin(bool reset_preferred_login); // Helper for OnGetPasswordStoreResults to score an individual result // against the observed_form_. int ScoreResult(const autofill::PasswordForm& form) const; // Helper for Save in the case that best_matches.size() > 0, meaning // we have at least one match for this form/username/password. This // Updates the form managed by this object, as well as any matching forms // that now need to have preferred bit changed, since updated_credentials // is now implicitly 'preferred'. void UpdateLogin(); // Check to see if |pending| corresponds to an account creation form. If we // think that it does, we label it as such and upload this state to the // Autofill server, so that we will trigger password generation in the future. void CheckForAccountCreationForm(const autofill::PasswordForm& pending, const autofill::PasswordForm& observed); // Update all login matches to reflect new preferred state - preferred flag // will be reset on all matched logins that different than the current // |pending_credentials_|. void UpdatePreferredLoginState(PasswordStore* password_store); // Returns true if |username| is one of the other possible usernames for a // password form in |best_matches_| and sets |pending_credentials_| to the // match which had this username. bool UpdatePendingCredentialsIfOtherPossibleUsername( const base::string16& username); // Converts the "ActionsTaken" fields into an int so they can be logged to // UMA. int GetActionsTaken(); // Remove possible_usernames that may contains sensitive information and // duplicates. void SanitizePossibleUsernames(autofill::PasswordForm* form); // Set of PasswordForms from the DB that best match the form // being managed by this. Use a map instead of vector, because we most // frequently require lookups by username value in IsNewLogin. autofill::PasswordFormMap best_matches_; // Cleans up when best_matches_ goes out of scope. STLValueDeleter<autofill::PasswordFormMap> best_matches_deleter_; // The PasswordForm from the page or dialog managed by this. autofill::PasswordForm observed_form_; // The origin url path of observed_form_ tokenized, for convenience when // scoring. std::vector<std::string> form_path_tokens_; // Stores updated credentials when the form was submitted but success is // still unknown. autofill::PasswordForm pending_credentials_; // Whether pending_credentials_ stores a new login or is an update // to an existing one. bool is_new_login_; // Whether this form has an auto generated password. bool has_generated_password_; // Set if the user has selected one of the other possible usernames in // |pending_credentials_|. base::string16 selected_username_; // PasswordManager owning this. const PasswordManager* const password_manager_; // Convenience pointer to entry in best_matches_ that is marked // as preferred. This is only allowed to be null if there are no best matches // at all, since there will always be one preferred login when there are // multiple matches (when first saved, a login is marked preferred). const autofill::PasswordForm* preferred_match_; typedef enum { PRE_MATCHING_PHASE, // Have not yet invoked a GetLogins query to find // matching login information from password store. MATCHING_PHASE, // We've made a GetLogins request, but // haven't received or finished processing result. POST_MATCHING_PHASE // We've queried the DB and processed matching // login results. } PasswordFormManagerState; // State of matching process, used to verify that we don't call methods // assuming we've already processed the request for matching logins, // when we actually haven't. PasswordFormManagerState state_; // The client which implements embedder-specific PasswordManager operations. PasswordManagerClient* client_; // The driver which implements platform-specific PasswordManager operations. PasswordManagerDriver* driver_; // These three fields record the "ActionsTaken" by the browser and // the user with this form, and the result. They are combined and // recorded in UMA when the manager is destroyed. ManagerAction manager_action_; UserAction user_action_; SubmitResult submit_result_; DISALLOW_COPY_AND_ASSIGN(PasswordFormManager); }; #endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_FORM_MANAGER_H_