Shared Azure middleware between Azure Monitor and Prometheus datasources (#46002)
* Scopes in Azure middleware * Enable Azure middleware without feature flag * Use common Azure middleware in Azure Monitor * Apply feature flag to JsonData configuration of Azure auth * Enforce feature flag in Prometheus datasource * Prometheus provider tests * Datasource service tests * Fix http client provider tests * Pass sdkhttpclient.Options by reference * Add middleware to httpclient.Options * Remove dependency on Grafana settings * Unit-tests updated * Fix ds_proxy_test * Fix service_test
This commit is contained in:
@@ -1,86 +0,0 @@
|
||||
package httpclientprovider
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/azcredentials"
|
||||
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/aztokenprovider"
|
||||
)
|
||||
|
||||
const azureMiddlewareName = "AzureAuthentication.Provider"
|
||||
|
||||
func AzureMiddleware(cfg *setting.Cfg) httpclient.Middleware {
|
||||
return httpclient.NamedMiddlewareFunc(azureMiddlewareName, func(opts httpclient.Options, next http.RoundTripper) http.RoundTripper {
|
||||
credentials, err := getAzureCredentials(opts.CustomOptions)
|
||||
if err != nil {
|
||||
return errorResponse(err)
|
||||
} else if credentials == nil {
|
||||
return next
|
||||
}
|
||||
|
||||
tokenProvider, err := aztokenprovider.NewAzureAccessTokenProvider(cfg, credentials)
|
||||
if err != nil {
|
||||
return errorResponse(err)
|
||||
}
|
||||
|
||||
scopes, err := getAzureEndpointScopes(opts.CustomOptions)
|
||||
if err != nil {
|
||||
return errorResponse(err)
|
||||
}
|
||||
|
||||
return aztokenprovider.ApplyAuth(tokenProvider, scopes, next)
|
||||
})
|
||||
}
|
||||
|
||||
func errorResponse(err error) http.RoundTripper {
|
||||
return httpclient.RoundTripperFunc(func(req *http.Request) (*http.Response, error) {
|
||||
return nil, fmt.Errorf("invalid Azure configuration: %s", err)
|
||||
})
|
||||
}
|
||||
|
||||
func getAzureCredentials(customOptions map[string]interface{}) (azcredentials.AzureCredentials, error) {
|
||||
if untypedValue, ok := customOptions["_azureCredentials"]; !ok {
|
||||
return nil, nil
|
||||
} else if value, ok := untypedValue.(azcredentials.AzureCredentials); !ok {
|
||||
err := fmt.Errorf("the field 'azureCredentials' should be a valid credentials object")
|
||||
return nil, err
|
||||
} else {
|
||||
return value, nil
|
||||
}
|
||||
}
|
||||
|
||||
func getAzureEndpointResourceId(customOptions map[string]interface{}) (*url.URL, error) {
|
||||
var value string
|
||||
if untypedValue, ok := customOptions["azureEndpointResourceId"]; !ok {
|
||||
err := fmt.Errorf("the field 'azureEndpointResourceId' should be set")
|
||||
return nil, err
|
||||
} else if value, ok = untypedValue.(string); !ok {
|
||||
err := fmt.Errorf("the field 'azureEndpointResourceId' should be a string")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resourceId, err := url.Parse(value)
|
||||
if err != nil || resourceId.Scheme == "" || resourceId.Host == "" {
|
||||
err := fmt.Errorf("invalid endpoint Resource ID URL '%s'", value)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return resourceId, nil
|
||||
}
|
||||
|
||||
func getAzureEndpointScopes(customOptions map[string]interface{}) ([]string, error) {
|
||||
resourceId, err := getAzureEndpointResourceId(customOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resourceId.Path = path.Join(resourceId.Path, ".default")
|
||||
scopes := []string{resourceId.String()}
|
||||
|
||||
return scopes, nil
|
||||
}
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/infra/metrics/metricutil"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/mwitkow/go-conntrack"
|
||||
)
|
||||
@@ -17,7 +16,7 @@ import (
|
||||
var newProviderFunc = sdkhttpclient.NewProvider
|
||||
|
||||
// New creates a new HTTP client provider with pre-configured middlewares.
|
||||
func New(cfg *setting.Cfg, tracer tracing.Tracer, features featuremgmt.FeatureToggles) *sdkhttpclient.Provider {
|
||||
func New(cfg *setting.Cfg, tracer tracing.Tracer) *sdkhttpclient.Provider {
|
||||
logger := log.New("httpclient")
|
||||
userAgent := fmt.Sprintf("Grafana/%s", cfg.BuildVersion)
|
||||
|
||||
@@ -36,10 +35,6 @@ func New(cfg *setting.Cfg, tracer tracing.Tracer, features featuremgmt.FeatureTo
|
||||
|
||||
setDefaultTimeoutOptions(cfg)
|
||||
|
||||
if features.IsEnabled(featuremgmt.FlagHttpclientproviderAzureAuth) {
|
||||
middlewares = append(middlewares, AzureMiddleware(cfg))
|
||||
}
|
||||
|
||||
return newProviderFunc(sdkhttpclient.ProviderOptions{
|
||||
Middlewares: middlewares,
|
||||
ConfigureTransport: func(opts sdkhttpclient.Options, transport *http.Transport) {
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
|
||||
sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
|
||||
"github.com/grafana/grafana/pkg/infra/tracing"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@@ -23,7 +22,7 @@ func TestHTTPClientProvider(t *testing.T) {
|
||||
})
|
||||
tracer, err := tracing.InitializeTracerForTest()
|
||||
require.NoError(t, err)
|
||||
_ = New(&setting.Cfg{SigV4AuthEnabled: false}, tracer, featuremgmt.WithFeatures())
|
||||
_ = New(&setting.Cfg{SigV4AuthEnabled: false}, tracer)
|
||||
require.Len(t, providerOpts, 1)
|
||||
o := providerOpts[0]
|
||||
require.Len(t, o.Middlewares, 6)
|
||||
@@ -47,7 +46,7 @@ func TestHTTPClientProvider(t *testing.T) {
|
||||
})
|
||||
tracer, err := tracing.InitializeTracerForTest()
|
||||
require.NoError(t, err)
|
||||
_ = New(&setting.Cfg{SigV4AuthEnabled: true}, tracer, featuremgmt.WithFeatures())
|
||||
_ = New(&setting.Cfg{SigV4AuthEnabled: true}, tracer)
|
||||
require.Len(t, providerOpts, 1)
|
||||
o := providerOpts[0]
|
||||
require.Len(t, o.Middlewares, 7)
|
||||
|
||||
Reference in New Issue
Block a user