diff --git a/doc/api/admin/token.md b/doc/api/admin/token.md index 01266a4518bcb71dd01f0d409670b8411fc0d2c2..b305a2abfe141a7e797f5ce3ce8368974b1e3e18 100644 --- a/doc/api/admin/token.md +++ b/doc/api/admin/token.md @@ -33,6 +33,7 @@ Prerequisites: > - [CI/CD Job Tokens added](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/175234) in GitLab 17.9. > - [Feature flags client tokens added](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/177431) in GitLab 17.9. > - [GitLab session cookies added](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/178022) in GitLab 17.9. +> - [Incoming email tokens added](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/177077) in GitLab 17.9. Gets information for a given token. This endpoint supports the following tokens: @@ -47,6 +48,7 @@ Gets information for a given token. This endpoint supports the following tokens: - [CI/CD Job Tokens](../../security/tokens/_index.md#cicd-job-tokens) - [Feature flags client tokens](../../operations/feature_flags.md#get-access-credentials) - [GitLab session cookies](../../user/profile/active_sessions.md) +- [Incoming email tokens](../../security/tokens/_index.md#incoming-email-token) ```plaintext POST /api/v4/admin/token diff --git a/lib/authn/agnostic_token_identifier.rb b/lib/authn/agnostic_token_identifier.rb index e727b9763e16cb7b439a609a4055ed9ed98b3a11..01b83cb60ebbb9c28bac972d80fcace48929917b 100644 --- a/lib/authn/agnostic_token_identifier.rb +++ b/lib/authn/agnostic_token_identifier.rb @@ -14,7 +14,8 @@ class AgnosticTokenIdentifier ::Authn::Tokens::CiTriggerToken, ::Authn::Tokens::CiJobToken, ::Authn::Tokens::FeatureFlagsClientToken, - ::Authn::Tokens::GitlabSession + ::Authn::Tokens::GitlabSession, + ::Authn::Tokens::IncomingEmailToken ].freeze def self.token_for(plaintext, source) diff --git a/lib/authn/tokens/incoming_email_token.rb b/lib/authn/tokens/incoming_email_token.rb new file mode 100644 index 0000000000000000000000000000000000000000..e4d2fd47686d5bb95e1c1eada7f251dc7d1a2fa4 --- /dev/null +++ b/lib/authn/tokens/incoming_email_token.rb @@ -0,0 +1,28 @@ +# frozen_string_literal:true + +module Authn + module Tokens + class IncomingEmailToken + def self.prefix?(plaintext) + plaintext.start_with?(::User::INCOMING_MAIL_TOKEN_PREFIX) + end + + attr_reader :revocable, :source + + def initialize(plaintext, source) + @revocable = ::User.find_by_incoming_email_token(plaintext) + @source = source + end + + def present_with + ::API::Entities::User + 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 09d3b4a90c8594680a117b119c9500583abcf2b8..923f67fcc87e140a9c50b9d79ed504e65e6fc3d1 100644 --- a/spec/lib/authn/agnostic_token_identifier_spec.rb +++ b/spec/lib/authn/agnostic_token_identifier_spec.rb @@ -24,6 +24,7 @@ let_it_be(:ci_trigger_token) { create(:ci_trigger).token } let_it_be(:feature_flags_client_token) { create(:operations_feature_flags_client).token } let_it_be(:gitlab_session) { '_gitlab_session=session_id' } + let_it_be(:incoming_email_token) { user.incoming_email_token } subject(:token) { described_class.token_for(plaintext, :group_token_revocation_service) } @@ -39,6 +40,7 @@ ref(:ci_trigger_token) | ::Authn::Tokens::CiTriggerToken ref(:feature_flags_client_token) | ::Authn::Tokens::FeatureFlagsClientToken ref(:gitlab_session) | ::Authn::Tokens::GitlabSession + ref(:incoming_email_token) | ::Authn::Tokens::IncomingEmailToken 'unsupported' | NilClass end diff --git a/spec/lib/authn/tokens/incoming_email_token_spec.rb b/spec/lib/authn/tokens/incoming_email_token_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..bf44a3f4650eb85b6079bf73e7364b1eac2dc8a5 --- /dev/null +++ b/spec/lib/authn/tokens/incoming_email_token_spec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Authn::Tokens::IncomingEmailToken, feature_category: :system_access do + let_it_be(:user) { create(:user) } + + subject(:token) { described_class.new(plaintext, :api_admin_token) } + + context 'with valid incoming email token' do + let(:plaintext) { user.incoming_email_token } + let(:valid_revocable) { user } + + 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 40781e461c1f1f20c64fd092476371a22a990245..424783c5fb1e9f8483d956b11f564ad1bbbfc9e2 100644 --- a/spec/requests/api/admin/token_spec.rb +++ b/spec/requests/api/admin/token_spec.rb @@ -70,6 +70,7 @@ [ref(:group_deploy_token), lazy { group_deploy_token.token }], [ref(:project_deploy_token), lazy { project_deploy_token.token }], [ref(:user), lazy { user.feed_token }], + [ref(:user), lazy { user.incoming_email_token }], [ref(:oauth_application), lazy { oauth_application.plaintext_secret }], [ref(:cluster_agent_token), lazy { cluster_agent_token.token }], [ref(:runner_authentication_token), lazy { runner_authentication_token.token }],