grafana/pkg/api/pluginproxy/token_provider_generic.go
idafurjes e822c8a24d
CloudMonitoring: Migrate to use backend plugin SDK contracts (#38650)
* Use SDK contracts for cloudmonitoring

* Get build running, tests passing and do some refactoring (#38754)

* fix build+tests and refactor

* remove alerting stuff

* remove unused field

* fix plugin fetch

* end to end

* resp rename

* tidy annotations

* reformatting

* update refID

* reformat imports

* fix styling

* clean up unmarshalling

* uncomment + fix tests

* appease linter

* remove spaces

* remove old cruft

* add check for empty queries

* update tests

* remove pm as dep

* adjust proxy route contract

* fix service loading

* use UNIX val

* fix endpoint + resp

* h@ckz for frontend

* fix resp

* fix interval

* always set custom meta

* remove unused param

* fix labels fetch

* fix linter

* fix test + remove unused field

* apply pr feedback

* fix grafana-auto intervals

* fix tests

* resolve conflicts

* fix bad merge

* fix conflicts

* remove bad logger import

Co-authored-by: Will Browne <wbrowne@users.noreply.github.com>
Co-authored-by: Will Browne <will.browne@grafana.com>
2021-10-08 14:46:35 +02:00

128 lines
3.0 KiB
Go

package pluginproxy
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"net/url"
"strconv"
"sync"
"time"
"github.com/grafana/grafana/pkg/plugins"
)
var (
tokenCache = tokenCacheType{
cache: map[string]*jwtToken{},
}
)
type tokenCacheType struct {
cache map[string]*jwtToken
sync.Mutex
}
type genericAccessTokenProvider struct {
datasourceId int64
datasourceUpdated time.Time
route *plugins.AppPluginRoute
authParams *plugins.JwtTokenAuth
}
type jwtToken struct {
ExpiresOn time.Time
AccessToken string
}
func (token *jwtToken) UnmarshalJSON(b []byte) error {
var t struct {
AccessToken string `json:"access_token"`
ExpiresOn *json.Number `json:"expires_on"`
ExpiresIn *json.Number `json:"expires_in"`
}
if err := json.Unmarshal(b, &t); err != nil {
return err
}
token.AccessToken = t.AccessToken
token.ExpiresOn = timeNow()
if t.ExpiresOn != nil {
expiresOn, err := t.ExpiresOn.Int64()
if err != nil {
return err
}
token.ExpiresOn = time.Unix(expiresOn, 0)
} else if t.ExpiresIn != nil {
expiresIn, err := t.ExpiresIn.Int64()
if err != nil {
return err
}
token.ExpiresOn = timeNow().Add(time.Duration(expiresIn) * time.Second)
}
return nil
}
func newGenericAccessTokenProvider(ds DSInfo, pluginRoute *plugins.AppPluginRoute,
authParams *plugins.JwtTokenAuth) *genericAccessTokenProvider {
return &genericAccessTokenProvider{
datasourceId: ds.ID,
datasourceUpdated: ds.Updated,
route: pluginRoute,
authParams: authParams,
}
}
func (provider *genericAccessTokenProvider) GetAccessToken() (string, error) {
tokenCache.Lock()
defer tokenCache.Unlock()
if cachedToken, found := tokenCache.cache[provider.getAccessTokenCacheKey()]; found {
if cachedToken.ExpiresOn.After(timeNow().Add(time.Second * 10)) {
logger.Info("Using token from cache")
return cachedToken.AccessToken, nil
}
}
tokenUrl := provider.authParams.Url
params := make(url.Values)
for key, value := range provider.authParams.Params {
params.Add(key, value)
}
getTokenReq, err := http.NewRequest("POST", tokenUrl, bytes.NewBufferString(params.Encode()))
if err != nil {
return "", err
}
getTokenReq.Header.Set("Content-Type", "application/x-www-form-urlencoded")
getTokenReq.Header.Set("Content-Length", strconv.Itoa(len(params.Encode())))
resp, err := client.Do(getTokenReq)
if err != nil {
return "", err
}
defer func() {
if err := resp.Body.Close(); err != nil {
logger.Warn("Failed to close response body", "err", err)
}
}()
var token jwtToken
if err := json.NewDecoder(resp.Body).Decode(&token); err != nil {
return "", err
}
tokenCache.cache[provider.getAccessTokenCacheKey()] = &token
logger.Info("Got new access token", "ExpiresOn", token.ExpiresOn)
return token.AccessToken, nil
}
func (provider *genericAccessTokenProvider) getAccessTokenCacheKey() string {
return fmt.Sprintf("%v_%v_%v_%v", provider.datasourceId, provider.datasourceUpdated.Unix(), provider.route.Path, provider.route.Method)
}