Chore: Move api key models into apikey service package (#53241)

* Chore: move api key models into apikey service package

* force table name for api key
This commit is contained in:
Serge Zaitsev
2022-08-04 14:19:09 +02:00
committed by GitHub
parent af83a09a92
commit 191ab3bb01
21 changed files with 203 additions and 230 deletions
+7 -8
View File
@@ -3,7 +3,6 @@ package apikeyimpl
import (
"context"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/apikey"
"github.com/grafana/grafana/pkg/services/sqlstore/db"
"github.com/grafana/grafana/pkg/setting"
@@ -17,25 +16,25 @@ func ProvideService(db db.DB, cfg *setting.Cfg) apikey.Service {
return &Service{store: &sqlStore{db: db, cfg: cfg}}
}
func (s *Service) GetAPIKeys(ctx context.Context, query *models.GetApiKeysQuery) error {
func (s *Service) GetAPIKeys(ctx context.Context, query *apikey.GetApiKeysQuery) error {
return s.store.GetAPIKeys(ctx, query)
}
func (s *Service) GetAllAPIKeys(ctx context.Context, orgID int64) []*models.ApiKey {
func (s *Service) GetAllAPIKeys(ctx context.Context, orgID int64) []*apikey.APIKey {
return s.store.GetAllAPIKeys(ctx, orgID)
}
func (s *Service) GetApiKeyById(ctx context.Context, query *models.GetApiKeyByIdQuery) error {
func (s *Service) GetApiKeyById(ctx context.Context, query *apikey.GetByIDQuery) error {
return s.store.GetApiKeyById(ctx, query)
}
func (s *Service) GetApiKeyByName(ctx context.Context, query *models.GetApiKeyByNameQuery) error {
func (s *Service) GetApiKeyByName(ctx context.Context, query *apikey.GetByNameQuery) error {
return s.store.GetApiKeyByName(ctx, query)
}
func (s *Service) GetAPIKeyByHash(ctx context.Context, hash string) (*models.ApiKey, error) {
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 *models.DeleteApiKeyCommand) error {
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 *models.AddApiKeyCommand) error {
func (s *Service) AddAPIKey(ctx context.Context, cmd *apikey.AddCommand) error {
return s.store.AddAPIKey(ctx, cmd)
}
func (s *Service) UpdateAPIKeyLastUsedDate(ctx context.Context, tokenID int64) error {
+35 -35
View File
@@ -5,8 +5,8 @@ import (
"fmt"
"time"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/apikey"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/sqlstore/db"
"github.com/grafana/grafana/pkg/setting"
@@ -14,13 +14,13 @@ import (
)
type store interface {
GetAPIKeys(ctx context.Context, query *models.GetApiKeysQuery) error
GetAllAPIKeys(ctx context.Context, orgID int64) []*models.ApiKey
DeleteApiKey(ctx context.Context, cmd *models.DeleteApiKeyCommand) error
AddAPIKey(ctx context.Context, cmd *models.AddApiKeyCommand) error
GetApiKeyById(ctx context.Context, query *models.GetApiKeyByIdQuery) error
GetApiKeyByName(ctx context.Context, query *models.GetApiKeyByNameQuery) error
GetAPIKeyByHash(ctx context.Context, hash string) (*models.ApiKey, error)
GetAPIKeys(ctx context.Context, query *apikey.GetApiKeysQuery) error
GetAllAPIKeys(ctx context.Context, orgID int64) []*apikey.APIKey
DeleteApiKey(ctx context.Context, cmd *apikey.DeleteCommand) error
AddAPIKey(ctx context.Context, cmd *apikey.AddCommand) error
GetApiKeyById(ctx context.Context, query *apikey.GetByIDQuery) error
GetApiKeyByName(ctx context.Context, query *apikey.GetByNameQuery) error
GetAPIKeyByHash(ctx context.Context, hash string) (*apikey.APIKey, error)
UpdateAPIKeyLastUsedDate(ctx context.Context, tokenID int64) error
}
@@ -32,7 +32,7 @@ type sqlStore struct {
// timeNow makes it possible to test usage of time
var timeNow = time.Now
func (ss *sqlStore) GetAPIKeys(ctx context.Context, query *models.GetApiKeysQuery) error {
func (ss *sqlStore) GetAPIKeys(ctx context.Context, query *apikey.GetApiKeysQuery) error {
return ss.db.WithDbSession(ctx, func(dbSession *sqlstore.DBSession) error {
var sess *xorm.Session
@@ -56,13 +56,13 @@ func (ss *sqlStore) GetAPIKeys(ctx context.Context, query *models.GetApiKeysQuer
sess.And(filter.Where, filter.Args...)
}
query.Result = make([]*models.ApiKey, 0)
query.Result = make([]*apikey.APIKey, 0)
return sess.Find(&query.Result)
})
}
func (ss *sqlStore) GetAllAPIKeys(ctx context.Context, orgID int64) []*models.ApiKey {
result := make([]*models.ApiKey, 0)
func (ss *sqlStore) GetAllAPIKeys(ctx context.Context, orgID int64) []*apikey.APIKey {
result := make([]*apikey.APIKey, 0)
err := ss.db.WithDbSession(ctx, func(dbSession *sqlstore.DBSession) error {
sess := dbSession.Where("service_account_id IS NULL").Asc("name")
if orgID != -1 {
@@ -77,7 +77,7 @@ func (ss *sqlStore) GetAllAPIKeys(ctx context.Context, orgID int64) []*models.Ap
return result
}
func (ss *sqlStore) DeleteApiKey(ctx context.Context, cmd *models.DeleteApiKeyCommand) error {
func (ss *sqlStore) DeleteApiKey(ctx context.Context, cmd *apikey.DeleteCommand) error {
return ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) 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)
@@ -88,18 +88,18 @@ func (ss *sqlStore) DeleteApiKey(ctx context.Context, cmd *models.DeleteApiKeyCo
if err != nil {
return err
} else if n == 0 {
return models.ErrApiKeyNotFound
return apikey.ErrNotFound
}
return nil
})
}
func (ss *sqlStore) AddAPIKey(ctx context.Context, cmd *models.AddApiKeyCommand) error {
func (ss *sqlStore) AddAPIKey(ctx context.Context, cmd *apikey.AddCommand) error {
return ss.db.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
key := models.ApiKey{OrgId: cmd.OrgId, Name: cmd.Name}
key := apikey.APIKey{OrgId: cmd.OrgId, Name: cmd.Name}
exists, _ := sess.Get(&key)
if exists {
return models.ErrDuplicateApiKey
return apikey.ErrDuplicate
}
updated := timeNow()
@@ -108,10 +108,10 @@ func (ss *sqlStore) AddAPIKey(ctx context.Context, cmd *models.AddApiKeyCommand)
v := updated.Add(time.Second * time.Duration(cmd.SecondsToLive)).Unix()
expires = &v
} else if cmd.SecondsToLive < 0 {
return models.ErrInvalidApiKeyExpiration
return apikey.ErrInvalidExpiration
}
t := models.ApiKey{
t := apikey.APIKey{
OrgId: cmd.OrgId,
Name: cmd.Name,
Role: cmd.Role,
@@ -130,56 +130,56 @@ func (ss *sqlStore) AddAPIKey(ctx context.Context, cmd *models.AddApiKeyCommand)
})
}
func (ss *sqlStore) GetApiKeyById(ctx context.Context, query *models.GetApiKeyByIdQuery) error {
func (ss *sqlStore) GetApiKeyById(ctx context.Context, query *apikey.GetByIDQuery) error {
return ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
var apikey models.ApiKey
has, err := sess.ID(query.ApiKeyId).Get(&apikey)
var key apikey.APIKey
has, err := sess.ID(query.ApiKeyId).Get(&key)
if err != nil {
return err
} else if !has {
return models.ErrInvalidApiKey
return apikey.ErrInvalid
}
query.Result = &apikey
query.Result = &key
return nil
})
}
func (ss *sqlStore) GetApiKeyByName(ctx context.Context, query *models.GetApiKeyByNameQuery) error {
func (ss *sqlStore) GetApiKeyByName(ctx context.Context, query *apikey.GetByNameQuery) error {
return ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
var apikey models.ApiKey
has, err := sess.Where("org_id=? AND name=?", query.OrgId, query.KeyName).Get(&apikey)
var key apikey.APIKey
has, err := sess.Where("org_id=? AND name=?", query.OrgId, query.KeyName).Get(&key)
if err != nil {
return err
} else if !has {
return models.ErrInvalidApiKey
return apikey.ErrInvalid
}
query.Result = &apikey
query.Result = &key
return nil
})
}
func (ss *sqlStore) GetAPIKeyByHash(ctx context.Context, hash string) (*models.ApiKey, error) {
var apikey models.ApiKey
func (ss *sqlStore) GetAPIKeyByHash(ctx context.Context, hash string) (*apikey.APIKey, error) {
var key apikey.APIKey
err := ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
has, err := sess.Table("api_key").Where(fmt.Sprintf("%s = ?", ss.db.GetDialect().Quote("key")), hash).Get(&apikey)
has, err := sess.Table("api_key").Where(fmt.Sprintf("%s = ?", ss.db.GetDialect().Quote("key")), hash).Get(&key)
if err != nil {
return err
} else if !has {
return models.ErrInvalidApiKey
return apikey.ErrInvalid
}
return nil
})
return &apikey, err
return &key, err
}
func (ss *sqlStore) UpdateAPIKeyLastUsedDate(ctx context.Context, tokenID int64) error {
now := timeNow()
return ss.db.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
if _, err := sess.Table("api_key").ID(tokenID).Cols("last_used_at").Update(&models.ApiKey{LastUsedAt: &now}); err != nil {
if _, err := sess.Table("api_key").ID(tokenID).Cols("last_used_at").Update(&apikey.APIKey{LastUsedAt: &now}); err != nil {
return err
}
+24 -23
View File
@@ -11,6 +11,7 @@ import (
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/apikey"
"github.com/grafana/grafana/pkg/services/sqlstore"
)
@@ -40,12 +41,12 @@ func TestIntegrationApiKeyDataAccess(t *testing.T) {
ss := &sqlStore{db: db, cfg: db.Cfg}
t.Run("Given saved api key", func(t *testing.T) {
cmd := models.AddApiKeyCommand{OrgId: 1, Name: "hello", Key: "asd"}
cmd := apikey.AddCommand{OrgId: 1, Name: "hello", Key: "asd"}
err := ss.AddAPIKey(context.Background(), &cmd)
assert.Nil(t, err)
t.Run("Should be able to get key by name", func(t *testing.T) {
query := models.GetApiKeyByNameQuery{KeyName: "hello", OrgId: 1}
query := apikey.GetByNameQuery{KeyName: "hello", OrgId: 1}
err = ss.GetApiKeyByName(context.Background(), &query)
assert.Nil(t, err)
@@ -61,11 +62,11 @@ func TestIntegrationApiKeyDataAccess(t *testing.T) {
})
t.Run("Add non expiring key", func(t *testing.T) {
cmd := models.AddApiKeyCommand{OrgId: 1, Name: "non-expiring", Key: "asd1", SecondsToLive: 0}
cmd := apikey.AddCommand{OrgId: 1, Name: "non-expiring", Key: "asd1", SecondsToLive: 0}
err := ss.AddAPIKey(context.Background(), &cmd)
assert.Nil(t, err)
query := models.GetApiKeyByNameQuery{KeyName: "non-expiring", OrgId: 1}
query := apikey.GetByNameQuery{KeyName: "non-expiring", OrgId: 1}
err = ss.GetApiKeyByName(context.Background(), &query)
assert.Nil(t, err)
@@ -74,11 +75,11 @@ func TestIntegrationApiKeyDataAccess(t *testing.T) {
t.Run("Add an expiring key", func(t *testing.T) {
// expires in one hour
cmd := models.AddApiKeyCommand{OrgId: 1, Name: "expiring-in-an-hour", Key: "asd2", SecondsToLive: 3600}
cmd := apikey.AddCommand{OrgId: 1, Name: "expiring-in-an-hour", Key: "asd2", SecondsToLive: 3600}
err := ss.AddAPIKey(context.Background(), &cmd)
assert.Nil(t, err)
query := models.GetApiKeyByNameQuery{KeyName: "expiring-in-an-hour", OrgId: 1}
query := apikey.GetByNameQuery{KeyName: "expiring-in-an-hour", OrgId: 1}
err = ss.GetApiKeyByName(context.Background(), &query)
assert.Nil(t, err)
@@ -94,7 +95,7 @@ func TestIntegrationApiKeyDataAccess(t *testing.T) {
t.Run("Last Used At datetime update", func(t *testing.T) {
// expires in one hour
cmd := models.AddApiKeyCommand{OrgId: 1, Name: "last-update-at", Key: "asd3", SecondsToLive: 3600}
cmd := apikey.AddCommand{OrgId: 1, Name: "last-update-at", Key: "asd3", SecondsToLive: 3600}
err := ss.AddAPIKey(context.Background(), &cmd)
require.NoError(t, err)
@@ -103,7 +104,7 @@ func TestIntegrationApiKeyDataAccess(t *testing.T) {
err = ss.UpdateAPIKeyLastUsedDate(context.Background(), cmd.Result.Id)
require.NoError(t, err)
query := models.GetApiKeyByNameQuery{KeyName: "last-update-at", OrgId: 1}
query := apikey.GetByNameQuery{KeyName: "last-update-at", OrgId: 1}
err = ss.GetApiKeyByName(context.Background(), &query)
assert.Nil(t, err)
@@ -112,28 +113,28 @@ func TestIntegrationApiKeyDataAccess(t *testing.T) {
t.Run("Add a key with negative lifespan", func(t *testing.T) {
// expires in one day
cmd := models.AddApiKeyCommand{OrgId: 1, Name: "key-with-negative-lifespan", Key: "asd3", SecondsToLive: -3600}
cmd := apikey.AddCommand{OrgId: 1, Name: "key-with-negative-lifespan", Key: "asd3", SecondsToLive: -3600}
err := ss.AddAPIKey(context.Background(), &cmd)
assert.EqualError(t, err, models.ErrInvalidApiKeyExpiration.Error())
assert.EqualError(t, err, apikey.ErrInvalidExpiration.Error())
query := models.GetApiKeyByNameQuery{KeyName: "key-with-negative-lifespan", OrgId: 1}
query := apikey.GetByNameQuery{KeyName: "key-with-negative-lifespan", OrgId: 1}
err = ss.GetApiKeyByName(context.Background(), &query)
assert.EqualError(t, err, "invalid API key")
})
t.Run("Add keys", func(t *testing.T) {
// never expires
cmd := models.AddApiKeyCommand{OrgId: 1, Name: "key1", Key: "key1", SecondsToLive: 0}
cmd := apikey.AddCommand{OrgId: 1, Name: "key1", Key: "key1", SecondsToLive: 0}
err := ss.AddAPIKey(context.Background(), &cmd)
assert.Nil(t, err)
// expires in 1s
cmd = models.AddApiKeyCommand{OrgId: 1, Name: "key2", Key: "key2", SecondsToLive: 1}
cmd = apikey.AddCommand{OrgId: 1, Name: "key2", Key: "key2", SecondsToLive: 1}
err = ss.AddAPIKey(context.Background(), &cmd)
assert.Nil(t, err)
// expires in one hour
cmd = models.AddApiKeyCommand{OrgId: 1, Name: "key3", Key: "key3", SecondsToLive: 3600}
cmd = apikey.AddCommand{OrgId: 1, Name: "key3", Key: "key3", SecondsToLive: 3600}
err = ss.AddAPIKey(context.Background(), &cmd)
assert.Nil(t, err)
@@ -146,7 +147,7 @@ func TestIntegrationApiKeyDataAccess(t *testing.T) {
1: {accesscontrol.ActionAPIKeyRead: []string{accesscontrol.ScopeAPIKeysAll}},
},
}
query := models.GetApiKeysQuery{OrgId: 1, IncludeExpired: false, User: testUser}
query := apikey.GetApiKeysQuery{OrgId: 1, IncludeExpired: false, User: testUser}
err = ss.GetAPIKeys(context.Background(), &query)
assert.Nil(t, err)
@@ -156,7 +157,7 @@ func TestIntegrationApiKeyDataAccess(t *testing.T) {
}
}
query = models.GetApiKeysQuery{OrgId: 1, IncludeExpired: true, User: testUser}
query = apikey.GetApiKeysQuery{OrgId: 1, IncludeExpired: true, User: testUser}
err = ss.GetAPIKeys(context.Background(), &query)
assert.Nil(t, err)
@@ -183,22 +184,22 @@ func TestIntegrationApiKeyErrors(t *testing.T) {
ss := &sqlStore{db: db, cfg: db.Cfg}
t.Run("Delete non-existing key should return error", func(t *testing.T) {
cmd := models.DeleteApiKeyCommand{Id: 1}
cmd := apikey.DeleteCommand{Id: 1}
err := ss.DeleteApiKey(context.Background(), &cmd)
assert.EqualError(t, err, models.ErrApiKeyNotFound.Error())
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 := models.AddApiKeyCommand{OrgId: 0, Name: "duplicate", Key: "asd"}
cmd := apikey.AddCommand{OrgId: 0, Name: "duplicate", Key: "asd"}
err := ss.AddAPIKey(context.Background(), &cmd)
assert.Nil(t, err)
t.Run("Add API Key with existing Org ID and Name", func(t *testing.T) {
cmd := models.AddApiKeyCommand{OrgId: 0, Name: "duplicate", Key: "asd"}
cmd := apikey.AddCommand{OrgId: 0, Name: "duplicate", Key: "asd"}
err = ss.AddAPIKey(context.Background(), &cmd)
assert.EqualError(t, err, models.ErrDuplicateApiKey.Error())
assert.EqualError(t, err, apikey.ErrDuplicate.Error())
})
})
})
@@ -245,7 +246,7 @@ func TestIntegrationSQLStore_GetAPIKeys(t *testing.T) {
store := &sqlStore{db: db, cfg: db.Cfg}
seedApiKeys(t, store, 10)
query := &models.GetApiKeysQuery{OrgId: 1, User: tt.user}
query := &apikey.GetApiKeysQuery{OrgId: 1, User: tt.user}
err := store.GetAPIKeys(context.Background(), query)
require.NoError(t, err)
assert.Len(t, query.Result, tt.expectedNumKeys)
@@ -257,7 +258,7 @@ func seedApiKeys(t *testing.T, store store, num int) {
t.Helper()
for i := 0; i < num; i++ {
err := store.AddAPIKey(context.Background(), &models.AddApiKeyCommand{
err := store.AddAPIKey(context.Background(), &apikey.AddCommand{
Name: fmt.Sprintf("key:%d", i),
Key: fmt.Sprintf("key:%d", i),
OrgId: 1,