diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-10-21 10:08:36 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-10-21 10:08:36 +0300 |
commit | 48aff82709769b098321c738f3444b9bdaa694c6 (patch) | |
tree | e00c7c43e2d9b603a5a6af576b1685e400410dee /spec/requests/api/internal | |
parent | 879f5329ee916a948223f8f43d77fba4da6cd028 (diff) |
Add latest changes from gitlab-org/gitlab@13-5-stable-eev13.5.0-rc42
Diffstat (limited to 'spec/requests/api/internal')
-rw-r--r-- | spec/requests/api/internal/base_spec.rb | 334 | ||||
-rw-r--r-- | spec/requests/api/internal/lfs_spec.rb | 93 |
2 files changed, 295 insertions, 132 deletions
diff --git a/spec/requests/api/internal/base_spec.rb b/spec/requests/api/internal/base_spec.rb index 4a0a7c81781..ab5f09305ce 100644 --- a/spec/requests/api/internal/base_spec.rb +++ b/spec/requests/api/internal/base_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' RSpec.describe API::Internal::Base do + include APIInternalBaseHelpers + let_it_be(:user, reload: true) { create(:user) } let_it_be(:project, reload: true) { create(:project, :repository, :wiki_repo) } let_it_be(:personal_snippet) { create(:personal_snippet, :repository, author: user) } @@ -48,43 +50,63 @@ RSpec.describe API::Internal::Base do end end - describe 'GET /internal/two_factor_recovery_codes' do - it 'returns an error message when the key does not exist' do - post api('/internal/two_factor_recovery_codes'), - params: { - secret_token: secret_token, - key_id: non_existing_record_id - } + shared_examples 'actor key validations' do + context 'key id is not provided' do + let(:key_id) { nil } - expect(json_response['success']).to be_falsey - expect(json_response['message']).to eq('Could not find the given key') + it 'returns an error message' do + subject + + expect(json_response['success']).to be_falsey + expect(json_response['message']).to eq('Could not find a user without a key') + end end - it 'returns an error message when the key is a deploy key' do - deploy_key = create(:deploy_key) + context 'key does not exist' do + let(:key_id) { non_existing_record_id } - post api('/internal/two_factor_recovery_codes'), - params: { - secret_token: secret_token, - key_id: deploy_key.id - } + it 'returns an error message' do + subject - expect(json_response['success']).to be_falsey - expect(json_response['message']).to eq('Deploy keys cannot be used to retrieve recovery codes') + expect(json_response['success']).to be_falsey + expect(json_response['message']).to eq('Could not find the given key') + end + end + + context 'key without user' do + let(:key_id) { create(:key, user: nil).id } + + it 'returns an error message' do + subject + + expect(json_response['success']).to be_falsey + expect(json_response['message']).to eq('Could not find a user for the given key') + end end + end - it 'returns an error message when the user does not exist' do - key_without_user = create(:key, user: nil) + describe 'GET /internal/two_factor_recovery_codes' do + let(:key_id) { key.id } + subject do post api('/internal/two_factor_recovery_codes'), params: { secret_token: secret_token, - key_id: key_without_user.id + key_id: key_id } + end - expect(json_response['success']).to be_falsey - expect(json_response['message']).to eq('Could not find a user for the given key') - expect(json_response['recovery_codes']).to be_nil + it_behaves_like 'actor key validations' + + context 'key is a deploy key' do + let(:key_id) { create(:deploy_key).id } + + it 'returns an error message' do + subject + + expect(json_response['success']).to be_falsey + expect(json_response['message']).to eq('Deploy keys cannot be used to retrieve recovery codes') + end end context 'when two-factor is enabled' do @@ -93,11 +115,7 @@ RSpec.describe API::Internal::Base do allow_any_instance_of(User) .to receive(:generate_otp_backup_codes!).and_return(%w(119135e5a3ebce8e 34bd7b74adbc8861)) - post api('/internal/two_factor_recovery_codes'), - params: { - secret_token: secret_token, - key_id: key.id - } + subject expect(json_response['success']).to be_truthy expect(json_response['recovery_codes']).to match_array(%w(119135e5a3ebce8e 34bd7b74adbc8861)) @@ -108,11 +126,7 @@ RSpec.describe API::Internal::Base do it 'returns an error message' do allow_any_instance_of(User).to receive(:two_factor_enabled?).and_return(false) - post api('/internal/two_factor_recovery_codes'), - params: { - secret_token: secret_token, - key_id: key.id - } + subject expect(json_response['success']).to be_falsey expect(json_response['recovery_codes']).to be_nil @@ -121,42 +135,27 @@ RSpec.describe API::Internal::Base do end describe 'POST /internal/personal_access_token' do - it 'returns an error message when the key does not exist' do - post api('/internal/personal_access_token'), - params: { - secret_token: secret_token, - key_id: non_existing_record_id - } - - expect(json_response['success']).to be_falsey - expect(json_response['message']).to eq('Could not find the given key') - end - - it 'returns an error message when the key is a deploy key' do - deploy_key = create(:deploy_key) + let(:key_id) { key.id } + subject do post api('/internal/personal_access_token'), params: { secret_token: secret_token, - key_id: deploy_key.id + key_id: key_id } - - expect(json_response['success']).to be_falsey - expect(json_response['message']).to eq('Deploy keys cannot be used to create personal access tokens') end - it 'returns an error message when the user does not exist' do - key_without_user = create(:key, user: nil) + it_behaves_like 'actor key validations' - post api('/internal/personal_access_token'), - params: { - secret_token: secret_token, - key_id: key_without_user.id - } + context 'key is a deploy key' do + let(:key_id) { create(:deploy_key).id } - expect(json_response['success']).to be_falsey - expect(json_response['message']).to eq('Could not find a user for the given key') - expect(json_response['token']).to be_nil + it 'returns an error message' do + subject + + expect(json_response['success']).to be_falsey + expect(json_response['message']).to eq('Deploy keys cannot be used to create personal access tokens') + end end it 'returns an error message when given an non existent user' do @@ -459,7 +458,7 @@ RSpec.describe API::Internal::Base do end it_behaves_like 'sets hook env' do - let(:gl_repository) { Gitlab::GlRepository::WIKI.identifier_for_container(project) } + let(:gl_repository) { Gitlab::GlRepository::WIKI.identifier_for_container(project.wiki) } end end @@ -1207,86 +1206,157 @@ RSpec.describe API::Internal::Base do end end - def gl_repository_for(container) - case container - when ProjectWiki - Gitlab::GlRepository::WIKI.identifier_for_container(container.project) - when Project - Gitlab::GlRepository::PROJECT.identifier_for_container(container) - when Snippet - Gitlab::GlRepository::SNIPPET.identifier_for_container(container) - else - nil + describe 'POST /internal/two_factor_config' do + let(:key_id) { key.id } + + before do + stub_feature_flags(two_factor_for_cli: true) end - end - def full_path_for(container) - case container - when PersonalSnippet - "snippets/#{container.id}" - when ProjectSnippet - "#{container.project.full_path}/snippets/#{container.id}" - else - container.full_path + subject do + post api('/internal/two_factor_config'), + params: { + secret_token: secret_token, + key_id: key_id + } end - end - def pull(key, container, protocol = 'ssh') - post( - api("/internal/allowed"), - params: { - key_id: key.id, - project: full_path_for(container), - gl_repository: gl_repository_for(container), - action: 'git-upload-pack', - secret_token: secret_token, - protocol: protocol - } - ) - end + it_behaves_like 'actor key validations' - def push(key, container, protocol = 'ssh', env: nil, changes: nil) - push_with_path(key, - full_path: full_path_for(container), - gl_repository: gl_repository_for(container), - protocol: protocol, - env: env, - changes: changes) - end + context 'when the key is a deploy key' do + let(:key) { create(:deploy_key) } - def push_with_path(key, full_path:, gl_repository: nil, protocol: 'ssh', env: nil, changes: nil) - changes ||= 'd14d6c0abdd253381df51a723d58691b2ee1ab08 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/master' + it 'does not required two factor' do + subject - params = { - changes: changes, - key_id: key.id, - project: full_path, - action: 'git-receive-pack', - secret_token: secret_token, - protocol: protocol, - env: env - } - params[:gl_repository] = gl_repository if gl_repository + expect(json_response['success']).to be_truthy + expect(json_response['two_factor_required']).to be_falsey + end + end - post( - api("/internal/allowed"), - params: params - ) + context 'when two-factor is enabled' do + it 'returns user two factor config' do + allow_any_instance_of(User).to receive(:two_factor_enabled?).and_return(true) + + subject + + expect(json_response['success']).to be_truthy + expect(json_response['two_factor_required']).to be_truthy + end + end + + context 'when two-factor is not enabled' do + it 'returns an error message' do + allow_any_instance_of(User).to receive(:two_factor_enabled?).and_return(false) + + subject + + expect(json_response['success']).to be_truthy + expect(json_response['two_factor_required']).to be_falsey + end + end + + context 'two_factor_for_cli feature is disabled' do + before do + stub_feature_flags(two_factor_for_cli: false) + end + + context 'when two-factor is enabled for the user' do + it 'returns user two factor config' do + allow_any_instance_of(User).to receive(:two_factor_enabled?).and_return(true) + + subject + + expect(json_response['success']).to be_falsey + end + end + end end - def archive(key, container) - post( - api("/internal/allowed"), - params: { - ref: 'master', - key_id: key.id, - project: full_path_for(container), - gl_repository: gl_repository_for(container), - action: 'git-upload-archive', - secret_token: secret_token, - protocol: 'ssh' - } - ) + describe 'POST /internal/two_factor_otp_check' do + let(:key_id) { key.id } + let(:otp) { '123456'} + + before do + stub_feature_flags(two_factor_for_cli: true) + end + + subject do + post api('/internal/two_factor_otp_check'), + params: { + secret_token: secret_token, + key_id: key_id, + otp_attempt: otp + } + end + + it_behaves_like 'actor key validations' + + context 'when the key is a deploy key' do + let(:key_id) { create(:deploy_key).id } + + it 'returns an error message' do + subject + + expect(json_response['success']).to be_falsey + expect(json_response['message']).to eq('Deploy keys cannot be used for Two Factor') + end + end + + context 'when the two factor is enabled' do + before do + allow_any_instance_of(User).to receive(:two_factor_enabled?).and_return(true) + end + + context 'when the OTP is valid' do + it 'returns success' do + allow_any_instance_of(Users::ValidateOtpService).to receive(:execute).with(otp).and_return(status: :success) + + subject + + expect(json_response['success']).to be_truthy + end + end + + context 'when the OTP is invalid' do + it 'is not success' do + allow_any_instance_of(Users::ValidateOtpService).to receive(:execute).with(otp).and_return(status: :error) + + subject + + expect(json_response['success']).to be_falsey + end + end + end + + context 'when the two factor is disabled' do + before do + allow_any_instance_of(User).to receive(:two_factor_enabled?).and_return(false) + end + + it 'returns an error message' do + subject + + expect(json_response['success']).to be_falsey + expect(json_response['message']).to eq 'Two-factor authentication is not enabled for this user' + end + end + + context 'two_factor_for_cli feature is disabled' do + before do + stub_feature_flags(two_factor_for_cli: false) + end + + context 'when two-factor is enabled for the user' do + it 'returns user two factor config' do + allow_any_instance_of(User).to receive(:two_factor_enabled?).and_return(true) + + subject + + expect(json_response['success']).to be_falsey + end + end + end end def lfs_auth_project(project) diff --git a/spec/requests/api/internal/lfs_spec.rb b/spec/requests/api/internal/lfs_spec.rb new file mode 100644 index 00000000000..4739ec62992 --- /dev/null +++ b/spec/requests/api/internal/lfs_spec.rb @@ -0,0 +1,93 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe API::Internal::Lfs do + include APIInternalBaseHelpers + + let_it_be(:project) { create(:project) } + let_it_be(:lfs_object) { create(:lfs_object, :with_file) } + let_it_be(:lfs_objects_project) { create(:lfs_objects_project, project: project, lfs_object: lfs_object) } + let_it_be(:gl_repository) { "project-#{project.id}" } + let_it_be(:filename) { lfs_object.file.path } + + let(:secret_token) { Gitlab::Shell.secret_token } + + describe 'GET /internal/lfs' do + let(:valid_params) do + { oid: lfs_object.oid, gl_repository: gl_repository, secret_token: secret_token } + end + + context 'with invalid auth' do + let(:invalid_params) { valid_params.merge!(secret_token: 'invalid_tokne') } + + it 'returns 401' do + get api("/internal/lfs"), params: invalid_params + end + end + + context 'with valid auth' do + context 'LFS in local storage' do + it 'sends the file' do + get api("/internal/lfs"), params: valid_params + + expect(response).to have_gitlab_http_status(:ok) + expect(response.headers['Content-Type']).to eq('application/octet-stream') + expect(response.headers['Content-Length'].to_i).to eq(File.stat(filename).size) + expect(response.body).to eq(File.open(filename, 'rb', &:read)) + end + + # https://www.rubydoc.info/github/rack/rack/master/Rack/Sendfile + it 'delegates sending to Web server' do + get api("/internal/lfs"), params: valid_params, env: { 'HTTP_X_SENDFILE_TYPE' => 'X-Sendfile' } + + expect(response).to have_gitlab_http_status(:ok) + expect(response.headers['Content-Type']).to eq('application/octet-stream') + expect(response.headers['Content-Length'].to_i).to eq(0) + expect(response.headers['X-Sendfile']).to be_present + expect(response.body).to eq("") + end + + it 'retuns 404 for unknown file' do + params = valid_params.merge(oid: SecureRandom.hex) + + get api("/internal/lfs"), params: params + + expect(response).to have_gitlab_http_status(:not_found) + end + + it 'returns 404 if LFS object does not belong to project' do + other_lfs = create(:lfs_object, :with_file) + params = valid_params.merge(oid: other_lfs.oid) + + get api("/internal/lfs"), params: params + + expect(response).to have_gitlab_http_status(:not_found) + end + end + + context 'LFS in object storage' do + let!(:lfs_object2) { create(:lfs_object, :with_file) } + let!(:lfs_objects_project2) { create(:lfs_objects_project, project: project, lfs_object: lfs_object2) } + let(:valid_params) do + { oid: lfs_object2.oid, gl_repository: gl_repository, secret_token: secret_token } + end + + before do + stub_lfs_object_storage(enabled: true) + lfs_object2.file.migrate!(LfsObjectUploader::Store::REMOTE) + end + + it 'notifies Workhorse to send the file' do + get api("/internal/lfs"), params: valid_params + + expect(response).to have_gitlab_http_status(:ok) + expect(response.headers[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with("send-url:") + expect(response.headers['Content-Type']).to eq('application/octet-stream') + expect(response.headers['Content-Length'].to_i).to eq(0) + expect(response.body).to eq("") + end + end + end + end +end |