diff options
Diffstat (limited to 'spec/requests/api/internal/base_spec.rb')
-rw-r--r-- | spec/requests/api/internal/base_spec.rb | 334 |
1 files changed, 202 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) |