mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: AlertingProxy to elevate permissions for request forwarded to data proxy when RBAC enabled (#53620)
This commit is contained in:
@@ -1,9 +1,21 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/response"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
"github.com/grafana/grafana/pkg/web"
|
||||
)
|
||||
|
||||
func TestToMacaronPath(t *testing.T) {
|
||||
@@ -25,3 +37,124 @@ func TestToMacaronPath(t *testing.T) {
|
||||
assert.Equal(t, tc.expectedOutputPath, outputPath)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAlertingProxy_createProxyContext(t *testing.T) {
|
||||
ctx := &models.ReqContext{
|
||||
Context: &web.Context{
|
||||
Router: web.NewRouter(),
|
||||
Req: &http.Request{},
|
||||
},
|
||||
SignedInUser: &user.SignedInUser{},
|
||||
UserToken: &models.UserToken{},
|
||||
IsSignedIn: rand.Int63()%2 == 1,
|
||||
IsRenderCall: rand.Int63()%2 == 1,
|
||||
AllowAnonymous: rand.Int63()%2 == 1,
|
||||
SkipCache: rand.Int63()%2 == 1,
|
||||
Logger: log.New("test"),
|
||||
RequestNonce: util.GenerateShortUID(),
|
||||
IsPublicDashboardView: rand.Int63()%2 == 1,
|
||||
}
|
||||
|
||||
t.Run("should create a copy of request context", func(t *testing.T) {
|
||||
for _, mock := range []*accesscontrolmock.Mock{
|
||||
accesscontrolmock.New(), accesscontrolmock.New().WithDisabled(),
|
||||
} {
|
||||
proxy := AlertingProxy{
|
||||
DataProxy: nil,
|
||||
ac: mock,
|
||||
}
|
||||
|
||||
req := &http.Request{}
|
||||
resp := &response.NormalResponse{}
|
||||
|
||||
newCtx := proxy.createProxyContext(ctx, req, resp)
|
||||
|
||||
require.NotEqual(t, ctx, newCtx)
|
||||
require.Equal(t, ctx.UserToken, newCtx.UserToken)
|
||||
require.Equal(t, ctx.IsSignedIn, newCtx.IsSignedIn)
|
||||
require.Equal(t, ctx.IsRenderCall, newCtx.IsRenderCall)
|
||||
require.Equal(t, ctx.AllowAnonymous, newCtx.AllowAnonymous)
|
||||
require.Equal(t, ctx.SkipCache, newCtx.SkipCache)
|
||||
require.Equal(t, ctx.Logger, newCtx.Logger)
|
||||
require.Equal(t, ctx.RequestNonce, newCtx.RequestNonce)
|
||||
require.Equal(t, ctx.IsPublicDashboardView, newCtx.IsPublicDashboardView)
|
||||
}
|
||||
})
|
||||
t.Run("should overwrite response writer", func(t *testing.T) {
|
||||
proxy := AlertingProxy{
|
||||
DataProxy: nil,
|
||||
ac: accesscontrolmock.New(),
|
||||
}
|
||||
|
||||
req := &http.Request{}
|
||||
resp := &response.NormalResponse{}
|
||||
|
||||
newCtx := proxy.createProxyContext(ctx, req, resp)
|
||||
|
||||
require.NotEqual(t, ctx.Context.Resp, newCtx.Context.Resp)
|
||||
require.Equal(t, ctx.Context.Router, newCtx.Context.Router)
|
||||
require.Equal(t, ctx.Context.Req, newCtx.Context.Req)
|
||||
|
||||
require.NotEqual(t, 123, resp.Status())
|
||||
newCtx.Context.Resp.WriteHeader(123)
|
||||
require.Equal(t, 123, resp.Status())
|
||||
})
|
||||
t.Run("if access control is enabled", func(t *testing.T) {
|
||||
t.Run("should elevate permissions to Editor for Viewer", func(t *testing.T) {
|
||||
proxy := AlertingProxy{
|
||||
DataProxy: nil,
|
||||
ac: accesscontrolmock.New(),
|
||||
}
|
||||
|
||||
req := &http.Request{}
|
||||
resp := &response.NormalResponse{}
|
||||
|
||||
viewerCtx := *ctx
|
||||
viewerCtx.SignedInUser = &user.SignedInUser{
|
||||
OrgRole: org.RoleViewer,
|
||||
}
|
||||
|
||||
newCtx := proxy.createProxyContext(&viewerCtx, req, resp)
|
||||
require.NotEqual(t, viewerCtx.SignedInUser, newCtx.SignedInUser)
|
||||
require.Truef(t, newCtx.SignedInUser.HasRole(org.RoleEditor), "user of the proxy request should have at least Editor role but has %s", newCtx.SignedInUser.OrgRole)
|
||||
})
|
||||
t.Run("should not alter user if it is Editor", func(t *testing.T) {
|
||||
proxy := AlertingProxy{
|
||||
DataProxy: nil,
|
||||
ac: accesscontrolmock.New(),
|
||||
}
|
||||
|
||||
req := &http.Request{}
|
||||
resp := &response.NormalResponse{}
|
||||
|
||||
for _, roleType := range []org.RoleType{org.RoleEditor, org.RoleAdmin} {
|
||||
roleCtx := *ctx
|
||||
roleCtx.SignedInUser = &user.SignedInUser{
|
||||
OrgRole: roleType,
|
||||
}
|
||||
newCtx := proxy.createProxyContext(&roleCtx, req, resp)
|
||||
require.Equalf(t, roleCtx.SignedInUser, newCtx.SignedInUser, "user should not be altered if role is %s", roleType)
|
||||
}
|
||||
})
|
||||
})
|
||||
t.Run("if access control is disabled", func(t *testing.T) {
|
||||
t.Run("should not alter user", func(t *testing.T) {
|
||||
proxy := AlertingProxy{
|
||||
DataProxy: nil,
|
||||
ac: accesscontrolmock.New().WithDisabled(),
|
||||
}
|
||||
|
||||
req := &http.Request{}
|
||||
resp := &response.NormalResponse{}
|
||||
|
||||
for _, roleType := range []org.RoleType{org.RoleViewer, org.RoleEditor, org.RoleAdmin} {
|
||||
roleCtx := *ctx
|
||||
roleCtx.SignedInUser = &user.SignedInUser{
|
||||
OrgRole: roleType,
|
||||
}
|
||||
newCtx := proxy.createProxyContext(&roleCtx, req, resp)
|
||||
require.Equalf(t, roleCtx.SignedInUser, newCtx.SignedInUser, "user should not be altered if access control is disabled and role is %s", roleType)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user