Feature #31920 » 0005-per-group-2fa-requirement.patch
app/models/group.rb | ||
---|---|---|
40 | 40 |
scope :givable, lambda {where(:type => 'Group')} |
41 | 41 | |
42 | 42 |
safe_attributes 'name', |
43 |
'twofa_required', |
|
43 | 44 |
'user_ids', |
44 | 45 |
'custom_field_values', |
45 | 46 |
'custom_fields', |
app/models/setting.rb | ||
---|---|---|
211 | 211 |
params |
212 | 212 |
end |
213 | 213 | |
214 |
def self.twofa_required? |
|
215 |
twofa == '2' |
|
216 |
end |
|
217 | ||
218 |
def self.twofa_optional? |
|
219 |
twofa == '1' |
|
220 |
end |
|
221 | ||
214 | 222 |
# Helper that returns an array based on per_page_options setting |
215 | 223 |
def self.per_page_options_array |
216 | 224 |
per_page_options.split(%r{[\s,]}).collect(&:to_i).select {|n| n > 0}.sort |
app/models/user.rb | ||
---|---|---|
382 | 382 |
end |
383 | 383 | |
384 | 384 |
def must_activate_twofa? |
385 |
Setting.twofa == '2' && !twofa_active? |
|
385 |
( |
|
386 |
Setting.twofa_required? || |
|
387 |
(Setting.twofa_optional? && groups.any?(&:twofa_required?)) |
|
388 |
) && !twofa_active? |
|
386 | 389 |
end |
387 | 390 | |
388 | 391 |
def pref |
app/views/groups/_form.html.erb | ||
---|---|---|
3 | 3 |
<div class="box tabular"> |
4 | 4 |
<p><%= f.text_field :name, :required => true, :size => 60, |
5 | 5 |
:disabled => !@group.safe_attribute?('name') %></p> |
6 |
<p><%= f.check_box :twofa_required, disabled: !Setting.twofa_optional? %> |
|
7 |
<% if Setting.twofa_required? %> |
|
8 |
<em class="info"><%= l 'twofa_text_group_required' %></em> |
|
9 |
<% elsif !Setting.twofa_optional? %> |
|
10 |
<em class="info"><%= l 'twofa_text_group_disabled' %></em> |
|
11 |
<% end %> |
|
12 |
</p> |
|
6 | 13 | |
7 | 14 |
<% @group.custom_field_values.each do |value| %> |
8 | 15 |
<p><%= custom_field_tag_with_label :group, value %></p> |
app/views/settings/_authentication.html.erb | ||
---|---|---|
32 | 32 |
[l(:label_required_lower), "2"]] -%> |
33 | 33 |
<em class="info"> |
34 | 34 |
<%= t 'twofa_hint_disabled_html', label: t(:label_disabled) -%><br/> |
35 |
<%= t 'twofa_hint_optional_html', label: t(:label_optional) -%><br/> |
|
35 | 36 |
<%= t 'twofa_hint_required_html', label: t(:label_required_lower) -%> |
36 | 37 |
</em> |
37 | 38 |
</p> |
config/locales/en.yml | ||
---|---|---|
1279 | 1279 |
twofa_not_active: "Not activated" |
1280 | 1280 |
twofa_label_code: Code |
1281 | 1281 |
twofa_hint_disabled_html: Setting <strong>%{label}</strong> will deactivate and unpair two-factor authentication devices for all users. |
1282 |
twofa_hint_optional_html: Setting <strong>%{label}</strong> will let users set up two-factor authentication at will, unless it is required by one of their groups. |
|
1282 | 1283 |
twofa_hint_required_html: Setting <strong>%{label}</strong> will require all users to set up two-factor authentication at their next login. |
1283 | 1284 |
twofa_label_setup: Enable two-factor authentication |
1284 | 1285 |
twofa_label_deactivation_confirmation: Disable two-factor authentication |
... | ... | |
1303 | 1304 |
twofa_text_backup_codes_hint: Use these codes instead of a one-time password should you not have access to your second factor. Each code can only be used once. It is recommended to print and store them in a safe place. |
1304 | 1305 |
twofa_text_backup_codes_created_at: Backup codes generated %{datetime}. |
1305 | 1306 |
twofa_backup_codes_already_shown: Backup codes cannot be shown again, please <a data-method="post" href="%{bc_path}">generate new backup codes</a> if required. |
1307 |
field_twofa_required: Require two factor authentication |
|
1308 |
twofa_text_group_required: "This setting is only effective when the global two factor authentication setting is set to 'optional'. Currently, two factor authentication is required for all users." |
|
1309 |
twofa_text_group_disabled: "This setting is only effective when the global two factor authentication setting is set to 'optional'. Currently, two factor authentication is disabled." |
db/migrate/20190817093525_add_twofa_required_to_groups.rb | ||
---|---|---|
1 |
class AddTwofaRequiredToGroups < ActiveRecord::Migration[5.2] |
|
2 |
def change |
|
3 |
add_column :users, :twofa_required, :boolean, default: false |
|
4 |
end |
|
5 |
end |
test/integration/twofa_test.rb | ||
---|---|---|
3 | 3 |
class TwofaTest < Redmine::IntegrationTest |
4 | 4 |
fixtures :projects, :users, :email_addresses |
5 | 5 | |
6 |
setup do |
|
7 |
end |
|
8 | ||
6 | 9 |
test "should require twofa setup when configured" do |
7 | 10 |
with_settings twofa: "2" do |
11 |
assert Setting.twofa_required? |
|
12 |
log_user('jsmith', 'jsmith') |
|
13 |
follow_redirect! |
|
14 |
assert_redirected_to "/my/twofa/totp/activate/confirm" |
|
15 |
end |
|
16 |
end |
|
17 | ||
18 |
test "should require twofa setup when required by group" do |
|
19 |
user = User.find_by_login 'jsmith' |
|
20 |
refute user.must_activate_twofa? |
|
21 | ||
22 |
group = Group.all.first |
|
23 |
group.update_column :twofa_required, true |
|
24 |
group.users << user |
|
25 |
user.reload |
|
26 | ||
27 |
with_settings twofa: "0" do |
|
28 |
refute Setting.twofa_optional? |
|
29 |
refute Setting.twofa_required? |
|
30 |
refute user.must_activate_twofa? |
|
31 |
end |
|
32 | ||
33 |
with_settings twofa: "1" do |
|
34 |
assert Setting.twofa_optional? |
|
35 |
refute Setting.twofa_required? |
|
36 |
assert user.must_activate_twofa? |
|
8 | 37 |
log_user('jsmith', 'jsmith') |
9 | 38 |
follow_redirect! |
10 | 39 |
assert_redirected_to "/my/twofa/totp/activate/confirm" |