mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Chore: use remote cache instead of session storage (#16114)
Replaces session storage in auth_proxy middleware with remote cache Fixes #15161
This commit is contained in:
parent
645a6e5856
commit
67cbc7d4cf
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Any ldif files added to the prepopulate subdirectory will be automatically imported into the OpenLdap database.
|
Any ldif files added to the prepopulate subdirectory will be automatically imported into the OpenLdap database.
|
||||||
|
|
||||||
The ldif files add three users, `ldapviewer`, `ldapeditor` and `ldapadmin`. Two groups, `admins` and `users`, are added that correspond with the group mappings in the default conf/ldap.toml. `ldapadmin` is a member of `admins` and `ldapeditor` is a member of `users`.
|
The ldif files add eight users, `ldap-admin`, `ldap-editor`, `ldap-viewer`, `ldap-carl`, `ldap-daniel`, `ldap-leo`, `ldap-tobias` and `ldap-torkel`. Two groups, `admins` and `users`, are added that correspond with the group mappings in the default conf/ldap.toml. `ldap-admin` is a member of `admins` and `ldap-editor` is a member of `users`.
|
||||||
|
|
||||||
Note that users that are added here need to specify a `memberOf` attribute manually as well as the `member` attribute for the group. The `memberOf` module usually does this automatically (if you add a group in Apache Directory Studio for example) but this does not work in the entrypoint script as it uses the `slapadd` command to add entries before the server has started and before the `memberOf` module is loaded.
|
Note that users that are added here need to specify a `memberOf` attribute manually as well as the `member` attribute for the group. The `memberOf` module usually does this automatically (if you add a group in Apache Directory Studio for example) but this does not work in the entrypoint script as it uses the `slapadd` command to add entries before the server has started and before the `memberOf` module is loaded.
|
||||||
|
|
||||||
|
@ -9,9 +9,8 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/middleware"
|
"github.com/grafana/grafana/pkg/middleware"
|
||||||
m "github.com/grafana/grafana/pkg/models"
|
m "github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/auth"
|
"github.com/grafana/grafana/pkg/services/auth"
|
||||||
"gopkg.in/macaron.v1"
|
|
||||||
|
|
||||||
. "github.com/smartystreets/goconvey/convey"
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
|
"gopkg.in/macaron.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func loggedInUserScenario(desc string, url string, fn scenarioFunc) {
|
func loggedInUserScenario(desc string, url string, fn scenarioFunc) {
|
||||||
@ -124,7 +123,7 @@ func setupScenarioContext(url string) *scenarioContext {
|
|||||||
Delims: macaron.Delims{Left: "[[", Right: "]]"},
|
Delims: macaron.Delims{Left: "[[", Right: "]]"},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
sc.m.Use(middleware.GetContextHandler(nil))
|
sc.m.Use(middleware.GetContextHandler(nil, nil))
|
||||||
|
|
||||||
return sc
|
return sc
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ import (
|
|||||||
httpstatic "github.com/grafana/grafana/pkg/api/static"
|
httpstatic "github.com/grafana/grafana/pkg/api/static"
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/remotecache"
|
||||||
"github.com/grafana/grafana/pkg/log"
|
"github.com/grafana/grafana/pkg/log"
|
||||||
"github.com/grafana/grafana/pkg/middleware"
|
"github.com/grafana/grafana/pkg/middleware"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
@ -26,7 +27,6 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/hooks"
|
"github.com/grafana/grafana/pkg/services/hooks"
|
||||||
"github.com/grafana/grafana/pkg/services/quota"
|
"github.com/grafana/grafana/pkg/services/quota"
|
||||||
"github.com/grafana/grafana/pkg/services/rendering"
|
"github.com/grafana/grafana/pkg/services/rendering"
|
||||||
"github.com/grafana/grafana/pkg/services/session"
|
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
@ -48,15 +48,16 @@ type HTTPServer struct {
|
|||||||
streamManager *live.StreamManager
|
streamManager *live.StreamManager
|
||||||
httpSrv *http.Server
|
httpSrv *http.Server
|
||||||
|
|
||||||
RouteRegister routing.RouteRegister `inject:""`
|
RouteRegister routing.RouteRegister `inject:""`
|
||||||
Bus bus.Bus `inject:""`
|
Bus bus.Bus `inject:""`
|
||||||
RenderService rendering.Service `inject:""`
|
RenderService rendering.Service `inject:""`
|
||||||
Cfg *setting.Cfg `inject:""`
|
Cfg *setting.Cfg `inject:""`
|
||||||
HooksService *hooks.HooksService `inject:""`
|
HooksService *hooks.HooksService `inject:""`
|
||||||
CacheService *cache.CacheService `inject:""`
|
CacheService *cache.CacheService `inject:""`
|
||||||
DatasourceCache datasources.CacheService `inject:""`
|
DatasourceCache datasources.CacheService `inject:""`
|
||||||
AuthTokenService models.UserTokenService `inject:""`
|
AuthTokenService models.UserTokenService `inject:""`
|
||||||
QuotaService *quota.QuotaService `inject:""`
|
QuotaService *quota.QuotaService `inject:""`
|
||||||
|
RemoteCacheService *remotecache.RemoteCache `inject:""`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hs *HTTPServer) Init() error {
|
func (hs *HTTPServer) Init() error {
|
||||||
@ -66,8 +67,6 @@ func (hs *HTTPServer) Init() error {
|
|||||||
hs.macaron = hs.newMacaron()
|
hs.macaron = hs.newMacaron()
|
||||||
hs.registerRoutes()
|
hs.registerRoutes()
|
||||||
|
|
||||||
session.Init(&setting.SessionOptions, setting.SessionConnMaxLifetime)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,7 +225,10 @@ func (hs *HTTPServer) addMiddlewaresAndStaticRoutes() {
|
|||||||
|
|
||||||
m.Use(hs.healthHandler)
|
m.Use(hs.healthHandler)
|
||||||
m.Use(hs.metricsEndpoint)
|
m.Use(hs.metricsEndpoint)
|
||||||
m.Use(middleware.GetContextHandler(hs.AuthTokenService))
|
m.Use(middleware.GetContextHandler(
|
||||||
|
hs.AuthTokenService,
|
||||||
|
hs.RemoteCacheService,
|
||||||
|
))
|
||||||
m.Use(middleware.OrgRedirect())
|
m.Use(middleware.OrgRedirect())
|
||||||
|
|
||||||
// needs to be after context handler
|
// needs to be after context handler
|
||||||
|
@ -7,12 +7,10 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/log"
|
"github.com/grafana/grafana/pkg/log"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/registry"
|
"github.com/grafana/grafana/pkg/registry"
|
||||||
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -5,7 +5,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bmizerany/assert"
|
"github.com/bmizerany/assert"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
)
|
)
|
||||||
|
34
pkg/infra/remotecache/testing.go
Normal file
34
pkg/infra/remotecache/testing.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package remotecache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewFakeStore creates store for testing
|
||||||
|
func NewFakeStore(t *testing.T) *RemoteCache {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
opts := &setting.RemoteCacheOptions{
|
||||||
|
Name: "database",
|
||||||
|
ConnStr: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
SQLStore := sqlstore.InitTestDB(t)
|
||||||
|
|
||||||
|
dc := &RemoteCache{
|
||||||
|
SQLStore: SQLStore,
|
||||||
|
Cfg: &setting.Cfg{
|
||||||
|
RemoteCacheOptions: opts,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := dc.Init()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to init remote cache for test. error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return dc
|
||||||
|
}
|
@ -9,18 +9,19 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
"github.com/grafana/grafana/pkg/log"
|
"github.com/grafana/grafana/pkg/infra/remotecache"
|
||||||
"github.com/grafana/grafana/pkg/login"
|
"github.com/grafana/grafana/pkg/login"
|
||||||
m "github.com/grafana/grafana/pkg/models"
|
m "github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/session"
|
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
const (
|
||||||
AUTH_PROXY_SESSION_VAR = "authProxyHeaderValue"
|
|
||||||
|
// cachePrefix is a prefix for the cache key
|
||||||
|
cachePrefix = "auth-proxy-sync-ttl:%s"
|
||||||
)
|
)
|
||||||
|
|
||||||
func initContextWithAuthProxy(ctx *m.ReqContext, orgID int64) bool {
|
func initContextWithAuthProxy(store *remotecache.RemoteCache, ctx *m.ReqContext, orgID int64) bool {
|
||||||
if !setting.AuthProxyEnabled {
|
if !setting.AuthProxyEnabled {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -36,46 +37,17 @@ func initContextWithAuthProxy(ctx *m.ReqContext, orgID int64) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize session
|
|
||||||
if err := ctx.Session.Start(ctx.Context); err != nil {
|
|
||||||
log.Error(3, "Failed to start session. error %v", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
if err := ctx.Session.Release(); err != nil {
|
|
||||||
ctx.Logger.Error("failed to save session data", "error", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
query := &m.GetSignedInUserQuery{OrgId: orgID}
|
query := &m.GetSignedInUserQuery{OrgId: orgID}
|
||||||
|
cacheKey := fmt.Sprintf(cachePrefix, proxyHeaderValue)
|
||||||
|
userID, err := store.Get(cacheKey)
|
||||||
|
inCache := err == nil
|
||||||
|
|
||||||
// if this session has already been authenticated by authProxy just load the user
|
// load the user if we have them
|
||||||
sessProxyValue := ctx.Session.Get(AUTH_PROXY_SESSION_VAR)
|
if inCache {
|
||||||
if sessProxyValue != nil && sessProxyValue.(string) == proxyHeaderValue && getRequestUserId(ctx) > 0 {
|
query.UserId = userID.(int64)
|
||||||
// if we're using ldap, sync user periodically
|
|
||||||
if setting.LdapEnabled {
|
|
||||||
syncQuery := &m.LoginUserQuery{
|
|
||||||
ReqContext: ctx,
|
|
||||||
Username: proxyHeaderValue,
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := syncGrafanaUserWithLdapUser(syncQuery); err != nil {
|
|
||||||
if err == login.ErrInvalidCredentials {
|
|
||||||
ctx.Handle(500, "Unable to authenticate user", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.Handle(500, "Failed to sync user", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
query.UserId = getRequestUserId(ctx)
|
|
||||||
// if we're using ldap, pass authproxy login name to ldap user sync
|
// if we're using ldap, pass authproxy login name to ldap user sync
|
||||||
} else if setting.LdapEnabled {
|
} else if setting.LdapEnabled {
|
||||||
ctx.Session.Delete(session.SESS_KEY_LASTLDAPSYNC)
|
|
||||||
|
|
||||||
syncQuery := &m.LoginUserQuery{
|
syncQuery := &m.LoginUserQuery{
|
||||||
ReqContext: ctx,
|
ReqContext: ctx,
|
||||||
Username: proxyHeaderValue,
|
Username: proxyHeaderValue,
|
||||||
@ -86,9 +58,6 @@ func initContextWithAuthProxy(ctx *m.ReqContext, orgID int64) bool {
|
|||||||
ctx.Handle(500, "Unable to authenticate user", err)
|
ctx.Handle(500, "Unable to authenticate user", err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Handle(500, "Failed to sync user", err)
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if syncQuery.User == nil {
|
if syncQuery.User == nil {
|
||||||
@ -149,67 +118,40 @@ func initContextWithAuthProxy(ctx *m.ReqContext, orgID int64) bool {
|
|||||||
ctx.Handle(500, "Failed to find user", err)
|
ctx.Handle(500, "Failed to find user", err)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure that we cannot share a session between different users!
|
|
||||||
if getRequestUserId(ctx) > 0 && getRequestUserId(ctx) != query.Result.UserId {
|
|
||||||
// remove session
|
|
||||||
if err := ctx.Session.Destory(ctx.Context); err != nil {
|
|
||||||
log.Error(3, "Failed to destroy session. error: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// initialize a new session
|
|
||||||
if err := ctx.Session.Start(ctx.Context); err != nil {
|
|
||||||
log.Error(3, "Failed to start session. error: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.Session.Set(AUTH_PROXY_SESSION_VAR, proxyHeaderValue)
|
|
||||||
|
|
||||||
ctx.SignedInUser = query.Result
|
ctx.SignedInUser = query.Result
|
||||||
ctx.IsSignedIn = true
|
ctx.IsSignedIn = true
|
||||||
ctx.Session.Set(session.SESS_KEY_USERID, ctx.UserId)
|
|
||||||
|
expiration := time.Duration(-setting.AuthProxyLdapSyncTtl) * time.Minute
|
||||||
|
value := query.UserId
|
||||||
|
|
||||||
|
// This <if> is here to make sure we do not
|
||||||
|
// rewrite the expiration all the time
|
||||||
|
if inCache == false {
|
||||||
|
if err = store.Set(cacheKey, value, expiration); err != nil {
|
||||||
|
ctx.Handle(500, "Couldn't write a user in cache key", err)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
var syncGrafanaUserWithLdapUser = func(query *m.LoginUserQuery) error {
|
var syncGrafanaUserWithLdapUser = func(query *m.LoginUserQuery) error {
|
||||||
expireEpoch := time.Now().Add(time.Duration(-setting.AuthProxyLdapSyncTtl) * time.Minute).Unix()
|
ldapCfg := login.LdapCfg
|
||||||
|
if len(ldapCfg.Servers) < 1 {
|
||||||
var lastLdapSync int64
|
return fmt.Errorf("No LDAP servers available")
|
||||||
if lastLdapSyncInSession := query.ReqContext.Session.Get(session.SESS_KEY_LASTLDAPSYNC); lastLdapSyncInSession != nil {
|
|
||||||
lastLdapSync = lastLdapSyncInSession.(int64)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if lastLdapSync < expireEpoch {
|
for _, server := range ldapCfg.Servers {
|
||||||
ldapCfg := login.LdapCfg
|
author := login.NewLdapAuthenticator(server)
|
||||||
|
if err := author.SyncUser(query); err != nil {
|
||||||
if len(ldapCfg.Servers) < 1 {
|
return err
|
||||||
return fmt.Errorf("No LDAP servers available")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, server := range ldapCfg.Servers {
|
|
||||||
author := login.NewLdapAuthenticator(server)
|
|
||||||
if err := author.SyncUser(query); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
query.ReqContext.Session.Set(session.SESS_KEY_LASTLDAPSYNC, time.Now().Unix())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRequestUserId(c *m.ReqContext) int64 {
|
|
||||||
userID := c.Session.Get(session.SESS_KEY_USERID)
|
|
||||||
|
|
||||||
if userID != nil {
|
|
||||||
return userID.(int64)
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkAuthenticationProxy(remoteAddr string, proxyHeaderValue string) error {
|
func checkAuthenticationProxy(remoteAddr string, proxyHeaderValue string) error {
|
||||||
if len(strings.TrimSpace(setting.AuthProxyWhitelist)) == 0 {
|
if len(strings.TrimSpace(setting.AuthProxyWhitelist)) == 0 {
|
||||||
return nil
|
return nil
|
||||||
|
@ -1,145 +0,0 @@
|
|||||||
package middleware
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/login"
|
|
||||||
m "github.com/grafana/grafana/pkg/models"
|
|
||||||
"github.com/grafana/grafana/pkg/services/session"
|
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
|
||||||
. "github.com/smartystreets/goconvey/convey"
|
|
||||||
"gopkg.in/macaron.v1"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestAuthProxyWithLdapEnabled(t *testing.T) {
|
|
||||||
Convey("When calling sync grafana user with ldap user", t, func() {
|
|
||||||
|
|
||||||
setting.LdapEnabled = true
|
|
||||||
setting.AuthProxyLdapSyncTtl = 60
|
|
||||||
|
|
||||||
servers := []*login.LdapServerConf{{Host: "127.0.0.1"}}
|
|
||||||
login.LdapCfg = login.LdapConfig{Servers: servers}
|
|
||||||
mockLdapAuther := mockLdapAuthenticator{}
|
|
||||||
|
|
||||||
login.NewLdapAuthenticator = func(server *login.LdapServerConf) login.ILdapAuther {
|
|
||||||
return &mockLdapAuther
|
|
||||||
}
|
|
||||||
|
|
||||||
Convey("When user logs in, call SyncUser", func() {
|
|
||||||
// arrange
|
|
||||||
sess := newMockSession()
|
|
||||||
ctx := m.ReqContext{Session: &sess}
|
|
||||||
So(sess.Get(session.SESS_KEY_LASTLDAPSYNC), ShouldBeNil)
|
|
||||||
|
|
||||||
// act
|
|
||||||
syncGrafanaUserWithLdapUser(&m.LoginUserQuery{
|
|
||||||
ReqContext: &ctx,
|
|
||||||
Username: "test",
|
|
||||||
})
|
|
||||||
|
|
||||||
// assert
|
|
||||||
So(mockLdapAuther.syncUserCalled, ShouldBeTrue)
|
|
||||||
So(sess.Get(session.SESS_KEY_LASTLDAPSYNC), ShouldBeGreaterThan, 0)
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("When session variable not expired, don't sync and don't change session var", func() {
|
|
||||||
// arrange
|
|
||||||
sess := newMockSession()
|
|
||||||
ctx := m.ReqContext{Session: &sess}
|
|
||||||
now := time.Now().Unix()
|
|
||||||
sess.Set(session.SESS_KEY_LASTLDAPSYNC, now)
|
|
||||||
sess.Set(AUTH_PROXY_SESSION_VAR, "test")
|
|
||||||
|
|
||||||
// act
|
|
||||||
syncGrafanaUserWithLdapUser(&m.LoginUserQuery{
|
|
||||||
ReqContext: &ctx,
|
|
||||||
Username: "test",
|
|
||||||
})
|
|
||||||
|
|
||||||
// assert
|
|
||||||
So(sess.Get(session.SESS_KEY_LASTLDAPSYNC), ShouldEqual, now)
|
|
||||||
So(mockLdapAuther.syncUserCalled, ShouldBeFalse)
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("When lastldapsync is expired, session variable should be updated", func() {
|
|
||||||
// arrange
|
|
||||||
sess := newMockSession()
|
|
||||||
ctx := m.ReqContext{Session: &sess}
|
|
||||||
expiredTime := time.Now().Add(time.Duration(-120) * time.Minute).Unix()
|
|
||||||
sess.Set(session.SESS_KEY_LASTLDAPSYNC, expiredTime)
|
|
||||||
sess.Set(AUTH_PROXY_SESSION_VAR, "test")
|
|
||||||
|
|
||||||
// act
|
|
||||||
syncGrafanaUserWithLdapUser(&m.LoginUserQuery{
|
|
||||||
ReqContext: &ctx,
|
|
||||||
Username: "test",
|
|
||||||
})
|
|
||||||
|
|
||||||
// assert
|
|
||||||
So(sess.Get(session.SESS_KEY_LASTLDAPSYNC), ShouldBeGreaterThan, expiredTime)
|
|
||||||
So(mockLdapAuther.syncUserCalled, ShouldBeTrue)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
type mockSession struct {
|
|
||||||
value map[interface{}]interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func newMockSession() mockSession {
|
|
||||||
session := mockSession{}
|
|
||||||
session.value = make(map[interface{}]interface{})
|
|
||||||
return session
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *mockSession) Start(c *macaron.Context) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *mockSession) Set(k interface{}, v interface{}) error {
|
|
||||||
s.value[k] = v
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *mockSession) Get(k interface{}) interface{} {
|
|
||||||
return s.value[k]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *mockSession) Delete(k interface{}) interface{} {
|
|
||||||
delete(s.value, k)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *mockSession) ID() string {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *mockSession) Release() error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *mockSession) Destory(c *macaron.Context) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *mockSession) RegenerateId(c *macaron.Context) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type mockLdapAuthenticator struct {
|
|
||||||
syncUserCalled bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *mockLdapAuthenticator) Login(query *m.LoginUserQuery) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *mockLdapAuthenticator) SyncUser(query *m.LoginUserQuery) error {
|
|
||||||
a.syncUserCalled = true
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *mockLdapAuthenticator) GetGrafanaUserFor(ctx *m.ReqContext, ldapUser *login.LdapUserInfo) (*m.User, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
@ -11,7 +11,7 @@ func TestMiddlewareAuth(t *testing.T) {
|
|||||||
Convey("Given the grafana middleware", t, func() {
|
Convey("Given the grafana middleware", t, func() {
|
||||||
reqSignIn := Auth(&AuthOptions{ReqSignedIn: true})
|
reqSignIn := Auth(&AuthOptions{ReqSignedIn: true})
|
||||||
|
|
||||||
middlewareScenario("ReqSignIn true and unauthenticated request", func(sc *scenarioContext) {
|
middlewareScenario(t, "ReqSignIn true and unauthenticated request", func(sc *scenarioContext) {
|
||||||
sc.m.Get("/secure", reqSignIn, sc.defaultHandler)
|
sc.m.Get("/secure", reqSignIn, sc.defaultHandler)
|
||||||
|
|
||||||
sc.fakeReq("GET", "/secure").exec()
|
sc.fakeReq("GET", "/secure").exec()
|
||||||
@ -21,7 +21,7 @@ func TestMiddlewareAuth(t *testing.T) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
middlewareScenario("ReqSignIn true and unauthenticated API request", func(sc *scenarioContext) {
|
middlewareScenario(t, "ReqSignIn true and unauthenticated API request", func(sc *scenarioContext) {
|
||||||
sc.m.Get("/api/secure", reqSignIn, sc.defaultHandler)
|
sc.m.Get("/api/secure", reqSignIn, sc.defaultHandler)
|
||||||
|
|
||||||
sc.fakeReq("GET", "/api/secure").exec()
|
sc.fakeReq("GET", "/api/secure").exec()
|
||||||
|
@ -27,7 +27,7 @@ func TestMiddlewareDashboardRedirect(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
middlewareScenario("GET dashboard by legacy url", func(sc *scenarioContext) {
|
middlewareScenario(t, "GET dashboard by legacy url", func(sc *scenarioContext) {
|
||||||
sc.m.Get("/dashboard/db/:slug", redirectFromLegacyDashboardUrl, sc.defaultHandler)
|
sc.m.Get("/dashboard/db/:slug", redirectFromLegacyDashboardUrl, sc.defaultHandler)
|
||||||
|
|
||||||
sc.fakeReqWithParams("GET", "/dashboard/db/dash?orgId=1&panelId=2", map[string]string{}).exec()
|
sc.fakeReqWithParams("GET", "/dashboard/db/dash?orgId=1&panelId=2", map[string]string{}).exec()
|
||||||
@ -40,7 +40,7 @@ func TestMiddlewareDashboardRedirect(t *testing.T) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
middlewareScenario("GET dashboard solo by legacy url", func(sc *scenarioContext) {
|
middlewareScenario(t, "GET dashboard solo by legacy url", func(sc *scenarioContext) {
|
||||||
sc.m.Get("/dashboard-solo/db/:slug", redirectFromLegacyDashboardSoloUrl, sc.defaultHandler)
|
sc.m.Get("/dashboard-solo/db/:slug", redirectFromLegacyDashboardSoloUrl, sc.defaultHandler)
|
||||||
|
|
||||||
sc.fakeReqWithParams("GET", "/dashboard-solo/db/dash?orgId=1&panelId=2", map[string]string{}).exec()
|
sc.fakeReqWithParams("GET", "/dashboard-solo/db/dash?orgId=1&panelId=2", map[string]string{}).exec()
|
||||||
|
@ -8,9 +8,9 @@ import (
|
|||||||
|
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
"github.com/grafana/grafana/pkg/components/apikeygen"
|
"github.com/grafana/grafana/pkg/components/apikeygen"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/remotecache"
|
||||||
"github.com/grafana/grafana/pkg/log"
|
"github.com/grafana/grafana/pkg/log"
|
||||||
m "github.com/grafana/grafana/pkg/models"
|
m "github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/session"
|
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"github.com/grafana/grafana/pkg/util"
|
"github.com/grafana/grafana/pkg/util"
|
||||||
macaron "gopkg.in/macaron.v1"
|
macaron "gopkg.in/macaron.v1"
|
||||||
@ -23,12 +23,11 @@ var (
|
|||||||
ReqOrgAdmin = RoleAuth(m.ROLE_ADMIN)
|
ReqOrgAdmin = RoleAuth(m.ROLE_ADMIN)
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetContextHandler(ats m.UserTokenService) macaron.Handler {
|
func GetContextHandler(ats m.UserTokenService, remoteCache *remotecache.RemoteCache) macaron.Handler {
|
||||||
return func(c *macaron.Context) {
|
return func(c *macaron.Context) {
|
||||||
ctx := &m.ReqContext{
|
ctx := &m.ReqContext{
|
||||||
Context: c,
|
Context: c,
|
||||||
SignedInUser: &m.SignedInUser{},
|
SignedInUser: &m.SignedInUser{},
|
||||||
Session: session.GetSession(), // should only be used by auth_proxy
|
|
||||||
IsSignedIn: false,
|
IsSignedIn: false,
|
||||||
AllowAnonymous: false,
|
AllowAnonymous: false,
|
||||||
SkipCache: false,
|
SkipCache: false,
|
||||||
@ -50,7 +49,7 @@ func GetContextHandler(ats m.UserTokenService) macaron.Handler {
|
|||||||
case initContextWithRenderAuth(ctx):
|
case initContextWithRenderAuth(ctx):
|
||||||
case initContextWithApiKey(ctx):
|
case initContextWithApiKey(ctx):
|
||||||
case initContextWithBasicAuth(ctx, orgId):
|
case initContextWithBasicAuth(ctx, orgId):
|
||||||
case initContextWithAuthProxy(ctx, orgId):
|
case initContextWithAuthProxy(remoteCache, ctx, orgId):
|
||||||
case initContextWithToken(ats, ctx, orgId):
|
case initContextWithToken(ats, ctx, orgId):
|
||||||
case initContextWithAnonymousUser(ctx):
|
case initContextWithAnonymousUser(ctx):
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package middleware
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -10,6 +11,7 @@ import (
|
|||||||
|
|
||||||
msession "github.com/go-macaron/session"
|
msession "github.com/go-macaron/session"
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/remotecache"
|
||||||
m "github.com/grafana/grafana/pkg/models"
|
m "github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/auth"
|
"github.com/grafana/grafana/pkg/services/auth"
|
||||||
"github.com/grafana/grafana/pkg/services/session"
|
"github.com/grafana/grafana/pkg/services/session"
|
||||||
@ -23,29 +25,29 @@ func TestMiddlewareContext(t *testing.T) {
|
|||||||
setting.ERR_TEMPLATE_NAME = "error-template"
|
setting.ERR_TEMPLATE_NAME = "error-template"
|
||||||
|
|
||||||
Convey("Given the grafana middleware", t, func() {
|
Convey("Given the grafana middleware", t, func() {
|
||||||
middlewareScenario("middleware should add context to injector", func(sc *scenarioContext) {
|
middlewareScenario(t, "middleware should add context to injector", func(sc *scenarioContext) {
|
||||||
sc.fakeReq("GET", "/").exec()
|
sc.fakeReq("GET", "/").exec()
|
||||||
So(sc.context, ShouldNotBeNil)
|
So(sc.context, ShouldNotBeNil)
|
||||||
})
|
})
|
||||||
|
|
||||||
middlewareScenario("Default middleware should allow get request", func(sc *scenarioContext) {
|
middlewareScenario(t, "Default middleware should allow get request", func(sc *scenarioContext) {
|
||||||
sc.fakeReq("GET", "/").exec()
|
sc.fakeReq("GET", "/").exec()
|
||||||
So(sc.resp.Code, ShouldEqual, 200)
|
So(sc.resp.Code, ShouldEqual, 200)
|
||||||
})
|
})
|
||||||
|
|
||||||
middlewareScenario("middleware should add Cache-Control header for GET requests to API", func(sc *scenarioContext) {
|
middlewareScenario(t, "middleware should add Cache-Control header for GET requests to API", func(sc *scenarioContext) {
|
||||||
sc.fakeReq("GET", "/api/search").exec()
|
sc.fakeReq("GET", "/api/search").exec()
|
||||||
So(sc.resp.Header().Get("Cache-Control"), ShouldEqual, "no-cache")
|
So(sc.resp.Header().Get("Cache-Control"), ShouldEqual, "no-cache")
|
||||||
So(sc.resp.Header().Get("Pragma"), ShouldEqual, "no-cache")
|
So(sc.resp.Header().Get("Pragma"), ShouldEqual, "no-cache")
|
||||||
So(sc.resp.Header().Get("Expires"), ShouldEqual, "-1")
|
So(sc.resp.Header().Get("Expires"), ShouldEqual, "-1")
|
||||||
})
|
})
|
||||||
|
|
||||||
middlewareScenario("middleware should not add Cache-Control header to for non-API GET requests", func(sc *scenarioContext) {
|
middlewareScenario(t, "middleware should not add Cache-Control header to for non-API GET requests", func(sc *scenarioContext) {
|
||||||
sc.fakeReq("GET", "/").exec()
|
sc.fakeReq("GET", "/").exec()
|
||||||
So(sc.resp.Header().Get("Cache-Control"), ShouldBeEmpty)
|
So(sc.resp.Header().Get("Cache-Control"), ShouldBeEmpty)
|
||||||
})
|
})
|
||||||
|
|
||||||
middlewareScenario("Invalid api key", func(sc *scenarioContext) {
|
middlewareScenario(t, "Invalid api key", func(sc *scenarioContext) {
|
||||||
sc.apiKey = "invalid_key_test"
|
sc.apiKey = "invalid_key_test"
|
||||||
sc.fakeReq("GET", "/").exec()
|
sc.fakeReq("GET", "/").exec()
|
||||||
|
|
||||||
@ -59,7 +61,7 @@ func TestMiddlewareContext(t *testing.T) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
middlewareScenario("Using basic auth", func(sc *scenarioContext) {
|
middlewareScenario(t, "Using basic auth", func(sc *scenarioContext) {
|
||||||
|
|
||||||
bus.AddHandler("test", func(query *m.GetUserByLoginQuery) error {
|
bus.AddHandler("test", func(query *m.GetUserByLoginQuery) error {
|
||||||
query.Result = &m.User{
|
query.Result = &m.User{
|
||||||
@ -89,7 +91,7 @@ func TestMiddlewareContext(t *testing.T) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
middlewareScenario("Valid api key", func(sc *scenarioContext) {
|
middlewareScenario(t, "Valid api key", func(sc *scenarioContext) {
|
||||||
keyhash := util.EncodePassword("v5nAwpMafFP6znaS4urhdWDLS5511M42", "asd")
|
keyhash := util.EncodePassword("v5nAwpMafFP6znaS4urhdWDLS5511M42", "asd")
|
||||||
|
|
||||||
bus.AddHandler("test", func(query *m.GetApiKeyByNameQuery) error {
|
bus.AddHandler("test", func(query *m.GetApiKeyByNameQuery) error {
|
||||||
@ -110,7 +112,7 @@ func TestMiddlewareContext(t *testing.T) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
middlewareScenario("Valid api key, but does not match db hash", func(sc *scenarioContext) {
|
middlewareScenario(t, "Valid api key, but does not match db hash", func(sc *scenarioContext) {
|
||||||
keyhash := "something_not_matching"
|
keyhash := "something_not_matching"
|
||||||
|
|
||||||
bus.AddHandler("test", func(query *m.GetApiKeyByNameQuery) error {
|
bus.AddHandler("test", func(query *m.GetApiKeyByNameQuery) error {
|
||||||
@ -126,7 +128,7 @@ func TestMiddlewareContext(t *testing.T) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
middlewareScenario("Valid api key via Basic auth", func(sc *scenarioContext) {
|
middlewareScenario(t, "Valid api key via Basic auth", func(sc *scenarioContext) {
|
||||||
keyhash := util.EncodePassword("v5nAwpMafFP6znaS4urhdWDLS5511M42", "asd")
|
keyhash := util.EncodePassword("v5nAwpMafFP6znaS4urhdWDLS5511M42", "asd")
|
||||||
|
|
||||||
bus.AddHandler("test", func(query *m.GetApiKeyByNameQuery) error {
|
bus.AddHandler("test", func(query *m.GetApiKeyByNameQuery) error {
|
||||||
@ -148,7 +150,7 @@ func TestMiddlewareContext(t *testing.T) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
middlewareScenario("Non-expired auth token in cookie which not are being rotated", func(sc *scenarioContext) {
|
middlewareScenario(t, "Non-expired auth token in cookie which not are being rotated", func(sc *scenarioContext) {
|
||||||
sc.withTokenSessionCookie("token")
|
sc.withTokenSessionCookie("token")
|
||||||
|
|
||||||
bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
|
bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
|
||||||
@ -177,7 +179,7 @@ func TestMiddlewareContext(t *testing.T) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
middlewareScenario("Non-expired auth token in cookie which are being rotated", func(sc *scenarioContext) {
|
middlewareScenario(t, "Non-expired auth token in cookie which are being rotated", func(sc *scenarioContext) {
|
||||||
sc.withTokenSessionCookie("token")
|
sc.withTokenSessionCookie("token")
|
||||||
|
|
||||||
bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
|
bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
|
||||||
@ -224,7 +226,7 @@ func TestMiddlewareContext(t *testing.T) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
middlewareScenario("Invalid/expired auth token in cookie", func(sc *scenarioContext) {
|
middlewareScenario(t, "Invalid/expired auth token in cookie", func(sc *scenarioContext) {
|
||||||
sc.withTokenSessionCookie("token")
|
sc.withTokenSessionCookie("token")
|
||||||
|
|
||||||
sc.userAuthTokenService.LookupTokenProvider = func(unhashedToken string) (*m.UserToken, error) {
|
sc.userAuthTokenService.LookupTokenProvider = func(unhashedToken string) (*m.UserToken, error) {
|
||||||
@ -240,7 +242,7 @@ func TestMiddlewareContext(t *testing.T) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
middlewareScenario("When anonymous access is enabled", func(sc *scenarioContext) {
|
middlewareScenario(t, "When anonymous access is enabled", func(sc *scenarioContext) {
|
||||||
setting.AnonymousEnabled = true
|
setting.AnonymousEnabled = true
|
||||||
setting.AnonymousOrgName = "test"
|
setting.AnonymousOrgName = "test"
|
||||||
setting.AnonymousOrgRole = string(m.ROLE_EDITOR)
|
setting.AnonymousOrgRole = string(m.ROLE_EDITOR)
|
||||||
@ -265,287 +267,192 @@ func TestMiddlewareContext(t *testing.T) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
middlewareScenario("When auth_proxy is enabled enabled and user exists", func(sc *scenarioContext) {
|
Convey("auth_proxy", func() {
|
||||||
setting.AuthProxyEnabled = true
|
setting.AuthProxyEnabled = true
|
||||||
setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
|
setting.AuthProxyWhitelist = ""
|
||||||
setting.AuthProxyHeaderProperty = "username"
|
|
||||||
setting.LdapEnabled = false
|
|
||||||
|
|
||||||
bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
|
|
||||||
query.Result = &m.SignedInUser{OrgId: 2, UserId: 12}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
bus.AddHandler("test", func(cmd *m.UpsertUserCommand) error {
|
|
||||||
cmd.Result = &m.User{Id: 12}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
setting.SessionOptions = msession.Options{}
|
|
||||||
sc.fakeReq("GET", "/")
|
|
||||||
sc.req.Header.Add("X-WEBAUTH-USER", "torkelo")
|
|
||||||
sc.exec()
|
|
||||||
|
|
||||||
Convey("should init context with user info", func() {
|
|
||||||
So(sc.context.IsSignedIn, ShouldBeTrue)
|
|
||||||
So(sc.context.UserId, ShouldEqual, 12)
|
|
||||||
So(sc.context.OrgId, ShouldEqual, 2)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
middlewareScenario("When auth_proxy is enabled enabled and user does not exists", func(sc *scenarioContext) {
|
|
||||||
setting.AuthProxyEnabled = true
|
|
||||||
setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
|
|
||||||
setting.AuthProxyHeaderProperty = "username"
|
|
||||||
setting.AuthProxyAutoSignUp = true
|
setting.AuthProxyAutoSignUp = true
|
||||||
setting.LdapEnabled = false
|
setting.LdapEnabled = true
|
||||||
|
setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
|
||||||
|
setting.AuthProxyHeaderProperty = "username"
|
||||||
|
name := "markelog"
|
||||||
|
|
||||||
bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
|
middlewareScenario(t, "should sync the user if it's not in the cache", func(sc *scenarioContext) {
|
||||||
if query.UserId > 0 {
|
called := false
|
||||||
query.Result = &m.SignedInUser{OrgId: 4, UserId: 33}
|
syncGrafanaUserWithLdapUser = func(query *m.LoginUserQuery) error {
|
||||||
|
called = true
|
||||||
|
query.User = &m.User{Id: 32}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return m.ErrUserNotFound
|
|
||||||
|
bus.AddHandler("test", func(query *m.UpsertUserCommand) error {
|
||||||
|
query.Result = &m.User{Id: 32}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
|
||||||
|
query.Result = &m.SignedInUser{OrgId: 4, UserId: 32}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
sc.fakeReq("GET", "/")
|
||||||
|
|
||||||
|
sc.req.Header.Add(setting.AuthProxyHeaderName, name)
|
||||||
|
sc.exec()
|
||||||
|
|
||||||
|
Convey("Should init user via ldap", func() {
|
||||||
|
So(called, ShouldBeTrue)
|
||||||
|
So(sc.context.IsSignedIn, ShouldBeTrue)
|
||||||
|
So(sc.context.UserId, ShouldEqual, 32)
|
||||||
|
So(sc.context.OrgId, ShouldEqual, 4)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
bus.AddHandler("test", func(cmd *m.UpsertUserCommand) error {
|
middlewareScenario(t, "should not sync the user if it's in the cache", func(sc *scenarioContext) {
|
||||||
cmd.Result = &m.User{Id: 33}
|
called := false
|
||||||
return nil
|
syncGrafanaUserWithLdapUser = func(query *m.LoginUserQuery) error {
|
||||||
|
called = true
|
||||||
|
query.User = &m.User{Id: 32}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
bus.AddHandler("test", func(query *m.UpsertUserCommand) error {
|
||||||
|
query.Result = &m.User{Id: 32}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
|
||||||
|
query.Result = &m.SignedInUser{OrgId: 4, UserId: 32}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
key := fmt.Sprintf(cachePrefix, name)
|
||||||
|
sc.remoteCacheService.Set(key, int64(33), 0)
|
||||||
|
sc.fakeReq("GET", "/")
|
||||||
|
|
||||||
|
sc.req.Header.Add(setting.AuthProxyHeaderName, name)
|
||||||
|
sc.exec()
|
||||||
|
|
||||||
|
cacheValue, cacheErr := sc.remoteCacheService.Get(key)
|
||||||
|
|
||||||
|
Convey("Should init user via cache", func() {
|
||||||
|
So(called, ShouldBeFalse)
|
||||||
|
|
||||||
|
So(sc.context.IsSignedIn, ShouldBeTrue)
|
||||||
|
So(sc.context.UserId, ShouldEqual, 32)
|
||||||
|
So(sc.context.OrgId, ShouldEqual, 4)
|
||||||
|
|
||||||
|
So(cacheValue, ShouldEqual, 33)
|
||||||
|
So(cacheErr, ShouldBeNil)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
sc.fakeReq("GET", "/")
|
middlewareScenario(t, "should create an user from a header", func(sc *scenarioContext) {
|
||||||
sc.req.Header.Add("X-WEBAUTH-USER", "torkelo")
|
setting.LdapEnabled = false
|
||||||
sc.exec()
|
setting.AuthProxyAutoSignUp = true
|
||||||
|
|
||||||
Convey("Should create user if auto sign up is enabled", func() {
|
bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
|
||||||
So(sc.context.IsSignedIn, ShouldBeTrue)
|
if query.UserId > 0 {
|
||||||
So(sc.context.UserId, ShouldEqual, 33)
|
query.Result = &m.SignedInUser{OrgId: 4, UserId: 33}
|
||||||
So(sc.context.OrgId, ShouldEqual, 4)
|
return nil
|
||||||
|
}
|
||||||
|
return m.ErrUserNotFound
|
||||||
|
})
|
||||||
|
|
||||||
})
|
bus.AddHandler("test", func(cmd *m.UpsertUserCommand) error {
|
||||||
})
|
cmd.Result = &m.User{Id: 33}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
middlewareScenario("When auth_proxy is enabled and IPv4 request RemoteAddr is not trusted", func(sc *scenarioContext) {
|
sc.fakeReq("GET", "/")
|
||||||
setting.AuthProxyEnabled = true
|
sc.req.Header.Add(setting.AuthProxyHeaderName, name)
|
||||||
setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
|
sc.exec()
|
||||||
setting.AuthProxyHeaderProperty = "username"
|
|
||||||
setting.AuthProxyWhitelist = "192.168.1.1, 2001::23"
|
|
||||||
|
|
||||||
sc.fakeReq("GET", "/")
|
Convey("Should create user from header info", func() {
|
||||||
sc.req.Header.Add("X-WEBAUTH-USER", "torkelo")
|
So(sc.context.IsSignedIn, ShouldBeTrue)
|
||||||
sc.req.RemoteAddr = "192.168.3.1:12345"
|
So(sc.context.UserId, ShouldEqual, 33)
|
||||||
sc.exec()
|
So(sc.context.OrgId, ShouldEqual, 4)
|
||||||
|
})
|
||||||
Convey("should return 407 status code", func() {
|
|
||||||
So(sc.resp.Code, ShouldEqual, 407)
|
|
||||||
So(sc.resp.Body.String(), ShouldContainSubstring, "Request for user (torkelo) from 192.168.3.1 is not from the authentication proxy")
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
middlewareScenario("When auth_proxy is enabled and IPv4 request RemoteAddr is not within trusted CIDR block", func(sc *scenarioContext) {
|
|
||||||
setting.AuthProxyEnabled = true
|
|
||||||
setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
|
|
||||||
setting.AuthProxyHeaderProperty = "username"
|
|
||||||
setting.AuthProxyWhitelist = "192.168.1.0/24, 2001::0/120"
|
|
||||||
|
|
||||||
sc.fakeReq("GET", "/")
|
|
||||||
sc.req.Header.Add("X-WEBAUTH-USER", "torkelo")
|
|
||||||
sc.req.RemoteAddr = "192.168.3.1:12345"
|
|
||||||
sc.exec()
|
|
||||||
|
|
||||||
Convey("should return 407 status code", func() {
|
|
||||||
So(sc.resp.Code, ShouldEqual, 407)
|
|
||||||
So(sc.resp.Body.String(), ShouldContainSubstring, "Request for user (torkelo) from 192.168.3.1 is not from the authentication proxy")
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
middlewareScenario("When auth_proxy is enabled and IPv6 request RemoteAddr is not trusted", func(sc *scenarioContext) {
|
|
||||||
setting.AuthProxyEnabled = true
|
|
||||||
setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
|
|
||||||
setting.AuthProxyHeaderProperty = "username"
|
|
||||||
setting.AuthProxyWhitelist = "192.168.1.1, 2001::23"
|
|
||||||
|
|
||||||
sc.fakeReq("GET", "/")
|
|
||||||
sc.req.Header.Add("X-WEBAUTH-USER", "torkelo")
|
|
||||||
sc.req.RemoteAddr = "[2001:23]:12345"
|
|
||||||
sc.exec()
|
|
||||||
|
|
||||||
Convey("should return 407 status code", func() {
|
|
||||||
So(sc.resp.Code, ShouldEqual, 407)
|
|
||||||
So(sc.resp.Body.String(), ShouldContainSubstring, "Request for user (torkelo) from 2001:23 is not from the authentication proxy")
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
middlewareScenario("When auth_proxy is enabled and IPv6 request RemoteAddr is not within trusted CIDR block", func(sc *scenarioContext) {
|
|
||||||
setting.AuthProxyEnabled = true
|
|
||||||
setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
|
|
||||||
setting.AuthProxyHeaderProperty = "username"
|
|
||||||
setting.AuthProxyWhitelist = "192.168.1.0/24, 2001::0/120"
|
|
||||||
|
|
||||||
sc.fakeReq("GET", "/")
|
|
||||||
sc.req.Header.Add("X-WEBAUTH-USER", "torkelo")
|
|
||||||
sc.req.RemoteAddr = "[2001:23]:12345"
|
|
||||||
sc.exec()
|
|
||||||
|
|
||||||
Convey("should return 407 status code", func() {
|
|
||||||
So(sc.resp.Code, ShouldEqual, 407)
|
|
||||||
So(sc.resp.Body.String(), ShouldContainSubstring, "Request for user (torkelo) from 2001:23 is not from the authentication proxy")
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
middlewareScenario("When auth_proxy is enabled and request RemoteAddr is trusted", func(sc *scenarioContext) {
|
|
||||||
setting.AuthProxyEnabled = true
|
|
||||||
setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
|
|
||||||
setting.AuthProxyHeaderProperty = "username"
|
|
||||||
setting.AuthProxyWhitelist = "192.168.1.1, 2001::23"
|
|
||||||
|
|
||||||
bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
|
|
||||||
query.Result = &m.SignedInUser{OrgId: 4, UserId: 33}
|
|
||||||
return nil
|
|
||||||
})
|
})
|
||||||
|
|
||||||
bus.AddHandler("test", func(cmd *m.UpsertUserCommand) error {
|
middlewareScenario(t, "should get an existing user from header", func(sc *scenarioContext) {
|
||||||
cmd.Result = &m.User{Id: 33}
|
setting.LdapEnabled = false
|
||||||
return nil
|
|
||||||
|
bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
|
||||||
|
query.Result = &m.SignedInUser{OrgId: 2, UserId: 12}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
bus.AddHandler("test", func(cmd *m.UpsertUserCommand) error {
|
||||||
|
cmd.Result = &m.User{Id: 12}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
sc.fakeReq("GET", "/")
|
||||||
|
sc.req.Header.Add(setting.AuthProxyHeaderName, name)
|
||||||
|
sc.exec()
|
||||||
|
|
||||||
|
Convey("should init context with user info", func() {
|
||||||
|
So(sc.context.IsSignedIn, ShouldBeTrue)
|
||||||
|
So(sc.context.UserId, ShouldEqual, 12)
|
||||||
|
So(sc.context.OrgId, ShouldEqual, 2)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
sc.fakeReq("GET", "/")
|
middlewareScenario(t, "should allow the request from whitelist IP", func(sc *scenarioContext) {
|
||||||
sc.req.Header.Add("X-WEBAUTH-USER", "torkelo")
|
setting.AuthProxyWhitelist = "192.168.1.0/24, 2001::0/120"
|
||||||
sc.req.RemoteAddr = "[2001::23]:12345"
|
setting.LdapEnabled = false
|
||||||
sc.exec()
|
|
||||||
|
|
||||||
Convey("Should init context with user info", func() {
|
bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
|
||||||
So(sc.context.IsSignedIn, ShouldBeTrue)
|
query.Result = &m.SignedInUser{OrgId: 4, UserId: 33}
|
||||||
So(sc.context.UserId, ShouldEqual, 33)
|
return nil
|
||||||
So(sc.context.OrgId, ShouldEqual, 4)
|
})
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
middlewareScenario("When auth_proxy is enabled and IPv4 request RemoteAddr is within trusted CIDR block", func(sc *scenarioContext) {
|
bus.AddHandler("test", func(cmd *m.UpsertUserCommand) error {
|
||||||
setting.AuthProxyEnabled = true
|
cmd.Result = &m.User{Id: 33}
|
||||||
setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
|
return nil
|
||||||
setting.AuthProxyHeaderProperty = "username"
|
})
|
||||||
setting.AuthProxyWhitelist = "192.168.1.0/24, 2001::0/120"
|
|
||||||
|
|
||||||
bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
|
sc.fakeReq("GET", "/")
|
||||||
query.Result = &m.SignedInUser{OrgId: 4, UserId: 33}
|
sc.req.Header.Add(setting.AuthProxyHeaderName, name)
|
||||||
return nil
|
sc.req.RemoteAddr = "[2001::23]:12345"
|
||||||
|
sc.exec()
|
||||||
|
|
||||||
|
Convey("Should init context with user info", func() {
|
||||||
|
So(sc.context.IsSignedIn, ShouldBeTrue)
|
||||||
|
So(sc.context.UserId, ShouldEqual, 33)
|
||||||
|
So(sc.context.OrgId, ShouldEqual, 4)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
bus.AddHandler("test", func(cmd *m.UpsertUserCommand) error {
|
middlewareScenario(t, "should not allow the request from whitelist IP", func(sc *scenarioContext) {
|
||||||
cmd.Result = &m.User{Id: 33}
|
setting.AuthProxyWhitelist = "8.8.8.8"
|
||||||
return nil
|
setting.LdapEnabled = false
|
||||||
})
|
|
||||||
|
|
||||||
sc.fakeReq("GET", "/")
|
bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
|
||||||
sc.req.Header.Add("X-WEBAUTH-USER", "torkelo")
|
query.Result = &m.SignedInUser{OrgId: 4, UserId: 33}
|
||||||
sc.req.RemoteAddr = "192.168.1.10:12345"
|
return nil
|
||||||
sc.exec()
|
})
|
||||||
|
|
||||||
Convey("Should init context with user info", func() {
|
bus.AddHandler("test", func(cmd *m.UpsertUserCommand) error {
|
||||||
So(sc.context.IsSignedIn, ShouldBeTrue)
|
cmd.Result = &m.User{Id: 33}
|
||||||
So(sc.context.UserId, ShouldEqual, 33)
|
return nil
|
||||||
So(sc.context.OrgId, ShouldEqual, 4)
|
})
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
middlewareScenario("When auth_proxy is enabled and IPv6 request RemoteAddr is within trusted CIDR block", func(sc *scenarioContext) {
|
sc.fakeReq("GET", "/")
|
||||||
setting.AuthProxyEnabled = true
|
sc.req.Header.Add(setting.AuthProxyHeaderName, name)
|
||||||
setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
|
sc.req.RemoteAddr = "[2001::23]:12345"
|
||||||
setting.AuthProxyHeaderProperty = "username"
|
sc.exec()
|
||||||
setting.AuthProxyWhitelist = "192.168.1.0/24, 2001::0/120"
|
|
||||||
|
|
||||||
bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
|
Convey("should return 407 status code", func() {
|
||||||
query.Result = &m.SignedInUser{OrgId: 4, UserId: 33}
|
So(sc.resp.Code, ShouldEqual, 407)
|
||||||
return nil
|
So(sc.context, ShouldBeNil)
|
||||||
})
|
})
|
||||||
|
|
||||||
bus.AddHandler("test", func(cmd *m.UpsertUserCommand) error {
|
|
||||||
cmd.Result = &m.User{Id: 33}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
sc.fakeReq("GET", "/")
|
|
||||||
sc.req.Header.Add("X-WEBAUTH-USER", "torkelo")
|
|
||||||
sc.req.RemoteAddr = "[2001::23]:12345"
|
|
||||||
sc.exec()
|
|
||||||
|
|
||||||
Convey("Should init context with user info", func() {
|
|
||||||
So(sc.context.IsSignedIn, ShouldBeTrue)
|
|
||||||
So(sc.context.UserId, ShouldEqual, 33)
|
|
||||||
So(sc.context.OrgId, ShouldEqual, 4)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
middlewareScenario("When session exists for previous user, create a new session", func(sc *scenarioContext) {
|
|
||||||
setting.AuthProxyEnabled = true
|
|
||||||
setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
|
|
||||||
setting.AuthProxyHeaderProperty = "username"
|
|
||||||
setting.AuthProxyWhitelist = ""
|
|
||||||
|
|
||||||
bus.AddHandler("test", func(query *m.UpsertUserCommand) error {
|
|
||||||
query.Result = &m.User{Id: 32}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
|
|
||||||
query.Result = &m.SignedInUser{OrgId: 4, UserId: 32}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
// create session
|
|
||||||
sc.fakeReq("GET", "/").handler(func(c *m.ReqContext) {
|
|
||||||
c.Session.Set(session.SESS_KEY_USERID, int64(33))
|
|
||||||
}).exec()
|
|
||||||
|
|
||||||
oldSessionID := sc.context.Session.ID()
|
|
||||||
|
|
||||||
sc.req.Header.Add("X-WEBAUTH-USER", "torkelo")
|
|
||||||
sc.exec()
|
|
||||||
|
|
||||||
newSessionID := sc.context.Session.ID()
|
|
||||||
|
|
||||||
Convey("Should not share session with other user", func() {
|
|
||||||
So(oldSessionID, ShouldNotEqual, newSessionID)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
middlewareScenario("When auth_proxy and ldap enabled call sync with ldap user", func(sc *scenarioContext) {
|
|
||||||
setting.AuthProxyEnabled = true
|
|
||||||
setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
|
|
||||||
setting.AuthProxyHeaderProperty = "username"
|
|
||||||
setting.AuthProxyWhitelist = ""
|
|
||||||
setting.LdapEnabled = true
|
|
||||||
|
|
||||||
called := false
|
|
||||||
syncGrafanaUserWithLdapUser = func(query *m.LoginUserQuery) error {
|
|
||||||
called = true
|
|
||||||
query.User = &m.User{Id: 32}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
bus.AddHandler("test", func(query *m.UpsertUserCommand) error {
|
|
||||||
query.Result = &m.User{Id: 32}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
|
|
||||||
query.Result = &m.SignedInUser{OrgId: 4, UserId: 32}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
sc.fakeReq("GET", "/")
|
|
||||||
sc.req.Header.Add("X-WEBAUTH-USER", "torkelo")
|
|
||||||
sc.exec()
|
|
||||||
|
|
||||||
Convey("Should call syncGrafanaUserWithLdapUser", func() {
|
|
||||||
So(called, ShouldBeTrue)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func middlewareScenario(desc string, fn scenarioFunc) {
|
func middlewareScenario(t *testing.T, desc string, fn scenarioFunc) {
|
||||||
Convey(desc, func() {
|
Convey(desc, func() {
|
||||||
defer bus.ClearBusHandlers()
|
defer bus.ClearBusHandlers()
|
||||||
|
|
||||||
@ -562,9 +469,10 @@ func middlewareScenario(desc string, fn scenarioFunc) {
|
|||||||
Delims: macaron.Delims{Left: "[[", Right: "]]"},
|
Delims: macaron.Delims{Left: "[[", Right: "]]"},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
session.Init(&msession.Options{}, 0)
|
|
||||||
sc.userAuthTokenService = auth.NewFakeUserAuthTokenService()
|
sc.userAuthTokenService = auth.NewFakeUserAuthTokenService()
|
||||||
sc.m.Use(GetContextHandler(sc.userAuthTokenService))
|
sc.remoteCacheService = remotecache.NewFakeStore(t)
|
||||||
|
|
||||||
|
sc.m.Use(GetContextHandler(sc.userAuthTokenService, sc.remoteCacheService))
|
||||||
// mock out gc goroutine
|
// mock out gc goroutine
|
||||||
session.StartSessionGC = func() {}
|
session.StartSessionGC = func() {}
|
||||||
setting.SessionOptions = msession.Options{}
|
setting.SessionOptions = msession.Options{}
|
||||||
@ -597,6 +505,7 @@ type scenarioContext struct {
|
|||||||
defaultHandler macaron.Handler
|
defaultHandler macaron.Handler
|
||||||
url string
|
url string
|
||||||
userAuthTokenService *auth.FakeUserAuthTokenService
|
userAuthTokenService *auth.FakeUserAuthTokenService
|
||||||
|
remoteCacheService *remotecache.RemoteCache
|
||||||
|
|
||||||
req *http.Request
|
req *http.Request
|
||||||
}
|
}
|
||||||
@ -622,13 +531,6 @@ func (sc *scenarioContext) fakeReq(method, url string) *scenarioContext {
|
|||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
sc.req = req
|
sc.req = req
|
||||||
|
|
||||||
// add session cookie from last request
|
|
||||||
if sc.context != nil {
|
|
||||||
if sc.context.Session.ID() != "" {
|
|
||||||
req.Header.Add("Cookie", "grafana_sess="+sc.context.Session.ID()+";")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sc
|
return sc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
|
||||||
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
m "github.com/grafana/grafana/pkg/models"
|
m "github.com/grafana/grafana/pkg/models"
|
||||||
@ -13,7 +12,7 @@ import (
|
|||||||
func TestOrgRedirectMiddleware(t *testing.T) {
|
func TestOrgRedirectMiddleware(t *testing.T) {
|
||||||
|
|
||||||
Convey("Can redirect to correct org", t, func() {
|
Convey("Can redirect to correct org", t, func() {
|
||||||
middlewareScenario("when setting a correct org for the user", func(sc *scenarioContext) {
|
middlewareScenario(t, "when setting a correct org for the user", func(sc *scenarioContext) {
|
||||||
sc.withTokenSessionCookie("token")
|
sc.withTokenSessionCookie("token")
|
||||||
bus.AddHandler("test", func(query *m.SetUsingOrgCommand) error {
|
bus.AddHandler("test", func(query *m.SetUsingOrgCommand) error {
|
||||||
return nil
|
return nil
|
||||||
@ -39,7 +38,7 @@ func TestOrgRedirectMiddleware(t *testing.T) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
middlewareScenario("when setting an invalid org for user", func(sc *scenarioContext) {
|
middlewareScenario(t, "when setting an invalid org for user", func(sc *scenarioContext) {
|
||||||
sc.withTokenSessionCookie("token")
|
sc.withTokenSessionCookie("token")
|
||||||
bus.AddHandler("test", func(query *m.SetUsingOrgCommand) error {
|
bus.AddHandler("test", func(query *m.SetUsingOrgCommand) error {
|
||||||
return fmt.Errorf("")
|
return fmt.Errorf("")
|
||||||
|
@ -3,11 +3,10 @@ package middleware
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/services/auth"
|
|
||||||
"github.com/grafana/grafana/pkg/services/quota"
|
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
m "github.com/grafana/grafana/pkg/models"
|
m "github.com/grafana/grafana/pkg/models"
|
||||||
|
"github.com/grafana/grafana/pkg/services/auth"
|
||||||
|
"github.com/grafana/grafana/pkg/services/quota"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
. "github.com/smartystreets/goconvey/convey"
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
)
|
)
|
||||||
@ -43,7 +42,7 @@ func TestMiddlewareQuota(t *testing.T) {
|
|||||||
}
|
}
|
||||||
QuotaFn := Quota(qs)
|
QuotaFn := Quota(qs)
|
||||||
|
|
||||||
middlewareScenario("with user not logged in", func(sc *scenarioContext) {
|
middlewareScenario(t, "with user not logged in", func(sc *scenarioContext) {
|
||||||
bus.AddHandler("globalQuota", func(query *m.GetGlobalQuotaByTargetQuery) error {
|
bus.AddHandler("globalQuota", func(query *m.GetGlobalQuotaByTargetQuery) error {
|
||||||
query.Result = &m.GlobalQuotaDTO{
|
query.Result = &m.GlobalQuotaDTO{
|
||||||
Target: query.Target,
|
Target: query.Target,
|
||||||
@ -81,7 +80,7 @@ func TestMiddlewareQuota(t *testing.T) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
middlewareScenario("with user logged in", func(sc *scenarioContext) {
|
middlewareScenario(t, "with user logged in", func(sc *scenarioContext) {
|
||||||
sc.withTokenSessionCookie("token")
|
sc.withTokenSessionCookie("token")
|
||||||
bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
|
bus.AddHandler("test", func(query *m.GetSignedInUserQuery) error {
|
||||||
query.Result = &m.SignedInUser{OrgId: 2, UserId: 12}
|
query.Result = &m.SignedInUser{OrgId: 2, UserId: 12}
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
|
"github.com/grafana/grafana/pkg/infra/remotecache"
|
||||||
m "github.com/grafana/grafana/pkg/models"
|
m "github.com/grafana/grafana/pkg/models"
|
||||||
"github.com/grafana/grafana/pkg/services/auth"
|
"github.com/grafana/grafana/pkg/services/auth"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
@ -17,7 +18,7 @@ func TestRecoveryMiddleware(t *testing.T) {
|
|||||||
|
|
||||||
Convey("Given an api route that panics", t, func() {
|
Convey("Given an api route that panics", t, func() {
|
||||||
apiURL := "/api/whatever"
|
apiURL := "/api/whatever"
|
||||||
recoveryScenario("recovery middleware should return json", apiURL, func(sc *scenarioContext) {
|
recoveryScenario(t, "recovery middleware should return json", apiURL, func(sc *scenarioContext) {
|
||||||
sc.handlerFunc = PanicHandler
|
sc.handlerFunc = PanicHandler
|
||||||
sc.fakeReq("GET", apiURL).exec()
|
sc.fakeReq("GET", apiURL).exec()
|
||||||
sc.req.Header.Add("content-type", "application/json")
|
sc.req.Header.Add("content-type", "application/json")
|
||||||
@ -30,7 +31,7 @@ func TestRecoveryMiddleware(t *testing.T) {
|
|||||||
|
|
||||||
Convey("Given a non-api route that panics", t, func() {
|
Convey("Given a non-api route that panics", t, func() {
|
||||||
apiURL := "/whatever"
|
apiURL := "/whatever"
|
||||||
recoveryScenario("recovery middleware should return html", apiURL, func(sc *scenarioContext) {
|
recoveryScenario(t, "recovery middleware should return html", apiURL, func(sc *scenarioContext) {
|
||||||
sc.handlerFunc = PanicHandler
|
sc.handlerFunc = PanicHandler
|
||||||
sc.fakeReq("GET", apiURL).exec()
|
sc.fakeReq("GET", apiURL).exec()
|
||||||
|
|
||||||
@ -45,7 +46,7 @@ func PanicHandler(c *m.ReqContext) {
|
|||||||
panic("Handler has panicked")
|
panic("Handler has panicked")
|
||||||
}
|
}
|
||||||
|
|
||||||
func recoveryScenario(desc string, url string, fn scenarioFunc) {
|
func recoveryScenario(t *testing.T, desc string, url string, fn scenarioFunc) {
|
||||||
Convey(desc, func() {
|
Convey(desc, func() {
|
||||||
defer bus.ClearBusHandlers()
|
defer bus.ClearBusHandlers()
|
||||||
|
|
||||||
@ -64,7 +65,9 @@ func recoveryScenario(desc string, url string, fn scenarioFunc) {
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
sc.userAuthTokenService = auth.NewFakeUserAuthTokenService()
|
sc.userAuthTokenService = auth.NewFakeUserAuthTokenService()
|
||||||
sc.m.Use(GetContextHandler(sc.userAuthTokenService))
|
sc.remoteCacheService = remotecache.NewFakeStore(t)
|
||||||
|
|
||||||
|
sc.m.Use(GetContextHandler(sc.userAuthTokenService, sc.remoteCacheService))
|
||||||
// mock out gc goroutine
|
// mock out gc goroutine
|
||||||
sc.m.Use(OrgRedirect())
|
sc.m.Use(OrgRedirect())
|
||||||
sc.m.Use(AddDefaultResponseHeaders())
|
sc.m.Use(AddDefaultResponseHeaders())
|
||||||
|
@ -11,6 +11,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-sql-driver/mysql"
|
||||||
|
"github.com/go-xorm/xorm"
|
||||||
"github.com/grafana/grafana/pkg/bus"
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
"github.com/grafana/grafana/pkg/log"
|
"github.com/grafana/grafana/pkg/log"
|
||||||
m "github.com/grafana/grafana/pkg/models"
|
m "github.com/grafana/grafana/pkg/models"
|
||||||
@ -21,12 +23,8 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore/sqlutil"
|
"github.com/grafana/grafana/pkg/services/sqlstore/sqlutil"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
"github.com/grafana/grafana/pkg/util"
|
|
||||||
|
|
||||||
"github.com/go-sql-driver/mysql"
|
|
||||||
"github.com/go-xorm/xorm"
|
|
||||||
|
|
||||||
_ "github.com/grafana/grafana/pkg/tsdb/mssql"
|
_ "github.com/grafana/grafana/pkg/tsdb/mssql"
|
||||||
|
"github.com/grafana/grafana/pkg/util"
|
||||||
_ "github.com/lib/pq"
|
_ "github.com/lib/pq"
|
||||||
sqlite3 "github.com/mattn/go-sqlite3"
|
sqlite3 "github.com/mattn/go-sqlite3"
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user