2022-02-28 04:30:45 -06:00
package database
import (
"context"
2023-03-02 09:28:10 -06:00
"errors"
"fmt"
2022-10-14 14:33:06 -05:00
2022-10-19 08:02:15 -05:00
"github.com/grafana/grafana/pkg/infra/db"
2022-08-04 07:19:09 -05:00
"github.com/grafana/grafana/pkg/services/apikey"
2022-08-10 04:56:48 -05:00
"github.com/grafana/grafana/pkg/services/org"
2022-04-13 11:11:03 -05:00
"github.com/grafana/grafana/pkg/services/serviceaccounts"
2022-02-28 04:30:45 -06:00
)
2022-08-18 09:54:39 -05:00
const maxRetrievedTokens = 300
2022-06-15 07:59:40 -05:00
2022-08-18 09:54:39 -05:00
func ( s * ServiceAccountsStoreImpl ) ListTokens (
ctx context . Context , query * serviceaccounts . GetSATokensQuery ,
) ( [ ] apikey . APIKey , error ) {
result := make ( [ ] apikey . APIKey , 0 )
2022-10-19 08:02:15 -05:00
err := s . sqlStore . WithDbSession ( ctx , func ( dbSession * db . Session ) error {
2022-10-14 14:33:06 -05:00
quotedUser := s . sqlStore . GetDialect ( ) . Quote ( "user" )
2022-08-18 09:54:39 -05:00
sess := dbSession . Limit ( maxRetrievedTokens , 0 ) . Where ( "api_key.service_account_id IS NOT NULL" )
if query . OrgID != nil {
sess = sess . Where ( quotedUser + ".org_id=?" , * query . OrgID )
sess = sess . Where ( "api_key.org_id=?" , * query . OrgID )
}
if query . ServiceAccountID != nil {
sess = sess . Where ( "api_key.service_account_id=?" , * query . ServiceAccountID )
}
sess = sess . Join ( "inner" , quotedUser , quotedUser + ".id = api_key.service_account_id" ) .
2022-06-15 07:59:40 -05:00
Asc ( "api_key.name" )
2023-03-02 09:28:10 -06:00
if err := sess . Find ( & result ) ; err != nil {
return fmt . Errorf ( "%s: %w" , "list token error" , err )
}
return nil
2022-06-15 07:59:40 -05:00
} )
return result , err
}
2023-01-31 02:51:55 -06:00
func ( s * ServiceAccountsStoreImpl ) AddServiceAccountToken ( ctx context . Context , serviceAccountId int64 , cmd * serviceaccounts . AddServiceAccountTokenCommand ) ( * apikey . APIKey , error ) {
var apiKey * apikey . APIKey
return apiKey , s . sqlStore . WithTransactionalDbSession ( ctx , func ( sess * db . Session ) error {
2022-06-15 07:59:40 -05:00
if _ , err := s . RetrieveServiceAccount ( ctx , cmd . OrgId , serviceAccountId ) ; err != nil {
return err
}
2022-08-18 09:54:39 -05:00
addKeyCmd := & apikey . AddCommand {
2022-02-28 04:30:45 -06:00
Name : cmd . Name ,
2022-08-10 04:56:48 -05:00
Role : org . RoleViewer ,
2023-02-03 10:23:09 -06:00
OrgID : cmd . OrgId ,
2022-02-28 04:30:45 -06:00
Key : cmd . Key ,
2022-08-18 09:54:39 -05:00
SecondsToLive : cmd . SecondsToLive ,
ServiceAccountID : & serviceAccountId ,
2022-02-28 04:30:45 -06:00
}
2023-03-21 07:26:33 -05:00
key , err := s . apiKeyService . AddAPIKey ( ctx , addKeyCmd )
if err != nil {
2022-08-18 09:54:39 -05:00
switch {
case errors . Is ( err , apikey . ErrDuplicate ) :
2023-03-08 05:32:09 -06:00
return serviceaccounts . ErrDuplicateToken . Errorf ( "service account token with name %s already exists in the organization" , cmd . Name )
2022-08-18 09:54:39 -05:00
case errors . Is ( err , apikey . ErrInvalidExpiration ) :
2023-03-08 05:32:09 -06:00
return serviceaccounts . ErrInvalidTokenExpiration . Errorf ( "invalid service account token expiration value %d" , cmd . SecondsToLive )
2022-08-18 09:54:39 -05:00
}
2022-02-28 04:30:45 -06:00
return err
}
2022-08-18 09:54:39 -05:00
2023-03-21 07:26:33 -05:00
apiKey = key
2022-02-28 04:30:45 -06:00
return nil
} )
}
2022-06-15 07:59:40 -05:00
func ( s * ServiceAccountsStoreImpl ) DeleteServiceAccountToken ( ctx context . Context , orgId , serviceAccountId , tokenId int64 ) error {
2022-02-28 04:30:45 -06:00
rawSQL := "DELETE FROM api_key WHERE id=? and org_id=? and service_account_id=?"
2022-10-19 08:02:15 -05:00
return s . sqlStore . WithDbSession ( ctx , func ( sess * db . Session ) error {
2022-06-15 07:59:40 -05:00
result , err := sess . Exec ( rawSQL , tokenId , orgId , serviceAccountId )
2022-02-28 04:30:45 -06:00
if err != nil {
return err
}
2022-06-16 09:02:03 -05:00
affected , err := result . RowsAffected ( )
if affected == 0 {
2023-03-08 05:32:09 -06:00
return serviceaccounts . ErrServiceAccountTokenNotFound . Errorf ( "service account token with id %d not found" , tokenId )
2022-02-28 04:30:45 -06:00
}
2022-06-16 09:02:03 -05:00
return err
2022-02-28 04:30:45 -06:00
} )
}
2022-03-14 12:24:07 -05:00
2022-08-18 09:54:39 -05:00
func ( s * ServiceAccountsStoreImpl ) RevokeServiceAccountToken ( ctx context . Context , orgId , serviceAccountId , tokenId int64 ) error {
rawSQL := "UPDATE api_key SET is_revoked = ? WHERE id=? and org_id=? and service_account_id=?"
2022-10-19 08:02:15 -05:00
return s . sqlStore . WithDbSession ( ctx , func ( sess * db . Session ) error {
2022-10-14 14:33:06 -05:00
result , err := sess . Exec ( rawSQL , s . sqlStore . GetDialect ( ) . BooleanStr ( true ) , tokenId , orgId , serviceAccountId )
2022-08-18 09:54:39 -05:00
if err != nil {
return err
}
affected , err := result . RowsAffected ( )
if affected == 0 {
2023-03-08 05:32:09 -06:00
return serviceaccounts . ErrServiceAccountTokenNotFound . Errorf ( "service account token with id %d not found for service account with id %d" , tokenId , serviceAccountId )
2022-08-18 09:54:39 -05:00
}
return err
} )
}
2022-03-14 12:24:07 -05:00
// assignApiKeyToServiceAccount sets the API key service account ID
2023-06-08 03:09:30 -05:00
func ( s * ServiceAccountsStoreImpl ) assignApiKeyToServiceAccount ( ctx context . Context , apiKeyId int64 , serviceAccountId int64 ) error {
return s . sqlStore . WithDbSession ( ctx , func ( sess * db . Session ) error {
key := apikey . APIKey { ID : apiKeyId }
exists , err := sess . Get ( & key )
if err != nil {
s . log . Warn ( "API key not loaded" , "err" , err )
return err
}
if ! exists {
s . log . Warn ( "API key not found" , "err" , err )
return apikey . ErrNotFound
}
key . ServiceAccountId = & serviceAccountId
2022-03-14 12:24:07 -05:00
2023-06-08 03:09:30 -05:00
if _ , err := sess . ID ( key . ID ) . Update ( & key ) ; err != nil {
s . log . Warn ( "Could not update api key" , "err" , err )
return err
}
return nil
} )
2022-06-15 07:59:40 -05:00
}