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