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
diff options
context:
space:
mode:
Diffstat (limited to 'spec/requests/api/internal/kubernetes_spec.rb')
-rw-r--r--spec/requests/api/internal/kubernetes_spec.rb177
1 files changed, 174 insertions, 3 deletions
diff --git a/spec/requests/api/internal/kubernetes_spec.rb b/spec/requests/api/internal/kubernetes_spec.rb
index be76e55269a..c07382a6e04 100644
--- a/spec/requests/api/internal/kubernetes_spec.rb
+++ b/spec/requests/api/internal/kubernetes_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe API::Internal::Kubernetes, feature_category: :kubernetes_management do
+RSpec.describe API::Internal::Kubernetes, feature_category: :deployment_management do
let(:jwt_auth_headers) do
jwt_token = JWT.encode({ 'iss' => Gitlab::Kas::JWT_ISSUER }, Gitlab::Kas.secret, 'HS256')
@@ -59,12 +59,29 @@ RSpec.describe API::Internal::Kubernetes, feature_category: :kubernetes_manageme
end
end
+ shared_examples 'error handling' do
+ let!(:agent_token) { create(:cluster_agent_token) }
+
+ # this test verifies fix for an issue where AgentToken passed in Authorization
+ # header broke error handling in the api_helpers.rb. It can be removed after
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/406582 is done
+ it 'returns correct error for the endpoint' do
+ allow(Gitlab::Kas).to receive(:verify_api_request).and_raise(StandardError.new('Unexpected Error'))
+
+ send_request(headers: { 'Authorization' => "Bearer #{agent_token.token}" })
+
+ expect(response).to have_gitlab_http_status(:internal_server_error)
+ expect(response.body).to include("Unexpected Error")
+ end
+ end
+
describe 'POST /internal/kubernetes/usage_metrics', :clean_gitlab_redis_shared_state do
def send_request(headers: {}, params: {})
post api('/internal/kubernetes/usage_metrics'), params: params, headers: headers.reverse_merge(jwt_auth_headers)
end
include_examples 'authorization'
+ include_examples 'error handling'
context 'is authenticated for an agent' do
let!(:agent_token) { create(:cluster_agent_token) }
@@ -147,19 +164,30 @@ RSpec.describe API::Internal::Kubernetes, feature_category: :kubernetes_manageme
projects: [
{ id: project.full_path, default_namespace: 'staging' }
]
+ },
+ user_access: {
+ groups: [
+ { id: group.full_path }
+ ],
+ projects: [
+ { id: project.full_path }
+ ]
}
}
end
include_examples 'authorization'
+ include_examples 'error handling'
context 'agent exists' do
it 'configures the agent and returns a 204' do
send_request(params: { agent_id: agent.id, agent_config: config })
expect(response).to have_gitlab_http_status(:no_content)
- expect(agent.authorized_groups).to contain_exactly(group)
- expect(agent.authorized_projects).to contain_exactly(project)
+ expect(agent.ci_access_authorized_groups).to contain_exactly(group)
+ expect(agent.ci_access_authorized_projects).to contain_exactly(project)
+ expect(agent.user_access_authorized_groups).to contain_exactly(group)
+ expect(agent.user_access_authorized_projects).to contain_exactly(project)
end
end
@@ -179,6 +207,7 @@ RSpec.describe API::Internal::Kubernetes, feature_category: :kubernetes_manageme
include_examples 'authorization'
include_examples 'agent authentication'
+ include_examples 'error handling'
context 'an agent is found' do
let!(:agent_token) { create(:cluster_agent_token) }
@@ -223,6 +252,7 @@ RSpec.describe API::Internal::Kubernetes, feature_category: :kubernetes_manageme
include_examples 'authorization'
include_examples 'agent authentication'
+ include_examples 'error handling'
context 'an agent is found' do
let_it_be(:agent_token) { create(:cluster_agent_token) }
@@ -306,4 +336,145 @@ RSpec.describe API::Internal::Kubernetes, feature_category: :kubernetes_manageme
end
end
end
+
+ describe 'POST /internal/kubernetes/authorize_proxy_user', :clean_gitlab_redis_sessions do
+ include SessionHelpers
+
+ def send_request(headers: {}, params: {})
+ post api('/internal/kubernetes/authorize_proxy_user'), params: params, headers: headers.reverse_merge(jwt_auth_headers)
+ end
+
+ def stub_user_session(user, csrf_token)
+ stub_session(
+ {
+ 'warden.user.user.key' => [[user.id], user.authenticatable_salt],
+ '_csrf_token' => csrf_token
+ }
+ )
+ end
+
+ def stub_user_session_with_no_user_id(user, csrf_token)
+ stub_session(
+ {
+ 'warden.user.user.key' => [[nil], user.authenticatable_salt],
+ '_csrf_token' => csrf_token
+ }
+ )
+ end
+
+ def mask_token(encoded_token)
+ controller = ActionController::Base.new
+ raw_token = controller.send(:decode_csrf_token, encoded_token)
+ controller.send(:mask_token, raw_token)
+ end
+
+ def new_token
+ ActionController::Base.new.send(:generate_csrf_token)
+ end
+
+ let_it_be(:organization) { create(:group) }
+ let_it_be(:configuration_project) { create(:project, group: organization) }
+ let_it_be(:agent) { create(:cluster_agent, name: 'the-agent', project: configuration_project) }
+ let_it_be(:another_agent) { create(:cluster_agent) }
+ let_it_be(:deployment_project) { create(:project, group: organization) }
+ let_it_be(:deployment_group) { create(:group, parent: organization) }
+
+ let(:user_access_config) do
+ {
+ 'user_access' => {
+ 'access_as' => { 'agent' => {} },
+ 'projects' => [{ 'id' => deployment_project.full_path }],
+ 'groups' => [{ 'id' => deployment_group.full_path }]
+ }
+ }
+ end
+
+ let(:user) { create(:user) }
+
+ before do
+ allow(::Gitlab::Kas).to receive(:enabled?).and_return true
+ Clusters::Agents::Authorizations::UserAccess::RefreshService.new(agent, config: user_access_config).execute
+ end
+
+ it 'returns 400 when cookie is invalid' do
+ send_request(params: { agent_id: agent.id, access_type: 'session_cookie', access_key: '123', csrf_token: mask_token(new_token) })
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+
+ it 'returns 401 when session is not found' do
+ access_key = Gitlab::Kas::UserAccess.encrypt_public_session_id('abc')
+ send_request(params: { agent_id: agent.id, access_type: 'session_cookie', access_key: access_key, csrf_token: mask_token(new_token) })
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+
+ it 'returns 401 when CSRF token does not match' do
+ public_id = stub_user_session(user, new_token)
+ access_key = Gitlab::Kas::UserAccess.encrypt_public_session_id(public_id)
+ send_request(params: { agent_id: agent.id, access_type: 'session_cookie', access_key: access_key, csrf_token: mask_token(new_token) })
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+
+ it 'returns 404 for non-existent agent' do
+ token = new_token
+ public_id = stub_user_session(user, token)
+ access_key = Gitlab::Kas::UserAccess.encrypt_public_session_id(public_id)
+ send_request(params: { agent_id: non_existing_record_id, access_type: 'session_cookie', access_key: access_key, csrf_token: mask_token(token) })
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ it 'returns 403 when user has no access' do
+ token = new_token
+ public_id = stub_user_session(user, token)
+ access_key = Gitlab::Kas::UserAccess.encrypt_public_session_id(public_id)
+ send_request(params: { agent_id: agent.id, access_type: 'session_cookie', access_key: access_key, csrf_token: mask_token(token) })
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+
+ it 'returns 200 when user has access' do
+ deployment_project.add_member(user, :developer)
+ token = new_token
+ public_id = stub_user_session(user, token)
+ access_key = Gitlab::Kas::UserAccess.encrypt_public_session_id(public_id)
+ send_request(params: { agent_id: agent.id, access_type: 'session_cookie', access_key: access_key, csrf_token: mask_token(token) })
+
+ expect(response).to have_gitlab_http_status(:success)
+ end
+
+ it 'returns 401 when user has valid KAS cookie and CSRF token but has no access to requested agent' do
+ deployment_project.add_member(user, :developer)
+ token = new_token
+ public_id = stub_user_session(user, token)
+ access_key = Gitlab::Kas::UserAccess.encrypt_public_session_id(public_id)
+ send_request(params: { agent_id: another_agent.id, access_type: 'session_cookie', access_key: access_key, csrf_token: mask_token(token) })
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+
+ it 'returns 401 when global flag is disabled' do
+ stub_feature_flags(kas_user_access: false)
+
+ deployment_project.add_member(user, :developer)
+ token = new_token
+ public_id = stub_user_session(user, token)
+ access_key = Gitlab::Kas::UserAccess.encrypt_public_session_id(public_id)
+ send_request(params: { agent_id: agent.id, access_type: 'session_cookie', access_key: access_key, csrf_token: mask_token(token) })
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+
+ it 'returns 401 when user id is not found in session' do
+ deployment_project.add_member(user, :developer)
+ token = new_token
+ public_id = stub_user_session_with_no_user_id(user, token)
+ access_key = Gitlab::Kas::UserAccess.encrypt_public_session_id(public_id)
+ send_request(params: { agent_id: agent.id, access_type: 'session_cookie', access_key: access_key, csrf_token: mask_token(token) })
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+ end
end