Service account: Ensure that you can revert only service accounts which you can access (#52626)

* Service account: Ensure that you can revert only service accounts which you can access

* Remove prettier messup with docs

* Remove prettier messup with docs

* Prettier run
This commit is contained in:
Vardan Torosyan
2022-07-22 10:35:01 +02:00
committed by GitHub
parent 5d05d26e12
commit 18867d6d78
7 changed files with 69 additions and 38 deletions

View File

@@ -463,7 +463,7 @@ func (s *ServiceAccountsStoreImpl) CreateServiceAccountFromApikey(ctx context.Co
}
// RevertApiKey converts service account token to old API key
func (s *ServiceAccountsStoreImpl) RevertApiKey(ctx context.Context, keyId int64) error {
func (s *ServiceAccountsStoreImpl) RevertApiKey(ctx context.Context, saId int64, keyId int64) error {
query := models.GetApiKeyByIdQuery{ApiKeyId: keyId}
if err := s.sqlStore.GetApiKeyById(ctx, &query); err != nil {
return err
@@ -474,6 +474,10 @@ func (s *ServiceAccountsStoreImpl) RevertApiKey(ctx context.Context, keyId int64
return fmt.Errorf("API key is not service account token")
}
if *key.ServiceAccountId != saId {
return ErrServiceAccountAndTokenMismatch
}
tokens, err := s.ListTokens(ctx, key.OrgId, *key.ServiceAccountId)
if err != nil {
return fmt.Errorf("cannot revert token: %w", err)

View File

@@ -2,6 +2,7 @@ package database
import (
"context"
"math/rand"
"testing"
"github.com/grafana/grafana/pkg/infra/kvstore"
@@ -270,15 +271,22 @@ func TestStore_MigrateAllApiKeys(t *testing.T) {
func TestStore_RevertApiKey(t *testing.T) {
cases := []struct {
desc string
key tests.TestApiKey
expectedErr error
desc string
key tests.TestApiKey
forceMismatchServiceAccount bool
expectedErr error
}{
{
desc: "service account token should be reverted to api key",
key: tests.TestApiKey{Name: "Test1", Role: models.ROLE_EDITOR, OrgId: 1},
expectedErr: nil,
},
{
desc: "should fail reverting to api key when the token is assigned to a different service account",
key: tests.TestApiKey{Name: "Test1", Role: models.ROLE_EDITOR, OrgId: 1},
forceMismatchServiceAccount: true,
expectedErr: ErrServiceAccountAndTokenMismatch,
},
}
for _, c := range cases {
@@ -291,9 +299,23 @@ func TestStore_RevertApiKey(t *testing.T) {
require.NoError(t, err)
key := tests.SetupApiKey(t, db, c.key)
err = store.MigrateApiKey(context.Background(), key.OrgId, key.Id)
err = store.CreateServiceAccountFromApikey(context.Background(), key)
require.NoError(t, err)
err = store.RevertApiKey(context.Background(), key.Id)
var saId int64
if c.forceMismatchServiceAccount {
saId = rand.Int63()
} else {
serviceAccounts, err := store.SearchOrgServiceAccounts(context.Background(), key.OrgId, "", "all", 1, 50, &models.SignedInUser{UserId: 1, OrgId: 1, Permissions: map[int64]map[string][]string{
key.OrgId: {
"serviceaccounts:read": {"serviceaccounts:id:*"},
},
}})
require.NoError(t, err)
saId = serviceAccounts.ServiceAccounts[0].Id
}
err = store.RevertApiKey(context.Background(), saId, key.Id)
if c.expectedErr != nil {
require.ErrorIs(t, err, c.expectedErr)

View File

@@ -5,8 +5,9 @@ import (
)
var (
ErrServiceAccountAlreadyExists = errors.New("service account already exists")
ErrServiceAccountTokenNotFound = errors.New("service account token not found")
ErrInvalidTokenExpiration = errors.New("invalid SecondsToLive value")
ErrDuplicateToken = errors.New("service account token with given name already exists in the organization")
ErrServiceAccountAlreadyExists = errors.New("service account already exists")
ErrServiceAccountTokenNotFound = errors.New("service account token not found")
ErrInvalidTokenExpiration = errors.New("invalid SecondsToLive value")
ErrDuplicateToken = errors.New("service account token with given name already exists in the organization")
ErrServiceAccountAndTokenMismatch = errors.New("API token does not belong to the given service account")
)