summaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
authorGo MAEDA <maeda@farend.jp>2020-08-29 06:37:09 +0000
committerGo MAEDA <maeda@farend.jp>2020-08-29 06:37:09 +0000
commitbe7f5e21faa05bdc483d1b58c8887ff499082073 (patch)
tree3eb76db7dfd87ad1b41494261d54b48f0d3ac09f /app
parent560bca344ae467cda03e758159fbf131d5c49f43 (diff)
downloadredmine-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.rb30
-rw-r--r--app/controllers/twofa_controller.rb18
-rw-r--r--app/models/setting.rb6
-rw-r--r--app/models/user.rb4
-rw-r--r--app/views/my/account.html.erb2
-rw-r--r--app/views/settings/_authentication.html.erb11
-rw-r--r--app/views/twofa/activate_confirm.html.erb2
-rw-r--r--app/views/twofa/select_scheme.html.erb19
-rw-r--r--app/views/users/_form.html.erb2
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 + " &#187;".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>