diff options
author | Go MAEDA <maeda@farend.jp> | 2020-08-29 06:37:09 +0000 |
---|---|---|
committer | Go MAEDA <maeda@farend.jp> | 2020-08-29 06:37:09 +0000 |
commit | be7f5e21faa05bdc483d1b58c8887ff499082073 (patch) | |
tree | 3eb76db7dfd87ad1b41494261d54b48f0d3ac09f /app | |
parent | 560bca344ae467cda03e758159fbf131d5c49f43 (diff) | |
download | redmine-be7f5e21faa05bdc483d1b58c8887ff499082073.tar.gz redmine-be7f5e21faa05bdc483d1b58c8887ff499082073.zip |
Adds a setting to disable/enable/require 2fa auth (#1237).
Patch by Felix Schäfer.
git-svn-id: http://svn.redmine.org/redmine/trunk@19989 e93f8b46-1217-0410-a6f0-8f06a7374b81
Diffstat (limited to 'app')
-rw-r--r-- | app/controllers/application_controller.rb | 30 | ||||
-rw-r--r-- | app/controllers/twofa_controller.rb | 18 | ||||
-rw-r--r-- | app/models/setting.rb | 6 | ||||
-rw-r--r-- | app/models/user.rb | 4 | ||||
-rw-r--r-- | app/views/my/account.html.erb | 2 | ||||
-rw-r--r-- | app/views/settings/_authentication.html.erb | 11 | ||||
-rw-r--r-- | app/views/twofa/activate_confirm.html.erb | 2 | ||||
-rw-r--r-- | app/views/twofa/select_scheme.html.erb | 19 | ||||
-rw-r--r-- | app/views/users/_form.html.erb | 2 |
9 files changed, 88 insertions, 6 deletions
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index fca9ebc90..08dea30a7 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -56,7 +56,7 @@ class ApplicationController < ActionController::Base end end - before_action :session_expiration, :user_setup, :check_if_login_required, :set_localization, :check_password_change + before_action :session_expiration, :user_setup, :check_if_login_required, :set_localization, :check_password_change, :check_twofa_activation after_action :record_project_usage rescue_from ::Unauthorized, :with => :deny_access @@ -89,6 +89,9 @@ class ApplicationController < ActionController::Base if user.must_change_password? session[:pwd] = '1' end + if user.must_activate_twofa? + session[:must_activate_twofa] = '1' + end end def user_setup @@ -205,6 +208,31 @@ class ApplicationController < ActionController::Base end end + def init_twofa_pairing_and_send_code_for(twofa) + twofa.init_pairing! + if twofa.send_code(controller: 'twofa', action: 'activate') + flash[:notice] = l('twofa_code_sent') + end + redirect_to controller: 'twofa', action: 'activate_confirm', scheme: twofa.scheme_name + end + + def check_twofa_activation + if session[:must_activate_twofa] + if User.current.must_activate_twofa? + flash[:warning] = l('twofa_warning_require') + if Redmine::Twofa.available_schemes.length == 1 + twofa_scheme = Redmine::Twofa.for_twofa_scheme(Redmine::Twofa.available_schemes.first) + twofa = twofa_scheme.new(User.current) + init_twofa_pairing_and_send_code_for(twofa) + else + redirect_to controller: 'twofa', action: 'select_scheme' + end + else + session.delete(:must_activate_twofa) + end + end + end + def set_localization(user=User.current) lang = nil if user && user.logged? diff --git a/app/controllers/twofa_controller.rb b/app/controllers/twofa_controller.rb index 4cdeeee4f..8bbdb8056 100644 --- a/app/controllers/twofa_controller.rb +++ b/app/controllers/twofa_controller.rb @@ -23,16 +23,20 @@ class TwofaController < ApplicationController before_action :require_login before_action :require_admin, only: :admin_deactivate + before_action :require_active_twofa + require_sudo_mode :activate_init, :deactivate_init + skip_before_action :check_twofa_activation, only: [:select_scheme, :activate_init, :activate_confirm, :activate] + + def select_scheme + @user = User.current + end + before_action :activate_setup, only: [:activate_init, :activate_confirm, :activate] def activate_init - @twofa.init_pairing! - if @twofa.send_code(controller: 'twofa', action: 'activate') - flash[:notice] = l('twofa_code_sent') - end - redirect_to action: :activate_confirm, scheme: @twofa.scheme_name + init_twofa_pairing_and_send_code_for(@twofa) end def activate_confirm @@ -106,4 +110,8 @@ class TwofaController < ApplicationController redirect_to my_account_path end end + + def require_active_twofa + Setting.twofa? ? true : deny_access + end end diff --git a/app/models/setting.rb b/app/models/setting.rb index da121263d..e71a9a0cf 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -223,6 +223,12 @@ class Setting < ActiveRecord::Base s end + def self.twofa_from_params(params) + # unpair all current 2FA pairings when switching off 2FA + Redmine::Twofa.unpair_all! if params == '0' && self.twofa? + params + end + # Helper that returns an array based on per_page_options setting def self.per_page_options_array per_page_options.split(%r{[\s,]}).collect(&:to_i).select {|n| n > 0}.sort diff --git a/app/models/user.rb b/app/models/user.rb index 5b4089ea4..d905aa1b3 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -396,6 +396,10 @@ class User < Principal twofa_scheme.present? end + def must_activate_twofa? + Setting.twofa == '2' && !twofa_active? + end + def pref self.preference ||= UserPreference.new(:user => self) end diff --git a/app/views/my/account.html.erb b/app/views/my/account.html.erb index da7746bb2..996bead61 100644 --- a/app/views/my/account.html.erb +++ b/app/views/my/account.html.erb @@ -28,6 +28,7 @@ <% if Setting.openid? %> <p><%= f.text_field :identity_url %></p> <% end %> + <% if Setting.twofa? -%> <p> <label><%=l :setting_twofa -%></label> <% if @user.twofa_active? %> @@ -39,6 +40,7 @@ <% end %> <% end %> </p> + <% end -%> <% @user.custom_field_values.select(&:editable?).each do |value| %> <p><%= custom_field_tag_with_label :user, value %></p> diff --git a/app/views/settings/_authentication.html.erb b/app/views/settings/_authentication.html.erb index 9a39497b8..5522ff5cf 100644 --- a/app/views/settings/_authentication.html.erb +++ b/app/views/settings/_authentication.html.erb @@ -28,6 +28,17 @@ <p><%= setting_check_box :lost_password %></p> +<p> + <%= setting_select :twofa, [[l(:label_disabled), "0"], + [l(:label_optional), "1"], + [l(:label_required_lower), "2"]] -%> + <em class="info"> + <%= t 'twofa_hint_disabled_html', label: t(:label_disabled) -%><br/> + <%= t 'twofa_hint_required_html', label: t(:label_required_lower) -%> + </em> +</p> + + <p><%= setting_check_box :openid, :disabled => !Object.const_defined?(:OpenID) %></p> </div> diff --git a/app/views/twofa/activate_confirm.html.erb b/app/views/twofa/activate_confirm.html.erb index fc356323c..78194c62b 100644 --- a/app/views/twofa/activate_confirm.html.erb +++ b/app/views/twofa/activate_confirm.html.erb @@ -22,6 +22,8 @@ <% end %> </div> +<% unless @user.must_activate_twofa? %> <% content_for :sidebar do %> <%= render :partial => 'my/sidebar' %> <% end %> +<% end %> diff --git a/app/views/twofa/select_scheme.html.erb b/app/views/twofa/select_scheme.html.erb new file mode 100644 index 000000000..cbc7c3506 --- /dev/null +++ b/app/views/twofa/select_scheme.html.erb @@ -0,0 +1,19 @@ +<%= title l('twofa_label_setup') %> + +<%= form_tag({ controller: 'twofa', action: 'activate_init' }, method: :post) do %> + <div class="box"> + <p><%=l 'twofa_notice_select' -%></p> + <p> + <% Redmine::Twofa.available_schemes.each_with_index do |s, idx| %> + <label style="display:block;"><%= radio_button_tag 'scheme', s, idx == 0 -%> <%=l "twofa__#{s}__name" -%></label> + <% end %> + </p> + </div> + <p><%= submit_tag l(:label_next).html_safe + " »".html_safe -%></p> +<% end %> + +<% unless @user.must_activate_twofa? %> +<% content_for :sidebar do %> +<%= render partial: 'my/sidebar' %> +<% end %> +<% end %> diff --git a/app/views/users/_form.html.erb b/app/views/users/_form.html.erb index b9054a3b0..ab9f7b541 100644 --- a/app/views/users/_form.html.erb +++ b/app/views/users/_form.html.erb @@ -42,6 +42,7 @@ <p><%= f.check_box :generate_password %></p> <p><%= f.check_box :must_change_passwd %></p> </div> + <% if Setting.twofa? -%> <p> <label><%=l :setting_twofa -%></label> <% if @user.twofa_active? %> @@ -55,6 +56,7 @@ <%=l 'twofa_not_active' %> <% end %> </p> + <% end -%> </fieldset> </div> |