Skip to content

Commit

Permalink
Support Access service token rotation
Browse files Browse the repository at this point in the history
  • Loading branch information
Jesse Li committed Oct 27, 2022
1 parent 6a81124 commit e2db782
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .changelog/1120.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
access: add support for service token rotation
```
41 changes: 41 additions & 0 deletions access_service_tokens.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,18 @@ type AccessServiceTokenCreateResponse struct {
ClientSecret string `json:"client_secret"`
}

// AccessServiceTokenRotateResponse is the same API response as the Create
// operation.
type AccessServiceTokenRotateResponse struct {
CreatedAt *time.Time `json:"created_at"`
UpdatedAt *time.Time `json:"updated_at"`
ExpiresAt *time.Time `json:"expires_at"`
ID string `json:"id"`
Name string `json:"name"`
ClientID string `json:"client_id"`
ClientSecret string `json:"client_secret"`
}

// AccessServiceTokensListResponse represents the response from the list
// Access Service Tokens endpoint.
type AccessServiceTokensListResponse struct {
Expand Down Expand Up @@ -98,6 +110,15 @@ type AccessServiceTokensRefreshDetailResponse struct {
Result AccessServiceTokenRefreshResponse `json:"result"`
}

// AccessServiceTokensRotateSecretDetailResponse is the API response, containing a
// single Access Service Token.
type AccessServiceTokensRotateSecretDetailResponse struct {
Success bool `json:"success"`
Errors []string `json:"errors"`
Messages []string `json:"messages"`
Result AccessServiceTokenRotateResponse `json:"result"`
}

// AccessServiceTokens returns all Access Service Tokens for an account.
//
// API reference: https://api.cloudflare.com/#access-service-tokens-list-access-service-tokens
Expand Down Expand Up @@ -254,3 +275,23 @@ func (api *API) RefreshAccessServiceToken(ctx context.Context, rc *ResourceConta

return accessServiceTokenRefresh.Result, nil
}

// RotateAccessServiceToken rotates the client secret of an Access Service
// Token in place.
// API reference: https://api.cloudflare.com/#access-service-tokens-rotate-a-service-token
func (api *API) RotateAccessServiceToken(ctx context.Context, rc *ResourceContainer, id string) (AccessServiceTokenRotateResponse, error) {
uri := fmt.Sprintf("/%s/%s/access/service_tokens/%s/rotate", rc.Level, rc.Identifier, id)

res, err := api.makeRequestContext(ctx, http.MethodPost, uri, nil)
if err != nil {
return AccessServiceTokenRotateResponse{}, err
}

var accessServiceTokenRotate AccessServiceTokensRotateSecretDetailResponse
err = json.Unmarshal(res, &accessServiceTokenRotate)
if err != nil {
return AccessServiceTokenRotateResponse{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
}

return accessServiceTokenRotate.Result, nil
}
43 changes: 43 additions & 0 deletions access_service_tokens_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,49 @@ func TestRefreshAccessServiceToken(t *testing.T) {
}
}

func TestRotateAccessServiceToken(t *testing.T) {
setup()
defer teardown()

handler := func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodPost, r.Method, "Expected method 'POST', got %s", r.Method)
w.Header().Set("content-type", "application/json")
fmt.Fprintf(w, `{
"success": true,
"errors": [],
"messages": [],
"result": {
"created_at": "2014-01-01T05:20:00.12345Z",
"updated_at": "2014-01-01T05:20:00.12345Z",
"expires_at": "2015-01-01T05:20:00.12345Z",
"id": "f174e90a-fafe-4643-bbbc-4a0ed4fc8415",
"name": "CI/CD token",
"client_id": "88bf3b6d86161464f6509f7219099e57.access.example.com",
"client_secret": "bdd31cbc4dec990953e39163fbbb194c93313ca9f0a6e420346af9d326b1d2a5"
}
}
`)
}

expected := AccessServiceTokenRotateResponse{
CreatedAt: &createdAt,
UpdatedAt: &updatedAt,
ExpiresAt: &expiresAt,
ID: "f174e90a-fafe-4643-bbbc-4a0ed4fc8415",
Name: "CI/CD token",
ClientID: "88bf3b6d86161464f6509f7219099e57.access.example.com",
ClientSecret: "bdd31cbc4dec990953e39163fbbb194c93313ca9f0a6e420346af9d326b1d2a5",
}

mux.HandleFunc("/accounts/"+testAccountID+"/access/service_tokens/f174e90a-fafe-4643-bbbc-4a0ed4fc8415/rotate", handler)

actual, err := client.RotateAccessServiceToken(context.Background(), AccountIdentifier(testAccountID), "f174e90a-fafe-4643-bbbc-4a0ed4fc8415")

if assert.NoError(t, err) {
assert.Equal(t, expected, actual)
}
}

func TestDeleteAccessServiceToken(t *testing.T) {
setup()
defer teardown()
Expand Down

0 comments on commit e2db782

Please sign in to comment.