Commit 58665b64 authored by Douwe Maan's avatar Douwe Maan

Merge branch 'issue_3508' into 'master'

Restrict public users for private instances

Implements #3508

See merge request !3440
parents 70e6fa31 2366768d
......@@ -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
......
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
......
......@@ -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}",
......
......@@ -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
......
......@@ -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
......
......@@ -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
......
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
......@@ -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
......
......@@ -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)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment