mirror of
https://github.com/grafana/grafana.git
synced 2024-11-30 04:34:23 -06:00
7a38090bc0
* AuthN: remove IsAnonymous from identity struct and set correct namespace for anonymous and render * Don't parse user id for render namespace
171 lines
5.6 KiB
Go
171 lines
5.6 KiB
Go
package middleware
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"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/setting"
|
|
"github.com/grafana/grafana/pkg/web"
|
|
)
|
|
|
|
func setupAuthMiddlewareTest(t *testing.T, identity *authn.Identity, authErr error) *contexthandler.ContextHandler {
|
|
return contexthandler.ProvideService(setting.NewCfg(), tracing.InitializeTracerForTest(), featuremgmt.WithFeatures(), &authntest.FakeService{
|
|
ExpectedErr: authErr,
|
|
ExpectedIdentity: identity,
|
|
})
|
|
}
|
|
|
|
func TestAuth_Middleware(t *testing.T) {
|
|
type testCase struct {
|
|
desc string
|
|
identity *authn.Identity
|
|
path string
|
|
authErr error
|
|
authMiddleware web.Handler
|
|
expecedReached bool
|
|
expectedCode int
|
|
}
|
|
|
|
tests := []testCase{
|
|
{
|
|
desc: "ReqSignedIn should redirect unauthenticated request to secure endpoint",
|
|
path: "/secure",
|
|
authMiddleware: ReqSignedIn,
|
|
authErr: errors.New("no auth"),
|
|
expectedCode: http.StatusFound,
|
|
},
|
|
{
|
|
desc: "ReqSignedIn should return 401 for api endpint",
|
|
path: "/api/secure",
|
|
authMiddleware: ReqSignedIn,
|
|
authErr: errors.New("no auth"),
|
|
expectedCode: http.StatusUnauthorized,
|
|
},
|
|
{
|
|
desc: "ReqSignedIn should return 200 for anonymous user",
|
|
path: "/api/secure",
|
|
authMiddleware: ReqSignedIn,
|
|
identity: &authn.Identity{ID: authn.AnonymousNamespaceID},
|
|
expecedReached: true,
|
|
expectedCode: http.StatusOK,
|
|
},
|
|
{
|
|
desc: "ReqSignedIn should return redirect anonymous user with forceLogin query string",
|
|
path: "/secure?forceLogin=true",
|
|
authMiddleware: ReqSignedIn,
|
|
identity: &authn.Identity{ID: authn.AnonymousNamespaceID},
|
|
expecedReached: false,
|
|
expectedCode: http.StatusFound,
|
|
},
|
|
{
|
|
desc: "ReqSignedIn should return redirect anonymous user when orgId in query string is different from currently used",
|
|
path: "/secure?orgId=2",
|
|
authMiddleware: ReqSignedIn,
|
|
identity: &authn.Identity{ID: authn.AnonymousNamespaceID, OrgID: 1},
|
|
expecedReached: false,
|
|
expectedCode: http.StatusFound,
|
|
},
|
|
{
|
|
desc: "ReqSignedInNoAnonymous should return 401 for anonymous user",
|
|
path: "/api/secure",
|
|
authMiddleware: ReqSignedInNoAnonymous,
|
|
identity: &authn.Identity{ID: authn.AnonymousNamespaceID},
|
|
expecedReached: false,
|
|
expectedCode: http.StatusUnauthorized,
|
|
},
|
|
{
|
|
desc: "ReqSignedInNoAnonymous should return 200 for authenticated user",
|
|
path: "/api/secure",
|
|
authMiddleware: ReqSignedInNoAnonymous,
|
|
identity: &authn.Identity{ID: "user:1"},
|
|
expecedReached: true,
|
|
expectedCode: http.StatusOK,
|
|
},
|
|
{
|
|
desc: "snapshot public mode disabled should return 200 for authenticated user",
|
|
path: "/api/secure",
|
|
authMiddleware: SnapshotPublicModeOrSignedIn(&setting.Cfg{SnapshotPublicMode: false}),
|
|
identity: &authn.Identity{ID: "user:1"},
|
|
expecedReached: true,
|
|
expectedCode: http.StatusOK,
|
|
},
|
|
{
|
|
desc: "snapshot public mode disabled should return 401 for unauthenticated request",
|
|
path: "/api/secure",
|
|
authMiddleware: SnapshotPublicModeOrSignedIn(&setting.Cfg{SnapshotPublicMode: false}),
|
|
authErr: errors.New("no auth"),
|
|
expecedReached: false,
|
|
expectedCode: http.StatusUnauthorized,
|
|
},
|
|
{
|
|
desc: "snapshot public mode enabled should return 200 for unauthenticated request",
|
|
path: "/api/secure",
|
|
authMiddleware: SnapshotPublicModeOrSignedIn(&setting.Cfg{SnapshotPublicMode: true}),
|
|
authErr: errors.New("no auth"),
|
|
expecedReached: true,
|
|
expectedCode: http.StatusOK,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.desc, func(t *testing.T) {
|
|
ctxHandler := setupAuthMiddlewareTest(t, tt.identity, tt.authErr)
|
|
|
|
server := web.New()
|
|
server.Use(ctxHandler.Middleware)
|
|
server.Use(tt.authMiddleware)
|
|
|
|
var reached bool
|
|
server.Get("/secure", func(c *contextmodel.ReqContext) {
|
|
reached = true
|
|
c.Resp.WriteHeader(http.StatusOK)
|
|
})
|
|
server.Get("/api/secure", func(c *contextmodel.ReqContext) {
|
|
reached = true
|
|
c.Resp.WriteHeader(http.StatusOK)
|
|
})
|
|
|
|
req, err := http.NewRequest(http.MethodGet, tt.path, nil)
|
|
require.NoError(t, err)
|
|
recorder := httptest.NewRecorder()
|
|
server.ServeHTTP(recorder, req)
|
|
|
|
res := recorder.Result()
|
|
assert.Equal(t, tt.expecedReached, reached)
|
|
assert.Equal(t, tt.expectedCode, res.StatusCode)
|
|
require.NoError(t, res.Body.Close())
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRemoveForceLoginparams(t *testing.T) {
|
|
tcs := []struct {
|
|
inp string
|
|
exp string
|
|
}{
|
|
{inp: "/?forceLogin=true", exp: "/?"},
|
|
{inp: "/d/dash/dash-title?ordId=1&forceLogin=true", exp: "/d/dash/dash-title?ordId=1"},
|
|
{inp: "/?kiosk&forceLogin=true", exp: "/?kiosk"},
|
|
{inp: "/d/dash/dash-title?ordId=1&kiosk&forceLogin=true", exp: "/d/dash/dash-title?ordId=1&kiosk"},
|
|
{inp: "/d/dash/dash-title?ordId=1&forceLogin=true&kiosk", exp: "/d/dash/dash-title?ordId=1&kiosk"},
|
|
{inp: "/d/dash/dash-title?forceLogin=true&kiosk", exp: "/d/dash/dash-title?&kiosk"},
|
|
}
|
|
for i, tc := range tcs {
|
|
t.Run(fmt.Sprintf("testcase %d", i), func(t *testing.T) {
|
|
require.Equal(t, tc.exp, removeForceLoginParams(tc.inp))
|
|
})
|
|
}
|
|
}
|