grafana/pkg/services/contexthandler/contexthandler_test.go
Karl Persson be5ced4287
Identity: Use typed version of namespace id (#87257)
* Remove different constructors and only use NewNamespaceID

* AdminUser: check typed namespace id

* Identity: Add convinient function to parse valid user id when type is either user or service account

* Annotations: Use typed namespace id instead
2024-05-08 14:03:53 +02:00

211 lines
7.2 KiB
Go

package contexthandler_test
import (
"errors"
"net/http"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/services/authn"
"github.com/grafana/grafana/pkg/services/authn/authntest"
"github.com/grafana/grafana/pkg/services/contexthandler"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/login"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/web/webtest"
)
func TestContextHandler(t *testing.T) {
t.Run("should set auth error if authentication was unsuccessful", func(t *testing.T) {
handler := contexthandler.ProvideService(
setting.NewCfg(),
tracing.InitializeTracerForTest(),
featuremgmt.WithFeatures(),
&authntest.FakeService{ExpectedErr: errors.New("some error")},
)
server := webtest.NewServer(t, routing.NewRouteRegister())
server.Mux.Use(handler.Middleware)
server.Mux.Get("/api/handler", func(c *contextmodel.ReqContext) {
require.False(t, c.IsSignedIn)
require.EqualValues(t, &user.SignedInUser{Permissions: map[int64]map[string][]string{}}, c.SignedInUser)
require.Error(t, c.LookupTokenErr)
})
res, err := server.Send(server.NewGetRequest("/api/handler"))
require.NoError(t, err)
require.NoError(t, res.Body.Close())
})
t.Run("should set identity on successful authentication", func(t *testing.T) {
identity := &authn.Identity{ID: authn.NewNamespaceID(authn.NamespaceUser, 1), OrgID: 1}
handler := contexthandler.ProvideService(
setting.NewCfg(),
tracing.InitializeTracerForTest(),
featuremgmt.WithFeatures(),
&authntest.FakeService{ExpectedIdentity: identity},
)
server := webtest.NewServer(t, routing.NewRouteRegister())
server.Mux.Use(handler.Middleware)
server.Mux.Get("/api/handler", func(c *contextmodel.ReqContext) {
require.True(t, c.IsSignedIn)
require.EqualValues(t, identity.SignedInUser(), c.SignedInUser)
require.NoError(t, c.LookupTokenErr)
})
res, err := server.Send(server.NewGetRequest("/api/handler"))
require.NoError(t, err)
require.NoError(t, res.Body.Close())
})
t.Run("should not set IsSignedIn on anonymous identity", func(t *testing.T) {
identity := &authn.Identity{ID: authn.AnonymousNamespaceID, OrgID: 1}
handler := contexthandler.ProvideService(
setting.NewCfg(),
tracing.InitializeTracerForTest(),
featuremgmt.WithFeatures(),
&authntest.FakeService{ExpectedIdentity: identity},
)
server := webtest.NewServer(t, routing.NewRouteRegister())
server.Mux.Use(handler.Middleware)
server.Mux.Get("/api/handler", func(c *contextmodel.ReqContext) {
require.False(t, c.IsSignedIn)
require.EqualValues(t, identity.SignedInUser(), c.SignedInUser)
require.NoError(t, c.LookupTokenErr)
})
res, err := server.Send(server.NewGetRequest("/api/handler"))
require.NoError(t, err)
require.NoError(t, res.Body.Close())
})
t.Run("should set IsRenderCall when authenticated by render client", func(t *testing.T) {
identity := &authn.Identity{OrgID: 1, AuthenticatedBy: login.RenderModule}
handler := contexthandler.ProvideService(
setting.NewCfg(),
tracing.InitializeTracerForTest(),
featuremgmt.WithFeatures(),
&authntest.FakeService{ExpectedIdentity: identity},
)
server := webtest.NewServer(t, routing.NewRouteRegister())
server.Mux.Use(handler.Middleware)
server.Mux.Get("/api/handler", func(c *contextmodel.ReqContext) {
require.True(t, c.IsSignedIn)
require.True(t, c.IsRenderCall)
require.EqualValues(t, identity.SignedInUser(), c.SignedInUser)
require.NoError(t, c.LookupTokenErr)
})
res, err := server.Send(server.NewGetRequest("/api/handler"))
require.NoError(t, err)
require.NoError(t, res.Body.Close())
})
t.Run("should store auth header in context", func(t *testing.T) {
cfg := setting.NewCfg()
cfg.JWTAuth.Enabled = true
cfg.JWTAuth.HeaderName = "jwt-header"
cfg.AuthProxy.Enabled = true
cfg.AuthProxy.HeaderName = "proxy-header"
cfg.AuthProxy.Headers = map[string]string{
"name": "proxy-header-name",
}
handler := contexthandler.ProvideService(
cfg,
tracing.InitializeTracerForTest(),
featuremgmt.WithFeatures(),
&authntest.FakeService{ExpectedIdentity: &authn.Identity{}},
)
server := webtest.NewServer(t, routing.NewRouteRegister())
server.Mux.Use(handler.Middleware)
server.Mux.Get("/api/handler", func(c *contextmodel.ReqContext) {
list := contexthandler.AuthHTTPHeaderListFromContext(c.Req.Context())
require.NotNil(t, list)
assert.Contains(t, list.Items, "jwt-header")
assert.Contains(t, list.Items, "proxy-header")
assert.Contains(t, list.Items, "proxy-header-name")
assert.Contains(t, list.Items, "Authorization")
})
res, err := server.Send(server.NewGetRequest("/api/handler"))
require.NoError(t, err)
require.NoError(t, res.Body.Close())
})
t.Run("id response headers", func(t *testing.T) {
run := func(cfg *setting.Cfg, id string) *http.Response {
handler := contexthandler.ProvideService(
cfg,
tracing.InitializeTracerForTest(),
featuremgmt.WithFeatures(),
&authntest.FakeService{ExpectedIdentity: &authn.Identity{ID: authn.MustParseNamespaceID(id)}},
)
server := webtest.NewServer(t, routing.NewRouteRegister())
server.Mux.Use(handler.Middleware)
server.Mux.Get("/api/handler", func(c *contextmodel.ReqContext) {})
res, err := server.Send(server.NewGetRequest("/api/handler"))
require.NoError(t, err)
return res
}
t.Run("should add id header for user", func(t *testing.T) {
cfg := setting.NewCfg()
cfg.IDResponseHeaderEnabled = true
cfg.IDResponseHeaderPrefix = "X-Grafana"
cfg.IDResponseHeaderNamespaces = map[string]struct{}{"user": {}}
res := run(cfg, "user:1")
require.Equal(t, "user:1", res.Header.Get("X-Grafana-Identity-Id"))
require.NoError(t, res.Body.Close())
})
t.Run("should not add id header for user when id is 0", func(t *testing.T) {
cfg := setting.NewCfg()
cfg.IDResponseHeaderEnabled = true
cfg.IDResponseHeaderPrefix = "X-Grafana"
cfg.IDResponseHeaderNamespaces = map[string]struct{}{"user": {}}
res := run(cfg, "user:0")
require.Empty(t, res.Header.Get("X-Grafana-Identity-Id"))
require.NoError(t, res.Body.Close())
})
t.Run("should add id header for service account", func(t *testing.T) {
cfg := setting.NewCfg()
cfg.IDResponseHeaderEnabled = true
cfg.IDResponseHeaderPrefix = "X-Grafana"
cfg.IDResponseHeaderNamespaces = map[string]struct{}{"service-account": {}}
res := run(cfg, "service-account:1")
require.Equal(t, "service-account:1", res.Header.Get("X-Grafana-Identity-Id"))
require.NoError(t, res.Body.Close())
})
t.Run("should not add id header for service account when not configured", func(t *testing.T) {
cfg := setting.NewCfg()
cfg.IDResponseHeaderEnabled = true
cfg.IDResponseHeaderPrefix = "X-Grafana"
cfg.IDResponseHeaderNamespaces = map[string]struct{}{"user": {}}
res := run(cfg, "service-account:1")
require.Empty(t, res.Header.Get("X-Grafana-Identity-Id"))
require.NoError(t, res.Body.Close())
})
})
}