mirror of
https://github.com/grafana/grafana.git
synced 2024-11-25 10:20:29 -06:00
API Keys: Removal & Redirect of Create endpoint (#92144)
* API keys: redirecting of create endpont * update naming and using admonition * fmt * Apply suggestions from code review Co-authored-by: Ieva <ieva.vasiljeva@grafana.com> --------- Co-authored-by: Ieva <ieva.vasiljeva@grafana.com>
This commit is contained in:
parent
909d0fac35
commit
6a19278f23
@ -29,6 +29,11 @@ If you use Grafana v9.1 or newer, use service accounts instead of API keys. For
|
|||||||
|
|
||||||
## List API keys
|
## List API keys
|
||||||
|
|
||||||
|
{{% admonition type="warning" %}}
|
||||||
|
This endpoint is deprecated.
|
||||||
|
|
||||||
|
{{% /admonition %}}
|
||||||
|
|
||||||
`GET /api/auth/keys`
|
`GET /api/auth/keys`
|
||||||
|
|
||||||
**Required permissions**
|
**Required permissions**
|
||||||
@ -75,6 +80,13 @@ Content-Type: application/json
|
|||||||
|
|
||||||
## Create API Key
|
## Create API Key
|
||||||
|
|
||||||
|
{{% admonition type="warning" %}}
|
||||||
|
This endpoint has been made obsolete in Grafana 11.3.0.
|
||||||
|
|
||||||
|
{{% /admonition %}}
|
||||||
|
|
||||||
|
Endpoint is obsolete and has been moved to [Grafana service account API]({{< relref "./serviceaccount/" >}}). For more information, refer to [Migrate to Grafana service account API]({{< relref "../../administration/api-keys/#migrate-api-keys-to-grafana-service-accounts-using-the-api" >}}).
|
||||||
|
|
||||||
`POST /api/auth/keys`
|
`POST /api/auth/keys`
|
||||||
|
|
||||||
**Required permissions**
|
**Required permissions**
|
||||||
@ -114,14 +126,20 @@ Error statuses:
|
|||||||
**Example Response**:
|
**Example Response**:
|
||||||
|
|
||||||
```http
|
```http
|
||||||
HTTP/1.1 200
|
HTTP/1.1 301
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
|
|
||||||
{"name":"mykey","key":"eyJrIjoiWHZiSWd3NzdCYUZnNUtibE9obUpESmE3bzJYNDRIc0UiLCJuIjoibXlrZXkiLCJpZCI6MX1=","id":1}
|
""
|
||||||
```
|
```
|
||||||
|
|
||||||
## Delete API Key
|
## Delete API Key
|
||||||
|
|
||||||
|
{{% admonition type="warning" %}}
|
||||||
|
|
||||||
|
### DEPRECATED
|
||||||
|
|
||||||
|
{{% /admonition %}}
|
||||||
|
|
||||||
`DELETE /api/auth/keys/:id`
|
`DELETE /api/auth/keys/:id`
|
||||||
|
|
||||||
**Required permissions**
|
**Required permissions**
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
|
|
||||||
"github.com/grafana/grafana/pkg/api/dtos"
|
"github.com/grafana/grafana/pkg/api/dtos"
|
||||||
"github.com/grafana/grafana/pkg/api/response"
|
"github.com/grafana/grafana/pkg/api/response"
|
||||||
"github.com/grafana/grafana/pkg/components/apikeygen"
|
|
||||||
"github.com/grafana/grafana/pkg/services/apikey"
|
"github.com/grafana/grafana/pkg/services/apikey"
|
||||||
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
||||||
"github.com/grafana/grafana/pkg/web"
|
"github.com/grafana/grafana/pkg/web"
|
||||||
@ -114,59 +113,15 @@ func (hs *HTTPServer) DeleteAPIKey(c *contextmodel.ReqContext) response.Response
|
|||||||
// see: https://grafana.com/docs/grafana/next/administration/api-keys/#migrate-api-keys-to-grafana-service-accounts-using-the-api.
|
// see: https://grafana.com/docs/grafana/next/administration/api-keys/#migrate-api-keys-to-grafana-service-accounts-using-the-api.
|
||||||
//
|
//
|
||||||
// Responses:
|
// Responses:
|
||||||
// 200: postAPIkeyResponse
|
// 301: statusMovedPermanently
|
||||||
// 400: badRequestError
|
|
||||||
// 401: unauthorisedError
|
|
||||||
// 403: forbiddenError
|
|
||||||
// 409: conflictError
|
|
||||||
// 500: internalServerError
|
|
||||||
func (hs *HTTPServer) AddAPIKey(c *contextmodel.ReqContext) response.Response {
|
func (hs *HTTPServer) AddAPIKey(c *contextmodel.ReqContext) response.Response {
|
||||||
cmd := apikey.AddCommand{}
|
// Set the Location header to the new URL
|
||||||
if err := web.Bind(c.Req, &cmd); err != nil {
|
hs.log.Warn("Obsolete and Permanently moved API endpoint called", "path", c.Req.URL.Path)
|
||||||
return response.Error(http.StatusBadRequest, "bad request data", err)
|
c.Context.Resp.Header().Set("Location", "/api/serviceaccounts/tokens")
|
||||||
}
|
|
||||||
if !cmd.Role.IsValid() {
|
|
||||||
return response.Error(http.StatusBadRequest, "Invalid role specified", nil)
|
|
||||||
}
|
|
||||||
if !c.SignedInUser.GetOrgRole().Includes(cmd.Role) {
|
|
||||||
return response.Error(http.StatusForbidden, "Cannot assign a role higher than user's role", nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
if hs.Cfg.ApiKeyMaxSecondsToLive != -1 {
|
// Respond with a 301 Moved Permanently status code
|
||||||
if cmd.SecondsToLive == 0 {
|
// the Location header is enough for clients to know where to go next.
|
||||||
return response.Error(http.StatusBadRequest, "Number of seconds before expiration should be set", nil)
|
return response.JSON(http.StatusMovedPermanently, nil)
|
||||||
}
|
|
||||||
if cmd.SecondsToLive > hs.Cfg.ApiKeyMaxSecondsToLive {
|
|
||||||
return response.Error(http.StatusBadRequest, "Number of seconds before expiration is greater than the global limit", nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd.OrgID = c.SignedInUser.GetOrgID()
|
|
||||||
|
|
||||||
newKeyInfo, err := apikeygen.New(cmd.OrgID, cmd.Name)
|
|
||||||
if err != nil {
|
|
||||||
return response.Error(http.StatusInternalServerError, "Generating API key failed", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd.Key = newKeyInfo.HashedKey
|
|
||||||
key, err := hs.apiKeyService.AddAPIKey(c.Req.Context(), &cmd)
|
|
||||||
if err != nil {
|
|
||||||
if errors.Is(err, apikey.ErrInvalidExpiration) {
|
|
||||||
return response.Error(http.StatusBadRequest, err.Error(), nil)
|
|
||||||
}
|
|
||||||
if errors.Is(err, apikey.ErrDuplicate) {
|
|
||||||
return response.Error(http.StatusConflict, err.Error(), nil)
|
|
||||||
}
|
|
||||||
return response.Error(http.StatusInternalServerError, "Failed to add API Key", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
result := &dtos.NewApiKeyResult{
|
|
||||||
ID: key.ID,
|
|
||||||
Name: key.Name,
|
|
||||||
Key: newKeyInfo.ClientSecret,
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.JSON(http.StatusOK, result)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// swagger:parameters getAPIkeys
|
// swagger:parameters getAPIkeys
|
||||||
@ -178,13 +133,6 @@ type GetAPIkeysParams struct {
|
|||||||
IncludeExpired bool `json:"includeExpired"`
|
IncludeExpired bool `json:"includeExpired"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// swagger:parameters addAPIkey
|
|
||||||
type AddAPIkeyParams struct {
|
|
||||||
// in:body
|
|
||||||
// required:true
|
|
||||||
Body apikey.AddCommand
|
|
||||||
}
|
|
||||||
|
|
||||||
// swagger:parameters deleteAPIkey
|
// swagger:parameters deleteAPIkey
|
||||||
type DeleteAPIkeyParams struct {
|
type DeleteAPIkeyParams struct {
|
||||||
// in:path
|
// in:path
|
||||||
|
@ -82,6 +82,11 @@ type UnauthorizedError GenericError
|
|||||||
// swagger:response acceptedResponse
|
// swagger:response acceptedResponse
|
||||||
type AcceptedResponse GenericError
|
type AcceptedResponse GenericError
|
||||||
|
|
||||||
|
// StatusMovedPermanently
|
||||||
|
//
|
||||||
|
// swagger:response statusMovedPermanently
|
||||||
|
type StatusMovedPermanentlyRedirect GenericError
|
||||||
|
|
||||||
// documentation for PublicError defined in errutil.Error
|
// documentation for PublicError defined in errutil.Error
|
||||||
|
|
||||||
// swagger:response publicErrorResponse
|
// swagger:response publicErrorResponse
|
||||||
|
@ -2225,34 +2225,9 @@
|
|||||||
"summary": "Creates an API key.",
|
"summary": "Creates an API key.",
|
||||||
"operationId": "addAPIkey",
|
"operationId": "addAPIkey",
|
||||||
"deprecated": true,
|
"deprecated": true,
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "Body",
|
|
||||||
"in": "body",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/AddAPIKeyCommand"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"301": {
|
||||||
"$ref": "#/responses/postAPIkeyResponse"
|
"$ref": "#/responses/statusMovedPermanently"
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"$ref": "#/responses/badRequestError"
|
|
||||||
},
|
|
||||||
"401": {
|
|
||||||
"$ref": "#/responses/unauthorisedError"
|
|
||||||
},
|
|
||||||
"403": {
|
|
||||||
"$ref": "#/responses/forbiddenError"
|
|
||||||
},
|
|
||||||
"409": {
|
|
||||||
"$ref": "#/responses/conflictError"
|
|
||||||
},
|
|
||||||
"500": {
|
|
||||||
"$ref": "#/responses/internalServerError"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -24190,6 +24165,12 @@
|
|||||||
"$ref": "#/definitions/SnapshotListResponseDTO"
|
"$ref": "#/definitions/SnapshotListResponseDTO"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"statusMovedPermanently": {
|
||||||
|
"description": "StatusMovedPermanently",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ErrorResponseBody"
|
||||||
|
}
|
||||||
|
},
|
||||||
"unauthorisedError": {
|
"unauthorisedError": {
|
||||||
"description": "UnauthorizedError is returned when the request is not authenticated.",
|
"description": "UnauthorizedError is returned when the request is not authenticated.",
|
||||||
"schema": {
|
"schema": {
|
||||||
|
@ -1942,6 +1942,16 @@
|
|||||||
},
|
},
|
||||||
"description": "(empty)"
|
"description": "(empty)"
|
||||||
},
|
},
|
||||||
|
"statusMovedPermanently": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/ErrorResponseBody"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "StatusMovedPermanently"
|
||||||
|
},
|
||||||
"unauthorisedError": {
|
"unauthorisedError": {
|
||||||
"content": {
|
"content": {
|
||||||
"application/json": {
|
"application/json": {
|
||||||
@ -15304,35 +15314,9 @@
|
|||||||
"deprecated": true,
|
"deprecated": true,
|
||||||
"description": "Will return details of the created API key.",
|
"description": "Will return details of the created API key.",
|
||||||
"operationId": "addAPIkey",
|
"operationId": "addAPIkey",
|
||||||
"requestBody": {
|
|
||||||
"content": {
|
|
||||||
"application/json": {
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/components/schemas/AddAPIKeyCommand"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": true,
|
|
||||||
"x-originalParamName": "Body"
|
|
||||||
},
|
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"301": {
|
||||||
"$ref": "#/components/responses/postAPIkeyResponse"
|
"$ref": "#/components/responses/statusMovedPermanently"
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"$ref": "#/components/responses/badRequestError"
|
|
||||||
},
|
|
||||||
"401": {
|
|
||||||
"$ref": "#/components/responses/unauthorisedError"
|
|
||||||
},
|
|
||||||
"403": {
|
|
||||||
"$ref": "#/components/responses/forbiddenError"
|
|
||||||
},
|
|
||||||
"409": {
|
|
||||||
"$ref": "#/components/responses/conflictError"
|
|
||||||
},
|
|
||||||
"500": {
|
|
||||||
"$ref": "#/components/responses/internalServerError"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"summary": "Creates an API key.",
|
"summary": "Creates an API key.",
|
||||||
|
Loading…
Reference in New Issue
Block a user