Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/controllers/passwords_controller_spec.rb')
-rw-r--r--spec/controllers/passwords_controller_spec.rb131
1 files changed, 129 insertions, 2 deletions
diff --git a/spec/controllers/passwords_controller_spec.rb b/spec/controllers/passwords_controller_spec.rb
index aad946acad4..cff84da7382 100644
--- a/spec/controllers/passwords_controller_spec.rb
+++ b/spec/controllers/passwords_controller_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe PasswordsController do
+RSpec.describe PasswordsController, feature_category: :system_access do
include DeviseHelpers
before do
@@ -109,8 +109,9 @@ RSpec.describe PasswordsController do
describe '#create' do
let(:user) { create(:user) }
+ let(:email) { user.email }
- subject(:perform_request) { post(:create, params: { user: { email: user.email } }) }
+ subject(:perform_request) { post(:create, params: { user: { email: email } }) }
context 'when reCAPTCHA is disabled' do
before do
@@ -161,5 +162,131 @@ RSpec.describe PasswordsController do
expect(flash[:notice]).to include 'If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes.'
end
end
+
+ context "sending 'Reset password instructions' email" do
+ include EmailHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:user_confirmed_primary_email) { user.email }
+ let_it_be(:user_confirmed_secondary_email) { create(:email, :confirmed, user: user, email: 'confirmed-secondary-email@example.com').email }
+ let_it_be(:user_unconfirmed_secondary_email) { create(:email, user: user, email: 'unconfirmed-secondary-email@example.com').email }
+ let_it_be(:unknown_email) { 'attacker@example.com' }
+ let_it_be(:invalid_email) { 'invalid_email' }
+ let_it_be(:sql_injection_email) { 'sql-injection-email@example.com OR 1=1' }
+ let_it_be(:another_user_confirmed_primary_email) { create(:user).email }
+ let_it_be(:another_user_unconfirmed_primary_email) { create(:user, :unconfirmed).email }
+
+ before do
+ reset_delivered_emails!
+
+ perform_request
+
+ perform_enqueued_jobs
+ end
+
+ context "when email param matches user's confirmed primary email" do
+ let(:email) { user_confirmed_primary_email }
+
+ it 'sends email to the primary email only' do
+ expect_only_one_email_to_be_sent(subject: 'Reset password instructions', to: [user_confirmed_primary_email])
+ end
+ end
+
+ context "when email param matches user's unconfirmed primary email" do
+ let(:email) { another_user_unconfirmed_primary_email }
+
+ # By default 'devise' gem allows password reset by unconfirmed primary email.
+ # When user account with unconfirmed primary email that means it is unconfirmed.
+ #
+ # Password reset by unconfirmed primary email is very helpful from
+ # security perspective. Example:
+ # Malicious person creates user account on GitLab with someone's email.
+ # If the email owner confirms the email for newly created account, the malicious person will be able
+ # to sign in into the account by password they provided during account signup.
+ # The malicious person could set up 2FA to the user account, after that
+ # te email owner would not able to get access to that user account even
+ # after performing password reset.
+ # To deal with that case safely the email owner should reset password
+ # for the user account first. That will make sure that after the user account
+ # is confirmed the malicious person is not be able to sign in with
+ # the password they provided during the account signup. Then email owner
+ # could sign into the account, they will see a prompt to confirm the account email
+ # to proceed. They can safely confirm the email and take over the account.
+ # That is one of the reasons why password reset by unconfirmed primary email should be allowed.
+ it 'sends email to the primary email only' do
+ expect_only_one_email_to_be_sent(subject: 'Reset password instructions', to: [another_user_unconfirmed_primary_email])
+ end
+ end
+
+ context "when email param matches user's confirmed secondary email" do
+ let(:email) { user_confirmed_secondary_email }
+
+ it 'sends email to the confirmed secondary email only' do
+ expect_only_one_email_to_be_sent(subject: 'Reset password instructions', to: [user_confirmed_secondary_email])
+ end
+ end
+
+ # While unconfirmed primary emails are linked with users accounts,
+ # unconfirmed secondary emails should not be linked with any users till they are confirmed
+ # See https://gitlab.com/gitlab-org/gitlab/-/issues/356665
+ #
+ # In https://gitlab.com/gitlab-org/gitlab/-/issues/367823, it is considerd
+ # to prevent reserving emails on Gitlab by unconfirmed secondary emails.
+ # As per this issue, there might be cases that there are multiple users
+ # with the same unconfirmed secondary emails. It would be impossible to identify for
+ # what user account password reset is requested if password reset were allowed
+ # by unconfirmed secondary emails.
+ # Also note that it is not possible to request email confirmation for
+ # unconfirmed secondary emails without having access to the user account.
+ context "when email param matches user's unconfirmed secondary email" do
+ let(:email) { user_unconfirmed_secondary_email }
+
+ it 'does not send email to anyone' do
+ should_not_email_anyone
+ end
+ end
+
+ context 'when email param is unknown email' do
+ let(:email) { unknown_email }
+
+ it 'does not send email to anyone' do
+ should_not_email_anyone
+ end
+ end
+
+ context 'when email param is invalid email' do
+ let(:email) { invalid_email }
+
+ it 'does not send email to anyone' do
+ should_not_email_anyone
+ end
+ end
+
+ context 'when email param with attempt to cause SQL injection' do
+ let(:email) { sql_injection_email }
+
+ it 'does not send email to anyone' do
+ should_not_email_anyone
+ end
+ end
+
+ # See https://gitlab.com/gitlab-org/gitlab/-/issues/436084
+ context 'when email param with multiple emails' do
+ let(:email) do
+ [
+ user_confirmed_primary_email,
+ user_confirmed_secondary_email,
+ user_unconfirmed_secondary_email,
+ unknown_email,
+ another_user_confirmed_primary_email,
+ another_user_unconfirmed_primary_email
+ ]
+ end
+
+ it 'does not send email to anyone' do
+ should_not_email_anyone
+ end
+ end
+ end
end
end