mirror of https://github.com/grafana/grafana.git
				
				
				
			
		
			
				
	
	
		
			162 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			162 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
package pluginproxy
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"fmt"
 | 
						|
	"net/http"
 | 
						|
	"net/url"
 | 
						|
	"strings"
 | 
						|
	"time"
 | 
						|
 | 
						|
	"github.com/grafana/grafana/pkg/plugins"
 | 
						|
	"github.com/grafana/grafana/pkg/setting"
 | 
						|
	"github.com/grafana/grafana/pkg/util"
 | 
						|
)
 | 
						|
 | 
						|
type DSInfo struct {
 | 
						|
	ID                      int64
 | 
						|
	Updated                 time.Time
 | 
						|
	JSONData                map[string]interface{}
 | 
						|
	DecryptedSecureJSONData map[string]string
 | 
						|
}
 | 
						|
 | 
						|
// ApplyRoute should use the plugin route data to set auth headers and custom headers.
 | 
						|
func ApplyRoute(ctx context.Context, req *http.Request, proxyPath string, route *plugins.Route,
 | 
						|
	ds DSInfo, cfg *setting.Cfg) {
 | 
						|
	proxyPath = strings.TrimPrefix(proxyPath, route.Path)
 | 
						|
 | 
						|
	data := templateData{
 | 
						|
		JsonData:       ds.JSONData,
 | 
						|
		SecureJsonData: ds.DecryptedSecureJSONData,
 | 
						|
	}
 | 
						|
 | 
						|
	if len(route.URL) > 0 {
 | 
						|
		interpolatedURL, err := interpolateString(route.URL, data)
 | 
						|
		if err != nil {
 | 
						|
			logger.Error("Error interpolating proxy url", "error", err)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		routeURL, err := url.Parse(interpolatedURL)
 | 
						|
		if err != nil {
 | 
						|
			logger.Error("Error parsing plugin route url", "error", err)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		req.URL.Scheme = routeURL.Scheme
 | 
						|
		req.URL.Host = routeURL.Host
 | 
						|
		req.Host = routeURL.Host
 | 
						|
		req.URL.Path = util.JoinURLFragments(routeURL.Path, proxyPath)
 | 
						|
	}
 | 
						|
 | 
						|
	if err := addQueryString(req, route, data); err != nil {
 | 
						|
		logger.Error("Failed to render plugin URL query string", "error", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if err := addHeaders(&req.Header, route, data); err != nil {
 | 
						|
		logger.Error("Failed to render plugin headers", "error", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if err := setBodyContent(req, route, data); err != nil {
 | 
						|
		logger.Error("Failed to set plugin route body content", "error", err)
 | 
						|
	}
 | 
						|
 | 
						|
	if tokenProvider, err := getTokenProvider(ctx, cfg, ds, route, data); err != nil {
 | 
						|
		logger.Error("Failed to resolve auth token provider", "error", err)
 | 
						|
	} else if tokenProvider != nil {
 | 
						|
		if token, err := tokenProvider.GetAccessToken(); err != nil {
 | 
						|
			logger.Error("Failed to get access token", "error", err)
 | 
						|
		} else {
 | 
						|
			req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if cfg.DataProxyLogging {
 | 
						|
		logger.Debug("Requesting", "url", req.URL.String())
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func getTokenProvider(ctx context.Context, cfg *setting.Cfg, ds DSInfo, pluginRoute *plugins.Route,
 | 
						|
	data templateData) (accessTokenProvider, error) {
 | 
						|
	authType := pluginRoute.AuthType
 | 
						|
 | 
						|
	// Plugin can override authentication type specified in route configuration
 | 
						|
	if authTypeOverride, ok := ds.JSONData["authenticationType"].(string); ok && authTypeOverride != "" {
 | 
						|
		authType = authTypeOverride
 | 
						|
	}
 | 
						|
 | 
						|
	tokenAuth, err := interpolateAuthParams(pluginRoute.TokenAuth, data)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	jwtTokenAuth, err := interpolateAuthParams(pluginRoute.JwtTokenAuth, data)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	switch authType {
 | 
						|
	case "azure":
 | 
						|
		if tokenAuth == nil {
 | 
						|
			return nil, fmt.Errorf("'tokenAuth' not configured for authentication type '%s'", authType)
 | 
						|
		}
 | 
						|
		return newAzureAccessTokenProvider(ctx, cfg, tokenAuth)
 | 
						|
 | 
						|
	case "gce":
 | 
						|
		if jwtTokenAuth == nil {
 | 
						|
			return nil, fmt.Errorf("'jwtTokenAuth' not configured for authentication type '%s'", authType)
 | 
						|
		}
 | 
						|
		return newGceAccessTokenProvider(ctx, ds, pluginRoute, jwtTokenAuth), nil
 | 
						|
 | 
						|
	case "jwt":
 | 
						|
		if jwtTokenAuth == nil {
 | 
						|
			return nil, fmt.Errorf("'jwtTokenAuth' not configured for authentication type '%s'", authType)
 | 
						|
		}
 | 
						|
		provider := newJwtAccessTokenProvider(ctx, ds, pluginRoute, jwtTokenAuth)
 | 
						|
		return provider, nil
 | 
						|
 | 
						|
	case "":
 | 
						|
		// Fallback to authentication methods when authentication type isn't explicitly configured
 | 
						|
		if tokenAuth != nil {
 | 
						|
			provider := newGenericAccessTokenProvider(ds, pluginRoute, tokenAuth)
 | 
						|
			return provider, nil
 | 
						|
		}
 | 
						|
		if jwtTokenAuth != nil {
 | 
						|
			provider := newJwtAccessTokenProvider(ctx, ds, pluginRoute, jwtTokenAuth)
 | 
						|
			return provider, nil
 | 
						|
		}
 | 
						|
 | 
						|
		// No authentication
 | 
						|
		return nil, nil
 | 
						|
 | 
						|
	default:
 | 
						|
		return nil, fmt.Errorf("authentication type '%s' not supported", authType)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func interpolateAuthParams(tokenAuth *plugins.JWTTokenAuth, data templateData) (*plugins.JWTTokenAuth, error) {
 | 
						|
	if tokenAuth == nil {
 | 
						|
		// Nothing to interpolate
 | 
						|
		return nil, nil
 | 
						|
	}
 | 
						|
 | 
						|
	interpolatedUrl, err := interpolateString(tokenAuth.Url, data)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	interpolatedParams := make(map[string]string)
 | 
						|
	for key, value := range tokenAuth.Params {
 | 
						|
		interpolatedParam, err := interpolateString(value, data)
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
		interpolatedParams[key] = interpolatedParam
 | 
						|
	}
 | 
						|
 | 
						|
	return &plugins.JWTTokenAuth{
 | 
						|
		Url:    interpolatedUrl,
 | 
						|
		Scopes: tokenAuth.Scopes,
 | 
						|
		Params: interpolatedParams,
 | 
						|
	}, nil
 | 
						|
}
 |