Home | History | Annotate | Download | only in password_manager
      1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "testing/gtest/include/gtest/gtest.h"
      6 
      7 #include "base/string_util.h"
      8 #include "base/utf_string_conversions.h"
      9 #include "chrome/browser/password_manager/password_form_manager.h"
     10 #include "chrome/browser/password_manager/password_manager.h"
     11 #include "chrome/browser/profiles/profile_manager.h"
     12 #include "chrome/test/testing_profile.h"
     13 #include "webkit/glue/password_form.h"
     14 
     15 using webkit_glue::PasswordForm;
     16 
     17 class PasswordFormManagerTest : public testing::Test {
     18  public:
     19   PasswordFormManagerTest() {
     20   }
     21   virtual void SetUp() {
     22     observed_form_.origin = GURL("http://www.google.com/a/LoginAuth");
     23     observed_form_.action = GURL("http://www.google.com/a/Login");
     24     observed_form_.username_element = ASCIIToUTF16("Email");
     25     observed_form_.password_element = ASCIIToUTF16("Passwd");
     26     observed_form_.submit_element = ASCIIToUTF16("signIn");
     27     observed_form_.signon_realm = "http://www.google.com";
     28 
     29     saved_match_ = observed_form_;
     30     saved_match_.origin = GURL("http://www.google.com/a/ServiceLoginAuth");
     31     saved_match_.action = GURL("http://www.google.com/a/ServiceLogin");
     32     saved_match_.preferred = true;
     33     saved_match_.username_value = ASCIIToUTF16("test (at) gmail.com");
     34     saved_match_.password_value = ASCIIToUTF16("test1");
     35     profile_ = new TestingProfile();
     36   }
     37 
     38   virtual void TearDown() {
     39     delete profile_;
     40   }
     41 
     42   PasswordForm* GetPendingCredentials(PasswordFormManager* p) {
     43     return &p->pending_credentials_;
     44   }
     45 
     46   void SimulateMatchingPhase(PasswordFormManager* p, bool find_match) {
     47     // Roll up the state to mock out the matching phase.
     48     p->state_ = PasswordFormManager::POST_MATCHING_PHASE;
     49     if (!find_match)
     50       return;
     51 
     52     PasswordForm* match = new PasswordForm(saved_match_);
     53     // Heap-allocated form is owned by p.
     54     p->best_matches_[match->username_value] = match;
     55     p->preferred_match_ = match;
     56   }
     57 
     58   bool IgnoredResult(PasswordFormManager* p, PasswordForm* form) {
     59     return p->IgnoreResult(*form);
     60   }
     61 
     62   Profile* profile() { return profile_; }
     63 
     64   PasswordForm* observed_form() { return &observed_form_; }
     65   PasswordForm* saved_match() { return &saved_match_; }
     66 
     67  private:
     68   PasswordForm observed_form_;
     69   PasswordForm saved_match_;
     70   Profile* profile_;
     71 };
     72 
     73 TEST_F(PasswordFormManagerTest, TestNewLogin) {
     74   PasswordFormManager* manager = new PasswordFormManager(
     75       profile(), NULL, *observed_form(), false);
     76   SimulateMatchingPhase(manager, false);
     77   // User submits credentials for the observed form.
     78   PasswordForm credentials = *observed_form();
     79   credentials.username_value = saved_match()->username_value;
     80   credentials.password_value = saved_match()->password_value;
     81   credentials.preferred = true;
     82   manager->ProvisionallySave(credentials);
     83 
     84   // Successful login. The PasswordManager would instruct PasswordFormManager
     85   // to save, which should know this is a new login.
     86   EXPECT_TRUE(manager->IsNewLogin());
     87   // Make sure the credentials that would be submitted on successful login
     88   // are going to match the stored entry in the db.
     89   EXPECT_EQ(observed_form()->origin.spec(),
     90             GetPendingCredentials(manager)->origin.spec());
     91   EXPECT_EQ(observed_form()->signon_realm,
     92             GetPendingCredentials(manager)->signon_realm);
     93   EXPECT_TRUE(GetPendingCredentials(manager)->preferred);
     94   EXPECT_EQ(saved_match()->password_value,
     95             GetPendingCredentials(manager)->password_value);
     96   EXPECT_EQ(saved_match()->username_value,
     97             GetPendingCredentials(manager)->username_value);
     98 
     99   // Now, suppose the user re-visits the site and wants to save an additional
    100   // login for the site with a new username. In this case, the matching phase
    101   // will yield the previously saved login.
    102   SimulateMatchingPhase(manager, true);
    103   // Set up the new login.
    104   string16 new_user = ASCIIToUTF16("newuser");
    105   string16 new_pass = ASCIIToUTF16("newpass");
    106   credentials.username_value = new_user;
    107   credentials.password_value = new_pass;
    108   manager->ProvisionallySave(credentials);
    109 
    110   // Again, the PasswordFormManager should know this is still a new login.
    111   EXPECT_TRUE(manager->IsNewLogin());
    112   // And make sure everything squares up again.
    113   EXPECT_EQ(observed_form()->origin.spec(),
    114             GetPendingCredentials(manager)->origin.spec());
    115   EXPECT_EQ(observed_form()->signon_realm,
    116             GetPendingCredentials(manager)->signon_realm);
    117   EXPECT_TRUE(GetPendingCredentials(manager)->preferred);
    118   EXPECT_EQ(new_pass,
    119             GetPendingCredentials(manager)->password_value);
    120   EXPECT_EQ(new_user,
    121             GetPendingCredentials(manager)->username_value);
    122   // Done.
    123   delete manager;
    124 }
    125 
    126 TEST_F(PasswordFormManagerTest, TestUpdatePassword) {
    127   // Create a PasswordFormManager with observed_form, as if we just
    128   // saw this form and need to find matching logins.
    129   PasswordFormManager* manager = new PasswordFormManager(
    130       profile(), NULL, *observed_form(), false);
    131   SimulateMatchingPhase(manager, true);
    132 
    133   // User submits credentials for the observed form using a username previously
    134   // stored, but a new password. Note that the observed form may have different
    135   // origin URL (as it does in this case) than the saved_match, but we want to
    136   // make sure the updated password is reflected in saved_match, because that is
    137   // what we autofilled.
    138   string16 new_pass = ASCIIToUTF16("newpassword");
    139   PasswordForm credentials = *observed_form();
    140   credentials.username_value = saved_match()->username_value;
    141   credentials.password_value = new_pass;
    142   credentials.preferred = true;
    143   manager->ProvisionallySave(credentials);
    144 
    145   // Successful login. The PasswordManager would instruct PasswordFormManager
    146   // to save, and since this is an update, it should know not to save as a new
    147   // login.
    148   EXPECT_FALSE(manager->IsNewLogin());
    149 
    150   // Make sure the credentials that would be submitted on successful login
    151   // are going to match the stored entry in the db. (This verifies correct
    152   // behaviour for bug 1074420).
    153   EXPECT_EQ(GetPendingCredentials(manager)->origin.spec(),
    154             saved_match()->origin.spec());
    155   EXPECT_EQ(GetPendingCredentials(manager)->signon_realm,
    156             saved_match()->signon_realm);
    157   EXPECT_TRUE(GetPendingCredentials(manager)->preferred);
    158   EXPECT_EQ(new_pass,
    159             GetPendingCredentials(manager)->password_value);
    160   // Done.
    161   delete manager;
    162 }
    163 
    164 TEST_F(PasswordFormManagerTest, TestIgnoreResult) {
    165   PasswordFormManager* manager = new PasswordFormManager(
    166       profile(), NULL, *observed_form(), false);
    167   // Make sure we don't match a PasswordForm if it was originally saved on
    168   // an SSL-valid page and we are now on a page with invalid certificate.
    169   saved_match()->ssl_valid = true;
    170   EXPECT_TRUE(IgnoredResult(manager, saved_match()));
    171 
    172   saved_match()->ssl_valid = false;
    173   // Different paths for action / origin are okay.
    174   saved_match()->action = GURL("http://www.google.com/b/Login");
    175   saved_match()->origin = GURL("http://www.google.com/foo");
    176   EXPECT_FALSE(IgnoredResult(manager, saved_match()));
    177 
    178   // Done.
    179   delete manager;
    180 }
    181 
    182 TEST_F(PasswordFormManagerTest, TestEmptyAction) {
    183   scoped_ptr<PasswordFormManager> manager(new PasswordFormManager(
    184       profile(), NULL, *observed_form(), false));
    185 
    186   saved_match()->action = GURL();
    187   SimulateMatchingPhase(manager.get(), true);
    188   // User logs in with the autofilled username / password from saved_match.
    189   PasswordForm login = *observed_form();
    190   login.username_value = saved_match()->username_value;
    191   login.password_value = saved_match()->password_value;
    192   manager->ProvisionallySave(login);
    193   EXPECT_FALSE(manager->IsNewLogin());
    194   // We bless our saved PasswordForm entry with the action URL of the
    195   // observed form.
    196   EXPECT_EQ(observed_form()->action,
    197             GetPendingCredentials(manager.get())->action);
    198 }
    199 
    200 TEST_F(PasswordFormManagerTest, TestValidForms) {
    201   // User submits credentials for the observed form.
    202   PasswordForm credentials = *observed_form();
    203   credentials.scheme = PasswordForm::SCHEME_HTML;
    204   credentials.username_value = saved_match()->username_value;
    205   credentials.password_value = saved_match()->password_value;
    206 
    207   // Form with both username_element and password_element.
    208   PasswordFormManager manager1(profile(), NULL, credentials, false);
    209   SimulateMatchingPhase(&manager1, false);
    210   EXPECT_TRUE(manager1.HasValidPasswordForm());
    211 
    212   // Form without a username_element but with a password_element.
    213   credentials.username_element.clear();
    214   PasswordFormManager manager2(profile(), NULL, credentials, false);
    215   SimulateMatchingPhase(&manager2, false);
    216   EXPECT_FALSE(manager2.HasValidPasswordForm());
    217 
    218   // Form without a password_element but with a username_element.
    219   credentials.username_element = saved_match()->username_element;
    220   credentials.password_element.clear();
    221   PasswordFormManager manager3(profile(), NULL, credentials, false);
    222   SimulateMatchingPhase(&manager3, false);
    223   EXPECT_FALSE(manager3.HasValidPasswordForm());
    224 
    225   // Form with neither a password_element nor a username_element.
    226   credentials.username_element.clear();
    227   credentials.password_element.clear();
    228   PasswordFormManager manager4(profile(), NULL, credentials, false);
    229   SimulateMatchingPhase(&manager4, false);
    230   EXPECT_FALSE(manager4.HasValidPasswordForm());
    231 }
    232 
    233 TEST_F(PasswordFormManagerTest, TestValidFormsBasic) {
    234   // User submits credentials for the observed form.
    235   PasswordForm credentials = *observed_form();
    236   credentials.scheme = PasswordForm::SCHEME_BASIC;
    237   credentials.username_value = saved_match()->username_value;
    238   credentials.password_value = saved_match()->password_value;
    239 
    240   // Form with both username_element and password_element.
    241   PasswordFormManager manager1(profile(), NULL, credentials, false);
    242   SimulateMatchingPhase(&manager1, false);
    243   EXPECT_TRUE(manager1.HasValidPasswordForm());
    244 
    245   // Form without a username_element but with a password_element.
    246   credentials.username_element.clear();
    247   PasswordFormManager manager2(profile(), NULL, credentials, false);
    248   SimulateMatchingPhase(&manager2, false);
    249   EXPECT_TRUE(manager2.HasValidPasswordForm());
    250 
    251   // Form without a password_element but with a username_element.
    252   credentials.username_element = saved_match()->username_element;
    253   credentials.password_element.clear();
    254   PasswordFormManager manager3(profile(), NULL, credentials, false);
    255   SimulateMatchingPhase(&manager3, false);
    256   EXPECT_TRUE(manager3.HasValidPasswordForm());
    257 
    258   // Form with neither a password_element nor a username_element.
    259   credentials.username_element.clear();
    260   credentials.password_element.clear();
    261   PasswordFormManager manager4(profile(), NULL, credentials, false);
    262   SimulateMatchingPhase(&manager4, false);
    263   EXPECT_TRUE(manager4.HasValidPasswordForm());
    264 }
    265