2021-11-11 09:10:24 -06:00
package api
import (
2021-12-14 07:39:25 -06:00
"errors"
2021-11-11 09:10:24 -06:00
"net/http"
2022-01-14 10:55:57 -06:00
"strconv"
2021-11-11 09:10:24 -06:00
2022-02-08 13:19:22 -06:00
"github.com/grafana/grafana/pkg/api/dtos"
2021-11-11 09:10:24 -06:00
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/api/routing"
2022-02-08 13:19:22 -06:00
"github.com/grafana/grafana/pkg/infra/log"
2021-11-11 09:10:24 -06:00
"github.com/grafana/grafana/pkg/middleware"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol"
2022-08-10 04:56:48 -05:00
"github.com/grafana/grafana/pkg/services/org"
2021-11-11 09:10:24 -06:00
"github.com/grafana/grafana/pkg/services/serviceaccounts"
2022-03-08 05:07:58 -06:00
"github.com/grafana/grafana/pkg/services/serviceaccounts/database"
2022-02-07 07:51:54 -06:00
"github.com/grafana/grafana/pkg/setting"
2022-06-01 02:35:16 -05:00
"github.com/grafana/grafana/pkg/util"
2021-12-14 07:39:25 -06:00
"github.com/grafana/grafana/pkg/web"
2021-11-11 09:10:24 -06:00
)
type ServiceAccountsAPI struct {
2022-11-24 08:38:55 -06:00
cfg * setting . Cfg
service serviceaccounts . Service
accesscontrol accesscontrol . AccessControl
accesscontrolService accesscontrol . Service
RouterRegister routing . RouteRegister
store serviceaccounts . Store
log log . Logger
permissionService accesscontrol . ServiceAccountPermissionsService
2021-11-11 09:10:24 -06:00
}
func NewServiceAccountsAPI (
2022-02-07 07:51:54 -06:00
cfg * setting . Cfg ,
2021-11-11 09:10:24 -06:00
service serviceaccounts . Service ,
accesscontrol accesscontrol . AccessControl ,
2022-11-24 08:38:55 -06:00
accesscontrolService accesscontrol . Service ,
2021-11-11 09:10:24 -06:00
routerRegister routing . RouteRegister ,
2021-12-16 07:28:16 -06:00
store serviceaccounts . Store ,
2022-07-08 04:53:18 -05:00
permissionService accesscontrol . ServiceAccountPermissionsService ,
2021-11-11 09:10:24 -06:00
) * ServiceAccountsAPI {
return & ServiceAccountsAPI {
2022-11-24 08:38:55 -06:00
cfg : cfg ,
service : service ,
accesscontrol : accesscontrol ,
accesscontrolService : accesscontrolService ,
RouterRegister : routerRegister ,
store : store ,
log : log . New ( "serviceaccounts.api" ) ,
permissionService : permissionService ,
2021-11-11 09:10:24 -06:00
}
}
2022-06-27 03:22:49 -05:00
func ( api * ServiceAccountsAPI ) RegisterAPIEndpoints ( ) {
2022-04-28 03:46:18 -05:00
auth := accesscontrol . Middleware ( api . accesscontrol )
2022-02-02 09:32:37 -06:00
api . RouterRegister . Group ( "/api/serviceaccounts" , func ( serviceAccountsRoute routing . RouteRegister ) {
2022-03-15 04:48:10 -05:00
serviceAccountsRoute . Get ( "/search" , auth ( middleware . ReqOrgAdmin ,
accesscontrol . EvalPermission ( serviceaccounts . ActionRead ) ) , routing . Wrap ( api . SearchOrgServiceAccountsWithPaging ) )
2022-02-22 07:58:42 -06:00
serviceAccountsRoute . Post ( "/" , auth ( middleware . ReqOrgAdmin ,
accesscontrol . EvalPermission ( serviceaccounts . ActionCreate ) ) , routing . Wrap ( api . CreateServiceAccount ) )
serviceAccountsRoute . Get ( "/:serviceAccountId" , auth ( middleware . ReqOrgAdmin ,
accesscontrol . EvalPermission ( serviceaccounts . ActionRead , serviceaccounts . ScopeID ) ) , routing . Wrap ( api . RetrieveServiceAccount ) )
2022-02-17 06:19:58 -06:00
serviceAccountsRoute . Patch ( "/:serviceAccountId" , auth ( middleware . ReqOrgAdmin ,
2022-06-15 07:59:40 -05:00
accesscontrol . EvalPermission ( serviceaccounts . ActionWrite , serviceaccounts . ScopeID ) ) , routing . Wrap ( api . UpdateServiceAccount ) )
2022-03-15 04:48:10 -05:00
serviceAccountsRoute . Delete ( "/:serviceAccountId" , auth ( middleware . ReqOrgAdmin ,
accesscontrol . EvalPermission ( serviceaccounts . ActionDelete , serviceaccounts . ScopeID ) ) , routing . Wrap ( api . DeleteServiceAccount ) )
2022-02-07 07:51:54 -06:00
serviceAccountsRoute . Get ( "/:serviceAccountId/tokens" , auth ( middleware . ReqOrgAdmin ,
accesscontrol . EvalPermission ( serviceaccounts . ActionRead , serviceaccounts . ScopeID ) ) , routing . Wrap ( api . ListTokens ) )
serviceAccountsRoute . Post ( "/:serviceAccountId/tokens" , auth ( middleware . ReqOrgAdmin ,
accesscontrol . EvalPermission ( serviceaccounts . ActionWrite , serviceaccounts . ScopeID ) ) , routing . Wrap ( api . CreateToken ) )
serviceAccountsRoute . Delete ( "/:serviceAccountId/tokens/:tokenId" , auth ( middleware . ReqOrgAdmin ,
accesscontrol . EvalPermission ( serviceaccounts . ActionWrite , serviceaccounts . ScopeID ) ) , routing . Wrap ( api . DeleteToken ) )
2022-06-15 07:59:40 -05:00
serviceAccountsRoute . Get ( "/migrationstatus" , auth ( middleware . ReqOrgAdmin ,
accesscontrol . EvalPermission ( serviceaccounts . ActionRead ) ) , routing . Wrap ( api . GetAPIKeysMigrationStatus ) )
serviceAccountsRoute . Post ( "/hideApiKeys" , auth ( middleware . ReqOrgAdmin ,
accesscontrol . EvalPermission ( serviceaccounts . ActionCreate ) ) , routing . Wrap ( api . HideApiKeysTab ) )
serviceAccountsRoute . Post ( "/migrate" , auth ( middleware . ReqOrgAdmin ,
accesscontrol . EvalPermission ( serviceaccounts . ActionCreate ) ) , routing . Wrap ( api . MigrateApiKeysToServiceAccounts ) )
serviceAccountsRoute . Post ( "/migrate/:keyId" , auth ( middleware . ReqOrgAdmin ,
accesscontrol . EvalPermission ( serviceaccounts . ActionCreate ) ) , routing . Wrap ( api . ConvertToServiceAccount ) )
2022-07-22 03:35:01 -05:00
serviceAccountsRoute . Post ( "/:serviceAccountId/revert/:keyId" , auth ( middleware . ReqOrgAdmin ,
accesscontrol . EvalPermission ( serviceaccounts . ActionDelete , serviceaccounts . ScopeID ) ) , routing . Wrap ( api . RevertApiKey ) )
2021-11-11 09:10:24 -06:00
} )
}
2022-07-27 08:54:37 -05:00
// swagger:route POST /serviceaccounts service_accounts createServiceAccount
//
2022-08-18 09:54:39 -05:00
// # Create service account
2022-07-27 08:54:37 -05:00
//
// Required permissions (See note in the [introduction](https://grafana.com/docs/grafana/latest/developers/http_api/serviceaccount/#service-account-api) for an explanation):
// action: `serviceaccounts:write` scope: `serviceaccounts:*`
//
// Requires basic authentication and that the authenticated user is a Grafana Admin.
//
// Responses:
// 201: createServiceAccountResponse
// 400: badRequestError
// 401: unauthorisedError
// 403: forbiddenError
// 500: internalServerError
2021-12-14 07:39:25 -06:00
func ( api * ServiceAccountsAPI ) CreateServiceAccount ( c * models . ReqContext ) response . Response {
2022-06-16 09:02:03 -05:00
cmd := serviceaccounts . CreateServiceAccountForm { }
2021-12-14 07:39:25 -06:00
if err := web . Bind ( c . Req , & cmd ) ; err != nil {
return response . Error ( http . StatusBadRequest , "Bad request data" , err )
}
2022-02-22 07:58:42 -06:00
2022-07-07 11:32:56 -05:00
if err := api . validateRole ( cmd . Role , & c . OrgRole ) ; err != nil {
switch {
case errors . Is ( err , serviceaccounts . ErrServiceAccountInvalidRole ) :
return response . Error ( http . StatusBadRequest , err . Error ( ) , err )
case errors . Is ( err , serviceaccounts . ErrServiceAccountRolePrivilegeDenied ) :
return response . Error ( http . StatusForbidden , err . Error ( ) , err )
default :
return response . Error ( http . StatusInternalServerError , "failed to create service account" , err )
}
}
2022-08-11 06:28:55 -05:00
serviceAccount , err := api . store . CreateServiceAccount ( c . Req . Context ( ) , c . OrgID , & cmd )
2021-12-14 07:39:25 -06:00
switch {
2022-06-16 09:02:03 -05:00
case errors . Is ( err , database . ErrServiceAccountAlreadyExists ) :
return response . Error ( http . StatusBadRequest , "Failed to create service account" , err )
2021-12-14 07:39:25 -06:00
case err != nil :
return response . Error ( http . StatusInternalServerError , "Failed to create service account" , err )
}
2022-03-08 05:07:58 -06:00
2022-07-08 04:53:18 -05:00
if ! api . accesscontrol . IsDisabled ( ) {
if c . SignedInUser . IsRealUser ( ) {
2022-08-11 06:28:55 -05:00
if _ , err := api . permissionService . SetUserPermission ( c . Req . Context ( ) , c . OrgID , accesscontrol . User { ID : c . SignedInUser . UserID } , strconv . FormatInt ( serviceAccount . Id , 10 ) , "Admin" ) ; err != nil {
2022-07-08 04:53:18 -05:00
return response . Error ( http . StatusInternalServerError , "Failed to set permissions for service account creator" , err )
}
}
2022-11-24 08:38:55 -06:00
// Clear permission cache for the user who's created the service account, so that new permissions are fetched for their next call
// Required for cases when caller wants to immediately interact with the newly created object
api . accesscontrolService . ClearUserPermissionCache ( c . SignedInUser )
2022-07-08 04:53:18 -05:00
}
2022-03-08 05:07:58 -06:00
return response . JSON ( http . StatusCreated , serviceAccount )
2021-12-14 07:39:25 -06:00
}
2022-07-27 08:54:37 -05:00
// swagger:route GET /serviceaccounts/{serviceAccountId} service_accounts retrieveServiceAccount
//
2022-08-18 09:54:39 -05:00
// # Get single serviceaccount by Id
2022-07-27 08:54:37 -05:00
//
// Required permissions (See note in the [introduction](https://grafana.com/docs/grafana/latest/developers/http_api/serviceaccount/#service-account-api) for an explanation):
// action: `serviceaccounts:read` scope: `serviceaccounts:id:1` (single service account)
//
// Responses:
// 200: retrieveServiceAccountResponse
// 400: badRequestError
// 401: unauthorisedError
// 403: forbiddenError
// 404: notFoundError
// 500: internalServerError
2022-01-19 03:23:46 -06:00
func ( api * ServiceAccountsAPI ) RetrieveServiceAccount ( ctx * models . ReqContext ) response . Response {
scopeID , err := strconv . ParseInt ( web . Params ( ctx . Req ) [ ":serviceAccountId" ] , 10 , 64 )
if err != nil {
2022-03-01 02:21:55 -06:00
return response . Error ( http . StatusBadRequest , "Service Account ID is invalid" , err )
2022-01-19 03:23:46 -06:00
}
2022-08-11 06:28:55 -05:00
serviceAccount , err := api . store . RetrieveServiceAccount ( ctx . Req . Context ( ) , ctx . OrgID , scopeID )
2022-01-19 03:23:46 -06:00
if err != nil {
switch {
case errors . Is ( err , serviceaccounts . ErrServiceAccountNotFound ) :
return response . Error ( http . StatusNotFound , "Failed to retrieve service account" , err )
default :
return response . Error ( http . StatusInternalServerError , "Failed to retrieve service account" , err )
}
}
2022-02-22 07:58:42 -06:00
2022-02-25 04:33:34 -06:00
saIDString := strconv . FormatInt ( serviceAccount . Id , 10 )
metadata := api . getAccessControlMetadata ( ctx , map [ string ] bool { saIDString : true } )
2022-02-22 07:58:42 -06:00
serviceAccount . AvatarUrl = dtos . GetGravatarUrlWithDefault ( "" , serviceAccount . Name )
2022-02-25 04:33:34 -06:00
serviceAccount . AccessControl = metadata [ saIDString ]
2022-06-01 02:35:16 -05:00
2022-08-18 09:54:39 -05:00
tokens , err := api . store . ListTokens ( ctx . Req . Context ( ) , & serviceaccounts . GetSATokensQuery {
OrgID : & serviceAccount . OrgId ,
ServiceAccountID : & serviceAccount . Id ,
} )
2022-06-01 02:35:16 -05:00
if err != nil {
api . log . Warn ( "Failed to list tokens for service account" , "serviceAccount" , serviceAccount . Id )
}
serviceAccount . Tokens = int64 ( len ( tokens ) )
2022-01-19 03:23:46 -06:00
return response . JSON ( http . StatusOK , serviceAccount )
}
2022-02-17 06:19:58 -06:00
2022-07-27 08:54:37 -05:00
// swagger:route PATCH /serviceaccounts/{serviceAccountId} service_accounts updateServiceAccount
//
2022-08-18 09:54:39 -05:00
// # Update service account
2022-07-27 08:54:37 -05:00
//
// Required permissions (See note in the [introduction](https://grafana.com/docs/grafana/latest/developers/http_api/serviceaccount/#service-account-api) for an explanation):
// action: `serviceaccounts:write` scope: `serviceaccounts:id:1` (single service account)
//
// Responses:
// 200: updateServiceAccountResponse
// 400: badRequestError
// 401: unauthorisedError
// 403: forbiddenError
// 404: notFoundError
// 500: internalServerError
2022-06-15 07:59:40 -05:00
func ( api * ServiceAccountsAPI ) UpdateServiceAccount ( c * models . ReqContext ) response . Response {
2022-02-17 06:19:58 -06:00
scopeID , err := strconv . ParseInt ( web . Params ( c . Req ) [ ":serviceAccountId" ] , 10 , 64 )
if err != nil {
2022-03-01 02:21:55 -06:00
return response . Error ( http . StatusBadRequest , "Service Account ID is invalid" , err )
2022-02-17 06:19:58 -06:00
}
2022-06-16 09:02:03 -05:00
cmd := serviceaccounts . UpdateServiceAccountForm { }
2022-02-17 06:19:58 -06:00
if err := web . Bind ( c . Req , & cmd ) ; err != nil {
2022-03-01 02:21:55 -06:00
return response . Error ( http . StatusBadRequest , "Bad request data" , err )
2022-02-17 06:19:58 -06:00
}
2022-07-07 11:32:56 -05:00
if err := api . validateRole ( cmd . Role , & c . OrgRole ) ; err != nil {
switch {
case errors . Is ( err , serviceaccounts . ErrServiceAccountInvalidRole ) :
return response . Error ( http . StatusBadRequest , err . Error ( ) , err )
case errors . Is ( err , serviceaccounts . ErrServiceAccountRolePrivilegeDenied ) :
return response . Error ( http . StatusForbidden , err . Error ( ) , err )
default :
return response . Error ( http . StatusInternalServerError , "failed to update service account" , err )
}
2022-04-13 11:11:03 -05:00
}
2022-02-17 06:19:58 -06:00
2022-08-11 06:28:55 -05:00
resp , err := api . store . UpdateServiceAccount ( c . Req . Context ( ) , c . OrgID , scopeID , & cmd )
2022-02-17 06:19:58 -06:00
if err != nil {
switch {
case errors . Is ( err , serviceaccounts . ErrServiceAccountNotFound ) :
return response . Error ( http . StatusNotFound , "Failed to retrieve service account" , err )
default :
return response . Error ( http . StatusInternalServerError , "Failed update service account" , err )
}
}
2022-03-15 04:48:10 -05:00
saIDString := strconv . FormatInt ( resp . Id , 10 )
metadata := api . getAccessControlMetadata ( c , map [ string ] bool { saIDString : true } )
resp . AvatarUrl = dtos . GetGravatarUrlWithDefault ( "" , resp . Name )
resp . AccessControl = metadata [ saIDString ]
2022-06-01 02:35:16 -05:00
return response . JSON ( http . StatusOK , util . DynMap {
"message" : "Service account updated" ,
"id" : resp . Id ,
"name" : resp . Name ,
"serviceaccount" : resp ,
} )
2022-02-17 06:19:58 -06:00
}
2022-03-04 05:04:07 -06:00
2022-08-10 04:56:48 -05:00
func ( api * ServiceAccountsAPI ) validateRole ( r * org . RoleType , orgRole * org . RoleType ) error {
2022-07-07 11:32:56 -05:00
if r != nil && ! r . IsValid ( ) {
return serviceaccounts . ErrServiceAccountInvalidRole
}
if r != nil && ! orgRole . Includes ( * r ) {
return serviceaccounts . ErrServiceAccountRolePrivilegeDenied
}
return nil
}
2022-07-27 08:54:37 -05:00
// swagger:route DELETE /serviceaccounts/{serviceAccountId} service_accounts deleteServiceAccount
//
2022-08-18 09:54:39 -05:00
// # Delete service account
2022-07-27 08:54:37 -05:00
//
// Required permissions (See note in the [introduction](https://grafana.com/docs/grafana/latest/developers/http_api/serviceaccount/#service-account-api) for an explanation):
// action: `serviceaccounts:delete` scope: `serviceaccounts:id:1` (single service account)
//
// Responses:
// 200: okResponse
// 400: badRequestError
// 401: unauthorisedError
// 403: forbiddenError
// 500: internalServerError
2022-06-15 07:59:40 -05:00
func ( api * ServiceAccountsAPI ) DeleteServiceAccount ( ctx * models . ReqContext ) response . Response {
scopeID , err := strconv . ParseInt ( web . Params ( ctx . Req ) [ ":serviceAccountId" ] , 10 , 64 )
if err != nil {
return response . Error ( http . StatusBadRequest , "Service account ID is invalid" , err )
}
2022-08-11 06:28:55 -05:00
err = api . service . DeleteServiceAccount ( ctx . Req . Context ( ) , ctx . OrgID , scopeID )
2022-06-15 07:59:40 -05:00
if err != nil {
return response . Error ( http . StatusInternalServerError , "Service account deletion error" , err )
}
return response . Success ( "Service account deleted" )
}
2022-07-27 08:54:37 -05:00
// swagger:route GET /serviceaccounts/search service_accounts searchOrgServiceAccountsWithPaging
//
2022-08-18 09:54:39 -05:00
// # Search service accounts with paging
2022-07-27 08:54:37 -05:00
//
// Required permissions (See note in the [introduction](https://grafana.com/docs/grafana/latest/developers/http_api/serviceaccount/#service-account-api) for an explanation):
// action: `serviceaccounts:read` scope: `serviceaccounts:*`
//
// Responses:
// 200: searchOrgServiceAccountsWithPagingResponse
// 401: unauthorisedError
// 403: forbiddenError
// 500: internalServerError
2022-03-04 05:04:07 -06:00
func ( api * ServiceAccountsAPI ) SearchOrgServiceAccountsWithPaging ( c * models . ReqContext ) response . Response {
ctx := c . Req . Context ( )
perPage := c . QueryInt ( "perpage" )
if perPage <= 0 {
perPage = 1000
}
page := c . QueryInt ( "page" )
if page < 1 {
page = 1
}
2022-03-18 09:50:34 -05:00
// its okay that it fails, it is only filtering that might be weird, but to safe quard against any weird incoming query param
onlyWithExpiredTokens := c . QueryBool ( "expiredTokens" )
2022-06-01 02:35:16 -05:00
onlyDisabled := c . QueryBool ( "disabled" )
2022-03-18 09:50:34 -05:00
filter := serviceaccounts . FilterIncludeAll
if onlyWithExpiredTokens {
filter = serviceaccounts . FilterOnlyExpiredTokens
}
2022-06-01 02:35:16 -05:00
if onlyDisabled {
filter = serviceaccounts . FilterOnlyDisabled
}
2022-08-11 06:28:55 -05:00
serviceAccountSearch , err := api . store . SearchOrgServiceAccounts ( ctx , c . OrgID , c . Query ( "query" ) , filter , page , perPage , c . SignedInUser )
2022-03-04 05:04:07 -06:00
if err != nil {
return response . Error ( http . StatusInternalServerError , "Failed to get service accounts for current organization" , err )
}
saIDs := map [ string ] bool { }
2022-03-14 12:24:07 -05:00
for i := range serviceAccountSearch . ServiceAccounts {
sa := serviceAccountSearch . ServiceAccounts [ i ]
sa . AvatarUrl = dtos . GetGravatarUrlWithDefault ( "" , sa . Name )
2022-03-04 05:04:07 -06:00
2022-03-14 12:24:07 -05:00
saIDString := strconv . FormatInt ( sa . Id , 10 )
2022-03-04 05:04:07 -06:00
saIDs [ saIDString ] = true
metadata := api . getAccessControlMetadata ( c , map [ string ] bool { saIDString : true } )
2022-03-14 12:24:07 -05:00
sa . AccessControl = metadata [ strconv . FormatInt ( sa . Id , 10 ) ]
2022-08-18 09:54:39 -05:00
tokens , err := api . store . ListTokens ( ctx , & serviceaccounts . GetSATokensQuery {
OrgID : & sa . OrgId , ServiceAccountID : & sa . Id ,
} )
2022-03-04 05:04:07 -06:00
if err != nil {
2022-03-14 12:24:07 -05:00
api . log . Warn ( "Failed to list tokens for service account" , "serviceAccount" , sa . Id )
2022-03-04 05:04:07 -06:00
}
2022-03-14 12:24:07 -05:00
sa . Tokens = int64 ( len ( tokens ) )
2022-03-04 05:04:07 -06:00
}
2022-03-14 12:24:07 -05:00
return response . JSON ( http . StatusOK , serviceAccountSearch )
2022-03-04 05:04:07 -06:00
}
2022-06-15 07:59:40 -05:00
// GET /api/serviceaccounts/migrationstatus
func ( api * ServiceAccountsAPI ) GetAPIKeysMigrationStatus ( ctx * models . ReqContext ) response . Response {
2022-08-11 06:28:55 -05:00
upgradeStatus , err := api . store . GetAPIKeysMigrationStatus ( ctx . Req . Context ( ) , ctx . OrgID )
2022-06-15 07:59:40 -05:00
if err != nil {
return response . Error ( http . StatusInternalServerError , "Internal server error" , err )
}
return response . JSON ( http . StatusOK , upgradeStatus )
}
// POST /api/serviceaccounts/hideapikeys
func ( api * ServiceAccountsAPI ) HideApiKeysTab ( ctx * models . ReqContext ) response . Response {
2022-08-11 06:28:55 -05:00
if err := api . store . HideApiKeysTab ( ctx . Req . Context ( ) , ctx . OrgID ) ; err != nil {
2022-06-15 07:59:40 -05:00
return response . Error ( http . StatusInternalServerError , "Internal server error" , err )
}
return response . Success ( "API keys hidden" )
}
// POST /api/serviceaccounts/migrate
func ( api * ServiceAccountsAPI ) MigrateApiKeysToServiceAccounts ( ctx * models . ReqContext ) response . Response {
2022-08-11 06:28:55 -05:00
if err := api . store . MigrateApiKeysToServiceAccounts ( ctx . Req . Context ( ) , ctx . OrgID ) ; err != nil {
2022-06-15 07:59:40 -05:00
return response . Error ( http . StatusInternalServerError , "Internal server error" , err )
}
2022-06-16 05:11:22 -05:00
return response . Success ( "API keys migrated to service accounts" )
2022-06-15 07:59:40 -05:00
}
// POST /api/serviceaccounts/migrate/:keyId
func ( api * ServiceAccountsAPI ) ConvertToServiceAccount ( ctx * models . 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 )
}
2022-06-16 05:11:22 -05:00
2022-08-11 06:28:55 -05:00
if err := api . store . MigrateApiKey ( ctx . Req . Context ( ) , ctx . OrgID , keyId ) ; err != nil {
2022-06-15 07:59:40 -05:00
return response . Error ( http . StatusInternalServerError , "Error converting API key" , err )
}
2022-06-16 05:11:22 -05:00
return response . Success ( "Service accounts migrated" )
2022-06-15 07:59:40 -05:00
}
// POST /api/serviceaccounts/revert/:keyId
func ( api * ServiceAccountsAPI ) RevertApiKey ( ctx * models . ReqContext ) response . Response {
keyId , err := strconv . ParseInt ( web . Params ( ctx . Req ) [ ":keyId" ] , 10 , 64 )
if err != nil {
2022-07-22 03:35:01 -05:00
return response . Error ( http . StatusBadRequest , "key ID is invalid" , err )
}
serviceAccountId , err := strconv . ParseInt ( web . Params ( ctx . Req ) [ ":serviceAccountId" ] , 10 , 64 )
if err != nil {
return response . Error ( http . StatusBadRequest , "service account ID is invalid" , err )
2022-06-15 07:59:40 -05:00
}
2022-06-16 05:11:22 -05:00
2022-07-22 03:35:01 -05:00
if err := api . store . RevertApiKey ( ctx . Req . Context ( ) , serviceAccountId , keyId ) ; err != nil {
return response . Error ( http . StatusInternalServerError , "error reverting to API key" , err )
2022-06-15 07:59:40 -05:00
}
2022-07-22 03:35:01 -05:00
return response . Success ( "reverted service account to API key" )
2022-06-15 07:59:40 -05:00
}
func ( api * ServiceAccountsAPI ) getAccessControlMetadata ( c * models . ReqContext , saIDs map [ string ] bool ) map [ string ] accesscontrol . Metadata {
if api . accesscontrol . IsDisabled ( ) || ! c . QueryBool ( "accesscontrol" ) {
return map [ string ] accesscontrol . Metadata { }
}
if c . SignedInUser . Permissions == nil {
return map [ string ] accesscontrol . Metadata { }
}
2022-08-11 06:28:55 -05:00
permissions , ok := c . SignedInUser . Permissions [ c . OrgID ]
2022-06-15 07:59:40 -05:00
if ! ok {
return map [ string ] accesscontrol . Metadata { }
}
return accesscontrol . GetResourcesMetadata ( c . Req . Context ( ) , permissions , "serviceaccounts:id:" , saIDs )
}
2022-07-27 08:54:37 -05:00
// swagger:parameters searchOrgServiceAccountsWithPaging
type SearchOrgServiceAccountsWithPagingParams struct {
// in:query
// required:false
Disabled bool ` jsson:"disabled" `
// in:query
// required:false
ExpiredTokens bool ` json:"expiredTokens" `
// It will return results where the query value is contained in one of the name.
// Query values with spaces need to be URL encoded.
// in:query
// required:false
Query string ` json:"query" `
// The default value is 1000.
// in:query
// required:false
PerPage int ` json:"perpage" `
// The default value is 1.
// in:query
// required:false
Page int ` json:"page" `
}
// swagger:parameters createServiceAccount
type CreateServiceAccountParams struct {
//in:body
Body serviceaccounts . CreateServiceAccountForm
}
// swagger:parameters retrieveServiceAccount
type RetrieveServiceAccountParams struct {
// in:path
ServiceAccountId int64 ` json:"serviceAccountId" `
}
// swagger:parameters updateServiceAccount
type UpdateServiceAccountParams struct {
// in:path
ServiceAccountId int64 ` json:"serviceAccountId" `
// in:body
Body serviceaccounts . UpdateServiceAccountForm
}
// swagger:parameters deleteServiceAccount
type DeleteServiceAccountParams struct {
// in:path
ServiceAccountId int64 ` json:"serviceAccountId" `
}
// swagger:response searchOrgServiceAccountsWithPagingResponse
type SearchOrgServiceAccountsWithPagingResponse struct {
// in:body
Body * serviceaccounts . SearchServiceAccountsResult
}
// swagger:response createServiceAccountResponse
type CreateServiceAccountResponse struct {
// in:body
Body * serviceaccounts . ServiceAccountDTO
}
// swagger:response retrieveServiceAccountResponse
type RetrieveServiceAccountResponse struct {
// in:body
Body * serviceaccounts . ServiceAccountDTO
}
// swagger:response updateServiceAccountResponse
type UpdateServiceAccountResponse struct {
// in:body
Body struct {
Message string ` json:"message" `
ID int64 ` json:"id" `
Name string ` json:"name" `
ServiceAccount * serviceaccounts . ServiceAccountProfileDTO ` json:"serviceaccount" `
}
}