Add access specs
This commit is contained in:
parent
6b381f3fdf
commit
11f87700e8
5 changed files with 173 additions and 50 deletions
|
@ -25,7 +25,7 @@ class JwtController < ApplicationController
|
|||
authenticate_with_http_basic do |login, password|
|
||||
@authentication_result = Gitlab::Auth.find_for_git_client(login, password, ip: request.ip)
|
||||
|
||||
render_403 unless @authentication_result.success?
|
||||
render_403 unless @authentication_result.succeeded?
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -51,9 +51,9 @@ module API
|
|||
|
||||
access =
|
||||
if wiki?
|
||||
Gitlab::GitAccessWiki.new(actor, project, protocol)
|
||||
Gitlab::GitAccessWiki.new(actor, project, protocol, capabilities: ssh_capabilities)
|
||||
else
|
||||
Gitlab::GitAccess.new(actor, project, protocol)
|
||||
Gitlab::GitAccess.new(actor, project, protocol, capabilities: ssh_capabilities)
|
||||
end
|
||||
|
||||
access_status = access.check(params[:action], params[:changes])
|
||||
|
@ -130,6 +130,16 @@ module API
|
|||
|
||||
{ success: true, recovery_codes: codes }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ssh_capabilities
|
||||
[
|
||||
:read_project,
|
||||
:download_code,
|
||||
:push_code
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,14 +1,8 @@
|
|||
module Gitlab
|
||||
module Auth
|
||||
class Result
|
||||
attr_reader :user, :project, :type, :capabilities
|
||||
|
||||
def initialize?(user = nil, project = nil, type = nil, capabilities = nil)
|
||||
@user, @project, @type, @capabilities = user, project, type, capabilities
|
||||
end
|
||||
|
||||
def success?
|
||||
user.present? || [:ci, :missing_personal_token].include?(type)
|
||||
Result = Struct.new(:user, :project, :type, :capabilities) do
|
||||
def succeeded?
|
||||
user.present? || [:ci].include?(type)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -23,7 +17,7 @@ module Gitlab
|
|||
personal_access_token_check(login, password) ||
|
||||
Result.new
|
||||
|
||||
rate_limit!(ip, success: result.success?, login: login)
|
||||
rate_limit!(ip, success: result.succeeded?, login: login)
|
||||
result
|
||||
end
|
||||
|
||||
|
@ -94,7 +88,7 @@ module Gitlab
|
|||
:gitlab_or_ldap
|
||||
end
|
||||
|
||||
Result.new(user, type, nil, full_capabilities)
|
||||
Result.new(user, nil, type, full_capabilities)
|
||||
end
|
||||
|
||||
def oauth_access_token_check(login, password)
|
||||
|
@ -111,7 +105,9 @@ module Gitlab
|
|||
if login && password
|
||||
user = User.find_by_personal_access_token(password)
|
||||
validation = User.by_login(login)
|
||||
Result.new(user, nil, :personal_token, full_capabilities) if user == validation
|
||||
if user && user == validation
|
||||
Result.new(user, nil, :personal_token, full_capabilities)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -4,15 +4,51 @@ describe Gitlab::Auth, lib: true do
|
|||
let(:gl_auth) { described_class }
|
||||
|
||||
describe 'find_for_git_client' do
|
||||
it 'recognizes CI' do
|
||||
token = '123'
|
||||
context 'build token' do
|
||||
subject { gl_auth.find_for_git_client('gitlab-ci-token', build.token, project: project, ip: 'ip') }
|
||||
|
||||
context 'for running build' do
|
||||
let!(:build) { create(:ci_build, :running) }
|
||||
let(:project) { build.project }
|
||||
|
||||
before do
|
||||
expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: 'gitlab-ci-token')
|
||||
end
|
||||
|
||||
it 'recognises user-less build' do
|
||||
expect(subject).to eq(Gitlab::Auth::Result.new(nil, build.project, :ci, build_capabilities))
|
||||
end
|
||||
|
||||
it 'recognises user token' do
|
||||
build.update(user: create(:user))
|
||||
|
||||
expect(subject).to eq(Gitlab::Auth::Result.new(build.user, build.project, :build, build_capabilities))
|
||||
end
|
||||
end
|
||||
|
||||
context 'for non-running build' do
|
||||
let!(:build) { create(:ci_build, :pending) }
|
||||
let(:project) { build.project }
|
||||
|
||||
before do
|
||||
expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: 'gitlab-ci-token')
|
||||
end
|
||||
|
||||
it 'denies authentication' do
|
||||
expect(subject).to eq(Gitlab::Auth::Result.new)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'recognizes other ci services' do
|
||||
project = create(:empty_project)
|
||||
project.update_attributes(runners_token: token)
|
||||
project.create_drone_ci_service(active: true)
|
||||
project.drone_ci_service.update(token: 'token')
|
||||
|
||||
ip = 'ip'
|
||||
|
||||
expect(gl_auth).to receive(:rate_limit!).with(ip, success: true, login: 'gitlab-ci-token')
|
||||
expect(gl_auth.find_for_git_client('gitlab-ci-token', token, project: project, ip: ip)).to eq(Gitlab::Auth::Result.new(nil, :ci))
|
||||
expect(gl_auth).to receive(:rate_limit!).with(ip, success: true, login: 'drone-ci-token')
|
||||
expect(gl_auth.find_for_git_client('drone-ci-token', 'token', project: project, ip: ip)).to eq(Gitlab::Auth::Result.new(nil, project, :ci, build_capabilities))
|
||||
end
|
||||
|
||||
it 'recognizes master passwords' do
|
||||
|
@ -20,7 +56,7 @@ describe Gitlab::Auth, lib: true do
|
|||
ip = 'ip'
|
||||
|
||||
expect(gl_auth).to receive(:rate_limit!).with(ip, success: true, login: user.username)
|
||||
expect(gl_auth.find_for_git_client(user.username, 'password', project: nil, ip: ip)).to eq(Gitlab::Auth::Result.new(user, :gitlab_or_ldap))
|
||||
expect(gl_auth.find_for_git_client(user.username, 'password', project: nil, ip: ip)).to eq(Gitlab::Auth::Result.new(user, nil, :gitlab_or_ldap, full_capabilities))
|
||||
end
|
||||
|
||||
it 'recognizes OAuth tokens' do
|
||||
|
@ -30,7 +66,7 @@ describe Gitlab::Auth, lib: true do
|
|||
ip = 'ip'
|
||||
|
||||
expect(gl_auth).to receive(:rate_limit!).with(ip, success: true, login: 'oauth2')
|
||||
expect(gl_auth.find_for_git_client("oauth2", token.token, project: nil, ip: ip)).to eq(Gitlab::Auth::Result.new(user, :oauth))
|
||||
expect(gl_auth.find_for_git_client("oauth2", token.token, project: nil, ip: ip)).to eq(Gitlab::Auth::Result.new(user, nil, :oauth, read_capabilities))
|
||||
end
|
||||
|
||||
it 'returns double nil for invalid credentials' do
|
||||
|
@ -92,4 +128,30 @@ describe Gitlab::Auth, lib: true do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def build_capabilities
|
||||
[
|
||||
:read_project,
|
||||
:build_download_code,
|
||||
:build_read_container_image,
|
||||
:build_create_container_image
|
||||
]
|
||||
end
|
||||
|
||||
def read_capabilities
|
||||
[
|
||||
:read_project,
|
||||
:download_code,
|
||||
:read_container_image
|
||||
]
|
||||
end
|
||||
|
||||
def full_capabilities
|
||||
read_capabilities + [
|
||||
:push_code,
|
||||
:update_container_image
|
||||
]
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,10 +1,17 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::GitAccess, lib: true do
|
||||
let(:access) { Gitlab::GitAccess.new(actor, project, 'web') }
|
||||
let(:access) { Gitlab::GitAccess.new(actor, project, 'web', capabilities: capabilities) }
|
||||
let(:project) { create(:project) }
|
||||
let(:user) { create(:user) }
|
||||
let(:actor) { user }
|
||||
let(:capabilities) do
|
||||
[
|
||||
:read_project,
|
||||
:download_code,
|
||||
:push_code
|
||||
]
|
||||
end
|
||||
|
||||
describe '#check with single protocols allowed' do
|
||||
def disable_protocol(protocol)
|
||||
|
@ -111,6 +118,36 @@ describe Gitlab::GitAccess, lib: true do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'build capabilities permissions' do
|
||||
let(:capabilities) { build_capabilities }
|
||||
|
||||
describe 'reporter user' do
|
||||
before { project.team << [user, :reporter] }
|
||||
|
||||
context 'pull code' do
|
||||
it { expect(subject).to be_allowed }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'admin user' do
|
||||
let(:user) { create(:admin) }
|
||||
|
||||
context 'when member of the project' do
|
||||
before { project.team << [user, :reporter] }
|
||||
|
||||
context 'pull code' do
|
||||
it { expect(subject).to be_allowed }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when is not member of the project' do
|
||||
context 'pull code' do
|
||||
it { expect(subject).not_to be_allowed }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'push_access_check' do
|
||||
|
@ -281,40 +318,58 @@ describe Gitlab::GitAccess, lib: true do
|
|||
admin: { push_protected_branch: false, push_all: false, merge_into_protected_branch: false }))
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
shared_examples 'can not push code' do
|
||||
subject { access.check('git-receive-pack', '_any') }
|
||||
|
||||
context 'when project is authorized' do
|
||||
before { key.projects << project }
|
||||
|
||||
it { expect(subject).not_to be_allowed }
|
||||
end
|
||||
|
||||
context 'when unauthorized' do
|
||||
context 'to public project' do
|
||||
let(:project) { create(:project, :public) }
|
||||
|
||||
it { expect(subject).not_to be_allowed }
|
||||
end
|
||||
|
||||
context 'to internal project' do
|
||||
let(:project) { create(:project, :internal) }
|
||||
|
||||
it { expect(subject).not_to be_allowed }
|
||||
end
|
||||
|
||||
context 'to private project' do
|
||||
let(:project) { create(:project, :internal) }
|
||||
|
||||
it { expect(subject).not_to be_allowed }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'build capabilities permissions' do
|
||||
let(:capabilities) { build_capabilities }
|
||||
|
||||
it_behaves_like 'cannot push code'
|
||||
end
|
||||
|
||||
describe 'deploy key permissions' do
|
||||
let(:key) { create(:deploy_key) }
|
||||
let(:actor) { key }
|
||||
|
||||
context 'push code' do
|
||||
subject { access.check('git-receive-pack', '_any') }
|
||||
it_behaves_like 'cannot push code'
|
||||
end
|
||||
|
||||
context 'when project is authorized' do
|
||||
before { key.projects << project }
|
||||
private
|
||||
|
||||
it { expect(subject).not_to be_allowed }
|
||||
end
|
||||
|
||||
context 'when unauthorized' do
|
||||
context 'to public project' do
|
||||
let(:project) { create(:project, :public) }
|
||||
|
||||
it { expect(subject).not_to be_allowed }
|
||||
end
|
||||
|
||||
context 'to internal project' do
|
||||
let(:project) { create(:project, :internal) }
|
||||
|
||||
it { expect(subject).not_to be_allowed }
|
||||
end
|
||||
|
||||
context 'to private project' do
|
||||
let(:project) { create(:project, :internal) }
|
||||
|
||||
it { expect(subject).not_to be_allowed }
|
||||
end
|
||||
end
|
||||
end
|
||||
def build_capabilities
|
||||
[
|
||||
:read_project,
|
||||
:build_download_code
|
||||
]
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue