NARKOZ / gitlab

Ruby wrapper and CLI for the GitLab REST API
https://narkoz.github.io/gitlab
BSD 2-Clause "Simplified" License
1.06k stars 394 forks source link

Support using CI_JOB_TOKEN for authentication #668

Closed balasankarc closed 7 months ago

balasankarc commented 1 year ago

When using the job token, the header needs to be JOB-TOKEN instead of PRIVATE-TOKEN.

Starting with GitLab 14.5, glpat- is used as a default prefix for personal access tokens (though this is configurable). So maybe we can accept pat_prefix as an argument, and then detect if the specified token starts with it or not, and then set the headers accordingly?

balasankarc commented 1 year ago

Maybe something like the following?

diff --git a/lib/gitlab/configuration.rb b/lib/gitlab/configuration.rb
index 8c37354..fa5fcc7 100644
--- a/lib/gitlab/configuration.rb
+++ b/lib/gitlab/configuration.rb
@@ -5,7 +5,7 @@ module Gitlab
   # Defines constants and methods related to configuration.
   module Configuration
     # An array of valid keys in the options hash when configuring a Gitlab::API.
-    VALID_OPTIONS_KEYS = %i[endpoint private_token user_agent sudo httparty].freeze
+    VALID_OPTIONS_KEYS = %i[endpoint private_token user_agent sudo httparty pat_prefix].freeze

     # The user agent that will be sent to the API endpoint if none is set.
     DEFAULT_USER_AGENT = "Gitlab Ruby Gem #{Gitlab::VERSION}"
@@ -37,6 +37,7 @@ module Gitlab
     def reset
       self.endpoint       = ENV['GITLAB_API_ENDPOINT'] || ENV['CI_API_V4_URL']
       self.private_token  = ENV['GITLAB_API_PRIVATE_TOKEN'] || ENV['GITLAB_API_AUTH_TOKEN']
+      self.pat_prefix     = 'glpat-'
       self.httparty       = get_httparty_config(ENV['GITLAB_API_HTTPARTY_OPTIONS'])
       self.sudo           = nil
       self.user_agent     = DEFAULT_USER_AGENT
diff --git a/lib/gitlab/request.rb b/lib/gitlab/request.rb
index 218b81b..307f5ee 100644
--- a/lib/gitlab/request.rb
+++ b/lib/gitlab/request.rb
@@ -12,7 +12,7 @@ module Gitlab
     headers 'Accept' => 'application/json', 'Content-Type' => 'application/x-www-form-urlencoded'
     parser(proc { |body, _| parse(body) })

-    attr_accessor :private_token, :endpoint
+    attr_accessor :private_token, :endpoint, :pat_prefix

     # Converts the response body to an ObjectifiedHash.
     def self.parse(body)
@@ -93,10 +93,21 @@ module Gitlab
     def authorization_header
       raise Error::MissingCredentials, 'Please provide a private_token or auth_token for user' unless private_token

-      if private_token.size < 21
+      pat_prefix ||= 'glpat-'
+
+      # The Personal Access Token prefix can be at most 20 characters, and the
+      # generated part is of length 20 characters. Personal Access Tokens, thus
+      # can have a maximum size of 40 characters. GitLab uses
+      # `Doorkeeper::OAuth::Helpers::UniqueToken.generate` for generating
+      # OAuth2 tokens, and specified `hex` as token generator method. Thus, the
+      # OAuth2 tokens are of length more than 64. If the token length is below
+      # that, it is probably a Personal Access Token or CI_JOB_TOKEN.
+      if private_token.size >= 64
+        { 'Authorization' => "Bearer #{private_token}" }
+      elsif private_token.start_with?(pat_prefix)
         { 'PRIVATE-TOKEN' => private_token }
       else
-        { 'Authorization' => "Bearer #{private_token}" }
+        { 'JOB-TOKEN' => private_token }
       end
     end
balasankarc commented 1 year ago

I tested the above diff in https://gitlab.com/balasankarc/test-ci-job-token-gitlab-gem/-/jobs/4372664465 (you can check https://gitlab.com/balasankarc/test-ci-job-token-gitlab-gem/-/blob/main/code.rb to see what it does)

brodock commented 1 year ago

@balasankarc 👋 do you think we can have the token be a bit smarter without requiring pat_prefix? My understanding is that the prefix is not relevant... we can test if ENV['CI_JOB_TOKEN'] is present and use the 'JOB-TOKEN' instead, wdyt?

github-actions[bot] commented 11 months ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

brodock commented 11 months ago

not stale

balasankarc commented 10 months ago

@brodock Users might want to explicitly use a normal PAT even in CI, because Job token can't access all endpoints. Which is why I went with making it an explicit decision than an automatic detection.

github-actions[bot] commented 7 months ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.