mirror of https://github.com/grafana/grafana.git
				
				
				
			
		
			
				
	
	
		
			128 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			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.Route
 | |
| 	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.Route,
 | |
| 	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)
 | |
| }
 |