IDForwarding: Require that id forwarding is enabled for data source (#77131)

* Require that id forwarding is enabled for data source

* Address feedback
This commit is contained in:
Karl Persson 2023-10-27 08:30:33 +02:00 committed by GitHub
parent 7d2bfea777
commit 1b6d39f823
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 65 additions and 5 deletions

View File

@ -19,6 +19,7 @@ import (
glog "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/services/auth"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
"github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/featuremgmt"
@ -269,7 +270,7 @@ func (proxy *DataSourceProxy) director(req *http.Request) {
}
}
if proxy.features.IsEnabled(featuremgmt.FlagIdForwarding) {
if proxy.features.IsEnabled(featuremgmt.FlagIdForwarding) && auth.IsIDForwardingEnabledForDataSource(proxy.ds) {
proxyutil.ApplyForwardIDHeader(req, proxy.ctx.SignedInUser)
}
}

View File

@ -4,7 +4,9 @@ import (
"context"
"github.com/go-jose/go-jose/v3/jwt"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/datasources"
)
type IDService interface {
@ -19,3 +21,9 @@ type IDSigner interface {
type IDClaims struct {
jwt.Claims
}
const settingsKey = "forwardIdToken"
func IsIDForwardingEnabledForDataSource(ds *datasources.DataSource) bool {
return ds.JsonData != nil && ds.JsonData.Get(settingsKey).MustBool()
}

View File

@ -4,8 +4,12 @@ import (
"context"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/services/auth"
"github.com/grafana/grafana/pkg/services/contexthandler"
"github.com/grafana/grafana/pkg/services/datasources"
)
const forwardIDHeaderName = "X-Grafana-Id"
@ -28,7 +32,16 @@ type ForwardIDMiddleware struct {
func (m *ForwardIDMiddleware) applyToken(ctx context.Context, pCtx backend.PluginContext, req backend.ForwardHTTPHeaders) error {
reqCtx := contexthandler.FromContext(ctx)
// if request not for a datasource or no HTTP request context skip middleware
if req == nil || reqCtx == nil || reqCtx.SignedInUser == nil {
if req == nil || reqCtx == nil || reqCtx.SignedInUser == nil || pCtx.DataSourceInstanceSettings == nil {
return nil
}
jsonDataBytes, err := simplejson.NewJson(pCtx.DataSourceInstanceSettings.JSONData)
if err != nil {
return err
}
if !auth.IsIDForwardingEnabledForDataSource(&datasources.DataSource{JsonData: jsonDataBytes}) {
return nil
}

View File

@ -2,20 +2,31 @@ package clientmiddleware
import (
"context"
"encoding/json"
"net/http"
"testing"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana/pkg/web"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/plugins/manager/client/clienttest"
"github.com/grafana/grafana/pkg/services/contexthandler/ctxkey"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/web"
)
func TestForwardIDMiddleware(t *testing.T) {
settingWithEnabled, err := json.Marshal(map[string]any{
"forwardIdToken": true,
})
require.NoError(t, err)
settingWithDisabled, err := json.Marshal(map[string]any{
"forwardIdToken": false,
})
require.NoError(t, err)
t.Run("Should set forwarded id header if present", func(t *testing.T) {
cdt := clienttest.NewClientDecoratorTest(t, clienttest.WithMiddlewares(NewForwardIDMiddleware()))
@ -25,13 +36,36 @@ func TestForwardIDMiddleware(t *testing.T) {
})
err := cdt.Decorator.CallResource(ctx, &backend.CallResourceRequest{
PluginContext: backend.PluginContext{},
PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{
JSONData: settingWithEnabled,
},
},
}, nopCallResourceSender)
require.NoError(t, err)
require.Equal(t, "some-token", cdt.CallResourceReq.Headers[forwardIDHeaderName][0])
})
t.Run("Should not set forwarded id header if setting is disabled", func(t *testing.T) {
cdt := clienttest.NewClientDecoratorTest(t, clienttest.WithMiddlewares(NewForwardIDMiddleware()))
ctx := context.WithValue(context.Background(), ctxkey.Key{}, &contextmodel.ReqContext{
Context: &web.Context{Req: &http.Request{}},
SignedInUser: &user.SignedInUser{IDToken: "some-token"},
})
err := cdt.Decorator.CallResource(ctx, &backend.CallResourceRequest{
PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{
JSONData: settingWithDisabled,
},
},
}, nopCallResourceSender)
require.NoError(t, err)
require.Len(t, cdt.CallResourceReq.Headers[forwardIDHeaderName], 0)
})
t.Run("Should not set forwarded id header if not present", func(t *testing.T) {
cdt := clienttest.NewClientDecoratorTest(t, clienttest.WithMiddlewares(NewForwardIDMiddleware()))
@ -41,7 +75,11 @@ func TestForwardIDMiddleware(t *testing.T) {
})
err := cdt.Decorator.CallResource(ctx, &backend.CallResourceRequest{
PluginContext: backend.PluginContext{},
PluginContext: backend.PluginContext{
DataSourceInstanceSettings: &backend.DataSourceInstanceSettings{
JSONData: settingWithEnabled,
},
},
}, nopCallResourceSender)
require.NoError(t, err)