summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYorick Peterse <yorickpeterse@gmail.com>2019-01-24 13:51:14 +0000
committerYorick Peterse <yorickpeterse@gmail.com>2019-01-24 14:04:07 +0000
commitd13973689d76de2a59065f3aff748d39370659b4 (patch)
treebbb7e41b53b9970e7e3d083adb35cdf1aa4c4158
parent7d847369f9e5486e6539de73ed693f16d9ae3715 (diff)
downloadgitlab-ce-d13973689d76de2a59065f3aff748d39370659b4.tar.gz
Merge branch 'security-project-move-users-11-5' into 'security-11-5'
[11.5] Sent notification only to authorized users See merge request gitlab/gitlabhq!2858 (cherry picked from commit 81c1e9455ca291841704687cdcff085570e89043) baa1b756 Sent notification only to authorized users
-rw-r--r--app/models/member.rb9
-rw-r--r--app/models/project_team.rb12
-rw-r--r--app/services/notification_service.rb3
-rw-r--r--changelogs/unreleased/security-project-move-users.yml5
-rw-r--r--spec/models/project_team_spec.rb15
-rw-r--r--spec/services/notification_service_spec.rb29
6 files changed, 66 insertions, 7 deletions
diff --git a/app/models/member.rb b/app/models/member.rb
index 99da80b5f93..7fadda3e2bd 100644
--- a/app/models/member.rb
+++ b/app/models/member.rb
@@ -7,6 +7,7 @@ class Member < ActiveRecord::Base
include Expirable
include Gitlab::Access
include Presentable
+ include FromUnion
attr_accessor :raw_invite_token
@@ -83,6 +84,14 @@ class Member < ActiveRecord::Base
scope :order_recent_sign_in, -> { left_join_users.reorder(Gitlab::Database.nulls_last_order('users.last_sign_in_at', 'DESC')) }
scope :order_oldest_sign_in, -> { left_join_users.reorder(Gitlab::Database.nulls_last_order('users.last_sign_in_at', 'ASC')) }
+ scope :on_project_and_ancestors, ->(project) do
+ if project.group
+ from_union([GroupMember.where(source_id: project.group.self_and_ancestors), project.project_members])
+ else
+ project.project_members
+ end
+ end
+
before_validation :generate_invite_token, on: :create, if: -> (member) { member.invite_email.present? }
after_create :send_invite, if: :invite?, unless: :importing?
diff --git a/app/models/project_team.rb b/app/models/project_team.rb
index 33bc6a561f9..aeba2843e5d 100644
--- a/app/models/project_team.rb
+++ b/app/models/project_team.rb
@@ -74,6 +74,14 @@ class ProjectTeam
end
alias_method :users, :members
+ # `members` method uses project_authorizations table which
+ # is updated asynchronously, on project move it still contains
+ # old members who may not have access to the new location,
+ # so we filter out only members of project or project's group
+ def members_in_project_and_ancestors
+ members.where(id: member_user_ids)
+ end
+
def guests
@guests ||= fetch_members(Gitlab::Access::GUEST)
end
@@ -191,4 +199,8 @@ class ProjectTeam
def group
project.group
end
+
+ def member_user_ids
+ Member.on_project_and_ancestors(project).select(:user_id)
+ end
end
diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb
index fb9c18ea75d..e72d6a82122 100644
--- a/app/services/notification_service.rb
+++ b/app/services/notification_service.rb
@@ -373,7 +373,8 @@ class NotificationService
end
def project_was_moved(project, old_path_with_namespace)
- recipients = notifiable_users(project.team.members, :mention, project: project)
+ recipients = project.private? ? project.team.members_in_project_and_ancestors : project.team.members
+ recipients = notifiable_users(recipients, :mention, project: project)
recipients.each do |recipient|
mailer.project_was_moved_email(
diff --git a/changelogs/unreleased/security-project-move-users.yml b/changelogs/unreleased/security-project-move-users.yml
new file mode 100644
index 00000000000..744df68651f
--- /dev/null
+++ b/changelogs/unreleased/security-project-move-users.yml
@@ -0,0 +1,5 @@
+---
+title: Notify only users who can access the project on project move.
+merge_request:
+author:
+type: security
diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb
index c4af17f4726..3537dead5d1 100644
--- a/spec/models/project_team_spec.rb
+++ b/spec/models/project_team_spec.rb
@@ -178,6 +178,21 @@ describe ProjectTeam do
end
end
+ describe '#members_in_project_and_ancestors' do
+ context 'group project' do
+ it 'filters out users who are not members of the project' do
+ group = create(:group)
+ project = create(:project, group: group)
+ group_member = create(:group_member, group: group)
+ old_user = create(:user)
+
+ ProjectAuthorization.create!(project: project, user: old_user, access_level: Gitlab::Access::GUEST)
+
+ expect(project.team.members_in_project_and_ancestors).to contain_exactly(group_member.user)
+ end
+ end
+ end
+
describe "#human_max_access" do
it 'returns Maintainer role' do
user = create(:user)
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index 2d8da7673dc..1566ab3287e 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -1646,6 +1646,23 @@ describe NotificationService, :mailer do
should_not_email(@u_guest_custom)
should_not_email(@u_disabled)
end
+
+ context 'users not having access to the new location' do
+ it 'does not send email' do
+ old_user = create(:user)
+ ProjectAuthorization.create!(project: project, user: old_user, access_level: Gitlab::Access::GUEST)
+
+ build_group(project)
+ reset_delivered_emails!
+
+ notification.project_was_moved(project, "gitlab/gitlab")
+
+ should_email(@g_watcher)
+ should_email(@g_global_watcher)
+ should_email(project.creator)
+ should_not_email(old_user)
+ end
+ end
end
context 'user with notifications disabled' do
@@ -2178,8 +2195,8 @@ describe NotificationService, :mailer do
# Users in the project's group but not part of project's team
# with different notification settings
- def build_group(project)
- group = create_nested_group
+ def build_group(project, visibility: :public)
+ group = create_nested_group(visibility)
project.update(namespace_id: group.id)
# Group member: global=disabled, group=watch
@@ -2195,10 +2212,10 @@ describe NotificationService, :mailer do
# Creates a nested group only if supported
# to avoid errors on MySQL
- def create_nested_group
+ def create_nested_group(visibility)
if Group.supports_nested_groups?
- parent_group = create(:group, :public)
- child_group = create(:group, :public, parent: parent_group)
+ parent_group = create(:group, visibility)
+ child_group = create(:group, visibility, parent: parent_group)
# Parent group member: global=disabled, parent_group=watch, child_group=global
@pg_watcher ||= create_user_with_notification(:watch, 'parent_group_watcher', parent_group)
@@ -2218,7 +2235,7 @@ describe NotificationService, :mailer do
child_group
else
- create(:group, :public)
+ create(:group, visibility)
end
end