From bb1b2f0eeaeaa608211aa781b73daa42bf0f883b Mon Sep 17 00:00:00 2001 From: Daria Mayorova Date: Fri, 5 Jul 2024 16:17:17 +0200 Subject: [PATCH] THREESCALE-10074: Do not reveal that email doesn't exist on Forgot password form (#3837) * Do not reveal that email doesn't exist on Forgot password form * Some fixes * Reorganize cucumbers for password reset --- .../buyer_password_reset.feature | 101 ++++++++++++++---- .../buyers/buyer_password_reset.feature | 68 ------------ features/step_definitions/password_steps.rb | 4 +- features/step_definitions/session_steps.rb | 2 +- .../admin/account/passwords_controller.rb | 8 +- .../passwords_controller_test.rb | 6 +- 6 files changed, 92 insertions(+), 97 deletions(-) delete mode 100644 features/old/accounts/buyers/buyer_password_reset.feature diff --git a/features/developer_portal/buyer_password_reset.feature b/features/developer_portal/buyer_password_reset.feature index 8a4de454e1..ccb9d8570c 100644 --- a/features/developer_portal/buyer_password_reset.feature +++ b/features/developer_portal/buyer_password_reset.feature @@ -1,25 +1,88 @@ -Feature: Buyer signup +Feature: Buyer password reset I want to reset my password as a buyer Background: Given a provider exists - And the default product of provider "master" has name "Master API" - And the following application plan: - | Product | Name | - | Master API | enterprise | - And the provider has bot protection enabled - And the provider account allows signups - @recaptcha - Scenario: Bot protection doesn't detect the client as a bot - And the client will be marked as a bot - When the buyer wants to reset their password - And the buyer fills in the form - Then the page should contain "Bot protection failed." + Rule: ReCAPTCHA protects from bots + Background: + Given the provider has bot protection enabled - @recaptcha - Scenario: Bot protection doesn't detect the client as a bot - And the client won't be marked as a bot - When the buyer wants to reset their password - And the buyer fills in the form - Then the page should contain "Email not found." + @recaptcha + Scenario: Bot protection doesn't detect the client as a bot + Given the client will be marked as a bot + When the buyer wants to reset their password + And the buyer fills in the form + Then the page should contain "Bot protection failed." + + @recaptcha + Scenario: Bot protection doesn't detect the client as a bot + Given the client won't be marked as a bot + When the buyer wants to reset their password + And the buyer fills in the form + Then the page should contain "A password reset link will be sent" + + Rule: Reset password flow for different scenarios + Background: + Given a buyer "bob" signed up to the provider + And an active user "zed" of account "bob" with email "zed@3scale.localhost" + And the current domain is foo.3scale.localhost + And they go to the login page + + Scenario: Reset password of an existing user + Given they follow "Forgot password?" + And they fill in "Email" with "zed@3scale.localhost" + And they press "Send instructions" + Then they should see "A password reset link will be sent to zed@3scale.localhost if a user exists with this email." + When they follow the link found in the password reset email send to "zed@3scale.localhost" + And they fill in "Password" with "monkey" + And they fill in "Password confirmation" with "monkey" + And they press "Change Password" + Then they should see "The password has been changed" + + When they go to the login page + And they fill in "Username" with "zed@3scale.localhost" + And they fill in "Password" with "monkey" + And they press "Sign in" + Then they should be logged in as "zed" + + Scenario: Invalid email + Given no user exists with an email of "bob@3scale.localhost" + And they follow "Forgot password?" + And they fill in "Email" with "bob@3scale.localhost" + And they press "Send instructions" + Then they should see "A password reset link will be sent to bob@3scale.localhost if a user exists with this email." + And "bob@3scale.localhost" should receive no emails + + Scenario: Wrong confirmation + Given they follow "Forgot password?" + And they fill in "Email" with "zed@3scale.localhost" + And they press "Send instructions" + And they follow the link found in the password reset email send to "zed@3scale.localhost" + And they fill in "Password" with "monkey" + And they fill in "Password confirmation" with "donkey" + And they press "Change Password" + Then they should see the password confirmation error + And the password of user "zed" should not be "monkey" + + Scenario: Blank passwords + When they follow "Forgot password?" + And they fill in "Email" with "zed@3scale.localhost" + And they press "Send instructions" + And they follow the link found in the password reset email send to "zed@3scale.localhost" + And they press "Change Password" + Then they should see "The password is invalid" + + Scenario: Invalid token + When they go to the password page with invalid password reset token + Then they should see "The password reset token is invalid" + + Scenario: Attempt to login with invalid credentials, then reset password + Given they fill in "Username" with "zed@3scale.localhost" + And they fill in "Password" with "ihavenoclue" + And they press "Sign in" + Then they should see "Incorrect email or password. Please try again." + When they follow "Forgot password?" + And they fill in "Email" with "zed@3scale.localhost" + And they press "Send instructions" + Then they should see "A password reset link will be sent to zed@3scale.localhost if a user exists with this email." diff --git a/features/old/accounts/buyers/buyer_password_reset.feature b/features/old/accounts/buyers/buyer_password_reset.feature deleted file mode 100644 index 07d1b93a1a..0000000000 --- a/features/old/accounts/buyers/buyer_password_reset.feature +++ /dev/null @@ -1,68 +0,0 @@ -Feature: Buyer password reset - In order to sign in even if I forgot my password - As a user - I should be able to reset it - - Background: - Given a provider "foo.3scale.localhost" - And a buyer "bob" signed up to provider "foo.3scale.localhost" - And an active user "zed" of account "bob" with email "zed@3scale.localhost" - When the current domain is foo.3scale.localhost - And I go to the login page - - Scenario: Reset password - Given I follow "Forgot password?" - And I fill in "Email" with "zed@3scale.localhost" - And I press "Send instructions" - Then I should see "A password reset link has been emailed to you." - When I follow the link found in the password reset email send to "zed@3scale.localhost" - And I fill in "Password" with "monkey" - And I fill in "Password confirmation" with "monkey" - And I press "Change Password" - Then I should see "The password has been changed" - - When I go to the login page - And I fill in "Username" with "zed@3scale.localhost" - And I fill in "Password" with "monkey" - And I press "Sign in" - Then I should be logged in as "zed" - - Scenario: Invalid email - Given no user exists with an email of "bob@3scale.localhost" - And I follow "Forgot password?" - And I fill in "Email" with "bob@3scale.localhost" - And I press "Send instructions" - Then I should see "Email not found." - - Scenario: Wrong confirmation - Given I follow "Forgot password?" - And I fill in "Email" with "zed@3scale.localhost" - And I press "Send instructions" - And I follow the link found in the password reset email send to "zed@3scale.localhost" - And I fill in "Password" with "monkey" - And I fill in "Password confirmation" with "donkey" - And I press "Change Password" - Then I should see the password confirmation error - And the password of user "zed" should not be "monkey" - - Scenario: Blank passwords - When I follow "Forgot password?" - And I fill in "Email" with "zed@3scale.localhost" - And I press "Send instructions" - And I follow the link found in the password reset email send to "zed@3scale.localhost" - And I press "Change Password" - Then I should see "The password is invalid" - - Scenario: Invalid token - When I go to the password page with invalid password reset token - Then I should see "The password reset token is invalid" - - Scenario: Attempt to login with invalid credentials, then reset password - Given I fill in "Username" with "zed@3scale.localhost" - And I fill in "Password" with "ihavenoclue" - And I press "Sign in" - Then I should see "Incorrect email or password. Please try again." - When I follow "Forgot password?" - And I fill in "Email" with "zed@3scale.localhost" - And I press "Send instructions" - Then I should see "A password reset link has been emailed to you." diff --git a/features/step_definitions/password_steps.rb b/features/step_definitions/password_steps.rb index 964a19bce9..63b53ae521 100644 --- a/features/step_definitions/password_steps.rb +++ b/features/step_definitions/password_steps.rb @@ -14,7 +14,7 @@ assert !user.authenticated?(password) end -When /^I follow the link found in the password reset email send to "([^"]*)"$/ do |email| +When /^(?:|I |they )follow the link found in the password reset email send to "([^"]*)"$/ do |email| visit_url_in_email(email, /Lost password recovery/) end @@ -34,7 +34,7 @@ def visit_url_in_email(email, subject) visit url end -Then 'I should see the password confirmation error' do +Then /^(?:|I |they )should see the password confirmation error$/ do %q(I should see error "doesn't match Password" for field "Password confirmation") end diff --git a/features/step_definitions/session_steps.rb b/features/step_definitions/session_steps.rb index 91eef61f55..e2932e53fc 100644 --- a/features/step_definitions/session_steps.rb +++ b/features/step_definitions/session_steps.rb @@ -114,7 +114,7 @@ click_button('Sign in') end -Then /^I should be logged in as "([^"]*)"$/ do |username| +Then /^(?:|I |they )should be logged in as "([^"]*)"$/ do |username| assert_current_user(username) end diff --git a/lib/developer_portal/app/controllers/developer_portal/admin/account/passwords_controller.rb b/lib/developer_portal/app/controllers/developer_portal/admin/account/passwords_controller.rb index 89470b4f03..7d74be3fb1 100644 --- a/lib/developer_portal/app/controllers/developer_portal/admin/account/passwords_controller.rb +++ b/lib/developer_portal/app/controllers/developer_portal/admin/account/passwords_controller.rb @@ -12,11 +12,11 @@ class DeveloperPortal::Admin::Account::PasswordsController < ::DeveloperPortal:: def create return redirect_to_request_password('Bot protection failed.') unless bot_check({ flash: false }) - user = @provider.buyer_users.find_by_email(params[:email]) - return redirect_to_request_password('Email not found.') unless user + email = params[:email] + user = @provider.buyer_users.find_by(email: email) + user&.generate_lost_password_token! - user.generate_lost_password_token! - flash[:notice] = 'A password reset link has been emailed to you.' + flash[:notice] = "A password reset link will be sent to #{email} if a user exists with this email." redirect_to login_url end diff --git a/test/integration/developer_portal/passwords_controller_test.rb b/test/integration/developer_portal/passwords_controller_test.rb index 86831f729e..aa51d81b3b 100644 --- a/test/integration/developer_portal/passwords_controller_test.rb +++ b/test/integration/developer_portal/passwords_controller_test.rb @@ -78,14 +78,14 @@ def test_update_password post developer_portal.admin_account_password_path(email: user.email) end assert_in_delta Time.now, user.reload.lost_password_token_generated_at, 2.seconds - assert_equal 'A password reset link has been emailed to you.', flash[:notice] + assert_equal "A password reset link will be sent to #{user.email} if a user exists with this email.", flash[:notice] assert_redirected_to developer_portal.login_path end test 'create renders the right error message when the email is not found' do post developer_portal.admin_account_password_path(email: 'fake@example.com') - assert_equal 'Email not found.', flash[:error] - assert_redirected_to developer_portal.new_admin_account_password_path(request_password_reset: true) + assert_equal "A password reset link will be sent to fake@example.com if a user exists with this email.", flash[:notice] + assert_redirected_to developer_portal.login_path end private