mirror of https://github.com/grafana/grafana.git
Separate API key store from SA token store (#45862)
* ServiceAccounts: Fix token-apikey cross deletion * ServiceAccounts: separate API key store and service account token store * ServiceAccounts: hide service account tokens from API Keys page * ServiceAccounts: uppercase statement * ServiceAccounts: fix and add new tests for SAT store * ServiceAccounts: remove service account ID from add API key * ServiceAccounts: clear up errors
This commit is contained in:
parent
15d681b823
commit
5cb03d6e62
|
|
@ -80,7 +80,6 @@ func (hs *HTTPServer) AddAPIKey(c *models.ReqContext) response.Response {
|
|||
}
|
||||
}
|
||||
|
||||
cmd.ServiceAccountId = nil // Security: API keys can't be added to SAs through this endpoint since we do not implement access checks here
|
||||
cmd.OrgId = c.OrgId
|
||||
|
||||
newKeyInfo, err := apikeygen.New(cmd.OrgId, cmd.Name)
|
||||
|
|
|
|||
|
|
@ -27,13 +27,12 @@ type ApiKey struct {
|
|||
// ---------------------
|
||||
// COMMANDS
|
||||
type AddApiKeyCommand struct {
|
||||
Name string `json:"name" binding:"Required"`
|
||||
Role RoleType `json:"role" binding:"Required"`
|
||||
OrgId int64 `json:"-"`
|
||||
Key string `json:"-"`
|
||||
SecondsToLive int64 `json:"secondsToLive"`
|
||||
ServiceAccountId *int64 `json:"-"`
|
||||
Result *ApiKey `json:"-"`
|
||||
Name string `json:"name" binding:"Required"`
|
||||
Role RoleType `json:"role" binding:"Required"`
|
||||
OrgId int64 `json:"-"`
|
||||
Key string `json:"-"`
|
||||
SecondsToLive int64 `json:"secondsToLive"`
|
||||
Result *ApiKey `json:"-"`
|
||||
}
|
||||
|
||||
type DeleteApiKeyCommand struct {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
|
@ -20,19 +19,12 @@ import (
|
|||
"github.com/grafana/grafana/pkg/web"
|
||||
)
|
||||
|
||||
type APIKeyStore interface {
|
||||
AddAPIKey(ctx context.Context, cmd *models.AddApiKeyCommand) error
|
||||
GetApiKeyById(ctx context.Context, query *models.GetApiKeyByIdQuery) error
|
||||
DeleteApiKey(ctx context.Context, cmd *models.DeleteApiKeyCommand) error
|
||||
}
|
||||
|
||||
type ServiceAccountsAPI struct {
|
||||
cfg *setting.Cfg
|
||||
service serviceaccounts.Service
|
||||
accesscontrol accesscontrol.AccessControl
|
||||
RouterRegister routing.RouteRegister
|
||||
store serviceaccounts.Store
|
||||
apiKeyStore APIKeyStore
|
||||
log log.Logger
|
||||
}
|
||||
|
||||
|
|
@ -47,7 +39,6 @@ func NewServiceAccountsAPI(
|
|||
accesscontrol accesscontrol.AccessControl,
|
||||
routerRegister routing.RouteRegister,
|
||||
store serviceaccounts.Store,
|
||||
apiKeyStore APIKeyStore,
|
||||
) *ServiceAccountsAPI {
|
||||
return &ServiceAccountsAPI{
|
||||
cfg: cfg,
|
||||
|
|
@ -55,7 +46,6 @@ func NewServiceAccountsAPI(
|
|||
accesscontrol: accesscontrol,
|
||||
RouterRegister: routerRegister,
|
||||
store: store,
|
||||
apiKeyStore: apiKeyStore,
|
||||
log: log.New("serviceaccounts.api"),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ func setupTestServer(t *testing.T, svc *tests.ServiceAccountMock,
|
|||
routerRegister routing.RouteRegister,
|
||||
acmock *accesscontrolmock.Mock,
|
||||
sqlStore *sqlstore.SQLStore, saStore serviceaccounts.Store) *web.Mux {
|
||||
a := NewServiceAccountsAPI(setting.NewCfg(), svc, acmock, routerRegister, saStore, sqlStore)
|
||||
a := NewServiceAccountsAPI(setting.NewCfg(), svc, acmock, routerRegister, saStore)
|
||||
a.RegisterAPIEndpoints(featuremgmt.WithFeatures(featuremgmt.FlagServiceAccounts))
|
||||
|
||||
a.cfg.ApiKeyMaxSecondsToLive = -1 // disable api key expiration
|
||||
|
|
|
|||
|
|
@ -97,7 +97,6 @@ func (api *ServiceAccountsAPI) CreateToken(c *models.ReqContext) response.Respon
|
|||
}
|
||||
|
||||
// Force affected service account to be the one referenced in the URL
|
||||
cmd.ServiceAccountId = &saID
|
||||
cmd.OrgId = c.OrgId
|
||||
|
||||
if !cmd.Role.IsValid() {
|
||||
|
|
@ -120,7 +119,7 @@ func (api *ServiceAccountsAPI) CreateToken(c *models.ReqContext) response.Respon
|
|||
|
||||
cmd.Key = newKeyInfo.HashedKey
|
||||
|
||||
if err := api.apiKeyStore.AddAPIKey(c.Req.Context(), &cmd); err != nil {
|
||||
if err := api.store.AddServiceAccountToken(c.Req.Context(), saID, &cmd); err != nil {
|
||||
if errors.Is(err, models.ErrInvalidApiKeyExpiration) {
|
||||
return response.Error(http.StatusBadRequest, err.Error(), nil)
|
||||
}
|
||||
|
|
@ -143,7 +142,7 @@ func (api *ServiceAccountsAPI) CreateToken(c *models.ReqContext) response.Respon
|
|||
func (api *ServiceAccountsAPI) DeleteToken(c *models.ReqContext) response.Response {
|
||||
saID, err := strconv.ParseInt(web.Params(c.Req)[":serviceAccountId"], 10, 64)
|
||||
if err != nil {
|
||||
return response.Error(http.StatusBadRequest, "serviceAccountId is invalid", err)
|
||||
return response.Error(http.StatusBadRequest, "Service Account ID is invalid", err)
|
||||
}
|
||||
|
||||
// confirm service account exists
|
||||
|
|
@ -158,29 +157,10 @@ func (api *ServiceAccountsAPI) DeleteToken(c *models.ReqContext) response.Respon
|
|||
|
||||
tokenID, err := strconv.ParseInt(web.Params(c.Req)[":tokenId"], 10, 64)
|
||||
if err != nil {
|
||||
return response.Error(http.StatusBadRequest, "serviceAccountId is invalid", err)
|
||||
return response.Error(http.StatusBadRequest, "Token ID is invalid", err)
|
||||
}
|
||||
|
||||
// confirm API key belongs to service account. TODO: refactor get & delete to single call
|
||||
cmdGet := &models.GetApiKeyByIdQuery{ApiKeyId: tokenID}
|
||||
if err = api.apiKeyStore.GetApiKeyById(c.Req.Context(), cmdGet); err != nil {
|
||||
status := http.StatusNotFound
|
||||
if err != nil && !errors.Is(err, models.ErrApiKeyNotFound) {
|
||||
status = http.StatusInternalServerError
|
||||
} else {
|
||||
err = models.ErrApiKeyNotFound
|
||||
}
|
||||
|
||||
return response.Error(status, failedToDeleteMsg, err)
|
||||
}
|
||||
|
||||
// verify service account ID matches the URL
|
||||
if *cmdGet.Result.ServiceAccountId != saID {
|
||||
return response.Error(http.StatusNotFound, failedToDeleteMsg, err)
|
||||
}
|
||||
|
||||
cmdDel := &models.DeleteApiKeyCommand{Id: tokenID, OrgId: c.OrgId}
|
||||
if err = api.apiKeyStore.DeleteApiKey(c.Req.Context(), cmdDel); err != nil {
|
||||
if err = api.store.DeleteServiceAccountToken(c.Req.Context(), c.OrgId, saID, tokenID); err != nil {
|
||||
status := http.StatusNotFound
|
||||
if err != nil && !errors.Is(err, models.ErrApiKeyNotFound) {
|
||||
status = http.StatusInternalServerError
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/routing"
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/components/apikeygen"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
|
|
@ -31,19 +30,20 @@ const (
|
|||
serviceaccountIDTokensDetailPath = "/api/serviceaccounts/%v/tokens/%v" // #nosec G101
|
||||
)
|
||||
|
||||
func createTokenforSA(t *testing.T, keyName string, orgID int64, saID int64, secondsToLive int64) *models.ApiKey {
|
||||
func createTokenforSA(t *testing.T, store serviceaccounts.Store, keyName string, orgID int64, saID int64, secondsToLive int64) *models.ApiKey {
|
||||
key, err := apikeygen.New(orgID, keyName)
|
||||
require.NoError(t, err)
|
||||
|
||||
cmd := models.AddApiKeyCommand{
|
||||
Name: keyName,
|
||||
Role: "Viewer",
|
||||
OrgId: orgID,
|
||||
Key: key.HashedKey,
|
||||
SecondsToLive: secondsToLive,
|
||||
ServiceAccountId: &saID,
|
||||
Result: &models.ApiKey{},
|
||||
Name: keyName,
|
||||
Role: "Viewer",
|
||||
OrgId: orgID,
|
||||
Key: key.HashedKey,
|
||||
SecondsToLive: secondsToLive,
|
||||
Result: &models.ApiKey{},
|
||||
}
|
||||
err = bus.Dispatch(context.Background(), &cmd)
|
||||
|
||||
err = store.AddServiceAccountToken(context.Background(), saID, &cmd)
|
||||
require.NoError(t, err)
|
||||
return cmd.Result
|
||||
}
|
||||
|
|
@ -156,7 +156,8 @@ func TestServiceAccountsAPI_CreateToken(t *testing.T) {
|
|||
|
||||
func TestServiceAccountsAPI_DeleteToken(t *testing.T) {
|
||||
store := sqlstore.InitTestDB(t)
|
||||
svcmock := tests.ServiceAccountMock{}
|
||||
svcMock := &tests.ServiceAccountMock{}
|
||||
saStore := database.NewServiceAccountsStore(store)
|
||||
sa := tests.SetupUserServiceAccount(t, store, tests.TestUser{Login: "sa", IsServiceAccount: true})
|
||||
|
||||
type testCreateSAToken struct {
|
||||
|
|
@ -216,11 +217,11 @@ func TestServiceAccountsAPI_DeleteToken(t *testing.T) {
|
|||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
token := createTokenforSA(t, tc.keyName, sa.OrgId, sa.Id, 1)
|
||||
token := createTokenforSA(t, saStore, tc.keyName, sa.OrgId, sa.Id, 1)
|
||||
|
||||
endpoint := fmt.Sprintf(serviceaccountIDTokensDetailPath, sa.Id, token.Id)
|
||||
bodyString := ""
|
||||
server := setupTestServer(t, &svcmock, routing.NewRouteRegister(), tc.acmock, store, database.NewServiceAccountsStore(store))
|
||||
server := setupTestServer(t, svcMock, routing.NewRouteRegister(), tc.acmock, store, saStore)
|
||||
actual := requestResponse(server, http.MethodDelete, endpoint, strings.NewReader(bodyString))
|
||||
|
||||
actualCode := actual.Code
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
package database
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
)
|
||||
|
||||
type ErrMisingSAToken struct {
|
||||
}
|
||||
|
||||
func (e *ErrMisingSAToken) Error() string {
|
||||
return "service account token not found"
|
||||
}
|
||||
|
||||
func (e *ErrMisingSAToken) Unwrap() error {
|
||||
return models.ErrApiKeyNotFound
|
||||
}
|
||||
|
||||
type ErrInvalidExpirationSAToken struct {
|
||||
}
|
||||
|
||||
func (e *ErrInvalidExpirationSAToken) Error() string {
|
||||
return "service account token not found"
|
||||
}
|
||||
|
||||
func (e *ErrInvalidExpirationSAToken) Unwrap() error {
|
||||
return models.ErrInvalidApiKeyExpiration
|
||||
}
|
||||
|
||||
type ErrDuplicateSAToken struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func (e *ErrDuplicateSAToken) Error() string {
|
||||
return fmt.Sprintf("service account token %s already exists", e.name)
|
||||
}
|
||||
|
||||
func (e *ErrDuplicateSAToken) Unwrap() error {
|
||||
return models.ErrDuplicateApiKey
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
)
|
||||
|
||||
func (s *ServiceAccountsStoreImpl) AddServiceAccountToken(ctx context.Context, saID int64, cmd *models.AddApiKeyCommand) error {
|
||||
return s.sqlStore.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||
key := models.ApiKey{OrgId: cmd.OrgId, Name: cmd.Name}
|
||||
exists, _ := sess.Get(&key)
|
||||
if exists {
|
||||
return &ErrDuplicateSAToken{cmd.Name}
|
||||
}
|
||||
|
||||
updated := time.Now()
|
||||
var expires *int64 = nil
|
||||
if cmd.SecondsToLive > 0 {
|
||||
v := updated.Add(time.Second * time.Duration(cmd.SecondsToLive)).Unix()
|
||||
expires = &v
|
||||
} else if cmd.SecondsToLive < 0 {
|
||||
return &ErrInvalidExpirationSAToken{}
|
||||
}
|
||||
|
||||
t := models.ApiKey{
|
||||
OrgId: cmd.OrgId,
|
||||
Name: cmd.Name,
|
||||
Role: cmd.Role,
|
||||
Key: cmd.Key,
|
||||
Created: updated,
|
||||
Updated: updated,
|
||||
Expires: expires,
|
||||
ServiceAccountId: &saID,
|
||||
}
|
||||
|
||||
if _, err := sess.Insert(&t); err != nil {
|
||||
return err
|
||||
}
|
||||
cmd.Result = &t
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (s *ServiceAccountsStoreImpl) DeleteServiceAccountToken(ctx context.Context, orgID, serviceAccountID, tokenID int64) error {
|
||||
rawSQL := "DELETE FROM api_key WHERE id=? and org_id=? and service_account_id=?"
|
||||
|
||||
return s.sqlStore.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||
result, err := sess.Exec(rawSQL, tokenID, orgID, serviceAccountID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
n, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
return err
|
||||
} else if n == 0 {
|
||||
return &ErrMisingSAToken{}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/apikeygen"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/serviceaccounts/tests"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestStore_AddServiceAccountToken(t *testing.T) {
|
||||
userToCreate := tests.TestUser{Login: "servicetestwithTeam@admin", IsServiceAccount: true}
|
||||
db, store := setupTestDatabase(t)
|
||||
user := tests.SetupUserServiceAccount(t, db, userToCreate)
|
||||
|
||||
type testCasesAdd struct {
|
||||
secondsToLive int64
|
||||
desc string
|
||||
}
|
||||
|
||||
testCases := []testCasesAdd{{-10, "invalid"}, {0, "no expiry"}, {10, "valid"}}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
keyName := t.Name()
|
||||
key, err := apikeygen.New(user.OrgId, keyName)
|
||||
require.NoError(t, err)
|
||||
|
||||
cmd := models.AddApiKeyCommand{
|
||||
Name: keyName,
|
||||
Role: "Viewer",
|
||||
OrgId: user.OrgId,
|
||||
Key: key.HashedKey,
|
||||
SecondsToLive: tc.secondsToLive,
|
||||
Result: &models.ApiKey{},
|
||||
}
|
||||
|
||||
err = store.AddServiceAccountToken(context.Background(), user.Id, &cmd)
|
||||
if tc.secondsToLive < 0 {
|
||||
require.Error(t, err)
|
||||
return
|
||||
}
|
||||
|
||||
require.NoError(t, err)
|
||||
newKey := cmd.Result
|
||||
require.Equal(t, t.Name(), newKey.Name)
|
||||
|
||||
// Verify against DB
|
||||
keys, errT := store.ListTokens(context.Background(), user.OrgId, user.Id)
|
||||
|
||||
require.NoError(t, errT)
|
||||
|
||||
found := false
|
||||
for _, k := range keys {
|
||||
if k.Name == keyName {
|
||||
found = true
|
||||
require.Equal(t, key.HashedKey, newKey.Key)
|
||||
if tc.secondsToLive == 0 {
|
||||
require.Nil(t, k.Expires)
|
||||
} else {
|
||||
require.NotNil(t, k.Expires)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
require.True(t, found, "Key not found")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestStore_DeleteServiceAccountToken(t *testing.T) {
|
||||
userToCreate := tests.TestUser{Login: "servicetestwithTeam@admin", IsServiceAccount: true}
|
||||
db, store := setupTestDatabase(t)
|
||||
user := tests.SetupUserServiceAccount(t, db, userToCreate)
|
||||
|
||||
keyName := t.Name()
|
||||
key, err := apikeygen.New(user.OrgId, keyName)
|
||||
require.NoError(t, err)
|
||||
|
||||
cmd := models.AddApiKeyCommand{
|
||||
Name: keyName,
|
||||
Role: "Viewer",
|
||||
OrgId: user.OrgId,
|
||||
Key: key.HashedKey,
|
||||
SecondsToLive: 0,
|
||||
Result: &models.ApiKey{},
|
||||
}
|
||||
|
||||
err = store.AddServiceAccountToken(context.Background(), user.Id, &cmd)
|
||||
require.NoError(t, err)
|
||||
newKey := cmd.Result
|
||||
|
||||
// Delete key from wrong service account
|
||||
err = store.DeleteServiceAccountToken(context.Background(), user.OrgId, user.Id+2, newKey.Id)
|
||||
require.Error(t, err)
|
||||
|
||||
// Delete key from wrong org
|
||||
err = store.DeleteServiceAccountToken(context.Background(), user.OrgId+2, user.Id, newKey.Id)
|
||||
require.Error(t, err)
|
||||
|
||||
err = store.DeleteServiceAccountToken(context.Background(), user.OrgId, user.Id, newKey.Id)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify against DB
|
||||
keys, errT := store.ListTokens(context.Background(), user.OrgId, user.Id)
|
||||
require.NoError(t, errT)
|
||||
|
||||
for _, k := range keys {
|
||||
if k.Name == keyName {
|
||||
require.Fail(t, "Key not deleted")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -43,7 +43,7 @@ func ProvideServiceAccountsService(
|
|||
}
|
||||
}
|
||||
|
||||
serviceaccountsAPI := api.NewServiceAccountsAPI(cfg, s, ac, routeRegister, s.store, store)
|
||||
serviceaccountsAPI := api.NewServiceAccountsAPI(cfg, s, ac, routeRegister, s.store)
|
||||
serviceaccountsAPI.RegisterAPIEndpoints(features)
|
||||
|
||||
return s, nil
|
||||
|
|
|
|||
|
|
@ -21,4 +21,6 @@ type Store interface {
|
|||
UpgradeServiceAccounts(ctx context.Context) error
|
||||
ConvertToServiceAccounts(ctx context.Context, keys []int64) error
|
||||
ListTokens(ctx context.Context, orgID int64, serviceAccount int64) ([]*models.ApiKey, error)
|
||||
DeleteServiceAccountToken(ctx context.Context, orgID, serviceAccountID, tokenID int64) error
|
||||
AddServiceAccountToken(ctx context.Context, serviceAccountID int64, cmd *models.AddApiKeyCommand) error
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,14 +67,16 @@ func SetupMockAccesscontrol(t *testing.T,
|
|||
var _ serviceaccounts.Store = new(ServiceAccountsStoreMock)
|
||||
|
||||
type Calls struct {
|
||||
CreateServiceAccount []interface{}
|
||||
ListServiceAccounts []interface{}
|
||||
RetrieveServiceAccount []interface{}
|
||||
DeleteServiceAccount []interface{}
|
||||
UpgradeServiceAccounts []interface{}
|
||||
ConvertServiceAccounts []interface{}
|
||||
ListTokens []interface{}
|
||||
UpdateServiceAccount []interface{}
|
||||
CreateServiceAccount []interface{}
|
||||
ListServiceAccounts []interface{}
|
||||
RetrieveServiceAccount []interface{}
|
||||
DeleteServiceAccount []interface{}
|
||||
UpgradeServiceAccounts []interface{}
|
||||
ConvertServiceAccounts []interface{}
|
||||
ListTokens []interface{}
|
||||
DeleteServiceAccountToken []interface{}
|
||||
UpdateServiceAccount []interface{}
|
||||
AddServiceAccountToken []interface{}
|
||||
}
|
||||
|
||||
type ServiceAccountsStoreMock struct {
|
||||
|
|
@ -124,3 +126,13 @@ func (s *ServiceAccountsStoreMock) UpdateServiceAccount(ctx context.Context,
|
|||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (s *ServiceAccountsStoreMock) DeleteServiceAccountToken(ctx context.Context, orgID, serviceAccountID, tokenID int64) error {
|
||||
s.Calls.DeleteServiceAccountToken = append(s.Calls.DeleteServiceAccountToken, []interface{}{ctx, orgID, serviceAccountID, tokenID})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ServiceAccountsStoreMock) AddServiceAccountToken(ctx context.Context, serviceAccountID int64, cmd *models.AddApiKeyCommand) error {
|
||||
s.Calls.AddServiceAccountToken = append(s.Calls.AddServiceAccountToken, []interface{}{ctx, cmd})
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ func (ss *SQLStore) GetAPIKeys(ctx context.Context, query *models.GetApiKeysQuer
|
|||
Asc("name")
|
||||
}
|
||||
|
||||
sess = sess.Where("service_account_id IS NULL")
|
||||
|
||||
query.Result = make([]*models.ApiKey, 0)
|
||||
return sess.Find(&query.Result)
|
||||
})
|
||||
|
|
@ -61,7 +63,7 @@ func (ss *SQLStore) DeleteApiKey(ctx context.Context, cmd *models.DeleteApiKeyCo
|
|||
}
|
||||
|
||||
func deleteAPIKey(sess *DBSession, id, orgID int64) error {
|
||||
rawSQL := "DELETE FROM api_key WHERE id=? and org_id=?"
|
||||
rawSQL := "DELETE FROM api_key WHERE id=? and org_id=? and service_account_id IS NULL"
|
||||
result, err := sess.Exec(rawSQL, id, orgID)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -101,7 +103,7 @@ func (ss *SQLStore) AddAPIKey(ctx context.Context, cmd *models.AddApiKeyCommand)
|
|||
Created: updated,
|
||||
Updated: updated,
|
||||
Expires: expires,
|
||||
ServiceAccountId: cmd.ServiceAccountId,
|
||||
ServiceAccountId: nil,
|
||||
}
|
||||
|
||||
if _, err := sess.Insert(&t); err != nil {
|
||||
|
|
|
|||
|
|
@ -34,20 +34,7 @@ func TestApiKeyDataAccess(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, ServiceAccountId: nil}
|
||||
err := ss.AddAPIKey(context.Background(), &cmd)
|
||||
assert.Nil(t, err)
|
||||
|
||||
query := models.GetApiKeyByNameQuery{KeyName: "non-expiring", OrgId: 1}
|
||||
err = ss.GetApiKeyByName(context.Background(), &query)
|
||||
assert.Nil(t, err)
|
||||
|
||||
assert.Nil(t, query.Result.Expires)
|
||||
})
|
||||
|
||||
t.Run("Add key for service account", func(t *testing.T) {
|
||||
var one int64 = 1
|
||||
cmd := models.AddApiKeyCommand{OrgId: 1, Name: "non-expiring-SA", Key: "sa1-key", ServiceAccountId: &one}
|
||||
cmd := models.AddApiKeyCommand{OrgId: 1, Name: "non-expiring", Key: "asd1", SecondsToLive: 0}
|
||||
err := ss.AddAPIKey(context.Background(), &cmd)
|
||||
assert.Nil(t, err)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue