summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean McGivern <sean@gitlab.com>2017-04-25 14:41:26 +0000
committerLin Jen-Shin <godfat@godfat.org>2017-05-04 23:13:07 +0800
commit0690531ec62cf08a2e596f2de87d224480e34422 (patch)
tree561d574b052c99f7962c7b99edae6dcf3e7496ba
parented662aa6ca24400ea4e7ed8e2d3888084bfc4e45 (diff)
downloadgitlab-ce-0690531ec62cf08a2e596f2de87d224480e34422.tar.gz
Merge branch 'snippets_visibility' into 'security'
Fix snippets visibility for show action - external users can not see internal snippets See merge request !2087
-rw-r--r--app/controllers/snippets_controller.rb18
-rw-r--r--changelogs/unreleased/snippets_visibility.yml4
-rw-r--r--spec/controllers/snippets_controller_spec.rb331
-rw-r--r--spec/features/snippets/internal_snippet_spec.rb23
4 files changed, 161 insertions, 215 deletions
diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb
index f3fd3da8b20..56d7da1ba64 100644
--- a/app/controllers/snippets_controller.rb
+++ b/app/controllers/snippets_controller.rb
@@ -80,20 +80,20 @@ class SnippetsController < ApplicationController
protected
def snippet
- @snippet ||= if current_user
- PersonalSnippet.where("author_id = ? OR visibility_level IN (?)",
- current_user.id,
- [Snippet::PUBLIC, Snippet::INTERNAL]).
- find(params[:id])
- else
- PersonalSnippet.find(params[:id])
- end
+ @snippet ||= PersonalSnippet.find_by(id: params[:id])
end
+
alias_method :awardable, :snippet
alias_method :spammable, :snippet
def authorize_read_snippet!
- authenticate_user! unless can?(current_user, :read_personal_snippet, @snippet)
+ return if can?(current_user, :read_personal_snippet, @snippet)
+
+ if current_user
+ render_404
+ else
+ authenticate_user!
+ end
end
def authorize_update_snippet!
diff --git a/changelogs/unreleased/snippets_visibility.yml b/changelogs/unreleased/snippets_visibility.yml
new file mode 100644
index 00000000000..4c10c6882ab
--- /dev/null
+++ b/changelogs/unreleased/snippets_visibility.yml
@@ -0,0 +1,4 @@
+---
+title: Fix snippets visibility for show action - external users can not see internal snippets
+merge_request:
+author:
diff --git a/spec/controllers/snippets_controller_spec.rb b/spec/controllers/snippets_controller_spec.rb
index 5de3b9890ef..079b922381d 100644
--- a/spec/controllers/snippets_controller_spec.rb
+++ b/spec/controllers/snippets_controller_spec.rb
@@ -25,119 +25,6 @@ describe SnippetsController do
end
end
- describe 'GET #show' do
- context 'when the personal snippet is private' do
- let(:personal_snippet) { create(:personal_snippet, :private, author: user) }
-
- context 'when signed in' do
- before do
- sign_in(user)
- end
-
- context 'when signed in user is not the author' do
- let(:other_author) { create(:author) }
- let(:other_personal_snippet) { create(:personal_snippet, :private, author: other_author) }
-
- it 'responds with status 404' do
- get :show, id: other_personal_snippet.to_param
-
- expect(response).to have_http_status(404)
- end
- end
-
- context 'when signed in user is the author' do
- it 'renders the snippet' do
- get :show, id: personal_snippet.to_param
-
- expect(assigns(:snippet)).to eq(personal_snippet)
- expect(response).to have_http_status(200)
- end
- end
- end
-
- context 'when not signed in' do
- it 'redirects to the sign in page' do
- get :show, id: personal_snippet.to_param
-
- expect(response).to redirect_to(new_user_session_path)
- end
- end
- end
-
- context 'when the personal snippet is internal' do
- let(:personal_snippet) { create(:personal_snippet, :internal, author: user) }
-
- context 'when signed in' do
- before do
- sign_in(user)
- end
-
- it 'renders the snippet' do
- get :show, id: personal_snippet.to_param
-
- expect(assigns(:snippet)).to eq(personal_snippet)
- expect(response).to have_http_status(200)
- end
- end
-
- context 'when not signed in' do
- it 'redirects to the sign in page' do
- get :show, id: personal_snippet.to_param
-
- expect(response).to redirect_to(new_user_session_path)
- end
- end
- end
-
- context 'when the personal snippet is public' do
- let(:personal_snippet) { create(:personal_snippet, :public, author: user) }
-
- context 'when signed in' do
- before do
- sign_in(user)
- end
-
- it 'renders the snippet' do
- get :show, id: personal_snippet.to_param
-
- expect(assigns(:snippet)).to eq(personal_snippet)
- expect(response).to have_http_status(200)
- end
- end
-
- context 'when not signed in' do
- it 'renders the snippet' do
- get :show, id: personal_snippet.to_param
-
- expect(assigns(:snippet)).to eq(personal_snippet)
- expect(response).to have_http_status(200)
- end
- end
- end
-
- context 'when the personal snippet does not exist' do
- context 'when signed in' do
- before do
- sign_in(user)
- end
-
- it 'responds with status 404' do
- get :show, id: 'doesntexist'
-
- expect(response).to have_http_status(404)
- end
- end
-
- context 'when not signed in' do
- it 'responds with status 404' do
- get :show, id: 'doesntexist'
-
- expect(response).to have_http_status(404)
- end
- end
- end
- end
-
describe 'POST #create' do
def create_snippet(snippet_params = {}, additional_params = {})
sign_in(user)
@@ -350,149 +237,181 @@ describe SnippetsController do
end
end
- %w(raw download).each do |action|
- describe "GET #{action}" do
- context 'when the personal snippet is private' do
- let(:personal_snippet) { create(:personal_snippet, :private, author: user) }
+ shared_examples "line endings" do |action|
+ context 'CRLF line ending' do
+ let(:personal_snippet) do
+ create(:personal_snippet, :public, author: user, content: "first line\r\nsecond line\r\nthird line")
+ end
- context 'when signed in' do
- before do
- sign_in(user)
- end
+ it 'returns LF line endings by default' do
+ get action, id: personal_snippet.to_param
- context 'when signed in user is not the author' do
- let(:other_author) { create(:author) }
- let(:other_personal_snippet) { create(:personal_snippet, :private, author: other_author) }
+ expect(response.body).to eq("first line\nsecond line\nthird line")
+ end
- it 'responds with status 404' do
- get action, id: other_personal_snippet.to_param
+ it 'does not convert line endings when parameter present' do
+ get action, id: personal_snippet.to_param, line_ending: :raw
- expect(response).to have_http_status(404)
- end
+ expect(response.body).to eq("first line\r\nsecond line\r\nthird line")
+ end
+ end
+ end
+
+ shared_examples 'snippet response' do |action|
+ context 'when the personal snippet is private' do
+ let(:personal_snippet) { create(:personal_snippet, :private, author: user) }
+
+ context 'when signed in' do
+ before do
+ sign_in(user)
+ end
+
+ context 'when signed in user is not the author' do
+ let(:other_author) { create(:author) }
+ let(:other_personal_snippet) { create(:personal_snippet, :private, author: other_author) }
+
+ it 'responds with status 404' do
+ get action, id: other_personal_snippet.to_param
+
+ expect(response).to have_http_status(404)
end
+ end
- context 'when signed in user is the author' do
- before { get action, id: personal_snippet.to_param }
+ context 'when signed in user is the author' do
+ before { get action, id: personal_snippet.to_param }
- it 'responds with status 200' do
- expect(assigns(:snippet)).to eq(personal_snippet)
- expect(response).to have_http_status(200)
- end
+ it 'responds with status 200' do
+ expect(assigns(:snippet)).to eq(personal_snippet)
+ expect(response).to have_http_status(200)
+ end
- it 'has expected headers' do
+ it 'has expected headers' do
+ if action == :show
+ expect(response.header['Content-Type']).to eq('text/html; charset=utf-8')
+ else
expect(response.header['Content-Type']).to eq('text/plain; charset=utf-8')
+ end
- if action == :download
- expect(response.header['Content-Disposition']).to match(/attachment/)
- elsif action == :raw
- expect(response.header['Content-Disposition']).to match(/inline/)
- end
+ if action == :download
+ expect(response.header['Content-Disposition']).to match(/attachment/)
+ elsif action == :raw
+ expect(response.header['Content-Disposition']).to match(/inline/)
end
end
end
+ end
- context 'when not signed in' do
- it 'redirects to the sign in page' do
- get action, id: personal_snippet.to_param
+ context 'when not signed in' do
+ it 'redirects to the sign in page' do
+ get action, id: personal_snippet.to_param
- expect(response).to redirect_to(new_user_session_path)
- end
+ expect(response).to redirect_to(new_user_session_path)
end
end
+ end
- context 'when the personal snippet is internal' do
- let(:personal_snippet) { create(:personal_snippet, :internal, author: user) }
+ context 'when the personal snippet is internal' do
+ let(:personal_snippet) { create(:personal_snippet, :internal, author: user) }
- context 'when signed in' do
- before do
- sign_in(user)
- end
+ context 'when signed in' do
+ before do
+ sign_in(user)
+ end
- it 'responds with status 200' do
- get action, id: personal_snippet.to_param
+ it 'responds with status 200' do
+ get action, id: personal_snippet.to_param
- expect(assigns(:snippet)).to eq(personal_snippet)
- expect(response).to have_http_status(200)
- end
+ expect(assigns(:snippet)).to eq(personal_snippet)
+ expect(response).to have_http_status(200)
end
+ end
- context 'when not signed in' do
- it 'redirects to the sign in page' do
- get action, id: personal_snippet.to_param
+ context 'when not signed in' do
+ it 'redirects to the sign in page' do
+ get action, id: personal_snippet.to_param
- expect(response).to redirect_to(new_user_session_path)
- end
+ expect(response).to redirect_to(new_user_session_path)
end
end
- context 'when the personal snippet is public' do
- let(:personal_snippet) { create(:personal_snippet, :public, author: user) }
-
- context 'when signed in' do
- before do
- sign_in(user)
- end
+ context 'when signed in as an external user' do
+ let(:external_user) { create(:user, external: true) }
- it 'responds with status 200' do
- get action, id: personal_snippet.to_param
+ before do
+ sign_in(external_user)
+ end
- expect(assigns(:snippet)).to eq(personal_snippet)
- expect(response).to have_http_status(200)
- end
+ it 'responds with status 404' do
+ get :show, id: personal_snippet.to_param
- context 'CRLF line ending' do
- let(:personal_snippet) do
- create(:personal_snippet, :public, author: user, content: "first line\r\nsecond line\r\nthird line")
- end
+ expect(response).to have_http_status(404)
+ end
+ end
+ end
- it 'returns LF line endings by default' do
- get action, id: personal_snippet.to_param
+ context 'when the personal snippet is public' do
+ let(:personal_snippet) { create(:personal_snippet, :public, author: user) }
- expect(response.body).to eq("first line\nsecond line\nthird line")
- end
+ context 'when signed in' do
+ before do
+ sign_in(user)
+ end
- it 'does not convert line endings when parameter present' do
- get action, id: personal_snippet.to_param, line_ending: :raw
+ it 'responds with status 200' do
+ get action, id: personal_snippet.to_param
- expect(response.body).to eq("first line\r\nsecond line\r\nthird line")
- end
- end
+ expect(assigns(:snippet)).to eq(personal_snippet)
+ expect(response).to have_http_status(200)
end
+ end
- context 'when not signed in' do
- it 'responds with status 200' do
- get action, id: personal_snippet.to_param
+ context 'when not signed in' do
+ it 'responds with status 200' do
+ get action, id: personal_snippet.to_param
- expect(assigns(:snippet)).to eq(personal_snippet)
- expect(response).to have_http_status(200)
- end
+ expect(assigns(:snippet)).to eq(personal_snippet)
+ expect(response).to have_http_status(200)
end
end
+ end
- context 'when the personal snippet does not exist' do
- context 'when signed in' do
- before do
- sign_in(user)
- end
+ context 'when the personal snippet does not exist' do
+ context 'when signed in' do
+ before do
+ sign_in(user)
+ end
- it 'responds with status 404' do
- get action, id: 'doesntexist'
+ it 'responds with status 404' do
+ get action, id: 'doesntexist'
- expect(response).to have_http_status(404)
- end
+ expect(response).to have_http_status(404)
end
+ end
- context 'when not signed in' do
- it 'responds with status 404' do
- get action, id: 'doesntexist'
+ context 'when not signed in' do
+ it 'redirects to the sign in page' do
+ get action, id: 'doesntexist'
- expect(response).to have_http_status(404)
- end
+ expect(response).to redirect_to(new_user_session_path)
end
end
end
end
+ describe "GET #raw" do
+ include_examples 'line endings', :raw
+ include_examples 'snippet response', :raw
+ end
+
+ describe "GET #download" do
+ include_examples 'line endings', :download
+ include_examples 'snippet response', :download
+ end
+
+ describe "GET #show" do
+ include_examples 'snippet response', :show
+ end
+
context 'award emoji on snippets' do
let(:personal_snippet) { create(:personal_snippet, :public, author: user) }
let(:another_user) { create(:user) }
diff --git a/spec/features/snippets/internal_snippet_spec.rb b/spec/features/snippets/internal_snippet_spec.rb
new file mode 100644
index 00000000000..2682b66dc26
--- /dev/null
+++ b/spec/features/snippets/internal_snippet_spec.rb
@@ -0,0 +1,23 @@
+require 'rails_helper'
+
+feature 'Internal Snippets', feature: true do
+ let(:internal_snippet) { create(:personal_snippet, :internal) }
+
+ describe 'normal user' do
+ before do
+ login_as :user
+ end
+
+ scenario 'sees internal snippets' do
+ visit snippet_path(internal_snippet)
+
+ expect(page).to have_content(internal_snippet.content)
+ end
+
+ scenario 'sees raw internal snippets' do
+ visit raw_snippet_path(internal_snippet)
+
+ expect(page).to have_content(internal_snippet.content)
+ end
+ end
+end