summaryrefslogtreecommitdiff
path: root/app/controllers/profiles/two_factor_auths_controller.rb
diff options
context:
space:
mode:
Diffstat (limited to 'app/controllers/profiles/two_factor_auths_controller.rb')
-rw-r--r--app/controllers/profiles/two_factor_auths_controller.rb98
1 files changed, 88 insertions, 10 deletions
diff --git a/app/controllers/profiles/two_factor_auths_controller.rb b/app/controllers/profiles/two_factor_auths_controller.rb
index 50fbf8146e5..5de6d84fdd9 100644
--- a/app/controllers/profiles/two_factor_auths_controller.rb
+++ b/app/controllers/profiles/two_factor_auths_controller.rb
@@ -2,6 +2,9 @@
class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
skip_before_action :check_two_factor_requirement
+ before_action do
+ push_frontend_feature_flag(:webauthn)
+ end
def show
unless current_user.two_factor_enabled?
@@ -33,7 +36,12 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
@qr_code = build_qr_code
@account_string = account_string
- setup_u2f_registration
+
+ if Feature.enabled?(:webauthn)
+ setup_webauthn_registration
+ else
+ setup_u2f_registration
+ end
end
def create
@@ -48,7 +56,13 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
else
@error = _('Invalid pin code')
@qr_code = build_qr_code
- setup_u2f_registration
+
+ if Feature.enabled?(:webauthn)
+ setup_webauthn_registration
+ else
+ setup_u2f_registration
+ end
+
render 'show'
end
end
@@ -56,7 +70,7 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
# A U2F (universal 2nd factor) device's information is stored after successful
# registration, which is then used while 2FA authentication is taking place.
def create_u2f
- @u2f_registration = U2fRegistration.register(current_user, u2f_app_id, u2f_registration_params, session[:challenges])
+ @u2f_registration = U2fRegistration.register(current_user, u2f_app_id, device_registration_params, session[:challenges])
if @u2f_registration.persisted?
session.delete(:challenges)
@@ -68,6 +82,21 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
end
end
+ def create_webauthn
+ @webauthn_registration = Webauthn::RegisterService.new(current_user, device_registration_params, session[:challenge]).execute
+ if @webauthn_registration.persisted?
+ session.delete(:challenge)
+
+ redirect_to profile_two_factor_auth_path, notice: s_("Your WebAuthn device was registered!")
+ else
+ @qr_code = build_qr_code
+
+ setup_webauthn_registration
+
+ render :show
+ end
+ end
+
def codes
Users::UpdateService.new(current_user, user: current_user).execute! do |user|
@codes = user.generate_otp_backup_codes!
@@ -75,9 +104,13 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
end
def destroy
- current_user.disable_two_factor!
+ result = TwoFactor::DestroyService.new(current_user, user: current_user).execute
- redirect_to profile_account_path, status: :found
+ if result[:status] == :success
+ redirect_to profile_account_path, status: :found, notice: s_('Two-factor authentication has been disabled successfully!')
+ else
+ redirect_to profile_account_path, status: :found, alert: result[:message]
+ end
end
def skip
@@ -108,11 +141,11 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
# Actual communication is performed using a Javascript API
def setup_u2f_registration
@u2f_registration ||= U2fRegistration.new
- @u2f_registrations = current_user.u2f_registrations
+ @registrations = u2f_registrations
u2f = U2F::U2F.new(u2f_app_id)
registration_requests = u2f.registration_requests
- sign_requests = u2f.authentication_requests(@u2f_registrations.map(&:key_handle))
+ sign_requests = u2f.authentication_requests(current_user.u2f_registrations.map(&:key_handle))
session[:challenges] = registration_requests.map(&:challenge)
gon.push(u2f: { challenges: session[:challenges], app_id: u2f_app_id,
@@ -120,8 +153,53 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
sign_requests: sign_requests })
end
- def u2f_registration_params
- params.require(:u2f_registration).permit(:device_response, :name)
+ def device_registration_params
+ params.require(:device_registration).permit(:device_response, :name)
+ end
+
+ def setup_webauthn_registration
+ @registrations = webauthn_registrations
+ @webauthn_registration ||= WebauthnRegistration.new
+
+ unless current_user.webauthn_xid
+ current_user.user_detail.update!(webauthn_xid: WebAuthn.generate_user_id)
+ end
+
+ options = webauthn_options
+ session[:challenge] = options.challenge
+
+ gon.push(webauthn: { options: options, app_id: u2f_app_id })
+ end
+
+ # Adds delete path to u2f registrations
+ # to reduce logic in view template
+ def u2f_registrations
+ current_user.u2f_registrations.map do |u2f_registration|
+ {
+ name: u2f_registration.name,
+ created_at: u2f_registration.created_at,
+ delete_path: profile_u2f_registration_path(u2f_registration)
+ }
+ end
+ end
+
+ def webauthn_registrations
+ current_user.webauthn_registrations.map do |webauthn_registration|
+ {
+ name: webauthn_registration.name,
+ created_at: webauthn_registration.created_at,
+ delete_path: profile_webauthn_registration_path(webauthn_registration)
+ }
+ end
+ end
+
+ def webauthn_options
+ WebAuthn::Credential.options_for_create(
+ user: { id: current_user.webauthn_xid, name: current_user.username },
+ exclude: current_user.webauthn_registrations.map { |c| c.credential_xid },
+ authenticator_selection: { user_verification: 'discouraged' },
+ rp: { name: 'GitLab' }
+ )
end
def groups_notification(groups)
@@ -129,6 +207,6 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
leave_group_links = groups.map { |group| view_context.link_to (s_("leave %{group_name}") % { group_name: group.full_name }), leave_group_members_path(group), remote: false, method: :delete}.to_sentence
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