diff --git a/doc/api/admin/token.md b/doc/api/admin/token.md index 74c8c31b2302ae75ab61e31e4762b62e975475f0..d801666497576e5d9c62b41e12d3e7cfcd1f6399 100644 --- a/doc/api/admin/token.md +++ b/doc/api/admin/token.md @@ -15,6 +15,7 @@ DETAILS: > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/165157) in GitLab 17.5 [with a flag](../../administration/feature_flags.md) named `admin_agnostic_token_finder`. Disabled by default. > - [Feed tokens added](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/169821) in GitLab 17.6. > - [OAuth application secrets added](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/172985) in GitLab 17.7. +> - [Cluster agent tokens added](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/172932) in GitLab 17.7. FLAG: The availability of this feature is controlled by a feature flag. @@ -39,6 +40,7 @@ Supported tokens: - [Deploy tokens](../../user/project/deploy_tokens/index.md) - [Feed tokens](../../security/tokens/index.md#feed-token) - [OAuth application secrets](../../integration/oauth_provider.md) +- [Cluster agent tokens](../../security/tokens/index.md#gitlab-cluster-agent-tokens) ```plaintext POST /api/v4/admin/token diff --git a/lib/authn/agnostic_token_identifier.rb b/lib/authn/agnostic_token_identifier.rb index 7f04f75e1bcc727c8bced6654c72152506c4d5f4..148d974693c739d5d6c6f93e1caac72d2bcbeeab 100644 --- a/lib/authn/agnostic_token_identifier.rb +++ b/lib/authn/agnostic_token_identifier.rb @@ -8,7 +8,8 @@ class AgnosticTokenIdentifier ::Authn::Tokens::DeployToken, ::Authn::Tokens::FeedToken, ::Authn::Tokens::PersonalAccessToken, - ::Authn::Tokens::OauthApplicationSecret + ::Authn::Tokens::OauthApplicationSecret, + ::Authn::Tokens::ClusterAgentToken ].freeze def self.token_for(plaintext, source) diff --git a/lib/authn/tokens/cluster_agent_token.rb b/lib/authn/tokens/cluster_agent_token.rb new file mode 100644 index 0000000000000000000000000000000000000000..d507a3dacace6bb595c905ca38f62bd0095995dc --- /dev/null +++ b/lib/authn/tokens/cluster_agent_token.rb @@ -0,0 +1,28 @@ +# frozen_string_literal:true + +module Authn + module Tokens + class ClusterAgentToken + def self.prefix?(plaintext) + plaintext.start_with?(::Clusters::AgentToken::TOKEN_PREFIX) + end + + attr_reader :revocable, :source + + def initialize(plaintext, source) + @revocable = ::Clusters::AgentToken.find_by_token(plaintext) + @source = source + end + + def present_with + ::API::Entities::Clusters::AgentToken + end + + def revoke!(_current_user) + raise ::Authn::AgnosticTokenIdentifier::NotFoundError, 'Not Found' if revocable.blank? + + raise ::Authn::AgnosticTokenIdentifier::UnsupportedTokenError, 'Unsupported token type' + end + end + end +end diff --git a/spec/lib/authn/agnostic_token_identifier_spec.rb b/spec/lib/authn/agnostic_token_identifier_spec.rb index 386b91894c2194a7ca984e26561f098e2ddc25dc..424cc75729d3cb4f08d8e4e6eb9b95ce5a378e97 100644 --- a/spec/lib/authn/agnostic_token_identifier_spec.rb +++ b/spec/lib/authn/agnostic_token_identifier_spec.rb @@ -10,6 +10,7 @@ let_it_be(:feed_token) { user.feed_token } let_it_be(:personal_access_token) { create(:personal_access_token, user: user).token } let_it_be(:oauth_application_secret) { create(:oauth_application).plaintext_secret } + let_it_be(:cluster_agent_token) { create(:cluster_agent_token, token_encrypted: nil).token } subject(:token) { described_class.token_for(plaintext, :group_token_revocation_service) } @@ -19,6 +20,7 @@ ref(:feed_token) | ::Authn::Tokens::FeedToken ref(:deploy_token) | ::Authn::Tokens::DeployToken ref(:oauth_application_secret) | ::Authn::Tokens::OauthApplicationSecret + ref(:cluster_agent_token) | ::Authn::Tokens::ClusterAgentToken 'unsupported' | NilClass end diff --git a/spec/lib/authn/tokens/cluster_agent_token_spec.rb b/spec/lib/authn/tokens/cluster_agent_token_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..4f93ad537ca7e423c6fa006850a746f4e041ece0 --- /dev/null +++ b/spec/lib/authn/tokens/cluster_agent_token_spec.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Authn::Tokens::ClusterAgentToken, feature_category: :system_access do + let_it_be(:user) { create(:user) } + + let(:cluster_agent_token) { create(:cluster_agent_token, token_encrypted: nil) } + + subject(:token) { described_class.new(plaintext, :api_admin_token) } + + context 'with valid cluster agent token' do + let(:plaintext) { cluster_agent_token.token } + let(:valid_revocable) { cluster_agent_token } + + it_behaves_like 'finding the valid revocable' + + describe '#revoke!' do + it 'does not support revocation yet' do + expect do + token.revoke!(user) + end.to raise_error(::Authn::AgnosticTokenIdentifier::UnsupportedTokenError, 'Unsupported token type') + end + end + end + + it_behaves_like 'token handling with unsupported token type' +end diff --git a/spec/requests/api/admin/token_spec.rb b/spec/requests/api/admin/token_spec.rb index 2f411f6aab1a34e1a3d7f0bdf551850a4ce59504..60b6dda764af23cd7f4767ebe8735e50514a723c 100644 --- a/spec/requests/api/admin/token_spec.rb +++ b/spec/requests/api/admin/token_spec.rb @@ -11,6 +11,7 @@ let_it_be(:personal_access_token) { create(:personal_access_token, user: user) } let_it_be(:deploy_token) { create(:deploy_token) } let_it_be(:oauth_application) { create(:oauth_application) } + let_it_be(:cluster_agent_token) { create(:cluster_agent_token, token_encrypted: nil) } let(:plaintext) { nil } let(:params) { { token: plaintext } } @@ -25,7 +26,8 @@ [ref(:personal_access_token), lazy { personal_access_token.token }], [ref(:deploy_token), lazy { deploy_token.token }], [ref(:user), lazy { user.feed_token }], - [ref(:oauth_application), lazy { oauth_application.plaintext_secret }] + [ref(:oauth_application), lazy { oauth_application.plaintext_secret }], + [ref(:cluster_agent_token), lazy { cluster_agent_token.token }] ] end