diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-01-10 20:36:29 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-01-10 20:36:29 +0000 |
commit | 1eef146c2d1de19d4e995d421e5787053e50db80 (patch) | |
tree | 2761efabea712248557826977a849e31e3fdb961 /spec/support | |
parent | 661d663ab2b7c69977ba8a0db02ef4afc2427e39 (diff) | |
download | gitlab-ce-1eef146c2d1de19d4e995d421e5787053e50db80.tar.gz |
Add latest changes from gitlab-org/security/gitlab@14-6-stable-ee
Diffstat (limited to 'spec/support')
3 files changed, 173 insertions, 153 deletions
diff --git a/spec/support/shared_examples/controllers/sessionless_auth_controller_shared_examples.rb b/spec/support/shared_examples/controllers/sessionless_auth_controller_shared_examples.rb deleted file mode 100644 index 041695d8111..00000000000 --- a/spec/support/shared_examples/controllers/sessionless_auth_controller_shared_examples.rb +++ /dev/null @@ -1,112 +0,0 @@ -# frozen_string_literal: true - -# This controller shared examples will be migrated to -# spec/support/shared_examples/requests/sessionless_auth_request_shared_examples.rb -# See also https://gitlab.com/groups/gitlab-org/-/epics/5076 - -RSpec.shared_examples 'authenticates sessionless user' do |path, format, params| - params ||= {} - - before do - stub_authentication_activity_metrics(debug: false) - end - - let(:user) { create(:user) } - let(:personal_access_token) { create(:personal_access_token, user: user) } - let(:default_params) { { format: format }.merge(params.except(:public) || {}) } - - context "when the 'personal_access_token' param is populated with the personal access token" do - it 'logs the user in' do - expect(authentication_metrics) - .to increment(:user_authenticated_counter) - .and increment(:user_session_override_counter) - .and increment(:user_sessionless_authentication_counter) - - get path, params: default_params.merge(private_token: personal_access_token.token) - - expect(response).to have_gitlab_http_status(:ok) - expect(controller.current_user).to eq(user) - end - - it 'does not log the user in if page is public', if: params[:public] do - get path, params: default_params - - expect(response).to have_gitlab_http_status(:ok) - expect(controller.current_user).to be_nil - end - end - - context 'when the personal access token has no api scope', unless: params[:public] do - it 'does not log the user in' do - # Several instances of where these specs are shared route the request - # through ApplicationController#route_not_found which does not involve - # the usual auth code from Devise, so does not increment the - # :user_unauthenticated_counter - # - unless params[:ignore_incrementing] - expect(authentication_metrics) - .to increment(:user_unauthenticated_counter) - end - - personal_access_token.update!(scopes: [:read_user]) - - get path, params: default_params.merge(private_token: personal_access_token.token) - - expect(response).not_to have_gitlab_http_status(:ok) - end - end - - context "when the 'PERSONAL_ACCESS_TOKEN' header is populated with the personal access token" do - it 'logs the user in' do - expect(authentication_metrics) - .to increment(:user_authenticated_counter) - .and increment(:user_session_override_counter) - .and increment(:user_sessionless_authentication_counter) - - @request.headers['PRIVATE-TOKEN'] = personal_access_token.token - get path, params: default_params - - expect(response).to have_gitlab_http_status(:ok) - end - end - - context "when the 'feed_token' param is populated with the feed token", if: format == :rss do - it "logs the user in" do - expect(authentication_metrics) - .to increment(:user_authenticated_counter) - .and increment(:user_session_override_counter) - .and increment(:user_sessionless_authentication_counter) - - get path, params: default_params.merge(feed_token: user.feed_token) - - expect(response).to have_gitlab_http_status(:ok) - end - end - - context "when the 'feed_token' param is populated with an invalid feed token", if: format == :rss, unless: params[:public] do - it "logs the user" do - expect(authentication_metrics) - .to increment(:user_unauthenticated_counter) - - get path, params: default_params.merge(feed_token: 'token') - - expect(response).not_to have_gitlab_http_status(:ok) - end - end - - it "doesn't log the user in otherwise", unless: params[:public] do - # Several instances of where these specs are shared route the request - # through ApplicationController#route_not_found which does not involve - # the usual auth code from Devise, so does not increment the - # :user_unauthenticated_counter - # - unless params[:ignore_incrementing] - expect(authentication_metrics) - .to increment(:user_unauthenticated_counter) - end - - get path, params: default_params.merge(private_token: 'token') - - expect(response).not_to have_gitlab_http_status(:ok) - end -end diff --git a/spec/support/shared_examples/models/integrations/chat_message_shared_examples.rb b/spec/support/shared_examples/models/integrations/chat_message_shared_examples.rb new file mode 100644 index 00000000000..2665f249ded --- /dev/null +++ b/spec/support/shared_examples/models/integrations/chat_message_shared_examples.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +RSpec.shared_examples Integrations::ChatMessage do + context 'when input contains link markup' do + let(:evil_input) { '[Markdown](http://evil.com) <a href="http://evil.com">HTML</a> <http://evil.com|Slack>' } + + # Attributes returned from #activity and #attributes which should be sanitized. + let(:sanitized_attributes) do + %i[title subtitle text fallback author_name] + end + + # Attributes passed to #initialize which can contain user input. + before do + args.deep_merge!( + project_name: evil_input, + user_name: evil_input, + user_full_name: evil_input, + commit_title: evil_input, + environment: evil_input, + project: { + name: evil_input + }, + user: { + name: evil_input, + username: evil_input + }, + object_attributes: { + title: evil_input + } + ) + end + + # NOTE: The `include` matcher is used here so the RSpec error messages will tell us + # which method or attribute is failing, even though it makes the spec a bit less readable. + it 'strips all link markup characters', :aggregate_failures do + expect(subject).not_to have_attributes( + pretext: include(evil_input), + summary: include(evil_input) + ) + + begin + sanitized_attributes.each do |attribute| + expect(subject.activity).not_to include(attribute => include(evil_input)) + end + rescue NotImplementedError + end + + begin + sanitized_attributes.each do |attribute| + expect(subject.attachments).not_to include(include(attribute => include(evil_input))) + end + rescue NotImplementedError + end + end + end +end diff --git a/spec/support/shared_examples/requests/sessionless_auth_request_shared_examples.rb b/spec/support/shared_examples/requests/sessionless_auth_request_shared_examples.rb index d82da1b01e1..56e90a6ec34 100644 --- a/spec/support/shared_examples/requests/sessionless_auth_request_shared_examples.rb +++ b/spec/support/shared_examples/requests/sessionless_auth_request_shared_examples.rb @@ -1,84 +1,160 @@ # frozen_string_literal: true -RSpec.shared_examples 'authenticates sessionless user for the request spec' do |params| - params ||= {} - +RSpec.shared_examples 'authenticates sessionless user for the request spec' do |name, public_resource:, ignore_metrics: false, params: {}| before do stub_authentication_activity_metrics(debug: false) end - let(:user) { create(:user) } + let_it_be(:user) { create(:user) } let(:personal_access_token) { create(:personal_access_token, user: user) } - let(:default_params) { params.except(:public) || {} } - context "when the 'personal_access_token' param is populated with the personal access token" do - it 'logs the user in' do + shared_examples 'authenticates user and returns response with ok status' do + it 'authenticates user and returns response with ok status' do expect(authentication_metrics) .to increment(:user_authenticated_counter) - .and increment(:user_session_override_counter) - .and increment(:user_sessionless_authentication_counter) + .and increment(:user_session_override_counter) + .and increment(:user_sessionless_authentication_counter) - get url, params: default_params.merge(private_token: personal_access_token.token) + subject - expect(response).to have_gitlab_http_status(:ok) expect(controller.current_user).to eq(user) + expect(response).to have_gitlab_http_status(:ok) end + end - it 'does not log the user in if page is public', if: params[:public] do - get url, params: default_params + shared_examples 'does not authenticate user and returns response with ok status' do + it 'does not authenticate user and returns response with ok status' do + subject - expect(response).to have_gitlab_http_status(:ok) expect(controller.current_user).to be_nil + expect(response).to have_gitlab_http_status(:ok) end end - context 'when the personal access token has no api scope', unless: params[:public] do - it 'does not log the user in' do + shared_examples 'does not return response with ok status' do + it 'does not return response with ok status' do # Several instances of where these specs are shared route the request # through ApplicationController#route_not_found which does not involve # the usual auth code from Devise, so does not increment the # :user_unauthenticated_counter - # - unless params[:ignore_incrementing] + unless ignore_metrics expect(authentication_metrics) .to increment(:user_unauthenticated_counter) end - personal_access_token.update!(scopes: [:read_user]) - - get url, params: default_params.merge(private_token: personal_access_token.token) + subject expect(response).not_to have_gitlab_http_status(:ok) end end - context "when the 'PERSONAL_ACCESS_TOKEN' header is populated with the personal access token" do - it 'logs the user in' do - expect(authentication_metrics) - .to increment(:user_authenticated_counter) - .and increment(:user_session_override_counter) - .and increment(:user_sessionless_authentication_counter) + shared_examples 'using valid token' do + context 'when resource is private', unless: public_resource do + include_examples 'authenticates user and returns response with ok status' - headers = { 'PRIVATE-TOKEN': personal_access_token.token } - get url, params: default_params, headers: headers + context 'when user with expired password' do + let_it_be(:user) { create(:user, password_expires_at: 2.minutes.ago) } - expect(response).to have_gitlab_http_status(:ok) + include_examples 'does not return response with ok status' + end + + context 'when password expiration is not applicable' do + context 'when ldap user' do + let_it_be(:user) { create(:omniauth_user, provider: 'ldap', password_expires_at: 2.minutes.ago) } + + include_examples 'authenticates user and returns response with ok status' + end + end + end + + context 'when resource is public', if: public_resource do + include_examples 'authenticates user and returns response with ok status' + + context 'when user with expired password' do + let_it_be(:user) { create(:user, password_expires_at: 2.minutes.ago) } + + include_examples 'does not authenticate user and returns response with ok status' + end end end - it "doesn't log the user in otherwise", unless: params[:public] do - # Several instances of where these specs are shared route the request - # through ApplicationController#route_not_found which does not involve - # the usual auth code from Devise, so does not increment the - # :user_unauthenticated_counter - # - unless params[:ignore_incrementing] - expect(authentication_metrics) - .to increment(:user_unauthenticated_counter) + shared_examples 'using invalid token' do + context 'when resource is private', unless: public_resource do + include_examples 'does not return response with ok status' + end + + context 'when resource is public', if: public_resource do + include_examples 'does not authenticate user and returns response with ok status' + end + end + + shared_examples 'personal access token has no api scope' do + context 'when the personal access token has no api scope' do + before do + personal_access_token.update!(scopes: [:read_user]) + end + + context 'when resource is private', unless: public_resource do + include_examples 'does not return response with ok status' + end + + context 'when resource is public', if: public_resource do + include_examples 'does not authenticate user and returns response with ok status' + end + end + end + + describe name do + context "when the 'private_token' param is populated with the personal access token" do + context 'when valid token' do + subject { get url, params: params.merge(private_token: personal_access_token.token) } + + include_examples 'using valid token' + + include_examples 'personal access token has no api scope' + end + + context 'when invalid token' do + subject { get url, params: params.merge(private_token: 'invalid token') } + + include_examples 'using invalid token' + end end - get url, params: default_params.merge(private_token: 'token') + context "when the 'PRIVATE-TOKEN' header is populated with the personal access token" do + context 'when valid token' do + subject do + headers = { 'PRIVATE-TOKEN': personal_access_token.token } + get url, params: params, headers: headers + end - expect(response).not_to have_gitlab_http_status(:ok) + include_examples 'using valid token' + + include_examples 'personal access token has no api scope' + end + + context 'when invalid token' do + subject do + headers = { 'PRIVATE-TOKEN': 'invalid token' } + get url, params: params, headers: headers + end + + include_examples 'using invalid token' + end + end + + context "when the 'feed_token' param is populated with the feed token" do + context 'when valid token' do + subject { get url, params: params.merge(feed_token: user.feed_token) } + + include_examples 'using valid token' + end + + context 'when invalid token' do + subject { get url, params: params.merge(feed_token: 'invalid token') } + + include_examples 'using invalid token' + end + end end end |