diff options
author | Douwe Maan <douwe@gitlab.com> | 2016-04-18 15:20:13 +0000 |
---|---|---|
committer | Douwe Maan <douwe@gitlab.com> | 2016-04-18 15:20:13 +0000 |
commit | 58665b64f5bd8795571876587ea3a19253532286 (patch) | |
tree | 6b7a6038e5c79cb244606b2a6ae9bf1c5fafa66f | |
parent | 70e6fa31064984c691e283eddf6712bc031e0842 (diff) | |
parent | 2366768d3b28ea70c91fc49c471e66152650d442 (diff) | |
download | gitlab-ce-58665b64f5bd8795571876587ea3a19253532286.tar.gz |
Merge branch 'issue_3508' into 'master'
Restrict public users for private instances
Implements #3508
See merge request !3440
-rw-r--r-- | CHANGELOG | 1 | ||||
-rw-r--r-- | app/controllers/users_controller.rb | 23 | ||||
-rw-r--r-- | app/models/ability.rb | 29 | ||||
-rw-r--r-- | app/views/admin/application_settings/_form.html.haml | 4 | ||||
-rw-r--r-- | doc/public_access/public_access.md | 3 | ||||
-rw-r--r-- | lib/api/users.rb | 10 | ||||
-rw-r--r-- | spec/controllers/groups/group_members_controller_spec.rb | 20 | ||||
-rw-r--r-- | spec/controllers/users_controller_spec.rb | 25 | ||||
-rw-r--r-- | spec/requests/api/users_spec.rb | 18 |
9 files changed, 113 insertions, 20 deletions
diff --git a/CHANGELOG b/CHANGELOG index e641adbfcef..350be45627f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -13,6 +13,7 @@ v 8.7.0 (unreleased) - Project switcher uses new dropdown styling - Load award emoji images separately unless opening the full picker. Saves several hundred KBs of data for most pages. (Connor Shea) - Do not include award_emojis in issue and merge_request comment_count !3610 (Lucas Charles) + - Restrict user profiles when public visibility level is restricted. - All images in discussions and wikis now link to their source files !3464 (Connor Shea). - Return status code 303 after a branch DELETE operation to avoid project deletion (Stan Hu) - Add setting for customizing the list of trusted proxies !3524 diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 8e7956da48f..2ae180c8a12 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1,6 +1,7 @@ class UsersController < ApplicationController skip_before_action :authenticate_user! - before_action :set_user + before_action :user + before_action :authorize_read_user!, only: [:show] def show respond_to do |format| @@ -75,22 +76,26 @@ class UsersController < ApplicationController private - def set_user - @user = User.find_by_username!(params[:username]) + def authorize_read_user! + render_404 unless can?(current_user, :read_user, user) + end + + def user + @user ||= User.find_by_username!(params[:username]) end def contributed_projects - ContributedProjectsFinder.new(@user).execute(current_user) + ContributedProjectsFinder.new(user).execute(current_user) end def contributions_calendar @contributions_calendar ||= Gitlab::ContributionsCalendar. - new(contributed_projects, @user) + new(contributed_projects, user) end def load_events # Get user activity feed for projects common for both users - @events = @user.recent_events. + @events = user.recent_events. merge(projects_for_current_user). references(:project). with_associations. @@ -99,16 +104,16 @@ class UsersController < ApplicationController def load_projects @projects = - PersonalProjectsFinder.new(@user).execute(current_user) + PersonalProjectsFinder.new(user).execute(current_user) .page(params[:page]) end def load_contributed_projects - @contributed_projects = contributed_projects.joined(@user) + @contributed_projects = contributed_projects.joined(user) end def load_groups - @groups = JoinedGroupsFinder.new(@user).execute(current_user) + @groups = JoinedGroupsFinder.new(user).execute(current_user) end def projects_for_current_user diff --git a/app/models/ability.rb b/app/models/ability.rb index c0bf6def7c5..6103a2947e2 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -18,6 +18,7 @@ class Ability when Namespace then namespace_abilities(user, subject) when GroupMember then group_member_abilities(user, subject) when ProjectMember then project_member_abilities(user, subject) + when User then user_abilities else [] end.concat(global_abilities(user)) end @@ -35,6 +36,8 @@ class Ability anonymous_project_abilities(subject) when subject.is_a?(Group) || subject.respond_to?(:group) anonymous_group_abilities(subject) + when subject.is_a?(User) + anonymous_user_abilities else [] end @@ -81,17 +84,17 @@ class Ability end def anonymous_group_abilities(subject) + rules = [] + group = if subject.is_a?(Group) subject else subject.group end - if group && group.public? - [:read_group] - else - [] - end + rules << :read_group if group.public? + + rules end def anonymous_personal_snippet_abilities(snippet) @@ -110,9 +113,14 @@ class Ability end end + def anonymous_user_abilities + [:read_user] unless restricted_public_level? + end + def global_abilities(user) rules = [] rules << :create_group if user.can_create_group + rules << :read_users_list rules end @@ -163,7 +171,7 @@ class Ability @public_project_rules ||= project_guest_rules + [ :download_code, :fork_project, - :read_commit_status, + :read_commit_status ] end @@ -284,7 +292,6 @@ class Ability def group_abilities(user, group) rules = [] - rules << :read_group if can_read_group?(user, group) # Only group masters and group owners can create new projects @@ -456,6 +463,10 @@ class Ability rules end + def user_abilities + [:read_user] + end + def abilities @abilities ||= begin abilities = Six.new @@ -470,6 +481,10 @@ class Ability private + def restricted_public_level? + current_application_settings.restricted_visibility_levels.include?(Gitlab::VisibilityLevel::PUBLIC) + end + def named_abilities(name) [ :"read_#{name}", diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml index 555aea554f0..aadd2c54f20 100644 --- a/app/views/admin/application_settings/_form.html.haml +++ b/app/views/admin/application_settings/_form.html.haml @@ -26,7 +26,9 @@ .btn-group{ data: data_attrs } - restricted_level_checkboxes('restricted-visibility-help').each do |level| = level - %span.help-block#restricted-visibility-help Selected levels cannot be used by non-admin users for projects or snippets + %span.help-block#restricted-visibility-help + Selected levels cannot be used by non-admin users for projects or snippets. + If the public level is restricted, user profiles are only visible to logged in users. .form-group = f.label :import_sources, class: 'control-label col-sm-2' .col-sm-10 diff --git a/doc/public_access/public_access.md b/doc/public_access/public_access.md index 20aa90f0d69..17bb75ececd 100644 --- a/doc/public_access/public_access.md +++ b/doc/public_access/public_access.md @@ -58,6 +58,9 @@ you are logged in or not. When visiting the public page of a user, you can only see the projects which you are privileged to. +If the public level is restricted, user profiles are only visible to logged in users. + + ## Restricting the use of public or internal projects In the Admin area under **Settings** (`/admin/application_settings`), you can diff --git a/lib/api/users.rb b/lib/api/users.rb index 0a14bac07c0..ea6fa2dc8a8 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -11,6 +11,10 @@ module API # GET /users?search=Admin # GET /users?username=root get do + unless can?(current_user, :read_users_list, nil) + render_api_error!("Not authorized.", 403) + end + if params[:username].present? @users = User.where(username: params[:username]) else @@ -36,10 +40,12 @@ module API get ":id" do @user = User.find(params[:id]) - if current_user.is_admin? + if current_user && current_user.is_admin? present @user, with: Entities::UserFull - else + elsif can?(current_user, :read_user, @user) present @user, with: Entities::User + else + render_api_error!("User not found.", 404) end end diff --git a/spec/controllers/groups/group_members_controller_spec.rb b/spec/controllers/groups/group_members_controller_spec.rb new file mode 100644 index 00000000000..a5986598715 --- /dev/null +++ b/spec/controllers/groups/group_members_controller_spec.rb @@ -0,0 +1,20 @@ +require 'spec_helper' + +describe Groups::GroupMembersController do + let(:user) { create(:user) } + let(:group) { create(:group) } + + context "index" do + before do + group.add_owner(user) + stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC]) + end + + it 'renders index with group members' do + get :index, group_id: group.path + + expect(response.status).to eq(200) + expect(response).to render_template(:index) + end + end +end diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb index 7337ff58be1..8045c8b940d 100644 --- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -33,7 +33,30 @@ describe UsersController do it 'renders the show template' do get :show, username: user.username - expect(response).to be_success + expect(response.status).to eq(200) + expect(response).to render_template('show') + end + end + end + + context 'when public visibility level is restricted' do + before do + stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC]) + end + + context 'when logged out' do + it 'renders 404' do + get :show, username: user.username + expect(response.status).to eq(404) + end + end + + context 'when logged in' do + before { sign_in(user) } + + it 'renders show' do + get :show, username: user.username + expect(response.status).to eq(200) expect(response).to render_template('show') end end diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index 679227bf881..40b24c125b5 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -20,6 +20,24 @@ describe API::API, api: true do end context "when authenticated" do + #These specs are written just in case API authentication is not required anymore + context "when public level is restricted" do + before do + stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC]) + allow_any_instance_of(API::Helpers).to receive(:authenticate!).and_return(true) + end + + it "renders 403" do + get api("/users") + expect(response.status).to eq(403) + end + + it "renders 404" do + get api("/users/#{user.id}") + expect(response.status).to eq(404) + end + end + it "should return an array of users" do get api("/users", user) expect(response.status).to eq(200) |