grafana/pkg/api/apikey.go

138 lines
4.1 KiB
Go
Raw Normal View History

2015-01-27 01:26:11 -06:00
package api
import (
"errors"
"time"
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/response"
2015-02-05 03:37:13 -06:00
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/apikeygen"
Auth: Allow expiration of API keys (#17678) * Modify backend to allow expiration of API Keys * Add middleware test for expired api keys * Modify frontend to enable expiration of API Keys * Fix frontend tests * Fix migration and add index for `expires` field * Add api key tests for database access * Substitude time.Now() by a mock for test usage * Front-end modifications * Change input label to `Time to live` * Change input behavior to comply with the other similar * Add tooltip * Modify AddApiKey api call response Expiration should be *time.Time instead of string * Present expiration date in the selected timezone * Use kbn for transforming intervals to seconds * Use `assert` library for tests * Frontend fixes Add checks for empty/undefined/null values * Change expires column from datetime to integer * Restrict api key duration input It should be interval not number * AddApiKey must complain if SecondsToLive is negative * Declare ErrInvalidApiKeyExpiration * Move configuration to auth section * Update docs * Eliminate alias for models in modified files * Omit expiration from api response if empty * Eliminate Goconvey from test file * Fix test Do not sleep, use mocked timeNow() instead * Remove index for expires from api_key table The index should be anyway on both org_id and expires fields. However this commit eliminates completely the index for now since not many rows are expected to be in this table. * Use getTimeZone function * Minor change in api key listing The frontend should display a message instead of empty string if the key does not expire.
2019-06-26 01:47:03 -05:00
"github.com/grafana/grafana/pkg/models"
2015-01-27 01:26:11 -06:00
)
// GetAPIKeys returns a list of API keys
func GetAPIKeys(c *models.ReqContext) response.Response {
query := models.GetApiKeysQuery{OrgId: c.OrgId, IncludeExpired: c.QueryBool("includeExpired")}
2015-01-27 01:26:11 -06:00
if err := bus.DispatchCtx(c.Req.Context(), &query); err != nil {
return response.Error(500, "Failed to list api keys", err)
2015-01-27 01:26:11 -06:00
}
Auth: Allow expiration of API keys (#17678) * Modify backend to allow expiration of API Keys * Add middleware test for expired api keys * Modify frontend to enable expiration of API Keys * Fix frontend tests * Fix migration and add index for `expires` field * Add api key tests for database access * Substitude time.Now() by a mock for test usage * Front-end modifications * Change input label to `Time to live` * Change input behavior to comply with the other similar * Add tooltip * Modify AddApiKey api call response Expiration should be *time.Time instead of string * Present expiration date in the selected timezone * Use kbn for transforming intervals to seconds * Use `assert` library for tests * Frontend fixes Add checks for empty/undefined/null values * Change expires column from datetime to integer * Restrict api key duration input It should be interval not number * AddApiKey must complain if SecondsToLive is negative * Declare ErrInvalidApiKeyExpiration * Move configuration to auth section * Update docs * Eliminate alias for models in modified files * Omit expiration from api response if empty * Eliminate Goconvey from test file * Fix test Do not sleep, use mocked timeNow() instead * Remove index for expires from api_key table The index should be anyway on both org_id and expires fields. However this commit eliminates completely the index for now since not many rows are expected to be in this table. * Use getTimeZone function * Minor change in api key listing The frontend should display a message instead of empty string if the key does not expire.
2019-06-26 01:47:03 -05:00
result := make([]*models.ApiKeyDTO, len(query.Result))
2015-01-27 01:26:11 -06:00
for i, t := range query.Result {
Auth: Allow expiration of API keys (#17678) * Modify backend to allow expiration of API Keys * Add middleware test for expired api keys * Modify frontend to enable expiration of API Keys * Fix frontend tests * Fix migration and add index for `expires` field * Add api key tests for database access * Substitude time.Now() by a mock for test usage * Front-end modifications * Change input label to `Time to live` * Change input behavior to comply with the other similar * Add tooltip * Modify AddApiKey api call response Expiration should be *time.Time instead of string * Present expiration date in the selected timezone * Use kbn for transforming intervals to seconds * Use `assert` library for tests * Frontend fixes Add checks for empty/undefined/null values * Change expires column from datetime to integer * Restrict api key duration input It should be interval not number * AddApiKey must complain if SecondsToLive is negative * Declare ErrInvalidApiKeyExpiration * Move configuration to auth section * Update docs * Eliminate alias for models in modified files * Omit expiration from api response if empty * Eliminate Goconvey from test file * Fix test Do not sleep, use mocked timeNow() instead * Remove index for expires from api_key table The index should be anyway on both org_id and expires fields. However this commit eliminates completely the index for now since not many rows are expected to be in this table. * Use getTimeZone function * Minor change in api key listing The frontend should display a message instead of empty string if the key does not expire.
2019-06-26 01:47:03 -05:00
var expiration *time.Time = nil
if t.Expires != nil {
v := time.Unix(*t.Expires, 0)
expiration = &v
}
result[i] = &models.ApiKeyDTO{
Id: t.Id,
Name: t.Name,
Role: t.Role,
Expiration: expiration,
2015-01-27 01:26:11 -06:00
}
}
return response.JSON(200, result)
2015-01-27 01:26:11 -06:00
}
// DeleteAPIKey deletes an API key
func DeleteAPIKey(c *models.ReqContext) response.Response {
2015-01-27 01:26:11 -06:00
id := c.ParamsInt64(":id")
Auth: Allow expiration of API keys (#17678) * Modify backend to allow expiration of API Keys * Add middleware test for expired api keys * Modify frontend to enable expiration of API Keys * Fix frontend tests * Fix migration and add index for `expires` field * Add api key tests for database access * Substitude time.Now() by a mock for test usage * Front-end modifications * Change input label to `Time to live` * Change input behavior to comply with the other similar * Add tooltip * Modify AddApiKey api call response Expiration should be *time.Time instead of string * Present expiration date in the selected timezone * Use kbn for transforming intervals to seconds * Use `assert` library for tests * Frontend fixes Add checks for empty/undefined/null values * Change expires column from datetime to integer * Restrict api key duration input It should be interval not number * AddApiKey must complain if SecondsToLive is negative * Declare ErrInvalidApiKeyExpiration * Move configuration to auth section * Update docs * Eliminate alias for models in modified files * Omit expiration from api response if empty * Eliminate Goconvey from test file * Fix test Do not sleep, use mocked timeNow() instead * Remove index for expires from api_key table The index should be anyway on both org_id and expires fields. However this commit eliminates completely the index for now since not many rows are expected to be in this table. * Use getTimeZone function * Minor change in api key listing The frontend should display a message instead of empty string if the key does not expire.
2019-06-26 01:47:03 -05:00
cmd := &models.DeleteApiKeyCommand{Id: id, OrgId: c.OrgId}
2015-01-27 01:26:11 -06:00
err := bus.DispatchCtx(c.Req.Context(), cmd)
2015-01-27 01:26:11 -06:00
if err != nil {
var status int
if errors.Is(err, models.ErrApiKeyNotFound) {
status = 404
} else {
status = 500
}
return response.Error(status, "Failed to delete API key", err)
2015-01-27 01:26:11 -06:00
}
return response.Success("API key deleted")
2015-01-27 01:26:11 -06:00
}
// AddAPIKey adds an API key
func (hs *HTTPServer) AddAPIKey(c *models.ReqContext, cmd models.AddApiKeyCommand) response.Response {
2015-01-27 01:26:11 -06:00
if !cmd.Role.IsValid() {
return response.Error(400, "Invalid role specified", nil)
2015-01-27 01:26:11 -06:00
}
Auth: Allow expiration of API keys (#17678) * Modify backend to allow expiration of API Keys * Add middleware test for expired api keys * Modify frontend to enable expiration of API Keys * Fix frontend tests * Fix migration and add index for `expires` field * Add api key tests for database access * Substitude time.Now() by a mock for test usage * Front-end modifications * Change input label to `Time to live` * Change input behavior to comply with the other similar * Add tooltip * Modify AddApiKey api call response Expiration should be *time.Time instead of string * Present expiration date in the selected timezone * Use kbn for transforming intervals to seconds * Use `assert` library for tests * Frontend fixes Add checks for empty/undefined/null values * Change expires column from datetime to integer * Restrict api key duration input It should be interval not number * AddApiKey must complain if SecondsToLive is negative * Declare ErrInvalidApiKeyExpiration * Move configuration to auth section * Update docs * Eliminate alias for models in modified files * Omit expiration from api response if empty * Eliminate Goconvey from test file * Fix test Do not sleep, use mocked timeNow() instead * Remove index for expires from api_key table The index should be anyway on both org_id and expires fields. However this commit eliminates completely the index for now since not many rows are expected to be in this table. * Use getTimeZone function * Minor change in api key listing The frontend should display a message instead of empty string if the key does not expire.
2019-06-26 01:47:03 -05:00
if hs.Cfg.ApiKeyMaxSecondsToLive != -1 {
if cmd.SecondsToLive == 0 {
return response.Error(400, "Number of seconds before expiration should be set", nil)
Auth: Allow expiration of API keys (#17678) * Modify backend to allow expiration of API Keys * Add middleware test for expired api keys * Modify frontend to enable expiration of API Keys * Fix frontend tests * Fix migration and add index for `expires` field * Add api key tests for database access * Substitude time.Now() by a mock for test usage * Front-end modifications * Change input label to `Time to live` * Change input behavior to comply with the other similar * Add tooltip * Modify AddApiKey api call response Expiration should be *time.Time instead of string * Present expiration date in the selected timezone * Use kbn for transforming intervals to seconds * Use `assert` library for tests * Frontend fixes Add checks for empty/undefined/null values * Change expires column from datetime to integer * Restrict api key duration input It should be interval not number * AddApiKey must complain if SecondsToLive is negative * Declare ErrInvalidApiKeyExpiration * Move configuration to auth section * Update docs * Eliminate alias for models in modified files * Omit expiration from api response if empty * Eliminate Goconvey from test file * Fix test Do not sleep, use mocked timeNow() instead * Remove index for expires from api_key table The index should be anyway on both org_id and expires fields. However this commit eliminates completely the index for now since not many rows are expected to be in this table. * Use getTimeZone function * Minor change in api key listing The frontend should display a message instead of empty string if the key does not expire.
2019-06-26 01:47:03 -05:00
}
if cmd.SecondsToLive > hs.Cfg.ApiKeyMaxSecondsToLive {
return response.Error(400, "Number of seconds before expiration is greater than the global limit", nil)
Auth: Allow expiration of API keys (#17678) * Modify backend to allow expiration of API Keys * Add middleware test for expired api keys * Modify frontend to enable expiration of API Keys * Fix frontend tests * Fix migration and add index for `expires` field * Add api key tests for database access * Substitude time.Now() by a mock for test usage * Front-end modifications * Change input label to `Time to live` * Change input behavior to comply with the other similar * Add tooltip * Modify AddApiKey api call response Expiration should be *time.Time instead of string * Present expiration date in the selected timezone * Use kbn for transforming intervals to seconds * Use `assert` library for tests * Frontend fixes Add checks for empty/undefined/null values * Change expires column from datetime to integer * Restrict api key duration input It should be interval not number * AddApiKey must complain if SecondsToLive is negative * Declare ErrInvalidApiKeyExpiration * Move configuration to auth section * Update docs * Eliminate alias for models in modified files * Omit expiration from api response if empty * Eliminate Goconvey from test file * Fix test Do not sleep, use mocked timeNow() instead * Remove index for expires from api_key table The index should be anyway on both org_id and expires fields. However this commit eliminates completely the index for now since not many rows are expected to be in this table. * Use getTimeZone function * Minor change in api key listing The frontend should display a message instead of empty string if the key does not expire.
2019-06-26 01:47:03 -05:00
}
}
cmd.OrgId = c.OrgId
var err error
if hs.Cfg.FeatureToggles["service-accounts"] {
//Every new API key must have an associated service account
if cmd.CreateNewServiceAccount {
//Create a new service account for the new API key
serviceAccount, err := hs.SQLStore.CloneUserToServiceAccount(c.Req.Context(), c.SignedInUser)
if err != nil {
return response.Error(500, "Unable to clone user to service account", err)
}
cmd.ServiceAccountId = serviceAccount.Id
} else {
//Link the new API key to an existing service account
//Check if user and service account are in the same org
query := models.GetUserByIdQuery{Id: cmd.ServiceAccountId}
err = bus.DispatchCtx(c.Req.Context(), &query)
if err != nil {
return response.Error(500, "Unable to clone user to service account", err)
}
serviceAccountDetails := query.Result
if serviceAccountDetails.OrgId != c.OrgId || serviceAccountDetails.OrgId != cmd.OrgId {
return response.Error(403, "Target service is not in the same organisation as requesting user or api key", err)
}
}
}
newKeyInfo, err := apikeygen.New(cmd.OrgId, cmd.Name)
if err != nil {
return response.Error(500, "Generating API key failed", err)
}
cmd.Key = newKeyInfo.HashedKey
2015-01-27 01:26:11 -06:00
if err := bus.DispatchCtx(c.Req.Context(), &cmd); err != nil {
if errors.Is(err, models.ErrInvalidApiKeyExpiration) {
return response.Error(400, err.Error(), nil)
Auth: Allow expiration of API keys (#17678) * Modify backend to allow expiration of API Keys * Add middleware test for expired api keys * Modify frontend to enable expiration of API Keys * Fix frontend tests * Fix migration and add index for `expires` field * Add api key tests for database access * Substitude time.Now() by a mock for test usage * Front-end modifications * Change input label to `Time to live` * Change input behavior to comply with the other similar * Add tooltip * Modify AddApiKey api call response Expiration should be *time.Time instead of string * Present expiration date in the selected timezone * Use kbn for transforming intervals to seconds * Use `assert` library for tests * Frontend fixes Add checks for empty/undefined/null values * Change expires column from datetime to integer * Restrict api key duration input It should be interval not number * AddApiKey must complain if SecondsToLive is negative * Declare ErrInvalidApiKeyExpiration * Move configuration to auth section * Update docs * Eliminate alias for models in modified files * Omit expiration from api response if empty * Eliminate Goconvey from test file * Fix test Do not sleep, use mocked timeNow() instead * Remove index for expires from api_key table The index should be anyway on both org_id and expires fields. However this commit eliminates completely the index for now since not many rows are expected to be in this table. * Use getTimeZone function * Minor change in api key listing The frontend should display a message instead of empty string if the key does not expire.
2019-06-26 01:47:03 -05:00
}
if errors.Is(err, models.ErrDuplicateApiKey) {
return response.Error(409, err.Error(), nil)
}
return response.Error(500, "Failed to add API Key", err)
2015-01-27 01:26:11 -06:00
}
result := &dtos.NewApiKeyResult{
ID: cmd.Result.Id,
2015-01-27 01:26:11 -06:00
Name: cmd.Result.Name,
Key: newKeyInfo.ClientSecret,
}
2015-01-27 01:26:11 -06:00
return response.JSON(200, result)
2015-01-27 01:26:11 -06:00
}
// AddAPIKey adds an additional API key to a service account
func (hs *HTTPServer) AdditionalAPIKey(c *models.ReqContext, cmd models.AddApiKeyCommand) response.Response {
if !hs.Cfg.FeatureToggles["service-accounts"] {
return response.Error(500, "Requires services-accounts feature", errors.New("feature missing"))
}
if cmd.CreateNewServiceAccount {
return response.Error(500, "Can't create service account while adding additional API key", nil)
}
return hs.AddAPIKey(c, cmd)
}