Send a notification when security settings are changed (#21421).

git-svn-id: http://svn.redmine.org/redmine/trunk@15148 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
Jean-Philippe Lang
2016-02-05 08:50:21 +00:00
parent c46c0e7452
commit b5366eb307
9 changed files with 116 additions and 4 deletions

View File

@@ -33,10 +33,7 @@ class SettingsController < ApplicationController
def edit def edit
@notifiables = Redmine::Notifiable.all @notifiables = Redmine::Notifiable.all
if request.post? && params[:settings] && params[:settings].is_a?(Hash) if request.post? && params[:settings] && params[:settings].is_a?(Hash)
settings = (params[:settings] || {}).dup.symbolize_keys Setting.set_all_from_params(params[:settings])
settings.each do |name, value|
Setting.set_from_params name, value
end
flash[:notice] = l(:notice_successful_update) flash[:notice] = l(:notice_successful_update)
redirect_to settings_path(:tab => params[:tab]) redirect_to settings_path(:tab => params[:tab])
else else

View File

@@ -332,6 +332,22 @@ class Mailer < ActionMailer::Base
:subject => l(:mail_subject_security_notification) :subject => l(:mail_subject_security_notification)
end end
def settings_updated(recipients, changes)
redmine_headers 'Sender' => User.current.login
@changes = changes
@url = url_for(controller: 'settings', action: 'index')
mail :to => recipients,
:subject => l(:mail_subject_security_notification)
end
# Notifies admins about settings changes
def self.security_settings_updated(changes)
return unless changes.present?
users = User.active.where(admin: true).to_a
Mailer.settings_updated(users, changes).deliver
end
def test_email(user) def test_email(user)
set_language_if_valid(user.language) set_language_if_valid(user.language)
@url = url_for(:controller => 'welcome') @url = url_for(:controller => 'welcome')

View File

@@ -118,6 +118,23 @@ class Setting < ActiveRecord::Base
setting.value setting.value
end end
# Updates multiple settings from params and sends a security notification if needed
def self.set_all_from_params(settings)
settings = (settings || {}).dup.symbolize_keys
changes = []
settings.each do |name, value|
previous_value = Setting[name]
set_from_params name, value
if available_settings[name.to_s]['security_notifications'] && Setting[name] != previous_value
changes << name
end
end
if changes.any?
Mailer.security_settings_updated(changes)
end
true
end
# Sets a setting value from params # Sets a setting value from params
def self.set_from_params(name, params) def self.set_from_params(name, params)
params = params.dup params = params.dup

View File

@@ -0,0 +1,14 @@
<p><%= l(:mail_body_settings_updated) %></p>
<ul>
<% @changes.each do |name| %>
<li><%= l("setting_#{name}") %></li>
<% end %>
</ul>
<%= link_to @url, @url %>
<p><%= l(:field_user) %>: <strong><%= User.current.login %></strong><br/>
<%= l(:field_remote_ip) %>: <strong><%= User.current.remote_ip %></strong><br/>
<%= l(:label_date) %>: <strong><%= format_time Time.now, true %></strong></p>

View File

@@ -0,0 +1,12 @@
<%= l(:mail_body_settings_updated) %>
<% @changes.each do |name| %>
* <%= l("setting_#{name}") %>
<% end %>
<%= @url %>
<%= l(:field_user) %>: <%= User.current.login %>
<%= l(:field_remote_ip) %>: <%= User.current.remote_ip %>
<%= l(:label_date) %>: <%= format_time Time.now, true %>

View File

@@ -235,6 +235,7 @@ en:
mail_body_security_notification_remove: "%{field} %{value} was removed." mail_body_security_notification_remove: "%{field} %{value} was removed."
mail_body_security_notification_notify_enabled: "Email address %{value} now receives notifications." mail_body_security_notification_notify_enabled: "Email address %{value} now receives notifications."
mail_body_security_notification_notify_disabled: "Email address %{value} no longer receives notifications." mail_body_security_notification_notify_disabled: "Email address %{value} no longer receives notifications."
mail_body_settings_updated: "The following settings were changed:"
field_name: Name field_name: Name
field_description: Description field_description: Description

View File

@@ -248,6 +248,7 @@ fr:
mail_body_wiki_content_added: "La page wiki '%{id}' a été ajoutée par %{author}." mail_body_wiki_content_added: "La page wiki '%{id}' a été ajoutée par %{author}."
mail_subject_wiki_content_updated: "Page wiki '%{id}' mise à jour" mail_subject_wiki_content_updated: "Page wiki '%{id}' mise à jour"
mail_body_wiki_content_updated: "La page wiki '%{id}' a été mise à jour par %{author}." mail_body_wiki_content_updated: "La page wiki '%{id}' a été mise à jour par %{author}."
mail_body_settings_updated: "Les paramètres suivants ont été modifiés :"
field_name: Nom field_name: Nom
field_description: Description field_description: Description

View File

@@ -27,19 +27,24 @@ welcome_text:
default: default:
login_required: login_required:
default: 0 default: 0
security_notifications: 1
self_registration: self_registration:
default: '2' default: '2'
security_notifications: 1
lost_password: lost_password:
default: 1 default: 1
security_notifications: 1
unsubscribe: unsubscribe:
default: 1 default: 1
password_min_length: password_min_length:
format: int format: int
default: 8 default: 8
security_notifications: 1
# Maximum password age in days # Maximum password age in days
password_max_age: password_max_age:
format: int format: int
default: 0 default: 0
security_notifications: 1
# Maximum number of additional email addresses per user # Maximum number of additional email addresses per user
max_additional_emails: max_additional_emails:
format: int format: int
@@ -48,10 +53,12 @@ max_additional_emails:
session_lifetime: session_lifetime:
format: int format: int
default: 0 default: 0
security_notifications: 1
# User session timeout in minutes # User session timeout in minutes
session_timeout: session_timeout:
format: int format: int
default: 0 default: 0
security_notifications: 1
attachment_max_size: attachment_max_size:
format: int format: int
default: 5120 default: 5120
@@ -91,6 +98,7 @@ host_name:
default: localhost:3000 default: localhost:3000
protocol: protocol:
default: http default: http
security_notifications: 1
feeds_limit: feeds_limit:
format: int format: int
default: 15 default: 15
@@ -114,12 +122,15 @@ enabled_scm:
- Cvs - Cvs
- Bazaar - Bazaar
- Git - Git
security_notifications: 1
autofetch_changesets: autofetch_changesets:
default: 1 default: 1
sys_api_enabled: sys_api_enabled:
default: 0 default: 0
security_notifications: 1
sys_api_key: sys_api_key:
default: '' default: ''
security_notifications: 1
commit_cross_project_ref: commit_cross_project_ref:
default: 0 default: 0
commit_ref_keywords: commit_ref_keywords:
@@ -173,8 +184,10 @@ mail_handler_excluded_filenames:
default: '' default: ''
mail_handler_api_enabled: mail_handler_api_enabled:
default: 0 default: 0
security_notifications: 1
mail_handler_api_key: mail_handler_api_key:
default: default:
security_notifications: 1
issue_list_default_columns: issue_list_default_columns:
serialized: true serialized: true
default: default:
@@ -237,14 +250,17 @@ gravatar_enabled:
default: 0 default: 0
openid: openid:
default: 0 default: 0
security_notifications: 1
gravatar_default: gravatar_default:
default: '' default: ''
start_of_week: start_of_week:
default: '' default: ''
rest_api_enabled: rest_api_enabled:
default: 0 default: 0
security_notifications: 1
jsonp_enabled: jsonp_enabled:
default: 0 default: 0
security_notifications: 1
default_notification_option: default_notification_option:
default: 'only_my_events' default: 'only_my_events'
emails_header: emails_header:

View File

@@ -136,6 +136,44 @@ class SettingsControllerTest < ActionController::TestCase
], Setting.commit_update_keywords) ], Setting.commit_update_keywords)
end end
def test_post_edit_should_send_security_notification_for_notified_settings
ActionMailer::Base.deliveries.clear
post :edit, :settings => {
:login_required => 1
}
assert_not_nil (mail = ActionMailer::Base.deliveries.last)
assert_mail_body_match '0.0.0.0', mail
assert_mail_body_match I18n.t(:setting_login_required), mail
assert_select_email do
assert_select 'a[href^=?]', 'http://localhost:3000/settings'
end
# All admins should receive this
recipients = [mail.bcc, mail.cc].flatten
User.active.where(admin: true).each do |admin|
assert_include admin.mail, recipients
end
end
def test_post_edit_should_not_send_security_notification_for_non_notified_settings
ActionMailer::Base.deliveries.clear
post :edit, :settings => {
:app_title => 'MineRed'
}
assert_nil (mail = ActionMailer::Base.deliveries.last)
end
def test_post_edit_should_not_send_security_notification_for_unchanged_settings
ActionMailer::Base.deliveries.clear
post :edit, :settings => {
:login_required => 0
}
assert_nil (mail = ActionMailer::Base.deliveries.last)
end
def test_get_plugin_settings def test_get_plugin_settings
ActionController::Base.append_view_path(File.join(Rails.root, "test/fixtures/plugins")) ActionController::Base.append_view_path(File.join(Rails.root, "test/fixtures/plugins"))
Redmine::Plugin.register :foo do Redmine::Plugin.register :foo do