Commit f027a6f2 authored by Kyle Edwards's avatar Kyle Edwards

API: Add endpoint to reset runner token with old token

By providing the old token, as long as it is not expired, the user
proves that they have the rights to the runner, and can reset the
runner token. This allows them to reset the token without a PAT.

Changelog: added
Issue: https://gitlab.com/gitlab-org/gitlab/-/issues/30942
Issue: https://gitlab.com/gitlab-org/gitlab/-/issues/345427
parent 94c2aa6c
......@@ -15,7 +15,7 @@ There are two tokens to take into account when connecting a runner with GitLab.
| Token | Description |
| ----- | ----------- |
| Registration token | Token used to [register the runner](https://docs.gitlab.com/runner/register/). It can be [obtained through GitLab](../ci/runners/index.md). |
| Authentication token | Token used to authenticate the runner with the GitLab instance. It is obtained automatically when you [register a runner](https://docs.gitlab.com/runner/register/) or by the Runner API when you manually [register a runner](#register-a-new-runner) or [reset the authentication token](#reset-runners-authentication-token). |
| Authentication token | Token used to authenticate the runner with the GitLab instance. It is obtained automatically when you [register a runner](https://docs.gitlab.com/runner/register/) or by the Runner API when you manually [register a runner](#register-a-new-runner) or [reset the authentication token](#reset-runners-authentication-token-by-using-the-runner-id). |
Here's an example of how the two tokens are used in runner registration:
......@@ -799,9 +799,9 @@ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
"https://gitlab.example.com/api/v4/groups/9/runners/reset_registration_token"
```
## Reset runner's authentication token
## Reset runner's authentication token by using the runner ID
Resets the runner's authentication token.
Resets the runner's authentication token by using its runner ID.
```plaintext
POST /runners/:id/reset_authentication_token
......@@ -824,3 +824,29 @@ Example response:
"token_expires_at": "2021-09-27T21:05:03.203Z"
}
```
## Reset runner's authentication token by using the current token
Resets the runner's authentication token by using the current token's value as an input.
```plaintext
POST /runners/reset_authentication_token
```
| Attribute | Type | Required | Description |
|-----------|---------|----------|---------------------------------|
| `token` | string | yes | The current token of the runner |
```shell
curl --request POST --form "token=<current token>" \
"https://gitlab.example.com/api/v4/runners/reset_authentication_token"
```
Example response:
```json
{
"token": "6337ff461c94fd3fa32ba3b1ff4125",
"token_expires_at": "2021-09-27T21:05:03.203Z"
}
```
......@@ -71,6 +71,19 @@ module API
status 200
body "200"
end
desc 'Reset runner authentication token with current token' do
success Entities::Ci::ResetTokenResult
end
params do
requires :token, type: String, desc: 'The current authentication token of the runner'
end
post '/reset_authentication_token', feature_category: :runner do
authenticate_runner!
current_runner.reset_token!
present current_runner.token_with_expiration, with: Entities::Ci::ResetTokenResult
end
end
resource :jobs do
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
include StubGitlabCalls
include RedisHelpers
include WorkhorseHelpers
before do
stub_feature_flags(ci_enable_live_trace: true)
stub_feature_flags(runner_registration_control: false)
stub_gitlab_calls
stub_application_setting(valid_runner_registrars: ApplicationSetting::VALID_RUNNER_REGISTRAR_TYPES)
end
let_it_be(:group_settings) { create(:namespace_settings, runner_token_expiration_interval: 5.days.to_i) }
let_it_be(:group) { create(:group, namespace_settings: group_settings) }
let_it_be(:instance_runner, reload: true) { create(:ci_runner, :instance) }
let_it_be(:group_runner) { create(:ci_runner, :group, groups: [group], token_expires_at: 1.day.from_now) }
describe 'POST /runners/reset_authentication_token', :freeze_time do
context 'current token provided' do
it "resets authentication token when token doesn't have an expiration" do
expect do
post api("/runners/reset_authentication_token"), params: { token: instance_runner.reload.token }
expect(response).to have_gitlab_http_status(:success)
expect(json_response).to eq({ 'token' => instance_runner.reload.token, 'token_expires_at' => nil })
expect(instance_runner.reload.token_expires_at).to be_nil
end.to change { instance_runner.reload.token }
end
it 'resets authentication token when token is not expired' do
expect do
post api("/runners/reset_authentication_token"), params: { token: group_runner.reload.token }
expect(response).to have_gitlab_http_status(:success)
expect(json_response).to eq({ 'token' => group_runner.reload.token, 'token_expires_at' => group_runner.reload.token_expires_at.iso8601(3) })
expect(group_runner.reload.token_expires_at).to eq(5.days.from_now)
end.to change { group_runner.reload.token }
end
it 'does not reset authentication token when token is expired' do
expect do
instance_runner.update!(token_expires_at: 1.day.ago)
post api("/runners/reset_authentication_token"), params: { token: instance_runner.reload.token }
expect(response).to have_gitlab_http_status(:forbidden)
instance_runner.update!(token_expires_at: nil)
end.not_to change { instance_runner.reload.token }
end
end
context 'wrong current token provided' do
it 'does not reset authentication token' do
expect do
post api("/runners/reset_authentication_token"), params: { token: 'garbage' }
expect(response).to have_gitlab_http_status(:forbidden)
end.not_to change { instance_runner.reload.token }
end
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment