From d57d184d20182b906e8f6d2ce15009af513ac04b Mon Sep 17 00:00:00 2001 From: Mihai Doarna Date: Wed, 4 Jun 2025 17:03:06 +0300 Subject: [PATCH] Auth: Remove api key endpoints (#106019) * remove api key endpoints * generate openapi specs * remove methods from mock service * remove ApiKeyDTO * generate openapi specs * remove apikey migration endpoints * remove unused function --- pkg/api/api.go | 9 -- pkg/api/apikey.go | 149 ------------------ pkg/api/dtos/apikey.go | 16 -- pkg/services/apikey/apikey.go | 4 - pkg/services/apikey/apikeyimpl/apikey.go | 16 -- pkg/services/apikey/apikeyimpl/store.go | 3 - pkg/services/apikey/apikeyimpl/store_test.go | 51 ------ pkg/services/apikey/apikeyimpl/xorm_store.go | 67 -------- pkg/services/apikey/apikeytest/fake.go | 10 -- pkg/services/apikey/model.go | 11 -- pkg/services/navtree/navtreeimpl/admin.go | 13 -- pkg/services/serviceaccounts/api/api.go | 26 --- pkg/services/serviceaccounts/api/api_test.go | 61 ------- .../serviceaccounts/database/store.go | 20 --- .../serviceaccounts/database/store_test.go | 124 --------------- .../serviceaccounts/manager/service.go | 15 -- .../serviceaccounts/manager/service_test.go | 5 - pkg/services/serviceaccounts/manager/store.go | 1 - pkg/services/serviceaccounts/proxy/service.go | 4 - .../serviceaccounts/serviceaccounts.go | 2 - pkg/services/serviceaccounts/tests/fakes.go | 4 - pkg/services/serviceaccounts/tests/mocks.go | 14 -- public/api-enterprise-spec.json | 41 ----- public/api-merged.json | 128 --------------- public/openapi3.json | 136 ---------------- 25 files changed, 930 deletions(-) delete mode 100644 pkg/api/apikey.go diff --git a/pkg/api/api.go b/pkg/api/api.go index cb7676312b5..d9ba624d32b 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -40,7 +40,6 @@ import ( "github.com/grafana/grafana/pkg/middleware/requestmeta" ac "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol/ssoutils" - "github.com/grafana/grafana/pkg/services/apikey" "github.com/grafana/grafana/pkg/services/auth" "github.com/grafana/grafana/pkg/services/cloudmigration" contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" @@ -396,14 +395,6 @@ func (hs *HTTPServer) registerRoutes() { // orgs (admin routes) apiRoute.Get("/orgs/name/:name/", authorizeInOrg(ac.UseGlobalOrg, ac.EvalPermission(ac.ActionOrgsRead)), routing.Wrap(hs.GetOrgByName)) - // auth api keys - apiRoute.Group("/auth/keys", func(keysRoute routing.RouteRegister) { - apikeyIDScope := ac.Scope("apikeys", "id", ac.Parameter(":id")) - keysRoute.Get("/", authorize(ac.EvalPermission(ac.ActionAPIKeyRead)), routing.Wrap(hs.GetAPIKeys)) - keysRoute.Post("/", authorize(ac.EvalPermission(ac.ActionAPIKeyCreate)), quota(string(apikey.QuotaTargetSrv)), routing.Wrap(hs.AddAPIKey)) - keysRoute.Delete("/:id", authorize(ac.EvalPermission(ac.ActionAPIKeyDelete, apikeyIDScope)), routing.Wrap(hs.DeleteAPIKey)) - }, requestmeta.SetOwner(requestmeta.TeamAuth)) - // Preferences apiRoute.Group("/preferences", func(prefRoute routing.RouteRegister) { prefRoute.Post("/set-home-dash", routing.Wrap(hs.SetHomeDashboard)) diff --git a/pkg/api/apikey.go b/pkg/api/apikey.go deleted file mode 100644 index b81de7e456e..00000000000 --- a/pkg/api/apikey.go +++ /dev/null @@ -1,149 +0,0 @@ -package api - -import ( - "errors" - "net/http" - "strconv" - "time" - - "github.com/grafana/grafana/pkg/api/dtos" - "github.com/grafana/grafana/pkg/api/response" - "github.com/grafana/grafana/pkg/services/apikey" - contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" - "github.com/grafana/grafana/pkg/web" -) - -// swagger:route GET /auth/keys api_keys getAPIkeys -// -// Get auth keys. -// -// Will return auth keys. -// -// Deprecated: true. -// -// Deprecated. Please use GET /api/serviceaccounts and GET /api/serviceaccounts/{id}/tokens instead -// see https://grafana.com/docs/grafana/next/administration/service-accounts/migrate-api-keys/. -// -// Responses: -// 200: getAPIkeyResponse -// 401: unauthorisedError -// 403: forbiddenError -// 404: notFoundError -// 500: internalServerError -func (hs *HTTPServer) GetAPIKeys(c *contextmodel.ReqContext) response.Response { - query := apikey.GetApiKeysQuery{OrgID: c.GetOrgID(), User: c.SignedInUser, IncludeExpired: c.QueryBool("includeExpired")} - - keys, err := hs.apiKeyService.GetAPIKeys(c.Req.Context(), &query) - if err != nil { - return response.Error(http.StatusInternalServerError, "Failed to list api keys", err) - } - - ids := map[string]bool{} - result := make([]*dtos.ApiKeyDTO, len(keys)) - for i, t := range keys { - ids[strconv.FormatInt(t.ID, 10)] = true - var expiration *time.Time = nil - if t.Expires != nil { - v := time.Unix(*t.Expires, 0) - expiration = &v - } - result[i] = &dtos.ApiKeyDTO{ - ID: t.ID, - Name: t.Name, - Role: t.Role, - Expiration: expiration, - LastUsedAt: t.LastUsedAt, - } - } - - metadata := getMultiAccessControlMetadata(c, "apikeys:id", ids) - if len(metadata) > 0 { - for _, key := range result { - key.AccessControl = metadata[strconv.FormatInt(key.ID, 10)] - } - } - - return response.JSON(http.StatusOK, result) -} - -// swagger:route DELETE /auth/keys/{id} api_keys deleteAPIkey -// -// Delete API key. -// -// Deletes an API key. -// Deprecated. See: https://grafana.com/docs/grafana/next/administration/service-accounts/migrate-api-keys/. -// -// Deprecated: true -// Responses: -// 200: okResponse -// 401: unauthorisedError -// 403: forbiddenError -// 404: notFoundError -// 500: internalServerError -func (hs *HTTPServer) DeleteAPIKey(c *contextmodel.ReqContext) response.Response { - id, err := strconv.ParseInt(web.Params(c.Req)[":id"], 10, 64) - if err != nil { - return response.Error(http.StatusBadRequest, "id is invalid", err) - } - - cmd := &apikey.DeleteCommand{ID: id, OrgID: c.GetOrgID()} - err = hs.apiKeyService.DeleteApiKey(c.Req.Context(), cmd) - if err != nil { - var status int - if errors.Is(err, apikey.ErrNotFound) { - status = http.StatusNotFound - } else { - status = http.StatusInternalServerError - } - return response.Error(status, "Failed to delete API key", err) - } - - return response.Success("API key deleted") -} - -// swagger:route POST /auth/keys api_keys addAPIkey -// -// Creates an API key. -// -// Will return details of the created API key. -// -// Deprecated: true -// Deprecated. Please use POST /api/serviceaccounts and POST /api/serviceaccounts/{id}/tokens -// -// see: https://grafana.com/docs/grafana/next/administration/service-accounts/migrate-api-keys/. -// -// Responses: -// 410: goneError -func (hs *HTTPServer) AddAPIKey(c *contextmodel.ReqContext) response.Response { - hs.log.Warn("Obsolete and Permanently moved API endpoint called", "path", c.Req.URL.Path) - - // Respond with a 410 Gone status code - return response.Error( - http.StatusGone, - "this endpoint has been removed, please use POST /api/serviceaccounts and POST /api/serviceaccounts/{id}/tokens instead", - nil, - ) -} - -// swagger:parameters getAPIkeys -type GetAPIkeysParams struct { - // Show expired keys - // in:query - // required:false - // default:false - IncludeExpired bool `json:"includeExpired"` -} - -// swagger:parameters deleteAPIkey -type DeleteAPIkeyParams struct { - // in:path - // required:true - ID int64 `json:"id"` -} - -// swagger:response getAPIkeyResponse -type GetAPIkeyResponse struct { - // The response message - // in: body - Body []*dtos.ApiKeyDTO `json:"body"` -} diff --git a/pkg/api/dtos/apikey.go b/pkg/api/dtos/apikey.go index eb7288771bd..28dd1389810 100644 --- a/pkg/api/dtos/apikey.go +++ b/pkg/api/dtos/apikey.go @@ -1,12 +1,5 @@ package dtos -import ( - "time" - - "github.com/grafana/grafana/pkg/services/accesscontrol" - "github.com/grafana/grafana/pkg/services/org" -) - // swagger:model type NewApiKeyResult struct { // example: 1 @@ -16,12 +9,3 @@ type NewApiKeyResult struct { // example: glsa_yscW25imSKJIuav8zF37RZmnbiDvB05G_fcaaf58a Key string `json:"key"` } - -type ApiKeyDTO struct { - ID int64 `json:"id"` - Name string `json:"name"` - Role org.RoleType `json:"role"` - Expiration *time.Time `json:"expiration,omitempty"` - LastUsedAt *time.Time `json:"lastUsedAt,omitempty"` - AccessControl accesscontrol.Metadata `json:"accessControl,omitempty"` -} diff --git a/pkg/services/apikey/apikey.go b/pkg/services/apikey/apikey.go index 2dd91a14d12..8ab20259432 100644 --- a/pkg/services/apikey/apikey.go +++ b/pkg/services/apikey/apikey.go @@ -5,13 +5,9 @@ import ( ) type Service interface { - GetAPIKeys(ctx context.Context, query *GetApiKeysQuery) (res []*APIKey, err error) GetAllAPIKeys(ctx context.Context, orgID int64) ([]*APIKey, error) - DeleteApiKey(ctx context.Context, cmd *DeleteCommand) error AddAPIKey(ctx context.Context, cmd *AddCommand) (res *APIKey, err error) GetApiKeyByName(ctx context.Context, query *GetByNameQuery) (res *APIKey, err error) GetAPIKeyByHash(ctx context.Context, hash string) (*APIKey, error) UpdateAPIKeyLastUsedDate(ctx context.Context, tokenID int64) error - // IsDisabled returns true if the API key is not available for use. - IsDisabled(ctx context.Context, orgID int64) (bool, error) } diff --git a/pkg/services/apikey/apikeyimpl/apikey.go b/pkg/services/apikey/apikeyimpl/apikey.go index b42bc49f341..750053dc265 100644 --- a/pkg/services/apikey/apikeyimpl/apikey.go +++ b/pkg/services/apikey/apikeyimpl/apikey.go @@ -37,9 +37,6 @@ func (s *Service) Usage(ctx context.Context, scopeParams *quota.ScopeParameters) return s.store.Count(ctx, scopeParams) } -func (s *Service) GetAPIKeys(ctx context.Context, query *apikey.GetApiKeysQuery) ([]*apikey.APIKey, error) { - return s.store.GetAPIKeys(ctx, query) -} func (s *Service) GetAllAPIKeys(ctx context.Context, orgID int64) ([]*apikey.APIKey, error) { return s.store.GetAllAPIKeys(ctx, orgID) } @@ -49,9 +46,6 @@ func (s *Service) GetApiKeyByName(ctx context.Context, query *apikey.GetByNameQu func (s *Service) GetAPIKeyByHash(ctx context.Context, hash string) (*apikey.APIKey, error) { return s.store.GetAPIKeyByHash(ctx, hash) } -func (s *Service) DeleteApiKey(ctx context.Context, cmd *apikey.DeleteCommand) error { - return s.store.DeleteApiKey(ctx, cmd) -} func (s *Service) AddAPIKey(ctx context.Context, cmd *apikey.AddCommand) (res *apikey.APIKey, err error) { return s.store.AddAPIKey(ctx, cmd) } @@ -59,16 +53,6 @@ func (s *Service) UpdateAPIKeyLastUsedDate(ctx context.Context, tokenID int64) e return s.store.UpdateAPIKeyLastUsedDate(ctx, tokenID) } -// IsDisabled returns true if the apikey service is disabled for the given org. -// This is the case if the org has no apikeys. -func (s *Service) IsDisabled(ctx context.Context, orgID int64) (bool, error) { - apikeys, err := s.store.CountAPIKeys(ctx, orgID) - if err != nil { - return false, err - } - return apikeys == 0, nil -} - func readQuotaConfig(cfg *setting.Cfg) (*quota.Map, error) { limits := "a.Map{} diff --git a/pkg/services/apikey/apikeyimpl/store.go b/pkg/services/apikey/apikeyimpl/store.go index 2b9fa5c2216..2269d259826 100644 --- a/pkg/services/apikey/apikeyimpl/store.go +++ b/pkg/services/apikey/apikeyimpl/store.go @@ -8,10 +8,7 @@ import ( ) type store interface { - GetAPIKeys(ctx context.Context, query *apikey.GetApiKeysQuery) (res []*apikey.APIKey, err error) GetAllAPIKeys(ctx context.Context, orgID int64) ([]*apikey.APIKey, error) - CountAPIKeys(ctx context.Context, orgID int64) (int64, error) - DeleteApiKey(ctx context.Context, cmd *apikey.DeleteCommand) error AddAPIKey(ctx context.Context, cmd *apikey.AddCommand) (res *apikey.APIKey, err error) GetApiKeyByName(ctx context.Context, query *apikey.GetByNameQuery) (res *apikey.APIKey, err error) GetAPIKeyByHash(ctx context.Context, hash string) (*apikey.APIKey, error) diff --git a/pkg/services/apikey/apikeyimpl/store_test.go b/pkg/services/apikey/apikeyimpl/store_test.go index d7ae8f27069..ac2cfb06088 100644 --- a/pkg/services/apikey/apikeyimpl/store_test.go +++ b/pkg/services/apikey/apikeyimpl/store_test.go @@ -11,7 +11,6 @@ import ( "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/infra/db" - "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/apikey" "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/tests/testsuite" @@ -26,7 +25,6 @@ type getStore func(db.DB) store type getApiKeysTestCase struct { desc string user identity.Requester - expectedNumKeys int expectedAllNumKeys int } @@ -86,12 +84,6 @@ func testIntegrationApiKeyDataAccess(t *testing.T, fn getStore) { assert.Nil(t, err) assert.NotNil(t, key) }) - t.Run("Should be able to delete key by id", func(t *testing.T) { - key, err := ss.GetAPIKeyByHash(context.Background(), cmd.Key) - assert.NoError(t, err) - err = ss.DeleteApiKey(context.Background(), &apikey.DeleteCommand{ID: key.ID, OrgID: key.OrgID}) - assert.NoError(t, err) - }) }) t.Run("Add non expiring key", func(t *testing.T) { @@ -171,34 +163,6 @@ func testIntegrationApiKeyDataAccess(t *testing.T, fn getStore) { // advance mocked getTime by 1s timeNow() - - testUser := &user.SignedInUser{ - OrgID: 1, - Permissions: map[int64]map[string][]string{ - 1: {accesscontrol.ActionAPIKeyRead: []string{accesscontrol.ScopeAPIKeysAll}}, - }, - } - query := apikey.GetApiKeysQuery{OrgID: 1, IncludeExpired: false, User: testUser} - keys, err := ss.GetAPIKeys(context.Background(), &query) - assert.Nil(t, err) - - for _, k := range keys { - if k.Name == "key2" { - t.Fatalf("key2 should not be there") - } - } - - query = apikey.GetApiKeysQuery{OrgID: 1, IncludeExpired: true, User: testUser} - keys, err = ss.GetAPIKeys(context.Background(), &query) - assert.Nil(t, err) - - found := false - for _, k := range keys { - if k.Name == "key2" { - found = true - } - } - assert.True(t, found) }) }) @@ -206,13 +170,6 @@ func testIntegrationApiKeyDataAccess(t *testing.T, fn getStore) { db := db.InitTestDB(t) ss := fn(db) - t.Run("Delete non-existing key should return error", func(t *testing.T) { - cmd := apikey.DeleteCommand{ID: 1} - err := ss.DeleteApiKey(context.Background(), &cmd) - - assert.EqualError(t, err, apikey.ErrNotFound.Error()) - }) - t.Run("Testing API Duplicate Key Errors", func(t *testing.T) { t.Run("Given saved api key", func(t *testing.T) { cmd := apikey.AddCommand{OrgID: 0, Name: "duplicate", Key: "asd"} @@ -235,7 +192,6 @@ func testIntegrationApiKeyDataAccess(t *testing.T, fn getStore) { user: &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{ 1: {"apikeys:read": {"apikeys:*"}}, }}, - expectedNumKeys: 10, expectedAllNumKeys: 10, }, { @@ -243,7 +199,6 @@ func testIntegrationApiKeyDataAccess(t *testing.T, fn getStore) { user: &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{ 1: {"apikeys:read": {"apikeys:id:1", "apikeys:id:3"}}, }}, - expectedNumKeys: 2, expectedAllNumKeys: 10, }, { @@ -251,7 +206,6 @@ func testIntegrationApiKeyDataAccess(t *testing.T, fn getStore) { user: &user.SignedInUser{OrgID: 1, Permissions: map[int64]map[string][]string{ 1: {"apikeys:read": {}}, }}, - expectedNumKeys: 0, expectedAllNumKeys: 10, }, } @@ -262,11 +216,6 @@ func testIntegrationApiKeyDataAccess(t *testing.T, fn getStore) { store := fn(db) seedApiKeys(t, store, 10) - query := &apikey.GetApiKeysQuery{OrgID: 1, User: tt.user} - keys, err := store.GetAPIKeys(context.Background(), query) - require.NoError(t, err) - assert.Len(t, keys, tt.expectedNumKeys) - res, err := store.GetAllAPIKeys(context.Background(), 1) require.NoError(t, err) assert.Equal(t, tt.expectedAllNumKeys, len(res)) diff --git a/pkg/services/apikey/apikeyimpl/xorm_store.go b/pkg/services/apikey/apikeyimpl/xorm_store.go index d631c96066d..27733e8c9c7 100644 --- a/pkg/services/apikey/apikeyimpl/xorm_store.go +++ b/pkg/services/apikey/apikeyimpl/xorm_store.go @@ -5,10 +5,7 @@ import ( "fmt" "time" - "github.com/grafana/grafana/pkg/util/xorm" - "github.com/grafana/grafana/pkg/infra/db" - "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/apikey" "github.com/grafana/grafana/pkg/services/quota" "github.com/grafana/grafana/pkg/services/sqlstore" @@ -21,34 +18,6 @@ type sqlStore struct { // timeNow makes it possible to test usage of time var timeNow = time.Now -func (ss *sqlStore) GetAPIKeys(ctx context.Context, query *apikey.GetApiKeysQuery) (res []*apikey.APIKey, err error) { - err = ss.db.WithDbSession(ctx, func(dbSession *db.Session) error { - var sess *xorm.Session - - if query.IncludeExpired { - sess = dbSession.Limit(100, 0). - Where("org_id=?", query.OrgID). - Asc("name") - } else { - sess = dbSession.Limit(100, 0). - Where("org_id=? and ( expires IS NULL or expires >= ?)", query.OrgID, timeNow().Unix()). - Asc("name") - } - - sess = sess.Where("service_account_id IS NULL") - - filter, err := accesscontrol.Filter(query.User, "id", "apikeys:id:", accesscontrol.ActionAPIKeyRead) - if err != nil { - return err - } - sess.And(filter.Where, filter.Args...) - - res = make([]*apikey.APIKey, 0) - return sess.Find(&res) - }) - return res, err -} - func (ss *sqlStore) GetAllAPIKeys(ctx context.Context, orgID int64) ([]*apikey.APIKey, error) { result := make([]*apikey.APIKey, 0) err := ss.db.WithDbSession(ctx, func(dbSession *db.Session) error { @@ -61,42 +30,6 @@ func (ss *sqlStore) GetAllAPIKeys(ctx context.Context, orgID int64) ([]*apikey.A return result, err } -func (ss *sqlStore) CountAPIKeys(ctx context.Context, orgID int64) (int64, error) { - type result struct { - Count int64 - } - - r := result{} - err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error { - rawSQL := "SELECT COUNT(*) AS count FROM api_key WHERE org_id = ? and service_account_id IS NULL" - if _, err := sess.SQL(rawSQL, orgID).Get(&r); err != nil { - return err - } - return nil - }) - if err != nil { - return 0, err - } - return r.Count, err -} - -func (ss *sqlStore) DeleteApiKey(ctx context.Context, cmd *apikey.DeleteCommand) error { - return ss.db.WithDbSession(ctx, func(sess *db.Session) error { - rawSQL := "DELETE FROM api_key WHERE id=? and org_id=? and service_account_id IS NULL" - result, err := sess.Exec(rawSQL, cmd.ID, cmd.OrgID) - if err != nil { - return err - } - n, err := result.RowsAffected() - if err != nil { - return err - } else if n == 0 { - return apikey.ErrNotFound - } - return nil - }) -} - func (ss *sqlStore) AddAPIKey(ctx context.Context, cmd *apikey.AddCommand) (res *apikey.APIKey, err error) { err = ss.db.WithTransactionalDbSession(ctx, func(sess *db.Session) error { key := apikey.APIKey{OrgID: cmd.OrgID, Name: cmd.Name} diff --git a/pkg/services/apikey/apikeytest/fake.go b/pkg/services/apikey/apikeytest/fake.go index 3ded2b80b70..b586510865c 100644 --- a/pkg/services/apikey/apikeytest/fake.go +++ b/pkg/services/apikey/apikeytest/fake.go @@ -8,14 +8,10 @@ import ( type Service struct { ExpectedError error - ExpectedBool bool ExpectedAPIKeys []*apikey.APIKey ExpectedAPIKey *apikey.APIKey } -func (s *Service) GetAPIKeys(ctx context.Context, query *apikey.GetApiKeysQuery) ([]*apikey.APIKey, error) { - return s.ExpectedAPIKeys, s.ExpectedError -} func (s *Service) GetAllAPIKeys(ctx context.Context, orgID int64) ([]*apikey.APIKey, error) { return s.ExpectedAPIKeys, s.ExpectedError } @@ -25,15 +21,9 @@ func (s *Service) GetApiKeyByName(ctx context.Context, query *apikey.GetByNameQu func (s *Service) GetAPIKeyByHash(ctx context.Context, hash string) (*apikey.APIKey, error) { return s.ExpectedAPIKey, s.ExpectedError } -func (s *Service) DeleteApiKey(ctx context.Context, cmd *apikey.DeleteCommand) error { - return s.ExpectedError -} func (s *Service) AddAPIKey(ctx context.Context, cmd *apikey.AddCommand) (*apikey.APIKey, error) { return s.ExpectedAPIKey, s.ExpectedError } func (s *Service) UpdateAPIKeyLastUsedDate(ctx context.Context, tokenID int64) error { return s.ExpectedError } -func (s *Service) IsDisabled(ctx context.Context, orgID int64) (bool, error) { - return s.ExpectedBool, s.ExpectedError -} diff --git a/pkg/services/apikey/model.go b/pkg/services/apikey/model.go index e5af5731c81..7e1bcf71446 100644 --- a/pkg/services/apikey/model.go +++ b/pkg/services/apikey/model.go @@ -4,7 +4,6 @@ import ( "errors" "time" - "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/services/org" "github.com/grafana/grafana/pkg/services/quota" ) @@ -42,16 +41,6 @@ type AddCommand struct { ServiceAccountID *int64 `json:"-"` } -type DeleteCommand struct { - ID int64 `json:"id"` - OrgID int64 `json:"-"` -} - -type GetApiKeysQuery struct { - OrgID int64 - IncludeExpired bool - User identity.Requester -} type GetByNameQuery struct { KeyName string OrgID int64 diff --git a/pkg/services/navtree/navtreeimpl/admin.go b/pkg/services/navtree/navtreeimpl/admin.go index a9db04da82c..7bc0bd5e102 100644 --- a/pkg/services/navtree/navtreeimpl/admin.go +++ b/pkg/services/navtree/navtreeimpl/admin.go @@ -154,19 +154,6 @@ func (s *ServiceImpl) getAdminNode(c *contextmodel.ReqContext) (*navtree.NavLink Url: s.cfg.AppSubURL + "/org/serviceaccounts", }) } - disabled, err := s.apiKeyService.IsDisabled(ctx, c.GetOrgID()) - if err != nil { - return nil, err - } - if hasAccess(ac.ApiKeyAccessEvaluator) && !disabled { - accessNodeLinks = append(accessNodeLinks, &navtree.NavLink{ - Text: "API keys", - Id: "apikeys", - SubTitle: "Manage and create API keys that are used to interact with Grafana HTTP APIs", - Icon: "key-skeleton-alt", - Url: s.cfg.AppSubURL + "/org/apikeys", - }) - } if s.license.FeatureEnabled("groupsync") && s.features.IsEnabled(ctx, featuremgmt.FlagGroupAttributeSync) && diff --git a/pkg/services/serviceaccounts/api/api.go b/pkg/services/serviceaccounts/api/api.go index 028a7d914f5..a7adf99fb56 100644 --- a/pkg/services/serviceaccounts/api/api.go +++ b/pkg/services/serviceaccounts/api/api.go @@ -65,8 +65,6 @@ func (api *ServiceAccountsAPI) RegisterAPIEndpoints() { serviceAccountsRoute.Get("/:serviceAccountId/tokens", saUIDResolver, auth(accesscontrol.EvalPermission(serviceaccounts.ActionRead, serviceaccounts.ScopeID)), routing.Wrap(api.ListTokens)) serviceAccountsRoute.Post("/:serviceAccountId/tokens", saUIDResolver, auth(accesscontrol.EvalPermission(serviceaccounts.ActionWrite, serviceaccounts.ScopeID)), routing.Wrap(api.CreateToken)) serviceAccountsRoute.Delete("/:serviceAccountId/tokens/:tokenId", saUIDResolver, auth(accesscontrol.EvalPermission(serviceaccounts.ActionWrite, serviceaccounts.ScopeID)), routing.Wrap(api.DeleteToken)) - serviceAccountsRoute.Post("/migrate", auth(accesscontrol.EvalPermission(serviceaccounts.ActionCreate)), routing.Wrap(api.MigrateApiKeysToServiceAccounts)) - serviceAccountsRoute.Post("/migrate/:keyId", auth(accesscontrol.EvalPermission(serviceaccounts.ActionCreate)), routing.Wrap(api.ConvertToServiceAccount)) }, requestmeta.SetOwner(requestmeta.TeamAuth)) } @@ -302,30 +300,6 @@ func (api *ServiceAccountsAPI) SearchOrgServiceAccountsWithPaging(c *contextmode return response.JSON(http.StatusOK, serviceAccountSearch) } -// POST /api/serviceaccounts/migrate -func (api *ServiceAccountsAPI) MigrateApiKeysToServiceAccounts(ctx *contextmodel.ReqContext) response.Response { - results, err := api.service.MigrateApiKeysToServiceAccounts(ctx.Req.Context(), ctx.GetOrgID()) - if err != nil { - return response.JSON(http.StatusInternalServerError, results) - } - - return response.JSON(http.StatusOK, results) -} - -// POST /api/serviceaccounts/migrate/:keyId -func (api *ServiceAccountsAPI) ConvertToServiceAccount(ctx *contextmodel.ReqContext) response.Response { - keyId, err := strconv.ParseInt(web.Params(ctx.Req)[":keyId"], 10, 64) - if err != nil { - return response.Error(http.StatusBadRequest, "Key ID is invalid", err) - } - - if err := api.service.MigrateApiKey(ctx.Req.Context(), ctx.GetOrgID(), keyId); err != nil { - return response.Error(http.StatusInternalServerError, "Error converting API key", err) - } - - return response.Success("Service accounts migrated") -} - func (api *ServiceAccountsAPI) getAccessControlMetadata(c *contextmodel.ReqContext, saIDs map[string]bool) map[string]accesscontrol.Metadata { if !c.QueryBool("accesscontrol") { return map[string]accesscontrol.Metadata{} diff --git a/pkg/services/serviceaccounts/api/api_test.go b/pkg/services/serviceaccounts/api/api_test.go index 144869b390a..b154eee6a42 100644 --- a/pkg/services/serviceaccounts/api/api_test.go +++ b/pkg/services/serviceaccounts/api/api_test.go @@ -2,7 +2,6 @@ package api import ( "context" - "encoding/json" "fmt" "net/http" "strings" @@ -239,66 +238,6 @@ func TestServiceAccountsAPI_UpdateServiceAccount(t *testing.T) { } } -func TestServiceAccountsAPI_MigrateApiKeysToServiceAccounts(t *testing.T) { - type TestCase struct { - desc string - orgId int64 - basicRole org.RoleType - permissions []accesscontrol.Permission - expectedMigrationResult *serviceaccounts.MigrationResult - expectedCode int - } - - tests := []TestCase{ - { - desc: "should be able to migrate API keys to service accounts with correct permissions", - orgId: 1, - basicRole: org.RoleAdmin, - permissions: []accesscontrol.Permission{ - {Action: serviceaccounts.ActionCreate, Scope: serviceaccounts.ScopeAll}, - }, - expectedMigrationResult: &serviceaccounts.MigrationResult{ - Total: 5, - Migrated: 4, - Failed: 1, - FailedDetails: []string{"API key name: failedKey - Error: migration error"}, - }, - expectedCode: http.StatusOK, - }, - { - desc: "should not be able to migrate API keys to service accounts with wrong permissions", - orgId: 2, - basicRole: org.RoleAdmin, - permissions: []accesscontrol.Permission{ - {Action: serviceaccounts.ActionCreate, Scope: serviceaccounts.ScopeAll}, - }, - expectedCode: http.StatusForbidden, - }, - } - - for _, tt := range tests { - t.Run(tt.desc, func(t *testing.T) { - server := setupTests(t, func(a *ServiceAccountsAPI) { - a.service = &satests.FakeServiceAccountService{ExpectedMigrationResult: tt.expectedMigrationResult} - }) - - req := server.NewRequest(http.MethodPost, "/api/serviceaccounts/migrate", nil) - webtest.RequestWithSignedInUser(req, &user.SignedInUser{OrgRole: tt.basicRole, OrgID: tt.orgId, Permissions: map[int64]map[string][]string{1: accesscontrol.GroupScopesByActionContext(context.Background(), tt.permissions)}}) - res, err := server.SendJSON(req) - require.NoError(t, err) - - assert.Equal(t, tt.expectedCode, res.StatusCode) - if tt.expectedCode == http.StatusOK { - var result serviceaccounts.MigrationResult - err := json.NewDecoder(res.Body).Decode(&result) - require.NoError(t, err) - assert.Equal(t, tt.expectedMigrationResult, &result) - } - require.NoError(t, res.Body.Close()) - }) - } -} - func setupTests(t *testing.T, opts ...func(a *ServiceAccountsAPI)) *webtest.Server { t.Helper() cfg := setting.NewCfg() diff --git a/pkg/services/serviceaccounts/database/store.go b/pkg/services/serviceaccounts/database/store.go index 68379c98cdc..6ed850b52db 100644 --- a/pkg/services/serviceaccounts/database/store.go +++ b/pkg/services/serviceaccounts/database/store.go @@ -480,26 +480,6 @@ func (s *ServiceAccountsStoreImpl) MigrateApiKeysToServiceAccounts(ctx context.C return migrationResult, nil } -func (s *ServiceAccountsStoreImpl) MigrateApiKey(ctx context.Context, orgId int64, keyId int64) error { - basicKeys, err := s.apiKeyService.GetAllAPIKeys(ctx, orgId) - if err != nil { - return err - } - if len(basicKeys) == 0 { - return fmt.Errorf("no API keys to convert found") - } - for _, key := range basicKeys { - if keyId == key.ID { - err := s.CreateServiceAccountFromApikey(ctx, key) - if err != nil { - s.log.Error("Converting to service account failed with error", "keyId", keyId, "error", err) - return err - } - } - } - return nil -} - func (s *ServiceAccountsStoreImpl) CreateServiceAccountFromApikey(ctx context.Context, key *apikey.APIKey) error { prefix := "sa-autogen" cmd := user.CreateUserCommand{ diff --git a/pkg/services/serviceaccounts/database/store_test.go b/pkg/services/serviceaccounts/database/store_test.go index 7ce1b331b5b..1d8d3c844dd 100644 --- a/pkg/services/serviceaccounts/database/store_test.go +++ b/pkg/services/serviceaccounts/database/store_test.go @@ -2,7 +2,6 @@ package database import ( "context" - "strings" "testing" "github.com/stretchr/testify/assert" @@ -320,129 +319,6 @@ func TestIntegrationStore_RetrieveServiceAccount(t *testing.T) { } } -func TestIntegrationStore_MigrateApiKeys(t *testing.T) { - if testing.Short() { - t.Skip("skipping test in short mode") - } - cases := []struct { - desc string - serviceAccounts []user.CreateUserCommand - key tests.TestApiKey - expectedLogin string - expectedErr error - }{ - { - desc: "api key should be migrated to service account token", - serviceAccounts: []user.CreateUserCommand{}, - key: tests.TestApiKey{Name: "test1", Role: org.RoleEditor, OrgId: 1}, - expectedLogin: "sa-AuToGeN-1-test1", // Using mixed-case to test case-insensitive search. - expectedErr: nil, - }, - { - desc: "api key should be migrated to service account token on second attempt", - serviceAccounts: []user.CreateUserCommand{ - {Login: "sa-autogen-1-test2"}, - }, - key: tests.TestApiKey{Name: "test2", Role: org.RoleEditor, OrgId: 1}, - expectedLogin: "sa-AuToGeN-1-test2-001", // Using mixed-case to test case-insensitive search. - expectedErr: nil, - }, - { - desc: "api key should be migrated to service account token on last attempt (the 10th)", - serviceAccounts: []user.CreateUserCommand{ - {Login: "sa-autogen-1-test3"}, - {Login: "sa-autogen-1-test3-001"}, - {Login: "sa-autogen-1-test3-002"}, - {Login: "sa-autogen-1-test3-003"}, - {Login: "sa-autogen-1-test3-004"}, - {Login: "sa-autogen-1-test3-005"}, - {Login: "sa-autogen-1-test3-006"}, - {Login: "sa-autogen-1-test3-007"}, - {Login: "sa-autogen-1-test3-008"}, - {Login: "sa-autogen-1-test3-009"}, - }, - key: tests.TestApiKey{Name: "test3", Role: org.RoleEditor, OrgId: 1}, - expectedLogin: "sa-AuToGeN-1-test3-010", // Using mixed-case to test case-insensitive search. - expectedErr: nil, - }, - { - desc: "api key should not be migrated to service account token because all attempts failed", - serviceAccounts: []user.CreateUserCommand{ - {Login: "sa-autogen-1-test4"}, - {Login: "sa-autogen-1-test4-001"}, - {Login: "sa-autogen-1-test4-002"}, - {Login: "sa-autogen-1-test4-003"}, - {Login: "sa-autogen-1-test4-004"}, - {Login: "sa-autogen-1-test4-005"}, - {Login: "sa-autogen-1-test4-006"}, - {Login: "sa-autogen-1-test4-007"}, - {Login: "sa-autogen-1-test4-008"}, - {Login: "sa-autogen-1-test4-009"}, - {Login: "sa-autogen-1-test4-010"}, - }, - key: tests.TestApiKey{Name: "test4", Role: org.RoleEditor, OrgId: 1}, - expectedErr: serviceaccounts.ErrServiceAccountAlreadyExists, - }, - } - - for _, c := range cases { - t.Run(c.desc, func(t *testing.T) { - db, store := setupTestDatabase(t) - - store.cfg.AutoAssignOrg = true - store.cfg.AutoAssignOrgId = 1 - store.cfg.AutoAssignOrgRole = "Viewer" - _, err := store.orgService.CreateWithMember(context.Background(), &org.CreateOrgCommand{Name: "main"}) - require.NoError(t, err) - - key := tests.SetupApiKey(t, db, store.cfg, c.key) - - for _, sa := range c.serviceAccounts { - sa.IsServiceAccount = true - sa.OrgID = key.OrgID - _, err := store.userService.CreateServiceAccount(context.Background(), &sa) - require.NoError(t, err) - } - - err = store.MigrateApiKey(context.Background(), key.OrgID, key.ID) - if c.expectedErr != nil { - require.ErrorIs(t, err, c.expectedErr) - } else { - require.NoError(t, err) - - q := serviceaccounts.SearchOrgServiceAccountsQuery{ - OrgID: key.OrgID, - Query: c.expectedLogin, - Page: 1, - Limit: 50, - SignedInUser: &user.SignedInUser{ - UserID: 1, - OrgID: 1, - Permissions: map[int64]map[string][]string{ - key.OrgID: { - "serviceaccounts:read": {"serviceaccounts:id:*"}, - }, - }, - }, - } - serviceAccounts, err := store.SearchOrgServiceAccounts(context.Background(), &q) - require.NoError(t, err) - require.Equal(t, int64(1), serviceAccounts.TotalCount) - saMigrated := serviceAccounts.ServiceAccounts[0] - require.Equal(t, string(key.Role), saMigrated.Role) - require.Equal(t, strings.ToLower(c.expectedLogin), saMigrated.Login) - - tokens, err := store.ListTokens(context.Background(), &serviceaccounts.GetSATokensQuery{ - OrgID: &key.OrgID, - ServiceAccountID: &saMigrated.Id, - }) - require.NoError(t, err) - require.Len(t, tokens, 1) - } - }) - } -} - func TestIntegrationStore_MigrateAllApiKeys(t *testing.T) { if testing.Short() { t.Skip("skipping test in short mode") diff --git a/pkg/services/serviceaccounts/manager/service.go b/pkg/services/serviceaccounts/manager/service.go index cde680f616d..f03e5602ff5 100644 --- a/pkg/services/serviceaccounts/manager/service.go +++ b/pkg/services/serviceaccounts/manager/service.go @@ -301,15 +301,6 @@ func (sa *ServiceAccountsService) DeleteServiceAccountToken(ctx context.Context, return sa.store.DeleteServiceAccountToken(ctx, orgID, serviceAccountID, tokenID) } -func (sa *ServiceAccountsService) MigrateApiKey(ctx context.Context, orgID, keyID int64) error { - if err := validOrgID(orgID); err != nil { - return err - } - if err := validAPIKeyID(keyID); err != nil { - return err - } - return sa.store.MigrateApiKey(ctx, orgID, keyID) -} func (sa *ServiceAccountsService) MigrateApiKeysToServiceAccounts(ctx context.Context, orgID int64) (*serviceaccounts.MigrationResult, error) { if err := validOrgID(orgID); err != nil { return nil, err @@ -389,9 +380,3 @@ func validServiceAccountTokenID(tokenID int64) error { } return nil } -func validAPIKeyID(apiKeyID int64) error { - if apiKeyID == 0 { - return serviceaccounts.ErrServiceAccountInvalidAPIKeyID.Errorf("invalid API key ID 0 has been specified") - } - return nil -} diff --git a/pkg/services/serviceaccounts/manager/service_test.go b/pkg/services/serviceaccounts/manager/service_test.go index 43614415dc9..9cfdcf62777 100644 --- a/pkg/services/serviceaccounts/manager/service_test.go +++ b/pkg/services/serviceaccounts/manager/service_test.go @@ -75,11 +75,6 @@ func (f *FakeServiceAccountStore) MigrateApiKeysToServiceAccounts(ctx context.Co return f.expectedMigratedResults, f.ExpectedError } -// MigrateApiKey is a fake migrating an api key to a service account. -func (f *FakeServiceAccountStore) MigrateApiKey(ctx context.Context, orgID int64, keyId int64) error { - return f.ExpectedError -} - // RevertApiKey is a fake reverting an api key to a service account. func (f *FakeServiceAccountStore) RevertApiKey(ctx context.Context, saId int64, keyId int64) error { return f.ExpectedError diff --git a/pkg/services/serviceaccounts/manager/store.go b/pkg/services/serviceaccounts/manager/store.go index 63235bc4fb2..506ab58dfa6 100644 --- a/pkg/services/serviceaccounts/manager/store.go +++ b/pkg/services/serviceaccounts/manager/store.go @@ -15,7 +15,6 @@ type store interface { EnableServiceAccount(ctx context.Context, orgID, serviceAccountID int64, enable bool) error GetUsageMetrics(ctx context.Context) (*serviceaccounts.Stats, error) ListTokens(ctx context.Context, query *serviceaccounts.GetSATokensQuery) ([]apikey.APIKey, error) - MigrateApiKey(ctx context.Context, orgID int64, keyId int64) error MigrateApiKeysToServiceAccounts(ctx context.Context, orgID int64) (*serviceaccounts.MigrationResult, error) RetrieveServiceAccount(ctx context.Context, query *serviceaccounts.GetServiceAccountQuery) (*serviceaccounts.ServiceAccountProfileDTO, error) RetrieveServiceAccountIdByName(ctx context.Context, orgID int64, name string) (int64, error) diff --git a/pkg/services/serviceaccounts/proxy/service.go b/pkg/services/serviceaccounts/proxy/service.go index 93917a58369..3b24a1a66ca 100644 --- a/pkg/services/serviceaccounts/proxy/service.go +++ b/pkg/services/serviceaccounts/proxy/service.go @@ -123,10 +123,6 @@ func (s *ServiceAccountsProxy) ListTokens(ctx context.Context, query *serviceacc return s.proxiedService.ListTokens(ctx, query) } -func (s *ServiceAccountsProxy) MigrateApiKey(ctx context.Context, orgID int64, keyId int64) error { - return s.proxiedService.MigrateApiKey(ctx, orgID, keyId) -} - func (s *ServiceAccountsProxy) MigrateApiKeysToServiceAccounts(ctx context.Context, orgID int64) (*serviceaccounts.MigrationResult, error) { return s.proxiedService.MigrateApiKeysToServiceAccounts(ctx, orgID) } diff --git a/pkg/services/serviceaccounts/serviceaccounts.go b/pkg/services/serviceaccounts/serviceaccounts.go index ae07ede8cb0..5c9ead576dc 100644 --- a/pkg/services/serviceaccounts/serviceaccounts.go +++ b/pkg/services/serviceaccounts/serviceaccounts.go @@ -41,8 +41,6 @@ type Service interface { DeleteServiceAccountToken(ctx context.Context, orgID, serviceAccountID, tokenID int64) error ListTokens(ctx context.Context, query *GetSATokensQuery) ([]apikey.APIKey, error) - // API specific functions - MigrateApiKey(ctx context.Context, orgID int64, keyId int64) error MigrateApiKeysToServiceAccounts(ctx context.Context, orgID int64) (*MigrationResult, error) } diff --git a/pkg/services/serviceaccounts/tests/fakes.go b/pkg/services/serviceaccounts/tests/fakes.go index 294069398d9..c8b1631db39 100644 --- a/pkg/services/serviceaccounts/tests/fakes.go +++ b/pkg/services/serviceaccounts/tests/fakes.go @@ -52,10 +52,6 @@ func (f *FakeServiceAccountService) ListTokens(ctx context.Context, query *servi return f.ExpectedServiceAccountTokens, f.ExpectedErr } -func (f *FakeServiceAccountService) MigrateApiKey(ctx context.Context, orgID, keyID int64) error { - return f.ExpectedErr -} - func (f *FakeServiceAccountService) MigrateApiKeysToServiceAccounts(ctx context.Context, orgID int64) (*serviceaccounts.MigrationResult, error) { return f.ExpectedMigrationResult, f.ExpectedErr } diff --git a/pkg/services/serviceaccounts/tests/mocks.go b/pkg/services/serviceaccounts/tests/mocks.go index 500b6f535fc..a33fc5ae5b4 100644 --- a/pkg/services/serviceaccounts/tests/mocks.go +++ b/pkg/services/serviceaccounts/tests/mocks.go @@ -137,20 +137,6 @@ func (_m *MockServiceAccountService) ListTokens(ctx context.Context, query *serv return r0, r1 } -// MigrateApiKey provides a mock function with given fields: ctx, orgID, keyId -func (_m *MockServiceAccountService) MigrateApiKey(ctx context.Context, orgID int64, keyId int64) error { - ret := _m.Called(ctx, orgID, keyId) - - var r0 error - if rf, ok := ret.Get(0).(func(context.Context, int64, int64) error); ok { - r0 = rf(ctx, orgID, keyId) - } else { - r0 = ret.Error(0) - } - - return r0 -} - // MigrateApiKeysToServiceAccounts provides a mock function with given fields: ctx, orgID func (_m *MockServiceAccountService) MigrateApiKeysToServiceAccounts(ctx context.Context, orgID int64) (*serviceaccounts.MigrationResult, error) { ret := _m.Called(ctx, orgID) diff --git a/public/api-enterprise-spec.json b/public/api-enterprise-spec.json index d9dc456570f..568b7826c44 100644 --- a/public/api-enterprise-spec.json +++ b/public/api-enterprise-spec.json @@ -3027,38 +3027,6 @@ } } }, - "ApiKeyDTO": { - "type": "object", - "properties": { - "accessControl": { - "$ref": "#/definitions/Metadata" - }, - "expiration": { - "type": "string", - "format": "date-time" - }, - "id": { - "type": "integer", - "format": "int64" - }, - "lastUsedAt": { - "type": "string", - "format": "date-time" - }, - "name": { - "type": "string" - }, - "role": { - "type": "string", - "enum": [ - "None", - "Viewer", - "Editor", - "Admin" - ] - } - } - }, "Assignments": { "type": "object", "properties": { @@ -9570,15 +9538,6 @@ "$ref": "#/definitions/ErrorResponseBody" } }, - "getAPIkeyResponse": { - "description": "", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/ApiKeyDTO" - } - } - }, "getAccessControlStatusResponse": { "description": "", "schema": { diff --git a/public/api-merged.json b/public/api-merged.json index 56f42df789e..7d0712c435e 100644 --- a/public/api-merged.json +++ b/public/api-merged.json @@ -2188,93 +2188,6 @@ } } }, - "/auth/keys": { - "get": { - "description": "Will return auth keys.\n\nDeprecated: true.\n\nDeprecated. Please use GET /api/serviceaccounts and GET /api/serviceaccounts/{id}/tokens instead\nsee https://grafana.com/docs/grafana/next/administration/service-accounts/migrate-api-keys/.", - "tags": [ - "api_keys" - ], - "summary": "Get auth keys.", - "operationId": "getAPIkeys", - "parameters": [ - { - "type": "boolean", - "default": false, - "description": "Show expired keys", - "name": "includeExpired", - "in": "query" - } - ], - "responses": { - "200": { - "$ref": "#/responses/getAPIkeyResponse" - }, - "401": { - "$ref": "#/responses/unauthorisedError" - }, - "403": { - "$ref": "#/responses/forbiddenError" - }, - "404": { - "$ref": "#/responses/notFoundError" - }, - "500": { - "$ref": "#/responses/internalServerError" - } - } - }, - "post": { - "description": "Will return details of the created API key.", - "tags": [ - "api_keys" - ], - "summary": "Creates an API key.", - "operationId": "addAPIkey", - "deprecated": true, - "responses": { - "410": { - "$ref": "#/responses/goneError" - } - } - } - }, - "/auth/keys/{id}": { - "delete": { - "description": "Deletes an API key.\nDeprecated. See: https://grafana.com/docs/grafana/next/administration/service-accounts/migrate-api-keys/.", - "tags": [ - "api_keys" - ], - "summary": "Delete API key.", - "operationId": "deleteAPIkey", - "deprecated": true, - "parameters": [ - { - "type": "integer", - "format": "int64", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "$ref": "#/responses/okResponse" - }, - "401": { - "$ref": "#/responses/unauthorisedError" - }, - "403": { - "$ref": "#/responses/forbiddenError" - }, - "404": { - "$ref": "#/responses/notFoundError" - }, - "500": { - "$ref": "#/responses/internalServerError" - } - } - } - }, "/cloudmigration/migration": { "get": { "tags": [ @@ -13308,38 +13221,6 @@ } } }, - "ApiKeyDTO": { - "type": "object", - "properties": { - "accessControl": { - "$ref": "#/definitions/Metadata" - }, - "expiration": { - "type": "string", - "format": "date-time" - }, - "id": { - "type": "integer", - "format": "int64" - }, - "lastUsedAt": { - "type": "string", - "format": "date-time" - }, - "name": { - "type": "string" - }, - "role": { - "type": "string", - "enum": [ - "None", - "Viewer", - "Editor", - "Admin" - ] - } - } - }, "ApiRuleNode": { "type": "object", "properties": { @@ -24160,15 +24041,6 @@ "$ref": "#/definitions/ErrorResponseBody" } }, - "getAPIkeyResponse": { - "description": "(empty)", - "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/ApiKeyDTO" - } - } - }, "getAccessControlStatusResponse": { "description": "(empty)", "schema": { diff --git a/public/openapi3.json b/public/openapi3.json index f32b82e15d3..22364cdfc6b 100644 --- a/public/openapi3.json +++ b/public/openapi3.json @@ -628,19 +628,6 @@ }, "description": "A GenericError is the default error message that is generated.\nFor certain status codes there are more appropriate error structures." }, - "getAPIkeyResponse": { - "content": { - "application/json": { - "schema": { - "items": { - "$ref": "#/components/schemas/ApiKeyDTO" - }, - "type": "array" - } - } - }, - "description": "(empty)" - }, "getAccessControlStatusResponse": { "content": { "application/json": { @@ -3284,38 +3271,6 @@ }, "type": "object" }, - "ApiKeyDTO": { - "properties": { - "accessControl": { - "$ref": "#/components/schemas/Metadata" - }, - "expiration": { - "format": "date-time", - "type": "string" - }, - "id": { - "format": "int64", - "type": "integer" - }, - "lastUsedAt": { - "format": "date-time", - "type": "string" - }, - "name": { - "type": "string" - }, - "role": { - "enum": [ - "None", - "Viewer", - "Editor", - "Admin" - ], - "type": "string" - } - }, - "type": "object" - }, "ApiRuleNode": { "properties": { "alert": { @@ -16055,97 +16010,6 @@ ] } }, - "/auth/keys": { - "get": { - "description": "Will return auth keys.\n\nDeprecated: true.\n\nDeprecated. Please use GET /api/serviceaccounts and GET /api/serviceaccounts/{id}/tokens instead\nsee https://grafana.com/docs/grafana/next/administration/service-accounts/migrate-api-keys/.", - "operationId": "getAPIkeys", - "parameters": [ - { - "description": "Show expired keys", - "in": "query", - "name": "includeExpired", - "schema": { - "default": false, - "type": "boolean" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/getAPIkeyResponse" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Get auth keys.", - "tags": [ - "api_keys" - ] - }, - "post": { - "deprecated": true, - "description": "Will return details of the created API key.", - "operationId": "addAPIkey", - "responses": { - "410": { - "$ref": "#/components/responses/goneError" - } - }, - "summary": "Creates an API key.", - "tags": [ - "api_keys" - ] - } - }, - "/auth/keys/{id}": { - "delete": { - "deprecated": true, - "description": "Deletes an API key.\nDeprecated. See: https://grafana.com/docs/grafana/next/administration/service-accounts/migrate-api-keys/.", - "operationId": "deleteAPIkey", - "parameters": [ - { - "in": "path", - "name": "id", - "required": true, - "schema": { - "format": "int64", - "type": "integer" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/okResponse" - }, - "401": { - "$ref": "#/components/responses/unauthorisedError" - }, - "403": { - "$ref": "#/components/responses/forbiddenError" - }, - "404": { - "$ref": "#/components/responses/notFoundError" - }, - "500": { - "$ref": "#/components/responses/internalServerError" - } - }, - "summary": "Delete API key.", - "tags": [ - "api_keys" - ] - } - }, "/cloudmigration/migration": { "get": { "operationId": "getSessionList",