diff --git a/app/controllers/projects/badges_controller.rb b/app/controllers/projects/badges_controller.rb index 09a384e89ab..66b51b17790 100644 --- a/app/controllers/projects/badges_controller.rb +++ b/app/controllers/projects/badges_controller.rb @@ -3,7 +3,8 @@ class Projects::BadgesController < Projects::ApplicationController layout 'project_settings' before_action :authorize_admin_project!, only: [:index] - before_action :no_cache_headers, except: [:index] + before_action :no_cache_headers, only: [:pipeline, :coverage] + before_action :authorize_read_build!, only: [:pipeline, :coverage] def pipeline pipeline_status = Gitlab::Badge::Pipeline::Status diff --git a/changelogs/unreleased/security-fix-badges-leaked-to-unauthorized-users.yml b/changelogs/unreleased/security-fix-badges-leaked-to-unauthorized-users.yml new file mode 100644 index 00000000000..9526f3c559f --- /dev/null +++ b/changelogs/unreleased/security-fix-badges-leaked-to-unauthorized-users.yml @@ -0,0 +1,5 @@ +--- +title: Show badges if pipelines are public otherwise default to project permissions. +erge_request: +author: +type: security diff --git a/spec/controllers/projects/badges_controller_spec.rb b/spec/controllers/projects/badges_controller_spec.rb index 5ec8d8d41d7..4ae29ba7f54 100644 --- a/spec/controllers/projects/badges_controller_spec.rb +++ b/spec/controllers/projects/badges_controller_spec.rb @@ -7,51 +7,115 @@ describe Projects::BadgesController do let!(:pipeline) { create(:ci_empty_pipeline) } let(:user) { create(:user) } - before do - project.add_maintainer(user) - sign_in(user) - end + shared_examples 'a badge resource' do |badge_type| + context 'when pipelines are public' do + before do + project.update!(public_builds: true) + end - it 'requests the pipeline badge successfully' do - get_badge(:pipeline) + context 'when project is public' do + before do + project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC) + end - expect(response).to have_gitlab_http_status(:ok) - end + it "returns the #{badge_type} badge to unauthenticated users" do + get_badge(badge_type) - it 'requests the coverage badge successfully' do - get_badge(:coverage) + expect(response).to have_gitlab_http_status(:ok) + end + end - expect(response).to have_gitlab_http_status(:ok) - end + context 'when project is restricted' do + before do + project.update!(visibility_level: Gitlab::VisibilityLevel::INTERNAL) + project.add_guest(user) + sign_in(user) + end - it 'renders the `flat` badge layout by default' do - get_badge(:coverage) + it "returns the #{badge_type} badge to guest users" do + get_badge(badge_type) - expect(response).to render_template('projects/badges/badge') - end + expect(response).to have_gitlab_http_status(:ok) + end + end + end - context 'when style param is set to `flat`' do - it 'renders the `flat` badge layout' do - get_badge(:coverage, 'flat') + context 'format' do + before do + project.add_maintainer(user) + sign_in(user) + end - expect(response).to render_template('projects/badges/badge') + it 'renders the `flat` badge layout by default' do + get_badge(badge_type) + + expect(response).to render_template('projects/badges/badge') + end + + context 'when style param is set to `flat`' do + it 'renders the `flat` badge layout' do + get_badge(badge_type, 'flat') + + expect(response).to render_template('projects/badges/badge') + end + end + + context 'when style param is set to an invalid type' do + it 'renders the `flat` (default) badge layout' do + get_badge(badge_type, 'xxx') + + expect(response).to render_template('projects/badges/badge') + end + end + + context 'when style param is set to `flat-square`' do + it 'renders the `flat-square` badge layout' do + get_badge(badge_type, 'flat-square') + + expect(response).to render_template('projects/badges/badge_flat-square') + end + end + end + + context 'when pipelines are not public' do + before do + project.update!(public_builds: false) + end + + context 'when project is public' do + before do + project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC) + end + + it 'returns 404 to unauthenticated users' do + get_badge(badge_type) + + expect(response).to have_gitlab_http_status(:not_found) + end + end + + context 'when project is restricted to the user' do + before do + project.update!(visibility_level: Gitlab::VisibilityLevel::INTERNAL) + project.add_guest(user) + sign_in(user) + end + + it 'defaults to project permissions' do + get_badge(:coverage) + + expect(response).to have_gitlab_http_status(:not_found) + end + end end end - context 'when style param is set to an invalid type' do - it 'renders the `flat` (default) badge layout' do - get_badge(:coverage, 'xxx') - - expect(response).to render_template('projects/badges/badge') - end + describe '#pipeline' do + it_behaves_like 'a badge resource', :pipeline end - context 'when style param is set to `flat-square`' do - it 'renders the `flat-square` badge layout' do - get_badge(:coverage, 'flat-square') - - expect(response).to render_template('projects/badges/badge_flat-square') - end + describe '#coverage' do + it_behaves_like 'a badge resource', :coverage end def get_badge(badge, style = nil)