diff options
Diffstat (limited to 'spec/requests/verifies_with_email_spec.rb')
-rw-r--r-- | spec/requests/verifies_with_email_spec.rb | 234 |
1 files changed, 234 insertions, 0 deletions
diff --git a/spec/requests/verifies_with_email_spec.rb b/spec/requests/verifies_with_email_spec.rb new file mode 100644 index 00000000000..2f249952455 --- /dev/null +++ b/spec/requests/verifies_with_email_spec.rb @@ -0,0 +1,234 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'VerifiesWithEmail', :clean_gitlab_redis_sessions, :clean_gitlab_redis_rate_limiting do + include SessionHelpers + include EmailHelpers + + let(:user) { create(:user) } + + shared_examples_for 'send verification instructions' do + it 'locks the user' do + user.reload + expect(user.unlock_token).not_to be_nil + expect(user.locked_at).not_to be_nil + end + + it 'sends an email' do + mail = find_email_for(user) + expect(mail.to).to match_array([user.email]) + expect(mail.subject).to eq('Verify your identity') + end + end + + shared_examples_for 'prompt for email verification' do + it 'sets the verification_user_id session variable and renders the email verification template' do + expect(request.session[:verification_user_id]).to eq(user.id) + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template('devise/sessions/email_verification') + end + end + + describe 'verify_with_email' do + context 'when user is locked and a verification_user_id session variable exists' do + before do + encrypted_token = Devise.token_generator.digest(User, :unlock_token, 'token') + user.update!(locked_at: Time.current, unlock_token: encrypted_token) + stub_session(verification_user_id: user.id) + end + + context 'when rate limited and a verification_token param exists' do + before do + allow(Gitlab::ApplicationRateLimiter).to receive(:throttled?).and_return(true) + + post(user_session_path(user: { verification_token: 'token' })) + end + + it_behaves_like 'prompt for email verification' + + it 'adds a verification error message' do + expect(response.body) + .to include("You've reached the maximum amount of tries. "\ + 'Wait 10 minutes or resend a new code and try again.') + end + end + + context 'when an invalid verification_token param exists' do + before do + post(user_session_path(user: { verification_token: 'invalid_token' })) + end + + it_behaves_like 'prompt for email verification' + + it 'adds a verification error message' do + expect(response.body).to include(('The code is incorrect. Enter it again, or resend a new code.')) + end + end + + context 'when an expired verification_token param exists' do + before do + user.update!(locked_at: 1.hour.ago) + post(user_session_path(user: { verification_token: 'token' })) + end + + it_behaves_like 'prompt for email verification' + + it 'adds a verification error message' do + expect(response.body).to include(('The code has expired. Resend a new code and try again.')) + end + end + + context 'when a valid verification_token param exists' do + before do + post(user_session_path(user: { verification_token: 'token' })) + end + + it 'unlocks the user' do + user.reload + expect(user.unlock_token).to be_nil + expect(user.locked_at).to be_nil + end + + it 'redirects to the successful verification path' do + expect(response).to redirect_to(users_successful_verification_path) + end + end + end + + context 'when signing in with a valid password' do + let(:sign_in) { post(user_session_path(user: { login: user.username, password: user.password })) } + + context 'when the feature flag is toggled on' do + before do + stub_feature_flags(require_email_verification: user) + end + + context 'when rate limited' do + before do + allow(Gitlab::ApplicationRateLimiter).to receive(:throttled?).and_return(true) + sign_in + end + + it 'redirects to the login form and shows an alert message' do + expect(response).to redirect_to(new_user_session_path) + expect(flash[:alert]).to eq('Maximum login attempts exceeded. Wait 10 minutes and try again.') + end + end + + context 'when the user already has an unlock_token set' do + before do + user.update!(unlock_token: 'token') + sign_in + end + + it_behaves_like 'prompt for email verification' + end + + context 'when the user is already locked' do + before do + user.update!(locked_at: Time.current) + perform_enqueued_jobs { sign_in } + end + + it_behaves_like 'send verification instructions' + it_behaves_like 'prompt for email verification' + end + + context 'when the user is signing in from an unknown ip address' do + before do + allow(AuthenticationEvent) + .to receive(:initial_login_or_known_ip_address?) + .and_return(false) + + perform_enqueued_jobs { sign_in } + end + + it_behaves_like 'send verification instructions' + it_behaves_like 'prompt for email verification' + end + end + + context 'when the feature flag is toggled off' do + let(:another_user) { build(:user) } + + before do + stub_feature_flags(require_email_verification: another_user) + sign_in + end + + it 'redirects to the root path' do + expect(response).to redirect_to(root_path) + end + end + end + end + + describe 'resend_verification_code' do + context 'when no verification_user_id session variable exists' do + before do + post(users_resend_verification_code_path) + end + + it 'returns 204 No Content' do + expect(response).to have_gitlab_http_status(:no_content) + expect(response.body).to be_empty + end + end + + context 'when a verification_user_id session variable exists' do + before do + stub_session(verification_user_id: user.id) + + perform_enqueued_jobs do + post(users_resend_verification_code_path) + end + end + + it_behaves_like 'send verification instructions' + it_behaves_like 'prompt for email verification' + end + + context 'when exceeding the rate limit' do + before do + allow(Gitlab::ApplicationRateLimiter).to receive(:throttled?).and_return(true) + + stub_session(verification_user_id: user.id) + + perform_enqueued_jobs do + post(users_resend_verification_code_path) + end + end + + it 'does not lock the user' do + user.reload + expect(user.unlock_token).to be_nil + expect(user.locked_at).to be_nil + end + + it 'does not send an email' do + mail = find_email_for(user) + expect(mail).to be_nil + end + + it_behaves_like 'prompt for email verification' + end + end + + describe 'successful_verification' do + before do + sign_in(user) + end + + it 'renders the template and removes the verification_user_id session variable' do + stub_session(verification_user_id: user.id) + + get(users_successful_verification_path) + + expect(request.session.has_key?(:verification_user_id)).to eq(false) + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template('successful_verification', layout: 'minimal') + expect(response.body).to include(root_path) + end + end +end |