summaryrefslogtreecommitdiff
path: root/app/controllers/concerns/enforces_two_factor_authentication.rb
blob: cdef1a45a272ef086ac6c6f05486fb49d281944e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# frozen_string_literal: true

# == EnforcesTwoFactorAuthentication
#
# Controller concern to enforce two-factor authentication requirements
#
# Upon inclusion, adds `check_two_factor_requirement` as a before_action,
# and makes `two_factor_grace_period_expired?` and `two_factor_skippable?`
# available as view helpers.
module EnforcesTwoFactorAuthentication
  extend ActiveSupport::Concern

  included do
    before_action :check_two_factor_requirement, except: [:route_not_found]

    # to include this in controllers inheriting from `ActionController::Metal`
    # we need to add this block
    helper_method :two_factor_grace_period_expired?, :two_factor_skippable? if respond_to?(:helper_method)
  end

  def check_two_factor_requirement
    return unless respond_to?(:current_user)

    if two_factor_authentication_required? && current_user_requires_two_factor?
      case self
      when GraphqlController
        render_error(
          format(
            _("Authentication error: enable 2FA in your profile settings to continue using GitLab: %{mfa_help_page}"),
             mfa_help_page: mfa_help_page_url),
          status: :unauthorized
        )
      else
        redirect_to profile_two_factor_auth_path
      end
    end
  end

  def two_factor_authentication_required?
    two_factor_verifier.two_factor_authentication_required?
  end

  def current_user_requires_two_factor?
    two_factor_verifier.current_user_needs_to_setup_two_factor? && !skip_two_factor?
  end

  # rubocop: disable CodeReuse/ActiveRecord
  def two_factor_authentication_reason(global: -> {}, group: -> {})
    if two_factor_authentication_required?
      if Gitlab::CurrentSettings.require_two_factor_authentication?
        global.call
      else
        groups = current_user.source_groups_of_two_factor_authentication_requirement.reorder(name: :asc)
        group.call(groups)
      end
    end
  end
  # rubocop: enable CodeReuse/ActiveRecord

  def two_factor_grace_period
    two_factor_verifier.two_factor_grace_period
  end

  def two_factor_grace_period_expired?
    two_factor_verifier.two_factor_grace_period_expired?
  end

  def two_factor_skippable?
    two_factor_authentication_required? &&
      !current_user.two_factor_enabled? &&
      !two_factor_grace_period_expired?
  end

  def skip_two_factor?
    session[:skip_two_factor] && session[:skip_two_factor] > Time.current
  end

  def two_factor_verifier
    @two_factor_verifier ||= Gitlab::Auth::TwoFactorAuthVerifier.new(current_user) # rubocop:disable Gitlab/ModuleWithInstanceVariables
  end

  def mfa_help_page_url
    Rails.application.routes.url_helpers.help_page_url(
      'user/profile/account/two_factor_authentication.html',
      anchor: 'enable-two-factor-authentication'
    )
  end
end

EnforcesTwoFactorAuthentication.prepend_mod_with('EnforcesTwoFactorAuthentication')