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