From a975d6eff6accec051ec009e406302d9c453e116 Mon Sep 17 00:00:00 2001 From: Nicholas Wittstruck <1494491-nwittstruck@users.noreply.gitlab.com> Date: Wed, 27 Nov 2024 11:53:36 +0100 Subject: [PATCH] Admin Token Api: Identify Runner Authentication Tokens Adds support for identification of runner authentication tokens in the Admin Token API. Issue: https://gitlab.com/gitlab-org/gitlab/-/issues/506513 Changelog: changed --- doc/api/admin/token.md | 4 ++- lib/authn/agnostic_token_identifier.rb | 3 +- .../tokens/runner_authentication_token.rb | 28 +++++++++++++++++++ .../authn/agnostic_token_identifier_spec.rb | 2 ++ .../runner_authentication_token_spec.rb | 28 +++++++++++++++++++ spec/requests/api/admin/token_spec.rb | 4 ++- 6 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 lib/authn/tokens/runner_authentication_token.rb create mode 100644 spec/lib/authn/tokens/runner_authentication_token_spec.rb diff --git a/doc/api/admin/token.md b/doc/api/admin/token.md index d801666497576e..3b68f042ffd7fc 100644 --- a/doc/api/admin/token.md +++ b/doc/api/admin/token.md @@ -16,6 +16,7 @@ DETAILS: > - [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. +> - [Runner authentication tokens added](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/173987) in GitLab 17.7. FLAG: The availability of this feature is controlled by a feature flag. @@ -30,7 +31,7 @@ Prerequisites: - You must be an administrator. -## Get Token Information +## Identify Token Returns information about a token. @@ -41,6 +42,7 @@ Supported tokens: - [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) +- [Runner authentication tokens](../../security/tokens/index.md#runner-authentication-tokens) ```plaintext POST /api/v4/admin/token diff --git a/lib/authn/agnostic_token_identifier.rb b/lib/authn/agnostic_token_identifier.rb index 148d974693c739..ccb20da2e81c37 100644 --- a/lib/authn/agnostic_token_identifier.rb +++ b/lib/authn/agnostic_token_identifier.rb @@ -9,7 +9,8 @@ class AgnosticTokenIdentifier ::Authn::Tokens::FeedToken, ::Authn::Tokens::PersonalAccessToken, ::Authn::Tokens::OauthApplicationSecret, - ::Authn::Tokens::ClusterAgentToken + ::Authn::Tokens::ClusterAgentToken, + ::Authn::Tokens::RunnerAuthenticationToken ].freeze def self.token_for(plaintext, source) diff --git a/lib/authn/tokens/runner_authentication_token.rb b/lib/authn/tokens/runner_authentication_token.rb new file mode 100644 index 00000000000000..d0422de2308b95 --- /dev/null +++ b/lib/authn/tokens/runner_authentication_token.rb @@ -0,0 +1,28 @@ +# frozen_string_literal:true + +module Authn + module Tokens + class RunnerAuthenticationToken + def self.prefix?(plaintext) + plaintext.start_with?(Ci::Runner::CREATED_RUNNER_TOKEN_PREFIX) + end + + attr_reader :revocable, :source + + def initialize(plaintext, source) + @revocable = ::Ci::Runner.find_by_token(plaintext) + @source = source + end + + def present_with + ::API::Entities::Ci::Runner + 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 424cc75729d3cb..89b0d80ce7a41e 100644 --- a/spec/lib/authn/agnostic_token_identifier_spec.rb +++ b/spec/lib/authn/agnostic_token_identifier_spec.rb @@ -11,6 +11,7 @@ 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 } + let_it_be(:runner_authentication_token) { create(:ci_runner, registration_type: :authenticated_user).token } subject(:token) { described_class.token_for(plaintext, :group_token_revocation_service) } @@ -21,6 +22,7 @@ ref(:deploy_token) | ::Authn::Tokens::DeployToken ref(:oauth_application_secret) | ::Authn::Tokens::OauthApplicationSecret ref(:cluster_agent_token) | ::Authn::Tokens::ClusterAgentToken + ref(:runner_authentication_token) | ::Authn::Tokens::RunnerAuthenticationToken 'unsupported' | NilClass end diff --git a/spec/lib/authn/tokens/runner_authentication_token_spec.rb b/spec/lib/authn/tokens/runner_authentication_token_spec.rb new file mode 100644 index 00000000000000..23055467613a29 --- /dev/null +++ b/spec/lib/authn/tokens/runner_authentication_token_spec.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Authn::Tokens::RunnerAuthenticationToken, feature_category: :system_access do + let_it_be(:user) { create(:user) } + + let(:runner) { create(:ci_runner, registration_type: :authenticated_user) } + + subject(:token) { described_class.new(plaintext, :api_admin_token) } + + context 'with valid runner authentication token' do + let(:plaintext) { runner.token } + let(:valid_revocable) { runner } + + 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 60b6dda764af23..1c9415489ef2fb 100644 --- a/spec/requests/api/admin/token_spec.rb +++ b/spec/requests/api/admin/token_spec.rb @@ -12,6 +12,7 @@ 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_it_be(:runner_authentication_token) { create(:ci_runner, registration_type: :authenticated_user) } let(:plaintext) { nil } let(:params) { { token: plaintext } } @@ -27,7 +28,8 @@ [ref(:deploy_token), lazy { deploy_token.token }], [ref(:user), lazy { user.feed_token }], [ref(:oauth_application), lazy { oauth_application.plaintext_secret }], - [ref(:cluster_agent_token), lazy { cluster_agent_token.token }] + [ref(:cluster_agent_token), lazy { cluster_agent_token.token }], + [ref(:runner_authentication_token), lazy { runner_authentication_token.token }] ] end -- GitLab