mirror of
https://github.com/redmine/redmine.git
synced 2025-11-11 07:46:02 +01:00
Send a security notification when users gain or loose admin (#21421).
Patch by Jan Schulz-Hofen. git-svn-id: http://svn.redmine.org/redmine/trunk@15265 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
@@ -123,7 +123,8 @@ class User < Principal
|
|||||||
before_create :set_mail_notification
|
before_create :set_mail_notification
|
||||||
before_save :generate_password_if_needed, :update_hashed_password
|
before_save :generate_password_if_needed, :update_hashed_password
|
||||||
before_destroy :remove_references_before_destroy
|
before_destroy :remove_references_before_destroy
|
||||||
after_save :update_notified_project_ids, :destroy_tokens
|
after_save :update_notified_project_ids, :destroy_tokens, :deliver_security_notification
|
||||||
|
after_destroy :deliver_security_notification
|
||||||
|
|
||||||
scope :in_group, lambda {|group|
|
scope :in_group, lambda {|group|
|
||||||
group_id = group.is_a?(Group) ? group.id : group.to_i
|
group_id = group.is_a?(Group) ? group.id : group.to_i
|
||||||
@@ -835,6 +836,34 @@ class User < Principal
|
|||||||
def self.generate_salt
|
def self.generate_salt
|
||||||
Redmine::Utils.random_hex(16)
|
Redmine::Utils.random_hex(16)
|
||||||
end
|
end
|
||||||
|
# Send a security notification to all admins if the user has gained/lost admin privileges
|
||||||
|
def deliver_security_notification
|
||||||
|
options = {
|
||||||
|
field: :field_admin,
|
||||||
|
value: login,
|
||||||
|
title: :label_user_plural,
|
||||||
|
url: {controller: 'users', action: 'index'}
|
||||||
|
}
|
||||||
|
deliver = false
|
||||||
|
if (admin? && id_changed? && active?) || # newly created admin
|
||||||
|
(admin? && admin_changed? && active?) || # regular user became admin
|
||||||
|
(admin? && status_changed? && active?) # locked admin became active again
|
||||||
|
|
||||||
|
deliver = true
|
||||||
|
options[:message] = :mail_body_security_notification_add
|
||||||
|
|
||||||
|
elsif (admin? && destroyed? && active?) || # active admin user was deleted
|
||||||
|
(!admin? && admin_changed? && active?) || # admin is no longer admin
|
||||||
|
(admin? && status_changed? && !active?) # admin was locked
|
||||||
|
|
||||||
|
deliver = true
|
||||||
|
options[:message] = :mail_body_security_notification_remove
|
||||||
|
end
|
||||||
|
|
||||||
|
User.where(admin: true, status: Principal::STATUS_ACTIVE).each{|u| Mailer.security_notification(u, options).deliver} if deliver
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -280,6 +280,48 @@ class UsersControllerTest < ActionController::TestCase
|
|||||||
assert_select 'input#pref_no_self_notified[value="1"][checked=checked]'
|
assert_select 'input#pref_no_self_notified[value="1"][checked=checked]'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_create_admin_should_send_security_notification
|
||||||
|
ActionMailer::Base.deliveries.clear
|
||||||
|
post :create,
|
||||||
|
:user => {
|
||||||
|
:firstname => 'Edgar',
|
||||||
|
:lastname => 'Schmoe',
|
||||||
|
:login => 'eschmoe',
|
||||||
|
:password => 'secret123',
|
||||||
|
:password_confirmation => 'secret123',
|
||||||
|
:mail => 'eschmoe@example.foo',
|
||||||
|
:admin => '1'
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_not_nil (mail = ActionMailer::Base.deliveries.last)
|
||||||
|
assert_mail_body_match '0.0.0.0', mail
|
||||||
|
assert_mail_body_match I18n.t(:mail_body_security_notification_add, field: I18n.t(:field_admin), value: 'eschmoe'), mail
|
||||||
|
assert_select_email do
|
||||||
|
assert_select 'a[href^=?]', 'http://localhost:3000/users', :text => 'Users'
|
||||||
|
end
|
||||||
|
|
||||||
|
# All admins should receive this
|
||||||
|
User.where(admin: true, status: Principal::STATUS_ACTIVE).each do |admin|
|
||||||
|
assert_not_nil ActionMailer::Base.deliveries.detect{|mail| [mail.bcc, mail.cc].flatten.include?(admin.mail) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_create_non_admin_should_not_send_security_notification
|
||||||
|
ActionMailer::Base.deliveries.clear
|
||||||
|
post :create,
|
||||||
|
:user => {
|
||||||
|
:firstname => 'Edgar',
|
||||||
|
:lastname => 'Schmoe',
|
||||||
|
:login => 'eschmoe',
|
||||||
|
:password => 'secret123',
|
||||||
|
:password_confirmation => 'secret123',
|
||||||
|
:mail => 'eschmoe@example.foo',
|
||||||
|
:admin => '0'
|
||||||
|
}
|
||||||
|
assert_nil ActionMailer::Base.deliveries.last
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
def test_edit
|
def test_edit
|
||||||
get :edit, :id => 2
|
get :edit, :id => 2
|
||||||
assert_response :success
|
assert_response :success
|
||||||
@@ -426,6 +468,92 @@ class UsersControllerTest < ActionController::TestCase
|
|||||||
assert_equal '1', user.pref[:no_self_notified]
|
assert_equal '1', user.pref[:no_self_notified]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_update_assign_admin_should_send_security_notification
|
||||||
|
ActionMailer::Base.deliveries.clear
|
||||||
|
put :update, :id => 2, :user => {
|
||||||
|
:admin => 1
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_not_nil (mail = ActionMailer::Base.deliveries.last)
|
||||||
|
assert_mail_body_match I18n.t(:mail_body_security_notification_add, field: I18n.t(:field_admin), value: User.find(2).login), mail
|
||||||
|
|
||||||
|
# All admins should receive this
|
||||||
|
User.where(admin: true, status: Principal::STATUS_ACTIVE).each do |admin|
|
||||||
|
assert_not_nil ActionMailer::Base.deliveries.detect{|mail| [mail.bcc, mail.cc].flatten.include?(admin.mail) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_update_unassign_admin_should_send_security_notification
|
||||||
|
user = User.find(2)
|
||||||
|
user.admin = true
|
||||||
|
user.save!
|
||||||
|
|
||||||
|
ActionMailer::Base.deliveries.clear
|
||||||
|
put :update, :id => user.id, :user => {
|
||||||
|
:admin => 0
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_not_nil (mail = ActionMailer::Base.deliveries.last)
|
||||||
|
assert_mail_body_match I18n.t(:mail_body_security_notification_remove, field: I18n.t(:field_admin), value: user.login), mail
|
||||||
|
|
||||||
|
# All admins should receive this
|
||||||
|
User.where(admin: true, status: Principal::STATUS_ACTIVE).each do |admin|
|
||||||
|
assert_not_nil ActionMailer::Base.deliveries.detect{|mail| [mail.bcc, mail.cc].flatten.include?(admin.mail) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_update_lock_admin_should_send_security_notification
|
||||||
|
user = User.find(2)
|
||||||
|
user.admin = true
|
||||||
|
user.save!
|
||||||
|
|
||||||
|
ActionMailer::Base.deliveries.clear
|
||||||
|
put :update, :id => 2, :user => {
|
||||||
|
:status => Principal::STATUS_LOCKED
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_not_nil (mail = ActionMailer::Base.deliveries.last)
|
||||||
|
assert_mail_body_match I18n.t(:mail_body_security_notification_remove, field: I18n.t(:field_admin), value: User.find(2).login), mail
|
||||||
|
|
||||||
|
# All admins should receive this
|
||||||
|
User.where(admin: true, status: Principal::STATUS_ACTIVE).each do |admin|
|
||||||
|
assert_not_nil ActionMailer::Base.deliveries.detect{|mail| [mail.bcc, mail.cc].flatten.include?(admin.mail) }
|
||||||
|
end
|
||||||
|
|
||||||
|
# if user is already locked, destroying should not send a second mail
|
||||||
|
# (for active admins see furtherbelow)
|
||||||
|
ActionMailer::Base.deliveries.clear
|
||||||
|
delete :destroy, :id => 1
|
||||||
|
assert_nil ActionMailer::Base.deliveries.last
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_update_unlock_admin_should_send_security_notification
|
||||||
|
user = User.find(5) # already locked
|
||||||
|
user.admin = true
|
||||||
|
user.save!
|
||||||
|
ActionMailer::Base.deliveries.clear
|
||||||
|
put :update, :id => user.id, :user => {
|
||||||
|
:status => Principal::STATUS_ACTIVE
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_not_nil (mail = ActionMailer::Base.deliveries.last)
|
||||||
|
assert_mail_body_match I18n.t(:mail_body_security_notification_add, field: I18n.t(:field_admin), value: user.login), mail
|
||||||
|
|
||||||
|
# All admins should receive this
|
||||||
|
User.where(admin: true, status: Principal::STATUS_ACTIVE).each do |admin|
|
||||||
|
assert_not_nil ActionMailer::Base.deliveries.detect{|mail| [mail.bcc, mail.cc].flatten.include?(admin.mail) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_update_admin_unrelated_property_should_not_send_security_notification
|
||||||
|
ActionMailer::Base.deliveries.clear
|
||||||
|
put :update, :id => 1, :user => {
|
||||||
|
:firstname => 'Jimmy'
|
||||||
|
}
|
||||||
|
assert_nil ActionMailer::Base.deliveries.last
|
||||||
|
end
|
||||||
|
|
||||||
def test_destroy
|
def test_destroy
|
||||||
assert_difference 'User.count', -1 do
|
assert_difference 'User.count', -1 do
|
||||||
delete :destroy, :id => 2
|
delete :destroy, :id => 2
|
||||||
@@ -449,4 +577,20 @@ class UsersControllerTest < ActionController::TestCase
|
|||||||
end
|
end
|
||||||
assert_redirected_to '/users?name=foo'
|
assert_redirected_to '/users?name=foo'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_destroy_active_admin_should_send_security_notification
|
||||||
|
user = User.find(2)
|
||||||
|
user.admin = true
|
||||||
|
user.save!
|
||||||
|
ActionMailer::Base.deliveries.clear
|
||||||
|
delete :destroy, :id => user.id
|
||||||
|
|
||||||
|
assert_not_nil (mail = ActionMailer::Base.deliveries.last)
|
||||||
|
assert_mail_body_match I18n.t(:mail_body_security_notification_remove, field: I18n.t(:field_admin), value: user.login), mail
|
||||||
|
|
||||||
|
# All admins should receive this
|
||||||
|
User.where(admin: true, status: Principal::STATUS_ACTIVE).each do |admin|
|
||||||
|
assert_not_nil ActionMailer::Base.deliveries.detect{|mail| [mail.bcc, mail.cc].flatten.include?(admin.mail) }
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user