mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Auth: Service account store refactor (#58961)
* refactor: renaming of files from database to store * refactor: make service account store private - moves store interface to manager package - adds an interface to the ProvideAPI constructor - refactors tests to use the store when necessary - adds mocks for the new interface implementations in the tests package * wip * refactor: make fakestore in service * wip * wip * wip * working tests * trailing whitespaces * Update pkg/services/serviceaccounts/api/api.go * Update pkg/services/serviceaccounts/tests/common.go * Update pkg/services/serviceaccounts/tests/common.go * refactor: doc string for retriever * fix import unused * remove: serviceaccount from featuretoggle * added: back legacy serviceaccounts feature toggle * added: docs * refactor: make query for the SearchQuery * add: validation of service input fields * add validation
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"strconv"
|
||||
@@ -12,6 +13,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/middleware"
|
||||
"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/org"
|
||||
"github.com/grafana/grafana/pkg/services/serviceaccounts"
|
||||
"github.com/grafana/grafana/pkg/services/serviceaccounts/database"
|
||||
@@ -22,22 +24,39 @@ import (
|
||||
|
||||
type ServiceAccountsAPI struct {
|
||||
cfg *setting.Cfg
|
||||
service serviceaccounts.Service
|
||||
service service
|
||||
accesscontrol accesscontrol.AccessControl
|
||||
accesscontrolService accesscontrol.Service
|
||||
RouterRegister routing.RouteRegister
|
||||
store serviceaccounts.Store
|
||||
log log.Logger
|
||||
permissionService accesscontrol.ServiceAccountPermissionsService
|
||||
}
|
||||
|
||||
// Service implements the API exposed methods for service accounts.
|
||||
type service interface {
|
||||
CreateServiceAccount(ctx context.Context, orgID int64, saForm *serviceaccounts.CreateServiceAccountForm) (*serviceaccounts.ServiceAccountDTO, error)
|
||||
RetrieveServiceAccount(ctx context.Context, orgID, serviceAccountID int64) (*serviceaccounts.ServiceAccountProfileDTO, error)
|
||||
UpdateServiceAccount(ctx context.Context, orgID, serviceAccountID int64,
|
||||
saForm *serviceaccounts.UpdateServiceAccountForm) (*serviceaccounts.ServiceAccountProfileDTO, error)
|
||||
SearchOrgServiceAccounts(ctx context.Context, query *serviceaccounts.SearchOrgServiceAccountsQuery) (*serviceaccounts.SearchOrgServiceAccountsResult, error)
|
||||
ListTokens(ctx context.Context, query *serviceaccounts.GetSATokensQuery) ([]apikey.APIKey, error)
|
||||
DeleteServiceAccount(ctx context.Context, orgID, serviceAccountID int64) error
|
||||
GetAPIKeysMigrationStatus(ctx context.Context, orgID int64) (*serviceaccounts.APIKeysMigrationStatus, error)
|
||||
HideApiKeysTab(ctx context.Context, orgID int64) error
|
||||
MigrateApiKeysToServiceAccounts(ctx context.Context, orgID int64) error
|
||||
MigrateApiKey(ctx context.Context, orgID int64, keyId int64) error
|
||||
RevertApiKey(ctx context.Context, saId int64, keyId int64) error
|
||||
// Service account tokens
|
||||
AddServiceAccountToken(ctx context.Context, serviceAccountID int64, cmd *serviceaccounts.AddServiceAccountTokenCommand) error
|
||||
DeleteServiceAccountToken(ctx context.Context, orgID, serviceAccountID, tokenID int64) error
|
||||
}
|
||||
|
||||
func NewServiceAccountsAPI(
|
||||
cfg *setting.Cfg,
|
||||
service serviceaccounts.Service,
|
||||
service service,
|
||||
accesscontrol accesscontrol.AccessControl,
|
||||
accesscontrolService accesscontrol.Service,
|
||||
routerRegister routing.RouteRegister,
|
||||
store serviceaccounts.Store,
|
||||
permissionService accesscontrol.ServiceAccountPermissionsService,
|
||||
) *ServiceAccountsAPI {
|
||||
return &ServiceAccountsAPI{
|
||||
@@ -46,7 +65,6 @@ func NewServiceAccountsAPI(
|
||||
accesscontrol: accesscontrol,
|
||||
accesscontrolService: accesscontrolService,
|
||||
RouterRegister: routerRegister,
|
||||
store: store,
|
||||
log: log.New("serviceaccounts.api"),
|
||||
permissionService: permissionService,
|
||||
}
|
||||
@@ -116,7 +134,7 @@ func (api *ServiceAccountsAPI) CreateServiceAccount(c *models.ReqContext) respon
|
||||
}
|
||||
}
|
||||
|
||||
serviceAccount, err := api.store.CreateServiceAccount(c.Req.Context(), c.OrgID, &cmd)
|
||||
serviceAccount, err := api.service.CreateServiceAccount(c.Req.Context(), c.OrgID, &cmd)
|
||||
switch {
|
||||
case errors.Is(err, database.ErrServiceAccountAlreadyExists):
|
||||
return response.Error(http.StatusBadRequest, "Failed to create service account", err)
|
||||
@@ -159,7 +177,7 @@ func (api *ServiceAccountsAPI) RetrieveServiceAccount(ctx *models.ReqContext) re
|
||||
return response.Error(http.StatusBadRequest, "Service Account ID is invalid", err)
|
||||
}
|
||||
|
||||
serviceAccount, err := api.store.RetrieveServiceAccount(ctx.Req.Context(), ctx.OrgID, scopeID)
|
||||
serviceAccount, err := api.service.RetrieveServiceAccount(ctx.Req.Context(), ctx.OrgID, scopeID)
|
||||
if err != nil {
|
||||
switch {
|
||||
case errors.Is(err, serviceaccounts.ErrServiceAccountNotFound):
|
||||
@@ -174,7 +192,7 @@ func (api *ServiceAccountsAPI) RetrieveServiceAccount(ctx *models.ReqContext) re
|
||||
serviceAccount.AvatarUrl = dtos.GetGravatarUrlWithDefault("", serviceAccount.Name)
|
||||
serviceAccount.AccessControl = metadata[saIDString]
|
||||
|
||||
tokens, err := api.store.ListTokens(ctx.Req.Context(), &serviceaccounts.GetSATokensQuery{
|
||||
tokens, err := api.service.ListTokens(ctx.Req.Context(), &serviceaccounts.GetSATokensQuery{
|
||||
OrgID: &serviceAccount.OrgId,
|
||||
ServiceAccountID: &serviceAccount.Id,
|
||||
})
|
||||
@@ -222,7 +240,7 @@ func (api *ServiceAccountsAPI) UpdateServiceAccount(c *models.ReqContext) respon
|
||||
}
|
||||
}
|
||||
|
||||
resp, err := api.store.UpdateServiceAccount(c.Req.Context(), c.OrgID, scopeID, &cmd)
|
||||
resp, err := api.service.UpdateServiceAccount(c.Req.Context(), c.OrgID, scopeID, &cmd)
|
||||
if err != nil {
|
||||
switch {
|
||||
case errors.Is(err, serviceaccounts.ErrServiceAccountNotFound):
|
||||
@@ -312,7 +330,15 @@ func (api *ServiceAccountsAPI) SearchOrgServiceAccountsWithPaging(c *models.ReqC
|
||||
if onlyDisabled {
|
||||
filter = serviceaccounts.FilterOnlyDisabled
|
||||
}
|
||||
serviceAccountSearch, err := api.store.SearchOrgServiceAccounts(ctx, c.OrgID, c.Query("query"), filter, page, perPage, c.SignedInUser)
|
||||
q := serviceaccounts.SearchOrgServiceAccountsQuery{
|
||||
OrgID: c.OrgID,
|
||||
Query: c.Query("query"),
|
||||
Page: page,
|
||||
Limit: perPage,
|
||||
Filter: filter,
|
||||
SignedInUser: c.SignedInUser,
|
||||
}
|
||||
serviceAccountSearch, err := api.service.SearchOrgServiceAccounts(ctx, &q)
|
||||
if err != nil {
|
||||
return response.Error(http.StatusInternalServerError, "Failed to get service accounts for current organization", err)
|
||||
}
|
||||
@@ -326,7 +352,7 @@ func (api *ServiceAccountsAPI) SearchOrgServiceAccountsWithPaging(c *models.ReqC
|
||||
saIDs[saIDString] = true
|
||||
metadata := api.getAccessControlMetadata(c, map[string]bool{saIDString: true})
|
||||
sa.AccessControl = metadata[strconv.FormatInt(sa.Id, 10)]
|
||||
tokens, err := api.store.ListTokens(ctx, &serviceaccounts.GetSATokensQuery{
|
||||
tokens, err := api.service.ListTokens(ctx, &serviceaccounts.GetSATokensQuery{
|
||||
OrgID: &sa.OrgId, ServiceAccountID: &sa.Id,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -340,7 +366,7 @@ func (api *ServiceAccountsAPI) SearchOrgServiceAccountsWithPaging(c *models.ReqC
|
||||
|
||||
// GET /api/serviceaccounts/migrationstatus
|
||||
func (api *ServiceAccountsAPI) GetAPIKeysMigrationStatus(ctx *models.ReqContext) response.Response {
|
||||
upgradeStatus, err := api.store.GetAPIKeysMigrationStatus(ctx.Req.Context(), ctx.OrgID)
|
||||
upgradeStatus, err := api.service.GetAPIKeysMigrationStatus(ctx.Req.Context(), ctx.OrgID)
|
||||
if err != nil {
|
||||
return response.Error(http.StatusInternalServerError, "Internal server error", err)
|
||||
}
|
||||
@@ -349,7 +375,7 @@ func (api *ServiceAccountsAPI) GetAPIKeysMigrationStatus(ctx *models.ReqContext)
|
||||
|
||||
// POST /api/serviceaccounts/hideapikeys
|
||||
func (api *ServiceAccountsAPI) HideApiKeysTab(ctx *models.ReqContext) response.Response {
|
||||
if err := api.store.HideApiKeysTab(ctx.Req.Context(), ctx.OrgID); err != nil {
|
||||
if err := api.service.HideApiKeysTab(ctx.Req.Context(), ctx.OrgID); err != nil {
|
||||
return response.Error(http.StatusInternalServerError, "Internal server error", err)
|
||||
}
|
||||
return response.Success("API keys hidden")
|
||||
@@ -357,7 +383,7 @@ func (api *ServiceAccountsAPI) HideApiKeysTab(ctx *models.ReqContext) response.R
|
||||
|
||||
// POST /api/serviceaccounts/migrate
|
||||
func (api *ServiceAccountsAPI) MigrateApiKeysToServiceAccounts(ctx *models.ReqContext) response.Response {
|
||||
if err := api.store.MigrateApiKeysToServiceAccounts(ctx.Req.Context(), ctx.OrgID); err != nil {
|
||||
if err := api.service.MigrateApiKeysToServiceAccounts(ctx.Req.Context(), ctx.OrgID); err != nil {
|
||||
return response.Error(http.StatusInternalServerError, "Internal server error", err)
|
||||
}
|
||||
|
||||
@@ -371,7 +397,7 @@ func (api *ServiceAccountsAPI) ConvertToServiceAccount(ctx *models.ReqContext) r
|
||||
return response.Error(http.StatusBadRequest, "Key ID is invalid", err)
|
||||
}
|
||||
|
||||
if err := api.store.MigrateApiKey(ctx.Req.Context(), ctx.OrgID, keyId); err != nil {
|
||||
if err := api.service.MigrateApiKey(ctx.Req.Context(), ctx.OrgID, keyId); err != nil {
|
||||
return response.Error(http.StatusInternalServerError, "Error converting API key", err)
|
||||
}
|
||||
|
||||
@@ -389,7 +415,7 @@ func (api *ServiceAccountsAPI) RevertApiKey(ctx *models.ReqContext) response.Res
|
||||
return response.Error(http.StatusBadRequest, "service account ID is invalid", err)
|
||||
}
|
||||
|
||||
if err := api.store.RevertApiKey(ctx.Req.Context(), serviceAccountId, keyId); err != nil {
|
||||
if err := api.service.RevertApiKey(ctx.Req.Context(), serviceAccountId, keyId); err != nil {
|
||||
return response.Error(http.StatusInternalServerError, "error reverting to API key", err)
|
||||
}
|
||||
return response.Success("reverted service account to API key")
|
||||
@@ -464,7 +490,7 @@ type DeleteServiceAccountParams struct {
|
||||
// swagger:response searchOrgServiceAccountsWithPagingResponse
|
||||
type SearchOrgServiceAccountsWithPagingResponse struct {
|
||||
// in:body
|
||||
Body *serviceaccounts.SearchServiceAccountsResult
|
||||
Body *serviceaccounts.SearchOrgServiceAccountsResult
|
||||
}
|
||||
|
||||
// swagger:response createServiceAccountResponse
|
||||
|
||||
@@ -32,6 +32,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
||||
"github.com/grafana/grafana/pkg/services/serviceaccounts"
|
||||
"github.com/grafana/grafana/pkg/services/serviceaccounts/database"
|
||||
"github.com/grafana/grafana/pkg/services/serviceaccounts/retriever"
|
||||
"github.com/grafana/grafana/pkg/services/serviceaccounts/tests"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
"github.com/grafana/grafana/pkg/services/team/teamimpl"
|
||||
@@ -46,6 +47,13 @@ var (
|
||||
serviceAccountIDPath = serviceAccountPath + "%v"
|
||||
)
|
||||
|
||||
// TODO:
|
||||
// refactor this set of tests to make use of fakes for the ServiceAccountService
|
||||
// all of the API tests are calling with all of the db store injections
|
||||
// which is not ideal
|
||||
// this is a bit of a hack to get the tests to pass until we refactor the tests
|
||||
// to use fakes as in the user service tests
|
||||
|
||||
func TestServiceAccountsAPI_CreateServiceAccount(t *testing.T) {
|
||||
store := db.InitTestDB(t)
|
||||
services := setupTestServices(t, store)
|
||||
@@ -162,7 +170,7 @@ func TestServiceAccountsAPI_CreateServiceAccount(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
serviceAccountRequestScenario(t, http.MethodPost, serviceAccountPath, testUser, func(httpmethod string, endpoint string, usr *tests.TestUser) {
|
||||
server, api := setupTestServer(t, &services.SAService, routing.NewRouteRegister(), tc.acmock, store, services.SAStore)
|
||||
server, api := setupTestServer(t, &services.SAService, routing.NewRouteRegister(), tc.acmock, store)
|
||||
marshalled, err := json.Marshal(tc.body)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -239,7 +247,7 @@ func TestServiceAccountsAPI_DeleteServiceAccount(t *testing.T) {
|
||||
}
|
||||
serviceAccountRequestScenario(t, http.MethodDelete, serviceAccountIDPath, &testcase.user, func(httpmethod string, endpoint string, user *tests.TestUser) {
|
||||
createduser := tests.SetupUserServiceAccount(t, store, testcase.user)
|
||||
server, _ := setupTestServer(t, &services.SAService, routing.NewRouteRegister(), testcase.acmock, store, services.SAStore)
|
||||
server, _ := setupTestServer(t, &services.SAService, routing.NewRouteRegister(), testcase.acmock, store)
|
||||
actual := requestResponse(server, httpmethod, fmt.Sprintf(endpoint, fmt.Sprint(createduser.ID))).Code
|
||||
require.Equal(t, testcase.expectedCode, actual)
|
||||
})
|
||||
@@ -263,7 +271,7 @@ func TestServiceAccountsAPI_DeleteServiceAccount(t *testing.T) {
|
||||
}
|
||||
serviceAccountRequestScenario(t, http.MethodDelete, serviceAccountIDPath, &testcase.user, func(httpmethod string, endpoint string, user *tests.TestUser) {
|
||||
createduser := tests.SetupUserServiceAccount(t, store, testcase.user)
|
||||
server, _ := setupTestServer(t, &services.SAService, routing.NewRouteRegister(), testcase.acmock, store, services.SAStore)
|
||||
server, _ := setupTestServer(t, &services.SAService, routing.NewRouteRegister(), testcase.acmock, store)
|
||||
actual := requestResponse(server, httpmethod, fmt.Sprintf(endpoint, createduser.ID)).Code
|
||||
require.Equal(t, testcase.expectedCode, actual)
|
||||
})
|
||||
@@ -275,21 +283,29 @@ func serviceAccountRequestScenario(t *testing.T, httpMethod string, endpoint str
|
||||
fn(httpMethod, endpoint, user)
|
||||
}
|
||||
|
||||
func setupTestServer(t *testing.T, svc *tests.ServiceAccountMock,
|
||||
func setupTestServer(
|
||||
t *testing.T,
|
||||
svc *tests.ServiceAccountMock,
|
||||
routerRegister routing.RouteRegister,
|
||||
acmock *accesscontrolmock.Mock,
|
||||
sqlStore db.DB, saStore serviceaccounts.Store) (*web.Mux, *ServiceAccountsAPI) {
|
||||
sqlStore db.DB,
|
||||
) (*web.Mux, *ServiceAccountsAPI) {
|
||||
cfg := setting.NewCfg()
|
||||
teamSvc := teamimpl.ProvideService(sqlStore, cfg)
|
||||
|
||||
userSvc, err := userimpl.ProvideService(sqlStore, nil, cfg, teamimpl.ProvideService(sqlStore, cfg), nil, quotatest.New(false, nil))
|
||||
orgSvc, err := orgimpl.ProvideService(sqlStore, cfg, quotatest.New(false, nil))
|
||||
require.NoError(t, err)
|
||||
|
||||
userSvc, err := userimpl.ProvideService(sqlStore, orgSvc, cfg, teamimpl.ProvideService(sqlStore, cfg), nil, quotatest.New(false, nil))
|
||||
require.NoError(t, err)
|
||||
|
||||
// TODO: create fake for retriever to pass into the permissionservice
|
||||
retrieverSvc := retriever.ProvideService(sqlStore, nil, nil, nil, nil)
|
||||
saPermissionService, err := ossaccesscontrol.ProvideServiceAccountPermissions(
|
||||
cfg, routing.NewRouteRegister(), sqlStore, acmock, &licensing.OSSLicensingService{}, saStore, acmock, teamSvc, userSvc)
|
||||
cfg, routing.NewRouteRegister(), sqlStore, acmock, &licensing.OSSLicensingService{}, retrieverSvc, acmock, teamSvc, userSvc)
|
||||
require.NoError(t, err)
|
||||
acService := actest.FakeService{}
|
||||
|
||||
a := NewServiceAccountsAPI(cfg, svc, acmock, acService, routerRegister, saStore, saPermissionService)
|
||||
a := NewServiceAccountsAPI(cfg, svc, acmock, acService, routerRegister, saPermissionService)
|
||||
a.RegisterAPIEndpoints()
|
||||
|
||||
a.cfg.ApiKeyMaxSecondsToLive = -1 // disable api key expiration
|
||||
@@ -317,6 +333,7 @@ func setupTestServer(t *testing.T, svc *tests.ServiceAccountMock,
|
||||
func TestServiceAccountsAPI_RetrieveServiceAccount(t *testing.T) {
|
||||
store := db.InitTestDB(t)
|
||||
services := setupTestServices(t, store)
|
||||
|
||||
type testRetrieveSATestCase struct {
|
||||
desc string
|
||||
user *tests.TestUser
|
||||
@@ -380,7 +397,7 @@ func TestServiceAccountsAPI_RetrieveServiceAccount(t *testing.T) {
|
||||
createdUser := tests.SetupUserServiceAccount(t, store, *tc.user)
|
||||
scopeID = int(createdUser.ID)
|
||||
}
|
||||
server, _ := setupTestServer(t, &services.SAService, routing.NewRouteRegister(), tc.acmock, store, services.SAStore)
|
||||
server, _ := setupTestServer(t, &services.SAService, routing.NewRouteRegister(), tc.acmock, store)
|
||||
|
||||
actual := requestResponse(server, httpmethod, fmt.Sprintf(endpoint, scopeID))
|
||||
|
||||
@@ -406,6 +423,7 @@ func newString(s string) *string {
|
||||
func TestServiceAccountsAPI_UpdateServiceAccount(t *testing.T) {
|
||||
store := db.InitTestDB(t)
|
||||
services := setupTestServices(t, store)
|
||||
|
||||
type testUpdateSATestCase struct {
|
||||
desc string
|
||||
user *tests.TestUser
|
||||
@@ -498,7 +516,7 @@ func TestServiceAccountsAPI_UpdateServiceAccount(t *testing.T) {
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
server, saAPI := setupTestServer(t, &services.SAService, routing.NewRouteRegister(), tc.acmock, store, services.SAStore)
|
||||
server, saAPI := setupTestServer(t, &services.SAService, routing.NewRouteRegister(), tc.acmock, store)
|
||||
scopeID := tc.Id
|
||||
if tc.user != nil {
|
||||
createdUser := tests.SetupUserServiceAccount(t, store, *tc.user)
|
||||
@@ -528,7 +546,7 @@ func TestServiceAccountsAPI_UpdateServiceAccount(t *testing.T) {
|
||||
assert.Equal(t, tc.user.Login, serviceAccountData["login"].(string))
|
||||
|
||||
// Ensure the user was updated in DB
|
||||
sa, err := saAPI.store.RetrieveServiceAccount(context.Background(), 1, int64(scopeID))
|
||||
sa, err := saAPI.service.RetrieveServiceAccount(context.Background(), 1, int64(scopeID))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, *tc.body.Name, sa.Name)
|
||||
require.Equal(t, string(*tc.body.Role), sa.Role)
|
||||
@@ -540,7 +558,6 @@ func TestServiceAccountsAPI_UpdateServiceAccount(t *testing.T) {
|
||||
type services struct {
|
||||
OrgService org.Service
|
||||
UserService user.Service
|
||||
SAStore serviceaccounts.Store
|
||||
SAService tests.ServiceAccountMock
|
||||
APIKeyService apikey.Service
|
||||
}
|
||||
@@ -555,13 +572,13 @@ func setupTestServices(t *testing.T, db *sqlstore.SQLStore) services {
|
||||
require.NoError(t, err)
|
||||
userSvc, err := userimpl.ProvideService(db, orgService, db.Cfg, nil, nil, quotaService)
|
||||
require.NoError(t, err)
|
||||
saStore := database.ProvideServiceAccountsStore(db, apiKeyService, kvStore, userSvc, orgService)
|
||||
svcmock := tests.ServiceAccountMock{}
|
||||
|
||||
saStore := database.ProvideServiceAccountsStore(nil, db, apiKeyService, kvStore, userSvc, orgService)
|
||||
svcmock := tests.ServiceAccountMock{Store: saStore, Calls: tests.Calls{}, Stats: nil, SecretScanEnabled: false}
|
||||
|
||||
return services{
|
||||
OrgService: orgService,
|
||||
UserService: userSvc,
|
||||
SAStore: saStore,
|
||||
SAService: svcmock,
|
||||
APIKeyService: apiKeyService,
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ func (api *ServiceAccountsAPI) ListTokens(ctx *models.ReqContext) response.Respo
|
||||
return response.Error(http.StatusBadRequest, "Service Account ID is invalid", err)
|
||||
}
|
||||
|
||||
saTokens, err := api.store.ListTokens(ctx.Req.Context(), &serviceaccounts.GetSATokensQuery{
|
||||
saTokens, err := api.service.ListTokens(ctx.Req.Context(), &serviceaccounts.GetSATokensQuery{
|
||||
OrgID: &ctx.OrgID,
|
||||
ServiceAccountID: &saID,
|
||||
})
|
||||
@@ -134,7 +134,7 @@ func (api *ServiceAccountsAPI) CreateToken(c *models.ReqContext) response.Respon
|
||||
}
|
||||
|
||||
// confirm service account exists
|
||||
if _, err := api.store.RetrieveServiceAccount(c.Req.Context(), c.OrgID, saID); err != nil {
|
||||
if _, err := api.service.RetrieveServiceAccount(c.Req.Context(), c.OrgID, saID); err != nil {
|
||||
switch {
|
||||
case errors.Is(err, serviceaccounts.ErrServiceAccountNotFound):
|
||||
return response.Error(http.StatusNotFound, "Failed to retrieve service account", err)
|
||||
@@ -175,7 +175,7 @@ func (api *ServiceAccountsAPI) CreateToken(c *models.ReqContext) response.Respon
|
||||
|
||||
cmd.Key = newKeyInfo.HashedKey
|
||||
|
||||
if err := api.store.AddServiceAccountToken(c.Req.Context(), saID, &cmd); err != nil {
|
||||
if err := api.service.AddServiceAccountToken(c.Req.Context(), saID, &cmd); err != nil {
|
||||
if errors.Is(err, database.ErrInvalidTokenExpiration) {
|
||||
return response.Error(http.StatusBadRequest, err.Error(), nil)
|
||||
}
|
||||
@@ -217,7 +217,7 @@ func (api *ServiceAccountsAPI) DeleteToken(c *models.ReqContext) response.Respon
|
||||
}
|
||||
|
||||
// confirm service account exists
|
||||
if _, err := api.store.RetrieveServiceAccount(c.Req.Context(), c.OrgID, saID); err != nil {
|
||||
if _, err := api.service.RetrieveServiceAccount(c.Req.Context(), c.OrgID, saID); err != nil {
|
||||
switch {
|
||||
case errors.Is(err, serviceaccounts.ErrServiceAccountNotFound):
|
||||
return response.Error(http.StatusNotFound, "Failed to retrieve service account", err)
|
||||
@@ -231,7 +231,7 @@ func (api *ServiceAccountsAPI) DeleteToken(c *models.ReqContext) response.Respon
|
||||
return response.Error(http.StatusBadRequest, "Token ID is invalid", err)
|
||||
}
|
||||
|
||||
if err = api.store.DeleteServiceAccountToken(c.Req.Context(), c.OrgID, saID, tokenID); err != nil {
|
||||
if err = api.service.DeleteServiceAccountToken(c.Req.Context(), c.OrgID, saID, tokenID); err != nil {
|
||||
status := http.StatusNotFound
|
||||
if err != nil && !errors.Is(err, apikey.ErrNotFound) {
|
||||
status = http.StatusInternalServerError
|
||||
|
||||
@@ -32,7 +32,7 @@ const (
|
||||
serviceaccountIDTokensDetailPath = "/api/serviceaccounts/%v/tokens/%v" // #nosec G101
|
||||
)
|
||||
|
||||
func createTokenforSA(t *testing.T, store serviceaccounts.Store, keyName string, orgID int64, saID int64, secondsToLive int64) *apikey.APIKey {
|
||||
func createTokenforSA(t *testing.T, service serviceaccounts.Service, keyName string, orgID int64, saID int64, secondsToLive int64) *apikey.APIKey {
|
||||
key, err := apikeygen.New(orgID, keyName)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -44,7 +44,7 @@ func createTokenforSA(t *testing.T, store serviceaccounts.Store, keyName string,
|
||||
Result: &apikey.APIKey{},
|
||||
}
|
||||
|
||||
err = store.AddServiceAccountToken(context.Background(), saID, &cmd)
|
||||
err = service.AddServiceAccountToken(context.Background(), saID, &cmd)
|
||||
require.NoError(t, err)
|
||||
return cmd.Result
|
||||
}
|
||||
@@ -131,7 +131,7 @@ func TestServiceAccountsAPI_CreateToken(t *testing.T) {
|
||||
bodyString = string(b)
|
||||
}
|
||||
|
||||
server, _ := setupTestServer(t, &services.SAService, routing.NewRouteRegister(), tc.acmock, store, services.SAStore)
|
||||
server, _ := setupTestServer(t, &services.SAService, routing.NewRouteRegister(), tc.acmock, store)
|
||||
actual := requestResponse(server, http.MethodPost, endpoint, strings.NewReader(bodyString))
|
||||
|
||||
actualCode := actual.Code
|
||||
@@ -166,6 +166,7 @@ func TestServiceAccountsAPI_CreateToken(t *testing.T) {
|
||||
func TestServiceAccountsAPI_DeleteToken(t *testing.T) {
|
||||
store := db.InitTestDB(t)
|
||||
services := setupTestServices(t, store)
|
||||
|
||||
sa := tests.SetupUserServiceAccount(t, store, tests.TestUser{Login: "sa", IsServiceAccount: true})
|
||||
|
||||
type testCreateSAToken struct {
|
||||
@@ -225,11 +226,11 @@ func TestServiceAccountsAPI_DeleteToken(t *testing.T) {
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
token := createTokenforSA(t, services.SAStore, tc.keyName, sa.OrgID, sa.ID, 1)
|
||||
token := createTokenforSA(t, &services.SAService, tc.keyName, sa.OrgID, sa.ID, 1)
|
||||
|
||||
endpoint := fmt.Sprintf(serviceaccountIDTokensDetailPath, sa.ID, token.Id)
|
||||
bodyString := ""
|
||||
server, _ := setupTestServer(t, &services.SAService, routing.NewRouteRegister(), tc.acmock, store, services.SAStore)
|
||||
server, _ := setupTestServer(t, &services.SAService, routing.NewRouteRegister(), tc.acmock, store)
|
||||
actual := requestResponse(server, http.MethodDelete, endpoint, strings.NewReader(bodyString))
|
||||
|
||||
actualCode := actual.Code
|
||||
@@ -249,20 +250,11 @@ func TestServiceAccountsAPI_DeleteToken(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
type saStoreMockTokens struct {
|
||||
serviceaccounts.Store
|
||||
saAPIKeys []apikey.APIKey
|
||||
}
|
||||
|
||||
func (s *saStoreMockTokens) ListTokens(ctx context.Context, query *serviceaccounts.GetSATokensQuery) ([]apikey.APIKey, error) {
|
||||
return s.saAPIKeys, nil
|
||||
}
|
||||
|
||||
func TestServiceAccountsAPI_ListTokens(t *testing.T) {
|
||||
store := db.InitTestDB(t)
|
||||
svcmock := tests.ServiceAccountMock{}
|
||||
sa := tests.SetupUserServiceAccount(t, store, tests.TestUser{Login: "sa", IsServiceAccount: true})
|
||||
services := setupTestServices(t, store)
|
||||
|
||||
sa := tests.SetupUserServiceAccount(t, store, tests.TestUser{Login: "sa", IsServiceAccount: true})
|
||||
type testCreateSAToken struct {
|
||||
desc string
|
||||
tokens []apikey.APIKey
|
||||
@@ -351,7 +343,8 @@ func TestServiceAccountsAPI_ListTokens(t *testing.T) {
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
endpoint := fmt.Sprintf(serviceAccountIDPath+"/tokens", sa.ID)
|
||||
server, _ := setupTestServer(t, &svcmock, routing.NewRouteRegister(), tc.acmock, store, &saStoreMockTokens{saAPIKeys: tc.tokens})
|
||||
services.SAService.ExpectedTokens = tc.tokens
|
||||
server, _ := setupTestServer(t, &services.SAService, routing.NewRouteRegister(), tc.acmock, store)
|
||||
actual := requestResponse(server, http.MethodGet, endpoint, http.NoBody)
|
||||
|
||||
actualCode := actual.Code
|
||||
|
||||
Reference in New Issue
Block a user