Feature #1237 » 0002-2-factor-authentication-disabled-enabled-required.patch
app/controllers/application_controller.rb | ||
---|---|---|
51 | 51 |
end |
52 | 52 |
end |
53 | 53 | |
54 |
before_action :session_expiration, :user_setup, :check_if_login_required, :set_localization, :check_password_change |
|
54 |
before_action :session_expiration, :user_setup, :check_if_login_required, :set_localization, :check_password_change, :check_twofa_activation
|
|
55 | 55 | |
56 | 56 |
rescue_from ::Unauthorized, :with => :deny_access |
57 | 57 |
rescue_from ::ActionView::MissingTemplate, :with => :missing_template |
... | ... | |
83 | 83 |
if user.must_change_password? |
84 | 84 |
session[:pwd] = '1' |
85 | 85 |
end |
86 |
if user.must_activate_twofa? |
|
87 |
session[:must_activate_twofa] = '1' |
|
88 |
end |
|
86 | 89 |
end |
87 | 90 | |
88 | 91 |
def user_setup |
... | ... | |
194 | 197 |
end |
195 | 198 |
end |
196 | 199 | |
200 |
def init_twofa_pairing_and_send_code_for(twofa) |
|
201 |
twofa.init_pairing! |
|
202 |
if twofa.send_code(controller: 'twofa', action: 'activate') |
|
203 |
flash[:notice] = l('twofa_code_sent') |
|
204 |
end |
|
205 |
redirect_to controller: 'twofa', action: 'activate_confirm', scheme: twofa.scheme_name |
|
206 |
end |
|
207 | ||
208 |
def check_twofa_activation |
|
209 |
if session[:must_activate_twofa] |
|
210 |
if User.current.must_activate_twofa? |
|
211 |
flash[:warning] = l('twofa_warning_require') |
|
212 |
if Redmine::Twofa.available_schemes.length == 1 |
|
213 |
twofa_scheme = Redmine::Twofa.for_twofa_scheme(Redmine::Twofa.available_schemes.first) |
|
214 |
twofa = twofa_scheme.new(User.current) |
|
215 |
init_twofa_pairing_and_send_code_for(twofa) |
|
216 |
else |
|
217 |
redirect_to controller: 'twofa', action: 'select_scheme' |
|
218 |
end |
|
219 |
else |
|
220 |
session.delete(:must_activate_twofa) |
|
221 |
end |
|
222 |
end |
|
223 |
end |
|
224 | ||
197 | 225 |
def set_localization(user=User.current) |
198 | 226 |
lang = nil |
199 | 227 |
if user && user.logged? |
app/controllers/twofa_controller.rb | ||
---|---|---|
4 | 4 |
before_action :require_login |
5 | 5 |
before_action :require_admin, only: :admin_deactivate |
6 | 6 | |
7 |
before_action :require_active_twofa |
|
8 | ||
7 | 9 |
require_sudo_mode :activate_init, :deactivate_init |
8 | 10 | |
11 |
skip_before_action :check_twofa_activation, only: [:select_scheme, :activate_init, :activate_confirm, :activate] |
|
12 | ||
13 |
def select_scheme |
|
14 |
@user = User.current |
|
15 |
end |
|
16 | ||
9 | 17 |
before_action :activate_setup, only: [:activate_init, :activate_confirm, :activate] |
10 | 18 | |
11 | 19 |
def activate_init |
12 |
@twofa.init_pairing! |
|
13 |
if @twofa.send_code(controller: 'twofa', action: 'activate') |
|
14 |
flash[:notice] = l('twofa_code_sent') |
|
15 |
end |
|
16 |
redirect_to action: :activate_confirm, scheme: @twofa.scheme_name |
|
20 |
init_twofa_pairing_and_send_code_for(@twofa) |
|
17 | 21 |
end |
18 | 22 | |
19 | 23 |
def activate_confirm |
... | ... | |
84 | 88 |
redirect_to my_account_path |
85 | 89 |
end |
86 | 90 |
end |
91 | ||
92 |
def require_active_twofa |
|
93 |
Setting.twofa? ? true : deny_access |
|
94 |
end |
|
87 | 95 |
end |
app/models/setting.rb | ||
---|---|---|
198 | 198 |
s |
199 | 199 |
end |
200 | 200 | |
201 |
def self.twofa_from_params(params) |
|
202 |
# unpair all current 2FA pairings when switching off 2FA |
|
203 |
Redmine::Twofa.unpair_all! if params == '0' && self.twofa? |
|
204 |
params |
|
205 |
end |
|
206 | ||
201 | 207 |
# Helper that returns an array based on per_page_options setting |
202 | 208 |
def self.per_page_options_array |
203 | 209 |
per_page_options.split(%r{[\s,]}).collect(&:to_i).select {|n| n > 0}.sort |
app/models/user.rb | ||
---|---|---|
373 | 373 |
twofa_scheme.present? |
374 | 374 |
end |
375 | 375 | |
376 |
def must_activate_twofa? |
|
377 |
Setting.twofa == '2' && !twofa_active? |
|
378 |
end |
|
379 | ||
376 | 380 |
def pref |
377 | 381 |
self.preference ||= UserPreference.new(:user => self) |
378 | 382 |
end |
app/views/my/account.html.erb | ||
---|---|---|
27 | 27 |
<% if Setting.openid? %> |
28 | 28 |
<p><%= f.text_field :identity_url %></p> |
29 | 29 |
<% end %> |
30 |
<% if Setting.twofa? -%> |
|
30 | 31 |
<p> |
31 | 32 |
<label><%=l :setting_twofa -%></label> |
32 | 33 |
<% if @user.twofa_active? %> |
... | ... | |
38 | 39 |
<% end %> |
39 | 40 |
<% end %> |
40 | 41 |
</p> |
42 |
<% end -%> |
|
41 | 43 | |
42 | 44 |
<% @user.custom_field_values.select(&:editable?).each do |value| %> |
43 | 45 |
<p><%= custom_field_tag_with_label :user, value %></p> |
app/views/settings/_authentication.html.erb | ||
---|---|---|
25 | 25 | |
26 | 26 |
<p><%= setting_check_box :lost_password %></p> |
27 | 27 | |
28 |
<p> |
|
29 |
<%= setting_select :twofa, [[l(:label_disabled), "0"], |
|
30 |
[l(:label_optional), "1"], |
|
31 |
[l(:label_required_lower), "2"]] -%> |
|
32 |
<em class="info"> |
|
33 |
<%= t 'twofa_hint_disabled_html', label: t(:label_disabled) -%><br/> |
|
34 |
<%= t 'twofa_hint_required_html', label: t(:label_required_lower) -%> |
|
35 |
</em> |
|
36 |
</p> |
|
37 | ||
28 | 38 |
<p><%= setting_text_field :max_additional_emails, :size => 6 %></p> |
29 | 39 | |
30 | 40 |
<p><%= setting_check_box :openid, :disabled => !Object.const_defined?(:OpenID) %></p> |
app/views/twofa/activate_confirm.html.erb | ||
---|---|---|
22 | 22 |
<% end %> |
23 | 23 |
</div> |
24 | 24 | |
25 |
<% unless @user.must_activate_twofa? %> |
|
25 | 26 |
<% content_for :sidebar do %> |
26 | 27 |
<%= render :partial => 'my/sidebar' %> |
27 | 28 |
<% end %> |
29 |
<% end %> |
app/views/twofa/select_scheme.html.erb | ||
---|---|---|
1 |
<%= title l('twofa_label_setup') %> |
|
2 | ||
3 |
<%= form_tag({ controller: 'twofa', action: 'activate_init' }, method: :post) do %> |
|
4 |
<div class="box"> |
|
5 |
<p><%=l 'twofa_notice_select' -%></p> |
|
6 |
<p> |
|
7 |
<% Redmine::Twofa.available_schemes.each_with_index do |s, idx| %> |
|
8 |
<label style="display:block;"><%= radio_button_tag 'scheme', s, idx == 0 -%> <%=l "twofa__#{s}__name" -%></label> |
|
9 |
<% end %> |
|
10 |
</p> |
|
11 |
</div> |
|
12 |
<p><%= submit_tag l(:label_next).html_safe + " »".html_safe -%></p> |
|
13 |
<% end %> |
|
14 | ||
15 |
<% unless @user.must_activate_twofa? %> |
|
16 |
<% content_for :sidebar do %> |
|
17 |
<%= render partial: 'my/sidebar' %> |
|
18 |
<% end %> |
|
19 |
<% end %> |
app/views/users/_form.html.erb | ||
---|---|---|
36 | 36 |
<p><%= f.check_box :generate_password %></p> |
37 | 37 |
<p><%= f.check_box :must_change_passwd %></p> |
38 | 38 |
</div> |
39 |
<% if Setting.twofa? -%> |
|
39 | 40 |
<p> |
40 | 41 |
<label><%=l :setting_twofa -%></label> |
41 | 42 |
<% if @user.twofa_active? %> |
... | ... | |
49 | 50 |
<%=l 'twofa_not_active' %> |
50 | 51 |
<% end %> |
51 | 52 |
</p> |
53 |
<% end -%> |
|
52 | 54 |
</fieldset> |
53 | 55 |
</div> |
54 | 56 |
config/locales/de.yml | ||
---|---|---|
713 | 713 |
label_repository_new: Neues Repository |
714 | 714 |
label_repository_plural: Repositories |
715 | 715 |
label_required: Erforderlich |
716 |
label_required_lower: erforderlich |
|
716 | 717 |
label_result_plural: Resultate |
717 | 718 |
label_reverse_chronological_order: in umgekehrter zeitlicher Reihenfolge |
718 | 719 |
label_revision: Revision |
... | ... | |
1244 | 1245 |
twofa_currently_active: "Aktiv: %{twofa_scheme_name}" |
1245 | 1246 |
twofa_not_active: "Nicht aktiv" |
1246 | 1247 |
twofa_label_code: Code |
1248 |
twofa_hint_disabled_html: Die Einstellung <strong>%{label}</strong> deaktiviert Zwei-Faktor-Authentifizierung für alle Nutzer und löscht verbundene Apps. |
|
1249 |
twofa_hint_required_html: Die Einstellung <strong>%{label}</strong> fordert alle Nutzer bei ihrem nächsten Login dazu auf Zwei-Faktor-Authentifizierung einzurichten. |
|
1247 | 1250 |
twofa_label_setup: Zwei-Faktor-Authentifizierung einrichten |
1248 | 1251 |
twofa_label_deactivation_confirmation: Zwei-Faktor-Authentifizierung abschalten |
1252 |
twofa_notice_select: "Bitte wählen Sie Ihr gewünschtes Schema für die Zwei-Faktor-Authentifizierung:" |
|
1253 |
twofa_warning_require: Der Administrator fordert Sie dazu auf Zwei-Faktor-Authentifizierung einzurichten. |
|
1249 | 1254 |
twofa_activated: Zwei-Faktor-Authentifizierung erfolgreich eingerichtet. |
1250 | 1255 |
twofa_deactivated: Zwei-Faktor-Authentifizierung abgeschaltet. |
1251 | 1256 |
twofa_mail_body_security_notification_paired: "Zwei-Faktor-Authentifizierung per %{field} eingerichtet." |
config/locales/en.yml | ||
---|---|---|
836 | 836 |
label_copied_from: Copied from |
837 | 837 |
label_stay_logged_in: Stay logged in |
838 | 838 |
label_disabled: disabled |
839 |
label_optional: optional |
|
839 | 840 |
label_show_completed_versions: Show completed versions |
840 | 841 |
label_me: me |
841 | 842 |
label_board: Forum |
... | ... | |
953 | 954 |
label_fields_permissions: Fields permissions |
954 | 955 |
label_readonly: Read-only |
955 | 956 |
label_required: Required |
957 |
label_required_lower: required |
|
956 | 958 |
label_hidden: Hidden |
957 | 959 |
label_attribute_of_project: "Project's %{name}" |
958 | 960 |
label_attribute_of_issue: "Issue's %{name}" |
... | ... | |
1225 | 1227 |
twofa_currently_active: "Currently active: %{twofa_scheme_name}" |
1226 | 1228 |
twofa_not_active: "Not activated" |
1227 | 1229 |
twofa_label_code: Code |
1230 |
twofa_hint_disabled_html: Setting <strong>%{label}</strong> will deactivate and unpair two-factor authentication devices for all users. |
|
1231 |
twofa_hint_required_html: Setting <strong>%{label}</strong> will require all users to set up two-factor authentication at their next login. |
|
1228 | 1232 |
twofa_label_setup: Enable two-factor authentication |
1229 | 1233 |
twofa_label_deactivation_confirmation: Disable two-factor authentication |
1234 |
twofa_notice_select: "Please select the two-factor scheme you would like to use:" |
|
1235 |
twofa_warning_require: The administrator requires you to enable two-factor authentication. |
|
1230 | 1236 |
twofa_activated: Two-factor authentication successfully enabled. |
1231 | 1237 |
twofa_deactivated: Two-factor authentication disabled. |
1232 | 1238 |
twofa_mail_body_security_notification_paired: "Two-factor authentication successfully enabled using %{field}." |
config/routes.rb | ||
---|---|---|
85 | 85 |
match 'my/add_block', :controller => 'my', :action => 'add_block', :via => :post |
86 | 86 |
match 'my/remove_block', :controller => 'my', :action => 'remove_block', :via => :post |
87 | 87 |
match 'my/order_blocks', :controller => 'my', :action => 'order_blocks', :via => :post |
88 |
match 'my/twofa/activate/init', :controller => 'twofa', :action => 'activate_init', :via => :post |
|
88 | 89 |
match 'my/twofa/:scheme/activate/init', :controller => 'twofa', :action => 'activate_init', :via => :post |
89 | 90 |
match 'my/twofa/:scheme/activate/confirm', :controller => 'twofa', :action => 'activate_confirm', :via => :get |
90 | 91 |
match 'my/twofa/:scheme/activate', :controller => 'twofa', :action => 'activate', :via => [:get, :post] |
91 | 92 |
match 'my/twofa/:scheme/deactivate/init', :controller => 'twofa', :action => 'deactivate_init', :via => :post |
92 | 93 |
match 'my/twofa/:scheme/deactivate/confirm', :controller => 'twofa', :action => 'deactivate_confirm', :via => :get |
93 | 94 |
match 'my/twofa/:scheme/deactivate', :controller => 'twofa', :action => 'deactivate', :via => [:get, :post] |
95 |
match 'my/twofa/select_scheme', :controller => 'twofa', :action => 'select_scheme', :via => :get |
|
94 | 96 |
match 'users/:user_id/twofa/deactivate', :controller => 'twofa', :action => 'admin_deactivate', :via => :post |
95 | 97 | |
96 | 98 |
resources :users do |
config/settings.yml | ||
---|---|---|
36 | 36 |
lost_password: |
37 | 37 |
default: 1 |
38 | 38 |
security_notifications: 1 |
39 |
twofa: |
|
40 |
default: 1 |
|
41 |
security_notifications: 1 |
|
39 | 42 |
unsubscribe: |
40 | 43 |
default: 1 |
41 | 44 |
password_min_length: |
lib/redmine/twofa.rb | ||
---|---|---|
17 | 17 |
for_twofa_scheme(user.twofa_scheme).try(:new, user) |
18 | 18 |
end |
19 | 19 | |
20 |
def self.unpair_all! |
|
21 |
users = User.where.not(twofa_scheme: nil) |
|
22 |
users.each { |u| self.for_user(u).destroy_pairing_without_verify! } |
|
23 |
end |
|
24 | ||
20 | 25 |
private |
21 | 26 | |
22 | 27 |
def self.schemes |