diff options
Diffstat (limited to 'spec/controllers/jira_connect/events_controller_spec.rb')
-rw-r--r-- | spec/controllers/jira_connect/events_controller_spec.rb | 165 |
1 files changed, 141 insertions, 24 deletions
diff --git a/spec/controllers/jira_connect/events_controller_spec.rb b/spec/controllers/jira_connect/events_controller_spec.rb index e9fecb594a7..78bd0dc8318 100644 --- a/spec/controllers/jira_connect/events_controller_spec.rb +++ b/spec/controllers/jira_connect/events_controller_spec.rb @@ -3,9 +3,49 @@ require 'spec_helper' RSpec.describe JiraConnect::EventsController do + shared_examples 'verifies asymmetric JWT token' do + context 'when token is valid' do + include_context 'valid JWT token' + + it 'renders successful' do + send_request + + expect(response).to have_gitlab_http_status(:success) + end + end + + context 'when token is invalid' do + include_context 'invalid JWT token' + + it 'renders unauthorized' do + send_request + + expect(response).to have_gitlab_http_status(:unauthorized) + end + end + end + + shared_context 'valid JWT token' do + before do + allow_next_instance_of(Atlassian::JiraConnect::AsymmetricJwt) do |asymmetric_jwt| + allow(asymmetric_jwt).to receive(:valid?).and_return(true) + allow(asymmetric_jwt).to receive(:iss_claim).and_return(client_key) + end + end + end + + shared_context 'invalid JWT token' do + before do + allow_next_instance_of(Atlassian::JiraConnect::AsymmetricJwt) do |asymmetric_jwt| + allow(asymmetric_jwt).to receive(:valid?).and_return(false) + end + end + end + describe '#installed' do let(:client_key) { '1234' } let(:shared_secret) { 'secret' } + let(:params) do { clientKey: client_key, @@ -14,10 +54,16 @@ RSpec.describe JiraConnect::EventsController do } end + include_context 'valid JWT token' + subject do post :installed, params: params end + it_behaves_like 'verifies asymmetric JWT token' do + let(:send_request) { subject } + end + it 'saves the jira installation data' do expect { subject }.to change { JiraConnectInstallation.count }.by(1) end @@ -31,13 +77,15 @@ RSpec.describe JiraConnect::EventsController do expect(installation.base_url).to eq('https://test.atlassian.net') end - context 'client key already exists' do - it 'returns 422' do - create(:jira_connect_installation, client_key: client_key) + context 'when jira_connect_asymmetric_jwt is disabled' do + before do + stub_feature_flags(jira_connect_asymmetric_jwt: false) + end - subject + it 'saves the jira installation data without JWT validation' do + expect(Atlassian::JiraConnect::AsymmetricJwt).not_to receive(:new) - expect(response).to have_gitlab_http_status(:unprocessable_entity) + expect { subject }.to change { JiraConnectInstallation.count }.by(1) end end @@ -49,27 +97,68 @@ RSpec.describe JiraConnect::EventsController do } end - it 'validates the JWT token in authorization header and returns 200 without creating a new installation' do - create(:jira_connect_installation, client_key: client_key, shared_secret: shared_secret) - request.headers["Authorization"] = "Bearer #{Atlassian::Jwt.encode({ iss: client_key }, shared_secret)}" + it 'returns 422' do + subject - expect { subject }.not_to change { JiraConnectInstallation.count } - expect(response).to have_gitlab_http_status(:ok) + expect(response).to have_gitlab_http_status(:unprocessable_entity) end - end - describe '#uninstalled' do - let!(:installation) { create(:jira_connect_installation) } - let(:qsh) { Atlassian::Jwt.create_query_string_hash('https://gitlab.test/events/uninstalled', 'POST', 'https://gitlab.test') } + context 'and an installation exists' do + let!(:installation) { create(:jira_connect_installation, client_key: client_key, shared_secret: shared_secret) } - before do - request.headers['Authorization'] = "JWT #{auth_token}" + it 'validates the JWT token in authorization header and returns 200 without creating a new installation' do + expect { subject }.not_to change { JiraConnectInstallation.count } + expect(response).to have_gitlab_http_status(:ok) + end + + context 'when jira_connect_asymmetric_jwt is disabled' do + before do + stub_feature_flags(jira_connect_asymmetric_jwt: false) + end + + it 'decodes the JWT token in authorization header and returns 200 without creating a new installation' do + request.headers["Authorization"] = "Bearer #{Atlassian::Jwt.encode({ iss: client_key }, shared_secret)}" + + expect(Atlassian::JiraConnect::AsymmetricJwt).not_to receive(:new) + + expect { subject }.not_to change { JiraConnectInstallation.count } + + expect(response).to have_gitlab_http_status(:ok) + end + end end + end + end + + describe '#uninstalled' do + let_it_be(:installation) { create(:jira_connect_installation) } + + let(:client_key) { installation.client_key } + let(:params) do + { + clientKey: client_key, + baseUrl: 'https://test.atlassian.net' + } + end + + it_behaves_like 'verifies asymmetric JWT token' do + let(:send_request) { post :uninstalled, params: params } + end + + subject(:post_uninstalled) { post :uninstalled, params: params } - subject(:post_uninstalled) { post :uninstalled } + context 'when JWT is invalid' do + include_context 'invalid JWT token' - context 'when JWT is invalid' do - let(:auth_token) { 'invalid_token' } + it 'does not delete the installation' do + expect { post_uninstalled }.not_to change { JiraConnectInstallation.count } + end + + context 'when jira_connect_asymmetric_jwt is disabled' do + before do + stub_feature_flags(jira_connect_asymmetric_jwt: false) + request.headers['Authorization'] = 'JWT invalid token' + end it 'returns 403' do post_uninstalled @@ -81,14 +170,42 @@ RSpec.describe JiraConnect::EventsController do expect { post_uninstalled }.not_to change { JiraConnectInstallation.count } end end + end + + context 'when JWT is valid' do + include_context 'valid JWT token' + + let(:jira_base_path) { '/-/jira_connect' } + let(:jira_event_path) { '/-/jira_connect/events/uninstalled' } + + it 'calls the DestroyService and returns ok in case of success' do + expect_next_instance_of(JiraConnectInstallations::DestroyService, installation, jira_base_path, jira_event_path) do |destroy_service| + expect(destroy_service).to receive(:execute).and_return(true) + end + + post_uninstalled + + expect(response).to have_gitlab_http_status(:ok) + end + + it 'calls the DestroyService and returns unprocessable_entity in case of failure' do + expect_next_instance_of(JiraConnectInstallations::DestroyService, installation, jira_base_path, jira_event_path) do |destroy_service| + expect(destroy_service).to receive(:execute).and_return(false) + end + + post_uninstalled + + expect(response).to have_gitlab_http_status(:unprocessable_entity) + end + + context 'when jira_connect_asymmetric_jwt is disabled' do + before do + stub_feature_flags(jira_connect_asymmetric_jwt: false) - context 'when JWT is valid' do - let(:auth_token) do - Atlassian::Jwt.encode({ iss: installation.client_key, qsh: qsh }, installation.shared_secret) + request.headers['Authorization'] = "JWT #{Atlassian::Jwt.encode({ iss: installation.client_key, qsh: qsh }, installation.shared_secret)}" end - let(:jira_base_path) { '/-/jira_connect' } - let(:jira_event_path) { '/-/jira_connect/events/uninstalled' } + let(:qsh) { Atlassian::Jwt.create_query_string_hash('https://gitlab.test/events/uninstalled', 'POST', 'https://gitlab.test') } it 'calls the DestroyService and returns ok in case of success' do expect_next_instance_of(JiraConnectInstallations::DestroyService, installation, jira_base_path, jira_event_path) do |destroy_service| |