diff --git a/ee/lib/api/group_service_accounts.rb b/ee/lib/api/group_service_accounts.rb index d3186918d17b74b6e246cf9fe8baa943ead89c42..09125897501101b3f7d888c3964c193ee4658dc6 100644 --- a/ee/lib/api/group_service_accounts.rb +++ b/ee/lib/api/group_service_accounts.rb @@ -12,6 +12,7 @@ class GroupServiceAccounts < ::API::Base set_current_organization end + helpers ::API::Helpers::PersonalAccessTokensHelpers helpers do def user user_group.provisioned_users.find_by_id(params[:user_id]) @@ -128,12 +129,10 @@ def validate_service_account_user end params do - requires :name, type: String, desc: 'The name of the personal access token' + use :create_personal_access_token_params requires :scopes, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, values: ::Gitlab::Auth.all_available_scopes.map(&:to_s), desc: 'The array of scopes of the personal access token' - optional :expires_at, type: Date, - desc: 'The expiration date of the personal access token in ISO 8601 format' end post do diff --git a/ee/spec/requests/api/group_service_accounts_spec.rb b/ee/spec/requests/api/group_service_accounts_spec.rb index 67663a8041651c67e8892216d187cb52328f88b5..f51f7c31e99e68b03fd2ef171e101982b82b3197 100644 --- a/ee/spec/requests/api/group_service_accounts_spec.rb +++ b/ee/spec/requests/api/group_service_accounts_spec.rb @@ -501,9 +501,10 @@ describe "POST /groups/:id/service_accounts/:user_id/personal_access_tokens" do let(:name) { 'new pat' } + let(:description) { 'description' } let(:expires_at) { 3.days.from_now.to_date.to_s } let(:scopes) { %w[api read_user] } - let(:params) { { name: name, scopes: scopes, expires_at: expires_at } } + let(:params) { { name: name, description: description, expires_at: expires_at, scopes: scopes } } subject(:perform_request) do post( @@ -530,6 +531,7 @@ expect(response).to have_gitlab_http_status(:created) expect(json_response['name']).to eq(name) + expect(json_response['description']).to eq(description) expect(json_response['scopes']).to eq(scopes) expect(json_response['expires_at']).to eq(expires_at) expect(json_response['id']).to be_present diff --git a/ee/spec/requests/api/users_spec.rb b/ee/spec/requests/api/users_spec.rb index 0a43ad565f899b7d6d054d1f0fb7140e57d49ebc..dd7413cc4e94d13172e5478a5fe812bb6d8907b8 100644 --- a/ee/spec/requests/api/users_spec.rb +++ b/ee/spec/requests/api/users_spec.rb @@ -511,9 +511,11 @@ describe 'POST /user/personal_access_tokens', :with_current_organization do let(:name) { 'new pat' } + let(:description) { 'description' } + let(:expires_at) { 3.days.from_now.to_date.to_s } let(:scopes) { %w[k8s_proxy] } let(:path) { "/user/personal_access_tokens" } - let(:params) { { name: name, scopes: scopes } } + let(:params) { { name: name, description: description, expires_at: expires_at, scopes: scopes } } context 'when disable_personal_access_tokens feature is available' do before do @@ -542,8 +544,9 @@ expect(response).to have_gitlab_http_status(:created) expect(json_response['name']).to eq(name) + expect(json_response['description']).to eq(description) + expect(json_response['expires_at']).to eq(expires_at) expect(json_response['scopes']).to eq(scopes) - expect(json_response['expires_at']).to eq(1.day.from_now.to_date.to_s) expect(json_response['id']).to be_present expect(json_response['created_at']).to be_present expect(json_response['active']).to be_truthy diff --git a/lib/api/helpers/personal_access_tokens_helpers.rb b/lib/api/helpers/personal_access_tokens_helpers.rb index cab5ec02e1f507e7ac747c71fae6f56030e53bb6..94fa8e0a99130dd04084e27a8e72f55ccdcd0f81 100644 --- a/lib/api/helpers/personal_access_tokens_helpers.rb +++ b/lib/api/helpers/personal_access_tokens_helpers.rb @@ -26,6 +26,15 @@ module PersonalAccessTokensHelpers optional :sort, type: String, desc: 'Sort tokens', documentation: { example: 'created_at_desc' } end + params :create_personal_access_token_params do + requires :name, type: String, desc: 'The name of the access token', documentation: { example: 'My token' } + optional :description, type: String, desc: 'The description of the access token', + documentation: { example: 'A token used for k8s' } + optional :expires_at, type: Date, desc: "Expiration date of the access token in ISO format (YYYY-MM-DD). " \ + "If undefined, the date is set to the maximum allowable lifetime limit.", + documentation: { example: '2021-01-31' } + end + def finder_params(current_user) user_param = if current_user.can_admin_all_resources? diff --git a/lib/api/resource_access_tokens.rb b/lib/api/resource_access_tokens.rb index 161a68a1bcc0940c455dc0a5878bfd77f7c1ee62..68fa7079deabe12c4a62dfa9b9890e6e80085c49 100644 --- a/lib/api/resource_access_tokens.rb +++ b/lib/api/resource_access_tokens.rb @@ -95,14 +95,11 @@ class ResourceAccessTokens < ::API::Base success Entities::ResourceAccessTokenWithToken end params do + use :create_personal_access_token_params requires :id, type: String, desc: "The #{source_type} ID", documentation: { example: 2 } - requires :name, - type: String, - desc: "Resource access token name", - documentation: { example: 'test' } requires :scopes, type: Array[String], values: ::Gitlab::Auth.resource_bot_scopes.map(&:to_s), @@ -113,10 +110,6 @@ class ResourceAccessTokens < ::API::Base desc: "The expiration date of the token", default: PersonalAccessToken::MAX_PERSONAL_ACCESS_TOKEN_LIFETIME_IN_DAYS.days.from_now, documentation: { example: '"2021-01-31' } - optional :description, - type: String, - desc: "Resource access token description", - documentation: { example: 'test description' } optional :access_level, type: Integer, values: ALLOWED_RESOURCE_ACCESS_LEVELS.values, diff --git a/lib/api/users.rb b/lib/api/users.rb index 75bb425cf928a76e18b61fef5c5feaf20b0018f0..62495a46f5287dfb733bbf7fe4242fbde67383f9 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -31,6 +31,7 @@ class Users < ::API::Base helpers Helpers::UsersHelpers helpers Gitlab::Tracking::Helpers::WeakPasswordErrorEvent + helpers ::API::Helpers::PersonalAccessTokensHelpers helpers do def custom_order_by_or_sort? @@ -1085,11 +1086,9 @@ def target_user success Entities::PersonalAccessTokenWithToken end params do - requires :name, type: String, desc: 'The name of the personal access token' + use :create_personal_access_token_params requires :scopes, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, values: ::Gitlab::Auth.all_available_scopes.map(&:to_s), desc: 'The array of scopes of the personal access token' - optional :description, type: String, desc: 'The description of the personal access token' - optional :expires_at, type: Date, desc: 'The expiration date in the format YEAR-MONTH-DAY of the personal access token' end post feature_category: :system_access do response = ::PersonalAccessTokens::CreateService.new( @@ -1112,6 +1111,8 @@ def target_user set_current_organization end + helpers ::API::Helpers::PersonalAccessTokensHelpers + # Enabling /user endpoint for the v3 version to allow oauth # authentication through this endpoint. version %w[v3 v4], using: :path do @@ -1534,14 +1535,12 @@ def set_user_status(include_missing_params:) success Entities::PersonalAccessTokenWithToken end params do - requires :name, type: String, desc: 'The name of the personal access token' + use :create_personal_access_token_params # NOTE: for security reasons only the k8s_proxy scope is allowed at the moment. # See details in https://gitlab.com/gitlab-org/gitlab/-/merge_requests/131923#note_1571272897 # and in https://gitlab.com/gitlab-org/gitlab/-/issues/425171 requires :scopes, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, values: [::Gitlab::Auth::K8S_PROXY_SCOPE].map(&:to_s), desc: 'The array of scopes of the personal access token' - optional :description, type: String, desc: 'The description of the personal access token' - optional :expires_at, type: Date, default: -> { 1.day.from_now.to_date }, desc: 'The expiration date in the format YEAR-MONTH-DAY of the personal access token' end post feature_category: :system_access do response = ::PersonalAccessTokens::CreateService.new( diff --git a/spec/requests/api/resource_access_tokens_spec.rb b/spec/requests/api/resource_access_tokens_spec.rb index 01f2237c3f0f082bfbc97b99be48caad71f0811c..19f4d27cab393f34dcb25cdc71b2bd88e12dd631 100644 --- a/spec/requests/api/resource_access_tokens_spec.rb +++ b/spec/requests/api/resource_access_tokens_spec.rb @@ -446,7 +446,11 @@ end context "POST #{source_type}s/:id/access_tokens" do - let(:params) { { name: "test", scopes: ["api"], expires_at: expires_at, access_level: access_level } } + let(:params) do + { name: "test", description: "description", scopes: ["api"], expires_at: expires_at, + access_level: access_level } + end + let(:expires_at) { 1.month.from_now } let(:access_level) { 20 } @@ -462,6 +466,7 @@ expect(response).to have_gitlab_http_status(:created) expect(json_response["name"]).to eq("test") + expect(json_response["description"]).to eq("description") expect(json_response["scopes"]).to eq(["api"]) expect(json_response["access_level"]).to eq(20) expect(json_response["expires_at"]).to eq(expires_at.to_date.iso8601) diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index 8c8f1902b9bca0d53a576493f612819d3e86ecc9..73e9a80846753bc6c70e835ae8abb1485dd8356a 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -5084,9 +5084,10 @@ def request let(:name) { 'new pat' } let(:description) { 'new pat description' } + let(:expires_at) { 3.days.from_now.to_date.to_s } let(:scopes) { %w[k8s_proxy] } let(:path) { "/user/personal_access_tokens" } - let(:params) { { name: name, scopes: scopes, description: description } } + let(:params) { { name: name, expires_at: expires_at, description: description, scopes: scopes } } let(:all_scopes) do ::Gitlab::Auth::API_SCOPES + ::Gitlab::Auth::AI_FEATURES_SCOPES + ::Gitlab::Auth::OPENID_SCOPES + @@ -5155,7 +5156,7 @@ def request expect(json_response['name']).to eq(name) expect(json_response['description']).to eq(description) expect(json_response['scopes']).to eq(scopes) - expect(json_response['expires_at']).to eq(1.day.from_now.to_date.to_s) + expect(json_response['expires_at']).to eq(expires_at) expect(json_response['id']).to be_present expect(json_response['created_at']).to be_present expect(json_response['active']).to be_truthy @@ -5176,25 +5177,6 @@ def request expect(json_response['active']).to be_falsey end end - - context 'when expires_at is in the future' do - let(:expires_at) { 1.month.from_now.to_date } - - it 'creates a personal access token' do - post api(path, user), params: params - - expect(response).to have_gitlab_http_status(:created) - expect(json_response['name']).to eq(name) - expect(json_response['description']).to eq(description) - expect(json_response['scopes']).to eq(scopes) - expect(json_response['expires_at']).to eq(1.month.from_now.to_date.to_s) - expect(json_response['id']).to be_present - expect(json_response['created_at']).to be_present - expect(json_response['active']).to be_truthy - expect(json_response['revoked']).to be_falsey - expect(json_response['token']).to be_present - end - end end context 'when an error is thrown by the model' do