Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorTimothy Andrew <mail@timothyandrew.net>2016-11-22 12:04:23 +0300
committerTimothy Andrew <mail@timothyandrew.net>2016-12-16 13:59:31 +0300
commit7fa06ed55d18af4d055041eb27d38fecf9b5548f (patch)
treed2565cdc70269e5f244e7cf542170b0d5d8cf7aa /spec
parent6c809dfae84e702f7a49d3fac5725745264e0ff9 (diff)
Calls to the API are checked for scope.
- Move the `Oauth2::AccessTokenValidationService` class to `AccessTokenValidationService`, since it is now being used for personal access token validation as well. - Each API endpoint declares the scopes it accepts (if any). Currently, the top level API module declares the `api` scope, and the `Users` API module declares the `read_user` scope (for GET requests). - Move the `find_user_by_private_token` from the API `Helpers` module to the `APIGuard` module, to avoid littering `Helpers` with more auth-related methods to support `find_user_by_private_token`
Diffstat (limited to 'spec')
-rw-r--r--spec/requests/api/doorkeeper_access_spec.rb2
-rw-r--r--spec/requests/api/helpers_spec.rb43
-rw-r--r--spec/services/access_token_validation_service_spec.rb42
3 files changed, 69 insertions, 18 deletions
diff --git a/spec/requests/api/doorkeeper_access_spec.rb b/spec/requests/api/doorkeeper_access_spec.rb
index 5262a623761..bd9ecaf2685 100644
--- a/spec/requests/api/doorkeeper_access_spec.rb
+++ b/spec/requests/api/doorkeeper_access_spec.rb
@@ -5,7 +5,7 @@ describe API::API, api: true do
let!(:user) { create(:user) }
let!(:application) { Doorkeeper::Application.create!(name: "MyApp", redirect_uri: "https://app.com", owner: user) }
- let!(:token) { Doorkeeper::AccessToken.create! application_id: application.id, resource_owner_id: user.id }
+ let!(:token) { Doorkeeper::AccessToken.create! application_id: application.id, resource_owner_id: user.id, scopes: "api" }
describe "when unauthenticated" do
it "returns authentication success" do
diff --git a/spec/requests/api/helpers_spec.rb b/spec/requests/api/helpers_spec.rb
index 4035fd97af5..15b93118ee4 100644
--- a/spec/requests/api/helpers_spec.rb
+++ b/spec/requests/api/helpers_spec.rb
@@ -1,6 +1,7 @@
require 'spec_helper'
describe API::Helpers, api: true do
+ include API::APIGuard::HelperMethods
include API::Helpers
include SentryHelper
@@ -15,24 +16,24 @@ describe API::Helpers, api: true do
def set_env(user_or_token, identifier)
clear_env
clear_param
- env[API::Helpers::PRIVATE_TOKEN_HEADER] = user_or_token.respond_to?(:private_token) ? user_or_token.private_token : user_or_token
+ env[API::APIGuard::PRIVATE_TOKEN_HEADER] = user_or_token.respond_to?(:private_token) ? user_or_token.private_token : user_or_token
env[API::Helpers::SUDO_HEADER] = identifier.to_s
end
def set_param(user_or_token, identifier)
clear_env
clear_param
- params[API::Helpers::PRIVATE_TOKEN_PARAM] = user_or_token.respond_to?(:private_token) ? user_or_token.private_token : user_or_token
+ params[API::APIGuard::PRIVATE_TOKEN_PARAM] = user_or_token.respond_to?(:private_token) ? user_or_token.private_token : user_or_token
params[API::Helpers::SUDO_PARAM] = identifier.to_s
end
def clear_env
- env.delete(API::Helpers::PRIVATE_TOKEN_HEADER)
+ env.delete(API::APIGuard::PRIVATE_TOKEN_HEADER)
env.delete(API::Helpers::SUDO_HEADER)
end
def clear_param
- params.delete(API::Helpers::PRIVATE_TOKEN_PARAM)
+ params.delete(API::APIGuard::PRIVATE_TOKEN_PARAM)
params.delete(API::Helpers::SUDO_PARAM)
end
@@ -94,22 +95,22 @@ describe API::Helpers, api: true do
describe "when authenticating using a user's private token" do
it "returns nil for an invalid token" do
- env[API::Helpers::PRIVATE_TOKEN_HEADER] = 'invalid token'
+ env[API::APIGuard::PRIVATE_TOKEN_HEADER] = 'invalid token'
allow_any_instance_of(self.class).to receive(:doorkeeper_guard){ false }
expect(current_user).to be_nil
end
it "returns nil for a user without access" do
- env[API::Helpers::PRIVATE_TOKEN_HEADER] = user.private_token
+ env[API::APIGuard::PRIVATE_TOKEN_HEADER] = user.private_token
allow_any_instance_of(Gitlab::UserAccess).to receive(:allowed?).and_return(false)
expect(current_user).to be_nil
end
it "leaves user as is when sudo not specified" do
- env[API::Helpers::PRIVATE_TOKEN_HEADER] = user.private_token
+ env[API::APIGuard::PRIVATE_TOKEN_HEADER] = user.private_token
expect(current_user).to eq(user)
clear_env
- params[API::Helpers::PRIVATE_TOKEN_PARAM] = user.private_token
+ params[API::APIGuard::PRIVATE_TOKEN_PARAM] = user.private_token
expect(current_user).to eq(user)
end
end
@@ -117,37 +118,45 @@ describe API::Helpers, api: true do
describe "when authenticating using a user's personal access tokens" do
let(:personal_access_token) { create(:personal_access_token, user: user) }
+ before do
+ allow_any_instance_of(self.class).to receive(:doorkeeper_guard) { false }
+ end
+
it "returns nil for an invalid token" do
- env[API::Helpers::PRIVATE_TOKEN_HEADER] = 'invalid token'
- allow_any_instance_of(self.class).to receive(:doorkeeper_guard){ false }
+ env[API::APIGuard::PRIVATE_TOKEN_HEADER] = 'invalid token'
expect(current_user).to be_nil
end
it "returns nil for a user without access" do
- env[API::Helpers::PRIVATE_TOKEN_HEADER] = personal_access_token.token
+ env[API::APIGuard::PRIVATE_TOKEN_HEADER] = personal_access_token.token
allow_any_instance_of(Gitlab::UserAccess).to receive(:allowed?).and_return(false)
expect(current_user).to be_nil
end
+ it "returns nil for a token without the appropriate scope" do
+ personal_access_token = create(:personal_access_token, user: user, scopes: ['read_user'])
+ env[API::APIGuard::PRIVATE_TOKEN_HEADER] = personal_access_token.token
+ allow_access_with_scope('write_user')
+ expect(current_user).to be_nil
+ end
+
it "leaves user as is when sudo not specified" do
- env[API::Helpers::PRIVATE_TOKEN_HEADER] = personal_access_token.token
+ env[API::APIGuard::PRIVATE_TOKEN_HEADER] = personal_access_token.token
expect(current_user).to eq(user)
clear_env
- params[API::Helpers::PRIVATE_TOKEN_PARAM] = personal_access_token.token
+ params[API::APIGuard::PRIVATE_TOKEN_PARAM] = personal_access_token.token
expect(current_user).to eq(user)
end
it 'does not allow revoked tokens' do
personal_access_token.revoke!
- env[API::Helpers::PRIVATE_TOKEN_HEADER] = personal_access_token.token
- allow_any_instance_of(self.class).to receive(:doorkeeper_guard){ false }
+ env[API::APIGuard::PRIVATE_TOKEN_HEADER] = personal_access_token.token
expect(current_user).to be_nil
end
it 'does not allow expired tokens' do
personal_access_token.update_attributes!(expires_at: 1.day.ago)
- env[API::Helpers::PRIVATE_TOKEN_HEADER] = personal_access_token.token
- allow_any_instance_of(self.class).to receive(:doorkeeper_guard){ false }
+ env[API::APIGuard::PRIVATE_TOKEN_HEADER] = personal_access_token.token
expect(current_user).to be_nil
end
end
diff --git a/spec/services/access_token_validation_service_spec.rb b/spec/services/access_token_validation_service_spec.rb
new file mode 100644
index 00000000000..8808934fa24
--- /dev/null
+++ b/spec/services/access_token_validation_service_spec.rb
@@ -0,0 +1,42 @@
+require 'spec_helper'
+
+describe AccessTokenValidationService, services: true do
+
+ describe ".sufficient_scope?" do
+ it "returns true if the required scope is present in the token's scopes" do
+ token = double("token", scopes: [:api, :read_user])
+
+ expect(described_class.sufficient_scope?(token, [:api])).to be(true)
+ end
+
+ it "returns true if more than one of the required scopes is present in the token's scopes" do
+ token = double("token", scopes: [:api, :read_user, :other_scope])
+
+ expect(described_class.sufficient_scope?(token, [:api, :other_scope])).to be(true)
+ end
+
+ it "returns true if the list of required scopes is an exact match for the token's scopes" do
+ token = double("token", scopes: [:api, :read_user, :other_scope])
+
+ expect(described_class.sufficient_scope?(token, [:api, :read_user, :other_scope])).to be(true)
+ end
+
+ it "returns true if the list of required scopes contains all of the token's scopes, in addition to others" do
+ token = double("token", scopes: [:api, :read_user])
+
+ expect(described_class.sufficient_scope?(token, [:api, :read_user, :other_scope])).to be(true)
+ end
+
+ it 'returns true if the list of required scopes is blank' do
+ token = double("token", scopes: [])
+
+ expect(described_class.sufficient_scope?(token, [])).to be(true)
+ end
+
+ it "returns false if there are no scopes in common between the required scopes and the token scopes" do
+ token = double("token", scopes: [:api, :read_user])
+
+ expect(described_class.sufficient_scope?(token, [:other_scope])).to be(false)
+ end
+ end
+end