Commit 5e365148 authored by Luke Duncalfe's avatar Luke Duncalfe Committed by Andy Soiron

Require verified email to enable 2FA

https://gitlab.com/gitlab-org/gitlab/-/issues/35102
parent b9653648
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
class Profiles::TwoFactorAuthsController < Profiles::ApplicationController class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
skip_before_action :check_two_factor_requirement skip_before_action :check_two_factor_requirement
before_action :ensure_verified_primary_email, only: [:show, :create]
before_action do before_action do
push_frontend_feature_flag(:webauthn) push_frontend_feature_flag(:webauthn)
end end
...@@ -218,4 +219,12 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController ...@@ -218,4 +219,12 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
s_(%{The group settings for %{group_links} require you to enable Two-Factor Authentication for your account. You can %{leave_group_links}.}) s_(%{The group settings for %{group_links} require you to enable Two-Factor Authentication for your account. You can %{leave_group_links}.})
.html_safe % { group_links: group_links.html_safe, leave_group_links: leave_group_links.html_safe } .html_safe % { group_links: group_links.html_safe, leave_group_links: leave_group_links.html_safe }
end end
def ensure_verified_primary_email
return unless Feature.enabled?(:ensure_verified_primary_email_for_2fa)
unless current_user.two_factor_enabled? || current_user.primary_email_verified?
redirect_to profile_emails_path, notice: s_('You need to verify your primary email first before enabling Two-Factor Authentication.')
end
end
end end
---
name: ensure_verified_primary_email_for_2fa
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/69593
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/340151
milestone: '14.3'
type: development
group: group::access
default_enabled: false
...@@ -38567,6 +38567,9 @@ msgstr "" ...@@ -38567,6 +38567,9 @@ msgstr ""
msgid "You need to upload a GitLab project export archive (ending in .gz)." msgid "You need to upload a GitLab project export archive (ending in .gz)."
msgstr "" msgstr ""
msgid "You need to verify your primary email first before enabling Two-Factor Authentication."
msgstr ""
msgid "You successfully declined the invitation" msgid "You successfully declined the invitation"
msgstr "" msgstr ""
......
...@@ -10,8 +10,33 @@ RSpec.describe Profiles::TwoFactorAuthsController do ...@@ -10,8 +10,33 @@ RSpec.describe Profiles::TwoFactorAuthsController do
allow(subject).to receive(:current_user).and_return(user) allow(subject).to receive(:current_user).and_return(user)
end end
shared_examples 'user must first verify their primary email address' do
before do
allow(user).to receive(:primary_email_verified?).and_return(false)
end
it 'redirects to profile_emails_path' do
go
expect(response).to redirect_to(profile_emails_path)
end
it 'displays a notice' do
go
expect(flash[:notice])
.to eq _('You need to verify your primary email first before enabling Two-Factor Authentication.')
end
it 'does not redirect when the `ensure_verified_primary_email_for_2fa` feature flag is disabled' do
stub_feature_flags(ensure_verified_primary_email_for_2fa: false)
expect(response).not_to redirect_to(profile_emails_path)
end
end
describe 'GET show' do describe 'GET show' do
let(:user) { create(:user) } let_it_be_with_reload(:user) { create(:user) }
it 'generates otp_secret for user' do it 'generates otp_secret for user' do
expect(User).to receive(:generate_otp_secret).with(32).and_call_original.once expect(User).to receive(:generate_otp_secret).with(32).and_call_original.once
...@@ -34,11 +59,16 @@ RSpec.describe Profiles::TwoFactorAuthsController do ...@@ -34,11 +59,16 @@ RSpec.describe Profiles::TwoFactorAuthsController do
get :show get :show
end end
end end
it_behaves_like 'user must first verify their primary email address' do
let(:go) { get :show }
end
end end
describe 'POST create' do describe 'POST create' do
let(:user) { create(:user) } let_it_be_with_reload(:user) { create(:user) }
let(:pin) { 'pin-code' }
let(:pin) { 'pin-code' }
def go def go
post :create, params: { pin_code: pin } post :create, params: { pin_code: pin }
...@@ -105,10 +135,12 @@ RSpec.describe Profiles::TwoFactorAuthsController do ...@@ -105,10 +135,12 @@ RSpec.describe Profiles::TwoFactorAuthsController do
expect(response).to render_template(:show) expect(response).to render_template(:show)
end end
end end
it_behaves_like 'user must first verify their primary email address'
end end
describe 'POST codes' do describe 'POST codes' do
let(:user) { create(:user, :two_factor) } let_it_be_with_reload(:user) { create(:user, :two_factor) }
it 'presents plaintext codes for the user to save' do it 'presents plaintext codes for the user to save' do
expect(user).to receive(:generate_otp_backup_codes!).and_return(%w(a b c)) expect(user).to receive(:generate_otp_backup_codes!).and_return(%w(a b c))
...@@ -135,7 +167,7 @@ RSpec.describe Profiles::TwoFactorAuthsController do ...@@ -135,7 +167,7 @@ RSpec.describe Profiles::TwoFactorAuthsController do
subject { delete :destroy } subject { delete :destroy }
context 'for a user that has 2FA enabled' do context 'for a user that has 2FA enabled' do
let(:user) { create(:user, :two_factor) } let_it_be_with_reload(:user) { create(:user, :two_factor) }
it 'disables two factor' do it 'disables two factor' do
subject subject
...@@ -158,7 +190,7 @@ RSpec.describe Profiles::TwoFactorAuthsController do ...@@ -158,7 +190,7 @@ RSpec.describe Profiles::TwoFactorAuthsController do
end end
context 'for a user that does not have 2FA enabled' do context 'for a user that does not have 2FA enabled' do
let(:user) { create(:user) } let_it_be_with_reload(:user) { create(:user) }
it 'redirects to profile_account_path' do it 'redirects to profile_account_path' do
subject subject
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment