Commit 3e83cecf authored by Lukas 'Eipi' Eipert's avatar Lukas 'Eipi' Eipert Committed by Sean McGivern

Allow HEAD requests for read_api and read_user scope tokens

> The HEAD method is identical to GET except that the server MUST NOT
> send a message body in the response (i.e., the response terminates at
> the end of the header section)

https://tools.ietf.org/html/rfc7231#section-4.3.2

Judging from that section of the RFC 7231 it should be safe to allow
HEAD requests in the read_api and read_user scopes
parent d2ef64ae
---
title: Allow HEAD requests for read_api and read_user scope tokens
merge_request: 53088
author:
type: fixed
...@@ -30,7 +30,7 @@ module API ...@@ -30,7 +30,7 @@ module API
] ]
allow_access_with_scope :api allow_access_with_scope :api
allow_access_with_scope :read_api, if: -> (request) { request.get? } allow_access_with_scope :read_api, if: -> (request) { request.get? || request.head? }
prefix :api prefix :api
version 'v3', using: :path do version 'v3', using: :path do
......
...@@ -6,7 +6,7 @@ module API ...@@ -6,7 +6,7 @@ module API
include APIGuard include APIGuard
helpers ::API::Helpers::EventsHelpers helpers ::API::Helpers::EventsHelpers
allow_access_with_scope :read_user, if: -> (request) { request.get? } allow_access_with_scope :read_user, if: -> (request) { request.get? || request.head? }
feature_category :users feature_category :users
......
...@@ -6,7 +6,7 @@ module API ...@@ -6,7 +6,7 @@ module API
include APIGuard include APIGuard
include Helpers::CustomAttributes include Helpers::CustomAttributes
allow_access_with_scope :read_user, if: -> (request) { request.get? } allow_access_with_scope :read_user, if: -> (request) { request.get? || request.head? }
feature_category :users, ['/users/:id/custom_attributes', '/users/:id/custom_attributes/:key'] feature_category :users, ['/users/:id/custom_attributes', '/users/:id/custom_attributes/:key']
......
...@@ -5,7 +5,7 @@ module API ...@@ -5,7 +5,7 @@ module API
helpers ::API::Helpers::GraphqlHelpers helpers ::API::Helpers::GraphqlHelpers
include APIGuard include APIGuard
allow_access_with_scope :read_user, if: -> (request) { request.get? } allow_access_with_scope :read_user, if: -> (request) { request.get? || request.head? }
before { authenticate! } before { authenticate! }
......
...@@ -36,6 +36,12 @@ RSpec.describe API::API do ...@@ -36,6 +36,12 @@ RSpec.describe API::API do
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
end end
it 'does authorize user for head request' do
head api('/groups', personal_access_token: token)
expect(response).to have_gitlab_http_status(:ok)
end
it 'does not authorize user for revoked token' do it 'does not authorize user for revoked token' do
revoked = create(:personal_access_token, :revoked, user: user, scopes: [:read_api]) revoked = create(:personal_access_token, :revoked, user: user, scopes: [:read_api])
......
...@@ -55,6 +55,12 @@ RSpec.describe API::Events do ...@@ -55,6 +55,12 @@ RSpec.describe API::Events do
expect(json_response).to be_an Array expect(json_response).to be_an Array
expect(json_response.size).to eq(1) expect(json_response.size).to eq(1)
end end
it 'returns "200" response on head request' do
head api('/events?action=closed&target_type=issue&after=2016-12-1&before=2016-12-31', personal_access_token: token)
expect(response).to have_gitlab_http_status(:ok)
end
end end
context 'when the requesting token does not have "read_user" or "api" scope' do context 'when the requesting token does not have "read_user" or "api" scope' do
......
...@@ -33,6 +33,12 @@ RSpec.describe API::Version do ...@@ -33,6 +33,12 @@ RSpec.describe API::Version do
expect_version expect_version
end end
it 'returns "200" response on head requests' do
head api('/version', personal_access_token: personal_access_token)
expect(response).to have_gitlab_http_status(:ok)
end
end end
context 'with read_user scope' do context 'with read_user scope' do
...@@ -43,6 +49,12 @@ RSpec.describe API::Version do ...@@ -43,6 +49,12 @@ RSpec.describe API::Version do
expect_version expect_version
end end
it 'returns "200" response on head requests' do
head api('/version', personal_access_token: personal_access_token)
expect(response).to have_gitlab_http_status(:ok)
end
end end
context 'with neither api nor read_user scope' do context 'with neither api nor read_user scope' do
......
...@@ -7,21 +7,33 @@ RSpec.shared_examples 'allows the "read_user" scope' do |api_version| ...@@ -7,21 +7,33 @@ RSpec.shared_examples 'allows the "read_user" scope' do |api_version|
context 'when the requesting token has the "api" scope' do context 'when the requesting token has the "api" scope' do
let(:token) { create(:personal_access_token, scopes: ['api'], user: user) } let(:token) { create(:personal_access_token, scopes: ['api'], user: user) }
it 'returns a "200" response' do it 'returns a "200" response on get request' do
get api_call.call(path, user, personal_access_token: token, version: version) get api_call.call(path, user, personal_access_token: token, version: version)
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
end end
it 'returns a "200" response on head request' do
head api_call.call(path, user, personal_access_token: token, version: version)
expect(response).to have_gitlab_http_status(:ok)
end
end end
context 'when the requesting token has the "read_user" scope' do context 'when the requesting token has the "read_user" scope' do
let(:token) { create(:personal_access_token, scopes: ['read_user'], user: user) } let(:token) { create(:personal_access_token, scopes: ['read_user'], user: user) }
it 'returns a "200" response' do it 'returns a "200" response on get request' do
get api_call.call(path, user, personal_access_token: token, version: version) get api_call.call(path, user, personal_access_token: token, version: version)
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
end end
it 'returns a "200" response on head request' do
head api_call.call(path, user, personal_access_token: token, version: version)
expect(response).to have_gitlab_http_status(:ok)
end
end end
context 'when the requesting token does not have any required scope' do context 'when the requesting token does not have any required scope' do
...@@ -45,21 +57,33 @@ RSpec.shared_examples 'allows the "read_user" scope' do |api_version| ...@@ -45,21 +57,33 @@ RSpec.shared_examples 'allows the "read_user" scope' do |api_version|
context 'when the requesting token has the "api" scope' do context 'when the requesting token has the "api" scope' do
let!(:token) { Doorkeeper::AccessToken.create! application_id: application.id, resource_owner_id: user.id, scopes: "api" } let!(:token) { Doorkeeper::AccessToken.create! application_id: application.id, resource_owner_id: user.id, scopes: "api" }
it 'returns a "200" response' do it 'returns a "200" response on get request' do
get api_call.call(path, user, oauth_access_token: token) get api_call.call(path, user, oauth_access_token: token)
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
end end
it 'returns a "200" response on head request' do
head api_call.call(path, user, oauth_access_token: token)
expect(response).to have_gitlab_http_status(:ok)
end
end end
context 'when the requesting token has the "read_user" scope' do context 'when the requesting token has the "read_user" scope' do
let!(:token) { Doorkeeper::AccessToken.create! application_id: application.id, resource_owner_id: user.id, scopes: "read_user" } let!(:token) { Doorkeeper::AccessToken.create! application_id: application.id, resource_owner_id: user.id, scopes: "read_user" }
it 'returns a "200" response' do it 'returns a "200" response on get request' do
get api_call.call(path, user, oauth_access_token: token) get api_call.call(path, user, oauth_access_token: token)
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
end end
it 'returns a "200" response on head request' do
head api_call.call(path, user, oauth_access_token: token)
expect(response).to have_gitlab_http_status(:ok)
end
end end
context 'when the requesting token does not have any required scope' do context 'when the requesting token does not have any required scope' do
......
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