mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Backend: Remove more globals (#29644)
Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>
This commit is contained in:
parent
aa8fb1ae98
commit
dd2d206d99
@ -24,8 +24,8 @@ func (hs *HTTPServer) registerRoutes() {
|
||||
reqCanAccessTeams := middleware.AdminOrFeatureEnabled(hs.Cfg.EditorsCanAdmin)
|
||||
reqSnapshotPublicModeOrSignedIn := middleware.SnapshotPublicModeOrSignedIn(hs.Cfg)
|
||||
redirectFromLegacyDashboardURL := middleware.RedirectFromLegacyDashboardURL()
|
||||
redirectFromLegacyDashboardSoloURL := middleware.RedirectFromLegacyDashboardSoloURL()
|
||||
redirectFromLegacyPanelEditURL := middleware.RedirectFromLegacyPanelEditURL()
|
||||
redirectFromLegacyDashboardSoloURL := middleware.RedirectFromLegacyDashboardSoloURL(hs.Cfg)
|
||||
redirectFromLegacyPanelEditURL := middleware.RedirectFromLegacyPanelEditURL(hs.Cfg)
|
||||
quota := middleware.Quota(hs.QuotaService)
|
||||
bind := binding.Bind
|
||||
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/infra/fs"
|
||||
"github.com/grafana/grafana/pkg/infra/remotecache"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/registry"
|
||||
@ -26,7 +27,7 @@ func loggedInUserScenario(t *testing.T, desc string, url string, fn scenarioFunc
|
||||
|
||||
func loggedInUserScenarioWithRole(t *testing.T, desc string, method string, url string, routePattern string, role models.RoleType, fn scenarioFunc) {
|
||||
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
|
||||
defer bus.ClearBusHandlers()
|
||||
t.Cleanup(bus.ClearBusHandlers)
|
||||
|
||||
sc := setupScenarioContext(t, url)
|
||||
sc.defaultHandler = Wrap(func(c *models.ReqContext) Response {
|
||||
@ -129,6 +130,7 @@ func (sc *scenarioContext) fakeReqNoAssertionsWithCookie(method, url string, coo
|
||||
|
||||
type scenarioContext struct {
|
||||
t *testing.T
|
||||
cfg *setting.Cfg
|
||||
m *macaron.Macaron
|
||||
context *models.ReqContext
|
||||
resp *httptest.ResponseRecorder
|
||||
@ -146,12 +148,15 @@ func (sc *scenarioContext) exec() {
|
||||
type scenarioFunc func(c *scenarioContext)
|
||||
type handlerFunc func(c *models.ReqContext) Response
|
||||
|
||||
func getContextHandler(t *testing.T) *contexthandler.ContextHandler {
|
||||
func getContextHandler(t *testing.T, cfg *setting.Cfg) *contexthandler.ContextHandler {
|
||||
t.Helper()
|
||||
|
||||
if cfg == nil {
|
||||
cfg = setting.NewCfg()
|
||||
}
|
||||
|
||||
sqlStore := sqlstore.InitTestDB(t)
|
||||
remoteCacheSvc := &remotecache.RemoteCache{}
|
||||
cfg := setting.NewCfg()
|
||||
cfg.RemoteCacheOptions = &setting.RemoteCacheOptions{
|
||||
Name: "database",
|
||||
}
|
||||
@ -187,19 +192,24 @@ func getContextHandler(t *testing.T) *contexthandler.ContextHandler {
|
||||
}
|
||||
|
||||
func setupScenarioContext(t *testing.T, url string) *scenarioContext {
|
||||
cfg := setting.NewCfg()
|
||||
sc := &scenarioContext{
|
||||
url: url,
|
||||
t: t,
|
||||
cfg: cfg,
|
||||
}
|
||||
viewsPath, err := filepath.Abs("../../public/views")
|
||||
require.NoError(t, err)
|
||||
exists, err := fs.Exists(viewsPath)
|
||||
require.NoError(t, err)
|
||||
require.Truef(t, exists, "Views should be in %q", viewsPath)
|
||||
|
||||
sc.m = macaron.New()
|
||||
sc.m.Use(macaron.Renderer(macaron.RenderOptions{
|
||||
Directory: viewsPath,
|
||||
Delims: macaron.Delims{Left: "[[", Right: "]]"},
|
||||
}))
|
||||
sc.m.Use(getContextHandler(t).Middleware)
|
||||
sc.m.Use(getContextHandler(t, cfg).Middleware)
|
||||
|
||||
return sc
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/live"
|
||||
"github.com/grafana/grafana/pkg/services/provisioning"
|
||||
"github.com/grafana/grafana/pkg/services/quota"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@ -1177,11 +1178,15 @@ func postDashboardScenario(t *testing.T, desc string, url string, routePattern s
|
||||
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
|
||||
t.Cleanup(bus.ClearBusHandlers)
|
||||
|
||||
cfg := setting.NewCfg()
|
||||
hs := HTTPServer{
|
||||
Bus: bus.GetBus(),
|
||||
Cfg: setting.NewCfg(),
|
||||
Cfg: cfg,
|
||||
ProvisioningService: provisioning.NewProvisioningServiceMock(),
|
||||
Live: &live.GrafanaLive{Cfg: setting.NewCfg()},
|
||||
QuotaService: "a.QuotaService{
|
||||
Cfg: cfg,
|
||||
},
|
||||
}
|
||||
|
||||
sc := setupScenarioContext(t, url)
|
||||
@ -1238,11 +1243,13 @@ func restoreDashboardVersionScenario(t *testing.T, desc string, url string, rout
|
||||
t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) {
|
||||
defer bus.ClearBusHandlers()
|
||||
|
||||
cfg := setting.NewCfg()
|
||||
hs := HTTPServer{
|
||||
Cfg: setting.NewCfg(),
|
||||
Cfg: cfg,
|
||||
Bus: bus.GetBus(),
|
||||
ProvisioningService: provisioning.NewProvisioningServiceMock(),
|
||||
Live: &live.GrafanaLive{Cfg: setting.NewCfg()},
|
||||
Live: &live.GrafanaLive{Cfg: cfg},
|
||||
QuotaService: "a.QuotaService{Cfg: cfg},
|
||||
}
|
||||
|
||||
sc := setupScenarioContext(t, url)
|
||||
|
@ -52,7 +52,7 @@ func setupTestEnvironment(t *testing.T, cfg *setting.Cfg) (*macaron.Macaron, *HT
|
||||
}
|
||||
|
||||
m := macaron.New()
|
||||
m.Use(getContextHandler(t).Middleware)
|
||||
m.Use(getContextHandler(t, cfg).Middleware)
|
||||
m.Use(macaron.Renderer(macaron.RenderOptions{
|
||||
Directory: filepath.Join(setting.StaticRootPath, "views"),
|
||||
IndentJSON: true,
|
||||
|
@ -337,11 +337,11 @@ func (hs *HTTPServer) addMiddlewaresAndStaticRoutes() {
|
||||
m.Use(hs.metricsEndpoint)
|
||||
|
||||
m.Use(hs.ContextHandler.Middleware)
|
||||
m.Use(middleware.OrgRedirect())
|
||||
m.Use(middleware.OrgRedirect(hs.Cfg))
|
||||
|
||||
// needs to be after context handler
|
||||
if setting.EnforceDomain {
|
||||
m.Use(middleware.ValidateHostHeader(hs.Cfg.Domain))
|
||||
m.Use(middleware.ValidateHostHeader(hs.Cfg))
|
||||
}
|
||||
|
||||
m.Use(middleware.HandleNoCacheHeader())
|
||||
|
@ -458,7 +458,7 @@ func (hs *HTTPServer) setIndexViewData(c *models.ReqContext) (*dtos.IndexViewDat
|
||||
func (hs *HTTPServer) Index(c *models.ReqContext) {
|
||||
data, err := hs.setIndexViewData(c)
|
||||
if err != nil {
|
||||
c.Handle(500, "Failed to get settings", err)
|
||||
c.Handle(hs.Cfg, 500, "Failed to get settings", err)
|
||||
return
|
||||
}
|
||||
c.HTML(200, "index", data)
|
||||
@ -472,7 +472,7 @@ func (hs *HTTPServer) NotFoundHandler(c *models.ReqContext) {
|
||||
|
||||
data, err := hs.setIndexViewData(c)
|
||||
if err != nil {
|
||||
c.Handle(500, "Failed to get settings", err)
|
||||
c.Handle(hs.Cfg, 500, "Failed to get settings", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/ldap"
|
||||
"github.com/grafana/grafana/pkg/services/multildap"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
)
|
||||
|
||||
@ -187,7 +186,7 @@ func (hs *HTTPServer) PostSyncUserWithLDAP(c *models.ReqContext) Response {
|
||||
user, _, err := ldapServer.User(query.Result.Login)
|
||||
if err != nil {
|
||||
if errors.Is(err, multildap.ErrDidNotFindUser) { // User was not in the LDAP server - we need to take action:
|
||||
if setting.AdminUser == query.Result.Login { // User is *the* Grafana Admin. We cannot disable it.
|
||||
if hs.Cfg.AdminUser == query.Result.Login { // User is *the* Grafana Admin. We cannot disable it.
|
||||
errMsg := fmt.Sprintf(`Refusing to sync grafana super admin "%s" - it would be disabled`, query.Result.Login)
|
||||
ldapLogger.Error(errMsg)
|
||||
return Error(http.StatusBadRequest, errMsg, err)
|
||||
|
@ -375,7 +375,7 @@ func TestGetLDAPStatusAPIEndpoint(t *testing.T) {
|
||||
// PostSyncUserWithLDAP tests
|
||||
// ***
|
||||
|
||||
func postSyncUserWithLDAPContext(t *testing.T, requestURL string, preHook func(t *testing.T)) *scenarioContext {
|
||||
func postSyncUserWithLDAPContext(t *testing.T, requestURL string, preHook func(*testing.T, *scenarioContext)) *scenarioContext {
|
||||
t.Helper()
|
||||
|
||||
sc := setupScenarioContext(t, requestURL)
|
||||
@ -387,7 +387,7 @@ func postSyncUserWithLDAPContext(t *testing.T, requestURL string, preHook func(t
|
||||
setting.LDAPEnabled = true
|
||||
|
||||
hs := &HTTPServer{
|
||||
Cfg: setting.NewCfg(),
|
||||
Cfg: sc.cfg,
|
||||
AuthTokenService: auth.NewFakeUserAuthTokenService(),
|
||||
}
|
||||
|
||||
@ -402,7 +402,7 @@ func postSyncUserWithLDAPContext(t *testing.T, requestURL string, preHook func(t
|
||||
req, err := http.NewRequest(http.MethodPost, requestURL, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
preHook(t)
|
||||
preHook(t, sc)
|
||||
|
||||
sc.req = req
|
||||
sc.exec()
|
||||
@ -411,7 +411,7 @@ func postSyncUserWithLDAPContext(t *testing.T, requestURL string, preHook func(t
|
||||
}
|
||||
|
||||
func TestPostSyncUserWithLDAPAPIEndpoint_Success(t *testing.T) {
|
||||
sc := postSyncUserWithLDAPContext(t, "/api/admin/ldap/sync/34", func(t *testing.T) {
|
||||
sc := postSyncUserWithLDAPContext(t, "/api/admin/ldap/sync/34", func(t *testing.T, sc *scenarioContext) {
|
||||
getLDAPConfig = func(*setting.Cfg) (*ldap.Config, error) {
|
||||
return &ldap.Config{}, nil
|
||||
}
|
||||
@ -456,7 +456,7 @@ func TestPostSyncUserWithLDAPAPIEndpoint_Success(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPostSyncUserWithLDAPAPIEndpoint_WhenUserNotFound(t *testing.T) {
|
||||
sc := postSyncUserWithLDAPContext(t, "/api/admin/ldap/sync/34", func(t *testing.T) {
|
||||
sc := postSyncUserWithLDAPContext(t, "/api/admin/ldap/sync/34", func(t *testing.T, sc *scenarioContext) {
|
||||
getLDAPConfig = func(*setting.Cfg) (*ldap.Config, error) {
|
||||
return &ldap.Config{}, nil
|
||||
}
|
||||
@ -484,7 +484,7 @@ func TestPostSyncUserWithLDAPAPIEndpoint_WhenUserNotFound(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPostSyncUserWithLDAPAPIEndpoint_WhenGrafanaAdmin(t *testing.T) {
|
||||
sc := postSyncUserWithLDAPContext(t, "/api/admin/ldap/sync/34", func(t *testing.T) {
|
||||
sc := postSyncUserWithLDAPContext(t, "/api/admin/ldap/sync/34", func(t *testing.T, sc *scenarioContext) {
|
||||
getLDAPConfig = func(*setting.Cfg) (*ldap.Config, error) {
|
||||
return &ldap.Config{}, nil
|
||||
}
|
||||
@ -495,9 +495,7 @@ func TestPostSyncUserWithLDAPAPIEndpoint_WhenGrafanaAdmin(t *testing.T) {
|
||||
|
||||
userSearchError = multildap.ErrDidNotFindUser
|
||||
|
||||
admin := setting.AdminUser
|
||||
t.Cleanup(func() { setting.AdminUser = admin })
|
||||
setting.AdminUser = "ldap-daniel"
|
||||
sc.cfg.AdminUser = "ldap-daniel"
|
||||
|
||||
bus.AddHandler("test", func(q *models.GetUserByIdQuery) error {
|
||||
require.Equal(t, q.Id, int64(34))
|
||||
@ -527,7 +525,7 @@ func TestPostSyncUserWithLDAPAPIEndpoint_WhenGrafanaAdmin(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPostSyncUserWithLDAPAPIEndpoint_WhenUserNotInLDAP(t *testing.T) {
|
||||
sc := postSyncUserWithLDAPContext(t, "/api/admin/ldap/sync/34", func(t *testing.T) {
|
||||
sc := postSyncUserWithLDAPContext(t, "/api/admin/ldap/sync/34", func(t *testing.T, sc *scenarioContext) {
|
||||
getLDAPConfig = func(*setting.Cfg) (*ldap.Config, error) {
|
||||
return &ldap.Config{}, nil
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ func (hs *HTTPServer) CookieOptionsFromCfg() cookies.CookieOptions {
|
||||
func (hs *HTTPServer) LoginView(c *models.ReqContext) {
|
||||
viewData, err := setIndexViewData(hs, c)
|
||||
if err != nil {
|
||||
c.Handle(500, "Failed to get settings", err)
|
||||
c.Handle(hs.Cfg, 500, "Failed to get settings", err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -117,7 +117,7 @@ func (hs *HTTPServer) LoginView(c *models.ReqContext) {
|
||||
user := &models.User{Id: c.SignedInUser.UserId, Email: c.SignedInUser.Email, Login: c.SignedInUser.Login}
|
||||
err := hs.loginUserWithUser(user, c)
|
||||
if err != nil {
|
||||
c.Handle(500, "Failed to sign in user", err)
|
||||
c.Handle(hs.Cfg, 500, "Failed to sign in user", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -277,7 +277,7 @@ type LoginError struct {
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) handleOAuthLoginError(ctx *models.ReqContext, info models.LoginInfo, err LoginError) {
|
||||
ctx.Handle(err.HttpStatus, err.PublicMessage, err.Err)
|
||||
ctx.Handle(hs.Cfg, err.HttpStatus, err.PublicMessage, err.Err)
|
||||
|
||||
info.Error = err.Err
|
||||
if info.Error == nil {
|
||||
|
@ -25,7 +25,11 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func mockSetIndexViewData() {
|
||||
func fakeSetIndexViewData(t *testing.T) {
|
||||
origSetIndexViewData := setIndexViewData
|
||||
t.Cleanup(func() {
|
||||
setIndexViewData = origSetIndexViewData
|
||||
})
|
||||
setIndexViewData = func(*HTTPServer, *models.ReqContext) (*dtos.IndexViewData, error) {
|
||||
data := &dtos.IndexViewData{
|
||||
User: &dtos.CurrentUser{},
|
||||
@ -36,22 +40,16 @@ func mockSetIndexViewData() {
|
||||
}
|
||||
}
|
||||
|
||||
func resetSetIndexViewData() {
|
||||
setIndexViewData = (*HTTPServer).setIndexViewData
|
||||
}
|
||||
|
||||
func mockViewIndex() {
|
||||
func fakeViewIndex(t *testing.T) {
|
||||
origGetViewIndex := getViewIndex
|
||||
t.Cleanup(func() {
|
||||
getViewIndex = origGetViewIndex
|
||||
})
|
||||
getViewIndex = func() string {
|
||||
return "index-template"
|
||||
}
|
||||
}
|
||||
|
||||
func resetViewIndex() {
|
||||
getViewIndex = func() string {
|
||||
return ViewIndex
|
||||
}
|
||||
}
|
||||
|
||||
func getBody(resp *httptest.ResponseRecorder) (string, error) {
|
||||
responseData, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
@ -86,16 +84,15 @@ type redirectCase struct {
|
||||
redirectURL string
|
||||
}
|
||||
|
||||
func TestLoginErrorCookieApiEndpoint(t *testing.T) {
|
||||
mockSetIndexViewData()
|
||||
defer resetSetIndexViewData()
|
||||
func TestLoginErrorCookieAPIEndpoint(t *testing.T) {
|
||||
fakeSetIndexViewData(t)
|
||||
|
||||
mockViewIndex()
|
||||
defer resetViewIndex()
|
||||
fakeViewIndex(t)
|
||||
|
||||
sc := setupScenarioContext(t, "/login")
|
||||
cfg := setting.NewCfg()
|
||||
hs := &HTTPServer{
|
||||
Cfg: setting.NewCfg(),
|
||||
Cfg: cfg,
|
||||
License: &licensing.OSSLicensingService{},
|
||||
}
|
||||
|
||||
@ -103,7 +100,7 @@ func TestLoginErrorCookieApiEndpoint(t *testing.T) {
|
||||
hs.LoginView(c)
|
||||
})
|
||||
|
||||
setting.LoginCookieName = "grafana_session"
|
||||
cfg.LoginCookieName = "grafana_session"
|
||||
setting.SecretKey = "login_testing"
|
||||
|
||||
setting.OAuthService = &setting.OAuther{}
|
||||
@ -142,11 +139,9 @@ func TestLoginErrorCookieApiEndpoint(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLoginViewRedirect(t *testing.T) {
|
||||
mockSetIndexViewData()
|
||||
defer resetSetIndexViewData()
|
||||
fakeSetIndexViewData(t)
|
||||
|
||||
mockViewIndex()
|
||||
defer resetViewIndex()
|
||||
fakeViewIndex(t)
|
||||
sc := setupScenarioContext(t, "/login")
|
||||
hs := &HTTPServer{
|
||||
Cfg: setting.NewCfg(),
|
||||
@ -318,11 +313,9 @@ func TestLoginViewRedirect(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLoginPostRedirect(t *testing.T) {
|
||||
mockSetIndexViewData()
|
||||
defer resetSetIndexViewData()
|
||||
fakeSetIndexViewData(t)
|
||||
|
||||
mockViewIndex()
|
||||
defer resetViewIndex()
|
||||
fakeViewIndex(t)
|
||||
sc := setupScenarioContext(t, "/login")
|
||||
hs := &HTTPServer{
|
||||
log: &FakeLogger{},
|
||||
@ -478,8 +471,7 @@ func TestLoginPostRedirect(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLoginOAuthRedirect(t *testing.T) {
|
||||
mockSetIndexViewData()
|
||||
defer resetSetIndexViewData()
|
||||
fakeSetIndexViewData(t)
|
||||
|
||||
sc := setupScenarioContext(t, "/login")
|
||||
hs := &HTTPServer{
|
||||
@ -511,11 +503,9 @@ func TestLoginOAuthRedirect(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestLoginInternal(t *testing.T) {
|
||||
mockSetIndexViewData()
|
||||
defer resetSetIndexViewData()
|
||||
fakeSetIndexViewData(t)
|
||||
|
||||
mockViewIndex()
|
||||
defer resetViewIndex()
|
||||
fakeViewIndex(t)
|
||||
sc := setupScenarioContext(t, "/login")
|
||||
hs := &HTTPServer{
|
||||
Cfg: setting.NewCfg(),
|
||||
@ -559,24 +549,23 @@ func TestAuthProxyLoginEnableLoginTokenDisabled(t *testing.T) {
|
||||
|
||||
func TestAuthProxyLoginWithEnableLoginToken(t *testing.T) {
|
||||
sc := setupAuthProxyLoginTest(t, true)
|
||||
require.Equal(t, sc.resp.Code, 302)
|
||||
|
||||
assert.Equal(t, sc.resp.Code, 302)
|
||||
location, ok := sc.resp.Header()["Location"]
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, location[0], "/")
|
||||
|
||||
setCookie, ok := sc.resp.Header()["Set-Cookie"]
|
||||
assert.True(t, ok, "Set-Cookie exists")
|
||||
setCookie := sc.resp.Header()["Set-Cookie"]
|
||||
require.NotNil(t, setCookie, "Set-Cookie should exist")
|
||||
assert.Equal(t, "grafana_session=; Path=/; Max-Age=0; HttpOnly", setCookie[0])
|
||||
}
|
||||
|
||||
func setupAuthProxyLoginTest(t *testing.T, enableLoginToken bool) *scenarioContext {
|
||||
mockSetIndexViewData()
|
||||
defer resetSetIndexViewData()
|
||||
fakeSetIndexViewData(t)
|
||||
|
||||
sc := setupScenarioContext(t, "/login")
|
||||
sc.cfg.LoginCookieName = "grafana_session"
|
||||
hs := &HTTPServer{
|
||||
Cfg: setting.NewCfg(),
|
||||
Cfg: sc.cfg,
|
||||
License: &licensing.OSSLicensingService{},
|
||||
AuthTokenService: auth.NewFakeUserAuthTokenService(),
|
||||
log: log.New("hello"),
|
||||
@ -592,8 +581,8 @@ func setupAuthProxyLoginTest(t *testing.T, enableLoginToken bool) *scenarioConte
|
||||
|
||||
setting.OAuthService = &setting.OAuther{}
|
||||
setting.OAuthService.OAuthInfos = make(map[string]*setting.OAuthInfo)
|
||||
hs.Cfg.AuthProxyEnabled = true
|
||||
hs.Cfg.AuthProxyEnableLoginToken = enableLoginToken
|
||||
sc.cfg.AuthProxyEnabled = true
|
||||
sc.cfg.AuthProxyEnableLoginToken = enableLoginToken
|
||||
|
||||
sc.m.Get(sc.url, sc.defaultHandler)
|
||||
sc.fakeReqNoAssertions("GET", sc.url).exec()
|
||||
|
@ -17,7 +17,7 @@ import (
|
||||
func (hs *HTTPServer) RenderToPng(c *models.ReqContext) {
|
||||
queryReader, err := util.NewURLQueryReader(c.Req.URL)
|
||||
if err != nil {
|
||||
c.Handle(400, "Render parameters error", err)
|
||||
c.Handle(hs.Cfg, 400, "Render parameters error", err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -25,25 +25,25 @@ func (hs *HTTPServer) RenderToPng(c *models.ReqContext) {
|
||||
|
||||
width, err := strconv.Atoi(queryReader.Get("width", "800"))
|
||||
if err != nil {
|
||||
c.Handle(400, "Render parameters error", fmt.Errorf("cannot parse width as int: %s", err))
|
||||
c.Handle(hs.Cfg, 400, "Render parameters error", fmt.Errorf("cannot parse width as int: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
height, err := strconv.Atoi(queryReader.Get("height", "400"))
|
||||
if err != nil {
|
||||
c.Handle(400, "Render parameters error", fmt.Errorf("cannot parse height as int: %s", err))
|
||||
c.Handle(hs.Cfg, 400, "Render parameters error", fmt.Errorf("cannot parse height as int: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
timeout, err := strconv.Atoi(queryReader.Get("timeout", "60"))
|
||||
if err != nil {
|
||||
c.Handle(400, "Render parameters error", fmt.Errorf("cannot parse timeout as int: %s", err))
|
||||
c.Handle(hs.Cfg, 400, "Render parameters error", fmt.Errorf("cannot parse timeout as int: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
scale, err := strconv.ParseFloat(queryReader.Get("scale", "1"), 64)
|
||||
if err != nil {
|
||||
c.Handle(400, "Render parameters error", fmt.Errorf("cannot parse scale as float: %s", err))
|
||||
c.Handle(hs.Cfg, 400, "Render parameters error", fmt.Errorf("cannot parse scale as float: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
@ -69,19 +69,19 @@ func (hs *HTTPServer) RenderToPng(c *models.ReqContext) {
|
||||
})
|
||||
if err != nil {
|
||||
if errors.Is(err, rendering.ErrTimeout) {
|
||||
c.Handle(500, err.Error(), err)
|
||||
c.Handle(hs.Cfg, 500, err.Error(), err)
|
||||
return
|
||||
}
|
||||
if errors.Is(err, rendering.ErrPhantomJSNotInstalled) {
|
||||
if strings.HasPrefix(runtime.GOARCH, "arm") {
|
||||
c.Handle(500, "Rendering failed - PhantomJS isn't included in arm build per default", err)
|
||||
c.Handle(hs.Cfg, 500, "Rendering failed - PhantomJS isn't included in arm build per default", err)
|
||||
} else {
|
||||
c.Handle(500, "Rendering failed - PhantomJS isn't installed correctly", err)
|
||||
c.Handle(hs.Cfg, 500, "Rendering failed - PhantomJS isn't installed correctly", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
c.Handle(500, "Rendering failed.", err)
|
||||
c.Handle(hs.Cfg, 500, "Rendering failed.", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -67,5 +67,5 @@ func WriteSessionCookie(ctx *models.ReqContext, cfg *setting.Cfg, value string,
|
||||
maxAge = int(maxLifetime.Seconds())
|
||||
}
|
||||
|
||||
WriteCookie(ctx.Resp, setting.LoginCookieName, url.QueryEscape(value), maxAge, nil)
|
||||
WriteCookie(ctx.Resp, cfg.LoginCookieName, url.QueryEscape(value), maxAge, nil)
|
||||
}
|
||||
|
@ -7,12 +7,11 @@ import (
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"gopkg.in/macaron.v1"
|
||||
)
|
||||
|
||||
func getDashboardURLBySlug(orgID int64, slug string) (string, error) {
|
||||
// TODO: Drop bus call
|
||||
query := models.GetDashboardQuery{Slug: slug, OrgId: orgID}
|
||||
|
||||
if err := bus.Dispatch(&query); err != nil {
|
||||
return "", models.ErrDashboardNotFound
|
||||
}
|
||||
@ -20,7 +19,7 @@ func getDashboardURLBySlug(orgID int64, slug string) (string, error) {
|
||||
return models.GetDashboardUrl(query.Result.Uid, query.Result.Slug), nil
|
||||
}
|
||||
|
||||
func RedirectFromLegacyDashboardURL() macaron.Handler {
|
||||
func RedirectFromLegacyDashboardURL() func(c *models.ReqContext) {
|
||||
return func(c *models.ReqContext) {
|
||||
slug := c.Params("slug")
|
||||
|
||||
@ -36,47 +35,50 @@ func RedirectFromLegacyDashboardURL() macaron.Handler {
|
||||
|
||||
// In Grafana v7.0 we changed panel edit & view query parameters.
|
||||
// This middleware tries to detect those old url parameters and direct to the new url query params
|
||||
func RedirectFromLegacyPanelEditURL() macaron.Handler {
|
||||
func RedirectFromLegacyPanelEditURL(cfg *setting.Cfg) func(c *models.ReqContext) {
|
||||
return func(c *models.ReqContext) {
|
||||
queryParams := c.Req.URL.Query()
|
||||
|
||||
panelId, hasPanelId := queryParams["panelId"]
|
||||
panelID, hasPanelID := queryParams["panelId"]
|
||||
_, hasFullscreen := queryParams["fullscreen"]
|
||||
_, hasEdit := queryParams["edit"]
|
||||
|
||||
if hasPanelId && hasFullscreen {
|
||||
if hasPanelID && hasFullscreen {
|
||||
delete(queryParams, "panelId")
|
||||
delete(queryParams, "fullscreen")
|
||||
delete(queryParams, "edit")
|
||||
|
||||
if hasEdit {
|
||||
queryParams["editPanel"] = panelId
|
||||
queryParams["editPanel"] = panelID
|
||||
} else {
|
||||
queryParams["viewPanel"] = panelId
|
||||
queryParams["viewPanel"] = panelID
|
||||
}
|
||||
|
||||
newURL := setting.ToAbsUrl(fmt.Sprintf("%s?%s", strings.TrimPrefix(c.Req.URL.Path, "/"), queryParams.Encode()))
|
||||
newURL := fmt.Sprintf("%s%s?%s", cfg.AppURL, strings.TrimPrefix(c.Req.URL.Path, "/"), queryParams.Encode())
|
||||
c.Redirect(newURL, 301)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func RedirectFromLegacyDashboardSoloURL() macaron.Handler {
|
||||
func RedirectFromLegacyDashboardSoloURL(cfg *setting.Cfg) func(c *models.ReqContext) {
|
||||
return func(c *models.ReqContext) {
|
||||
slug := c.Params("slug")
|
||||
renderRequest := c.QueryBool("render")
|
||||
|
||||
if slug != "" {
|
||||
if url, err := getDashboardURLBySlug(c.OrgId, slug); err == nil {
|
||||
if renderRequest && strings.Contains(url, setting.AppSubUrl) {
|
||||
url = strings.Replace(url, setting.AppSubUrl, "", 1)
|
||||
}
|
||||
|
||||
url = strings.Replace(url, "/d/", "/d-solo/", 1)
|
||||
url = fmt.Sprintf("%s?%s", url, c.Req.URL.RawQuery)
|
||||
c.Redirect(url, 301)
|
||||
url, err := getDashboardURLBySlug(c.OrgId, slug)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if renderRequest && strings.Contains(url, cfg.AppSubURL) {
|
||||
url = strings.Replace(url, cfg.AppSubURL, "", 1)
|
||||
}
|
||||
|
||||
url = strings.Replace(url, "/d/", "/d-solo/", 1)
|
||||
url = fmt.Sprintf("%s?%s", url, c.Req.URL.RawQuery)
|
||||
c.Redirect(url, 301)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,74 +7,79 @@ import (
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestMiddlewareDashboardRedirect(t *testing.T) {
|
||||
Convey("Given the dashboard redirect middleware", t, func() {
|
||||
bus.ClearBusHandlers()
|
||||
redirectFromLegacyDashboardUrl := RedirectFromLegacyDashboardURL()
|
||||
redirectFromLegacyDashboardSoloUrl := RedirectFromLegacyDashboardSoloURL()
|
||||
bus.ClearBusHandlers()
|
||||
fakeDash := models.NewDashboard("Child dash")
|
||||
fakeDash.Id = 1
|
||||
fakeDash.FolderId = 1
|
||||
fakeDash.HasAcl = false
|
||||
fakeDash.Uid = util.GenerateShortUID()
|
||||
|
||||
fakeDash := models.NewDashboard("Child dash")
|
||||
fakeDash.Id = 1
|
||||
fakeDash.FolderId = 1
|
||||
fakeDash.HasAcl = false
|
||||
fakeDash.Uid = util.GenerateShortUID()
|
||||
middlewareScenario(t, "GET dashboard by legacy url", func(t *testing.T, sc *scenarioContext) {
|
||||
redirectFromLegacyDashboardURL := RedirectFromLegacyDashboardURL()
|
||||
|
||||
middlewareScenario(t, "GET dashboard by legacy url", func(t *testing.T, sc *scenarioContext) {
|
||||
bus.AddHandler("test", func(query *models.GetDashboardQuery) error {
|
||||
query.Result = fakeDash
|
||||
return nil
|
||||
})
|
||||
|
||||
sc.m.Get("/dashboard/db/:slug", redirectFromLegacyDashboardUrl, sc.defaultHandler)
|
||||
|
||||
sc.fakeReqWithParams("GET", "/dashboard/db/dash?orgId=1&panelId=2", map[string]string{}).exec()
|
||||
|
||||
assert.Equal(t, 301, sc.resp.Code)
|
||||
// nolint:bodyclose
|
||||
resp := sc.resp.Result()
|
||||
t.Cleanup(func() {
|
||||
err := resp.Body.Close()
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
redirectURL, err := resp.Location()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, models.GetDashboardUrl(fakeDash.Uid, fakeDash.Slug), redirectURL.Path)
|
||||
assert.Equal(t, 2, len(redirectURL.Query()))
|
||||
bus.AddHandler("test", func(query *models.GetDashboardQuery) error {
|
||||
t.Log("Returning fake dashboard")
|
||||
query.Result = fakeDash
|
||||
return nil
|
||||
})
|
||||
|
||||
middlewareScenario(t, "GET dashboard solo by legacy url", func(t *testing.T, sc *scenarioContext) {
|
||||
bus.AddHandler("test", func(query *models.GetDashboardQuery) error {
|
||||
query.Result = fakeDash
|
||||
return nil
|
||||
})
|
||||
sc.handlerFunc = redirectFromLegacyDashboardURL
|
||||
sc.m.Get("/dashboard/db/:slug", sc.defaultHandler)
|
||||
sc.fakeReqWithParams("GET", "/dashboard/db/dash?orgId=1&panelId=2", map[string]string{}).exec()
|
||||
|
||||
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()
|
||||
|
||||
assert.Equal(t, 301, sc.resp.Code)
|
||||
// nolint:bodyclose
|
||||
resp := sc.resp.Result()
|
||||
t.Cleanup(func() {
|
||||
err := resp.Body.Close()
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
redirectURL, err := resp.Location()
|
||||
require.NoError(t, err)
|
||||
expectedURL := models.GetDashboardUrl(fakeDash.Uid, fakeDash.Slug)
|
||||
expectedURL = strings.Replace(expectedURL, "/d/", "/d-solo/", 1)
|
||||
assert.Equal(t, expectedURL, redirectURL.Path)
|
||||
assert.Equal(t, 2, len(redirectURL.Query()))
|
||||
assert.Equal(t, 301, sc.resp.Code)
|
||||
// nolint:bodyclose
|
||||
resp := sc.resp.Result()
|
||||
t.Cleanup(func() {
|
||||
err := resp.Body.Close()
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
redirectURL, err := resp.Location()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, models.GetDashboardUrl(fakeDash.Uid, fakeDash.Slug), redirectURL.Path)
|
||||
assert.Len(t, redirectURL.Query(), 2)
|
||||
})
|
||||
|
||||
middlewareScenario(t, "GET dashboard by legacy edit url", func(t *testing.T, sc *scenarioContext) {
|
||||
sc.m.Get("/d/:uid/:slug", RedirectFromLegacyPanelEditURL(), sc.defaultHandler)
|
||||
middlewareScenario(t, "GET dashboard solo by legacy url", func(t *testing.T, sc *scenarioContext) {
|
||||
redirectFromLegacyDashboardSoloURL := RedirectFromLegacyDashboardSoloURL(sc.cfg)
|
||||
|
||||
bus.AddHandler("test", func(query *models.GetDashboardQuery) error {
|
||||
t.Log("Returning fake dashboard")
|
||||
query.Result = fakeDash
|
||||
return nil
|
||||
})
|
||||
|
||||
sc.handlerFunc = redirectFromLegacyDashboardSoloURL
|
||||
sc.m.Get("/dashboard-solo/db/:slug", sc.defaultHandler)
|
||||
|
||||
sc.fakeReqWithParams("GET", "/dashboard-solo/db/dash?orgId=1&panelId=2", map[string]string{}).exec()
|
||||
|
||||
require.Equal(t, 301, sc.resp.Code)
|
||||
// nolint:bodyclose
|
||||
resp := sc.resp.Result()
|
||||
t.Cleanup(func() {
|
||||
err := resp.Body.Close()
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
redirectURL, err := resp.Location()
|
||||
require.NoError(t, err)
|
||||
// XXX: Should this be called path??
|
||||
expectedURL := models.GetDashboardUrl(fakeDash.Uid, fakeDash.Slug)
|
||||
expectedURL = strings.Replace(expectedURL, "/d/", "/d-solo/", 1)
|
||||
assert.Equal(t, expectedURL, redirectURL.Path)
|
||||
assert.Len(t, redirectURL.Query(), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func TestMiddlewareDashboardRedirect_legacyEditPanel(t *testing.T) {
|
||||
middlewareScenario(t, "GET dashboard by legacy edit URL", func(t *testing.T, sc *scenarioContext) {
|
||||
sc.handlerFunc = RedirectFromLegacyPanelEditURL(sc.cfg)
|
||||
sc.m.Get("/d/:uid/:slug", sc.defaultHandler)
|
||||
|
||||
sc.fakeReqWithParams("GET", "/d/asd/dash?orgId=1&panelId=12&fullscreen&edit", map[string]string{}).exec()
|
||||
|
||||
|
@ -17,6 +17,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/components/gtime"
|
||||
"github.com/grafana/grafana/pkg/infra/fs"
|
||||
"github.com/grafana/grafana/pkg/infra/remotecache"
|
||||
"github.com/grafana/grafana/pkg/login"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
@ -30,8 +31,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
)
|
||||
|
||||
const errorTemplate = "error-template"
|
||||
|
||||
func fakeGetTime() func() time.Time {
|
||||
var timeSeed int64
|
||||
return func() time.Time {
|
||||
@ -42,12 +41,6 @@ func fakeGetTime() func() time.Time {
|
||||
}
|
||||
|
||||
func TestMiddleWareSecurityHeaders(t *testing.T) {
|
||||
origErrTemplateName := setting.ErrTemplateName
|
||||
t.Cleanup(func() {
|
||||
setting.ErrTemplateName = origErrTemplateName
|
||||
})
|
||||
setting.ErrTemplateName = errorTemplate
|
||||
|
||||
middlewareScenario(t, "middleware should get correct x-xss-protection header", func(t *testing.T, sc *scenarioContext) {
|
||||
sc.fakeReq("GET", "/api/").exec()
|
||||
assert.Equal(t, "1; mode=block", sc.resp.Header().Get("X-XSS-Protection"))
|
||||
@ -79,11 +72,7 @@ func TestMiddleWareSecurityHeaders(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMiddlewareContext(t *testing.T) {
|
||||
origErrTemplateName := setting.ErrTemplateName
|
||||
t.Cleanup(func() {
|
||||
setting.ErrTemplateName = origErrTemplateName
|
||||
})
|
||||
setting.ErrTemplateName = errorTemplate
|
||||
const noCache = "no-cache"
|
||||
|
||||
middlewareScenario(t, "middleware should add context to injector", func(t *testing.T, sc *scenarioContext) {
|
||||
sc.fakeReq("GET", "/").exec()
|
||||
@ -97,8 +86,8 @@ func TestMiddlewareContext(t *testing.T) {
|
||||
|
||||
middlewareScenario(t, "middleware should add Cache-Control header for requests to API", func(t *testing.T, sc *scenarioContext) {
|
||||
sc.fakeReq("GET", "/api/search").exec()
|
||||
assert.Equal(t, "no-cache", sc.resp.Header().Get("Cache-Control"))
|
||||
assert.Equal(t, "no-cache", sc.resp.Header().Get("Pragma"))
|
||||
assert.Equal(t, noCache, sc.resp.Header().Get("Cache-Control"))
|
||||
assert.Equal(t, noCache, sc.resp.Header().Get("Pragma"))
|
||||
assert.Equal(t, "-1", sc.resp.Header().Get("Expires"))
|
||||
})
|
||||
|
||||
@ -110,20 +99,23 @@ func TestMiddlewareContext(t *testing.T) {
|
||||
assert.Empty(t, sc.resp.Header().Get("Expires"))
|
||||
})
|
||||
|
||||
middlewareScenario(t, "middleware should add Cache-Control header for requests with html response", func(
|
||||
middlewareScenario(t, "middleware should add Cache-Control header for requests with HTML response", func(
|
||||
t *testing.T, sc *scenarioContext) {
|
||||
sc.handler(func(c *models.ReqContext) {
|
||||
sc.handlerFunc = func(c *models.ReqContext) {
|
||||
t.Log("Handler called")
|
||||
data := &dtos.IndexViewData{
|
||||
User: &dtos.CurrentUser{},
|
||||
Settings: map[string]interface{}{},
|
||||
NavTree: []*dtos.NavLink{},
|
||||
}
|
||||
t.Log("Calling HTML", "data", data, "render", c.Render)
|
||||
c.HTML(200, "index-template", data)
|
||||
})
|
||||
t.Log("Returned HTML with code 200")
|
||||
}
|
||||
sc.fakeReq("GET", "/").exec()
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
assert.Equal(t, "no-cache", sc.resp.Header().Get("Cache-Control"))
|
||||
assert.Equal(t, "no-cache", sc.resp.Header().Get("Pragma"))
|
||||
require.Equal(t, 200, sc.resp.Code)
|
||||
assert.Equal(t, noCache, sc.resp.Header().Get("Cache-Control"))
|
||||
assert.Equal(t, noCache, sc.resp.Header().Get("Pragma"))
|
||||
assert.Equal(t, "-1", sc.resp.Header().Get("Expires"))
|
||||
})
|
||||
|
||||
@ -150,7 +142,7 @@ func TestMiddlewareContext(t *testing.T) {
|
||||
assert.Equal(t, contexthandler.InvalidAPIKey, sc.respJson["message"])
|
||||
})
|
||||
|
||||
middlewareScenario(t, "Valid api key", func(t *testing.T, sc *scenarioContext) {
|
||||
middlewareScenario(t, "Valid API key", func(t *testing.T, sc *scenarioContext) {
|
||||
const orgID int64 = 12
|
||||
keyhash, err := util.EncodePassword("v5nAwpMafFP6znaS4urhdWDLS5511M42", "asd")
|
||||
require.NoError(t, err)
|
||||
@ -162,15 +154,15 @@ func TestMiddlewareContext(t *testing.T) {
|
||||
|
||||
sc.fakeReq("GET", "/").withValidApiKey().exec()
|
||||
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
require.Equal(t, 200, sc.resp.Code)
|
||||
|
||||
assert.True(t, sc.context.IsSignedIn)
|
||||
assert.Equal(t, orgID, sc.context.OrgId)
|
||||
assert.Equal(t, models.ROLE_EDITOR, sc.context.OrgRole)
|
||||
})
|
||||
|
||||
middlewareScenario(t, "Valid api key, but does not match db hash", func(t *testing.T, sc *scenarioContext) {
|
||||
keyhash := "Something_not_matching"
|
||||
middlewareScenario(t, "Valid API key, but does not match DB hash", func(t *testing.T, sc *scenarioContext) {
|
||||
const keyhash = "Something_not_matching"
|
||||
|
||||
bus.AddHandler("test", func(query *models.GetApiKeyByNameQuery) error {
|
||||
query.Result = &models.ApiKey{OrgId: 12, Role: models.ROLE_EDITOR, Key: keyhash}
|
||||
@ -223,14 +215,16 @@ func TestMiddlewareContext(t *testing.T) {
|
||||
|
||||
sc.fakeReq("GET", "/").exec()
|
||||
|
||||
require.NotNil(t, sc.context)
|
||||
require.NotNil(t, sc.context.UserToken)
|
||||
assert.True(t, sc.context.IsSignedIn)
|
||||
assert.Equal(t, userID, sc.context.UserId)
|
||||
assert.Equal(t, userID, sc.context.UserToken.UserId)
|
||||
assert.Equal(t, "token", sc.context.UserToken.UnhashedToken)
|
||||
assert.Equal(t, "", sc.resp.Header().Get("Set-Cookie"))
|
||||
assert.Empty(t, sc.resp.Header().Get("Set-Cookie"))
|
||||
})
|
||||
|
||||
middlewareScenario(t, "Non-expired auth token in cookie which are being rotated", func(t *testing.T, sc *scenarioContext) {
|
||||
middlewareScenario(t, "Non-expired auth token in cookie which is being rotated", func(t *testing.T, sc *scenarioContext) {
|
||||
const userID int64 = 12
|
||||
|
||||
sc.withTokenSessionCookie("token")
|
||||
@ -253,7 +247,7 @@ func TestMiddlewareContext(t *testing.T) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
maxAge := int(setting.LoginMaxLifetime.Seconds())
|
||||
maxAge := int(sc.cfg.LoginMaxLifetime.Seconds())
|
||||
|
||||
sameSiteModes := []http.SameSite{
|
||||
http.SameSiteNoneMode,
|
||||
@ -269,11 +263,11 @@ func TestMiddlewareContext(t *testing.T) {
|
||||
setting.CookieSameSiteMode = sameSiteMode
|
||||
|
||||
expectedCookiePath := "/"
|
||||
if len(setting.AppSubUrl) > 0 {
|
||||
expectedCookiePath = setting.AppSubUrl
|
||||
if len(sc.cfg.AppSubURL) > 0 {
|
||||
expectedCookiePath = sc.cfg.AppSubURL
|
||||
}
|
||||
expectedCookie := &http.Cookie{
|
||||
Name: setting.LoginCookieName,
|
||||
Name: sc.cfg.LoginCookieName,
|
||||
Value: "rotated",
|
||||
Path: expectedCookiePath,
|
||||
HttpOnly: true,
|
||||
@ -303,11 +297,11 @@ func TestMiddlewareContext(t *testing.T) {
|
||||
setting.CookieSameSiteMode = http.SameSiteLaxMode
|
||||
|
||||
expectedCookiePath := "/"
|
||||
if len(setting.AppSubUrl) > 0 {
|
||||
expectedCookiePath = setting.AppSubUrl
|
||||
if len(sc.cfg.AppSubURL) > 0 {
|
||||
expectedCookiePath = sc.cfg.AppSubURL
|
||||
}
|
||||
expectedCookie := &http.Cookie{
|
||||
Name: setting.LoginCookieName,
|
||||
Name: sc.cfg.LoginCookieName,
|
||||
Value: "rotated",
|
||||
Path: expectedCookiePath,
|
||||
HttpOnly: true,
|
||||
@ -556,6 +550,8 @@ func middlewareScenario(t *testing.T, desc string, fn scenarioFunc, cbs ...func(
|
||||
cfg := setting.NewCfg()
|
||||
cfg.LoginCookieName = "grafana_session"
|
||||
cfg.LoginMaxLifetime = loginMaxLifetime
|
||||
// Required when rendering errors
|
||||
cfg.ErrTemplateName = "error-template"
|
||||
for _, cb := range cbs {
|
||||
cb(cfg)
|
||||
}
|
||||
@ -564,6 +560,9 @@ func middlewareScenario(t *testing.T, desc string, fn scenarioFunc, cbs ...func(
|
||||
|
||||
viewsPath, err := filepath.Abs("../../public/views")
|
||||
require.NoError(t, err)
|
||||
exists, err := fs.Exists(viewsPath)
|
||||
require.NoError(t, err)
|
||||
require.Truef(t, exists, "Views directory should exist at %q", viewsPath)
|
||||
|
||||
sc.m = macaron.New()
|
||||
sc.m.Use(AddDefaultResponseHeaders(cfg))
|
||||
@ -575,7 +574,7 @@ func middlewareScenario(t *testing.T, desc string, fn scenarioFunc, cbs ...func(
|
||||
ctxHdlr := getContextHandler(t, cfg)
|
||||
sc.contextHandler = ctxHdlr
|
||||
sc.m.Use(ctxHdlr.Middleware)
|
||||
sc.m.Use(OrgRedirect())
|
||||
sc.m.Use(OrgRedirect(sc.cfg))
|
||||
|
||||
sc.userAuthTokenService = ctxHdlr.AuthTokenService.(*auth.FakeUserAuthTokenService)
|
||||
sc.remoteCacheService = ctxHdlr.RemoteCache
|
||||
@ -587,6 +586,7 @@ func middlewareScenario(t *testing.T, desc string, fn scenarioFunc, cbs ...func(
|
||||
if sc.handlerFunc != nil {
|
||||
sc.handlerFunc(sc.context)
|
||||
} else {
|
||||
t.Log("Returning JSON OK")
|
||||
resp := make(map[string]interface{})
|
||||
resp["message"] = "OK"
|
||||
c.JSON(200, resp)
|
||||
|
@ -14,7 +14,7 @@ import (
|
||||
|
||||
// OrgRedirect changes org and redirects users if the
|
||||
// querystring `orgId` doesn't match the active org.
|
||||
func OrgRedirect() macaron.Handler {
|
||||
func OrgRedirect(cfg *setting.Cfg) macaron.Handler {
|
||||
return func(res http.ResponseWriter, req *http.Request, c *macaron.Context) {
|
||||
orgIdValue := req.URL.Query().Get("orgId")
|
||||
orgId, err := strconv.ParseInt(orgIdValue, 10, 64)
|
||||
@ -43,7 +43,7 @@ func OrgRedirect() macaron.Handler {
|
||||
return
|
||||
}
|
||||
|
||||
newURL := setting.ToAbsUrl(fmt.Sprintf("%s?%s", strings.TrimPrefix(c.Req.URL.Path, "/"), c.Req.URL.Query().Encode()))
|
||||
newURL := fmt.Sprintf("%s%s?%s", cfg.AppURL, strings.TrimPrefix(c.Req.URL.Path, "/"), c.Req.URL.Query().Encode())
|
||||
c.Redirect(newURL, 302)
|
||||
}
|
||||
}
|
||||
|
@ -10,13 +10,13 @@ import (
|
||||
)
|
||||
|
||||
// Quota returns a function that returns a function used to call quotaservice based on target name
|
||||
func Quota(quotaService *quota.QuotaService) func(target string) macaron.Handler {
|
||||
func Quota(quotaService *quota.QuotaService) func(string) macaron.Handler {
|
||||
//https://open.spotify.com/track/7bZSoBEAEEUsGEuLOf94Jm?si=T1Tdju5qRSmmR0zph_6RBw fuuuuunky
|
||||
return func(target string) macaron.Handler {
|
||||
return func(c *models.ReqContext) {
|
||||
limitReached, err := quotaService.QuotaReached(c, target)
|
||||
if err != nil {
|
||||
c.JsonApiErr(500, "failed to get quota", err)
|
||||
c.JsonApiErr(500, "Failed to get quota", err)
|
||||
return
|
||||
}
|
||||
if limitReached {
|
||||
|
@ -10,11 +10,220 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/quota"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/stretchr/testify/assert"
|
||||
macaron "gopkg.in/macaron.v1"
|
||||
)
|
||||
|
||||
func TestMiddlewareQuota(t *testing.T) {
|
||||
setting.AnonymousEnabled = false
|
||||
setting.Quota = setting.QuotaSettings{
|
||||
t.Run("With user not logged in", func(t *testing.T) {
|
||||
middlewareScenario(t, "and global quota not reached", func(t *testing.T, sc *scenarioContext) {
|
||||
bus.AddHandler("globalQuota", func(query *models.GetGlobalQuotaByTargetQuery) error {
|
||||
query.Result = &models.GlobalQuotaDTO{
|
||||
Target: query.Target,
|
||||
Limit: query.Default,
|
||||
Used: 4,
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
quotaHandler := getQuotaHandler(sc, "user")
|
||||
|
||||
sc.m.Get("/user", quotaHandler, sc.defaultHandler)
|
||||
sc.fakeReq("GET", "/user").exec()
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
}, configure)
|
||||
|
||||
middlewareScenario(t, "and global quota reached", func(t *testing.T, sc *scenarioContext) {
|
||||
bus.AddHandler("globalQuota", func(query *models.GetGlobalQuotaByTargetQuery) error {
|
||||
query.Result = &models.GlobalQuotaDTO{
|
||||
Target: query.Target,
|
||||
Limit: query.Default,
|
||||
Used: 4,
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
quotaHandler := getQuotaHandler(sc, "user")
|
||||
sc.m.Get("/user", quotaHandler, sc.defaultHandler)
|
||||
sc.fakeReq("GET", "/user").exec()
|
||||
assert.Equal(t, 403, sc.resp.Code)
|
||||
}, func(cfg *setting.Cfg) {
|
||||
configure(cfg)
|
||||
|
||||
cfg.Quota.Global.User = 4
|
||||
})
|
||||
|
||||
middlewareScenario(t, "and global session quota not reached", func(t *testing.T, sc *scenarioContext) {
|
||||
bus.AddHandler("globalQuota", func(query *models.GetGlobalQuotaByTargetQuery) error {
|
||||
query.Result = &models.GlobalQuotaDTO{
|
||||
Target: query.Target,
|
||||
Limit: query.Default,
|
||||
Used: 4,
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
quotaHandler := getQuotaHandler(sc, "session")
|
||||
sc.m.Get("/user", quotaHandler, sc.defaultHandler)
|
||||
sc.fakeReq("GET", "/user").exec()
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
}, func(cfg *setting.Cfg) {
|
||||
configure(cfg)
|
||||
|
||||
cfg.Quota.Global.Session = 10
|
||||
})
|
||||
|
||||
middlewareScenario(t, "and global session quota reached", func(t *testing.T, sc *scenarioContext) {
|
||||
quotaHandler := getQuotaHandler(sc, "session")
|
||||
sc.m.Get("/user", quotaHandler, sc.defaultHandler)
|
||||
sc.fakeReq("GET", "/user").exec()
|
||||
assert.Equal(t, 403, sc.resp.Code)
|
||||
}, func(cfg *setting.Cfg) {
|
||||
configure(cfg)
|
||||
|
||||
cfg.Quota.Global.Session = 1
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("with user logged in", func(t *testing.T) {
|
||||
const quotaUsed = 4
|
||||
|
||||
setUp := func(sc *scenarioContext) {
|
||||
sc.withTokenSessionCookie("token")
|
||||
bus.AddHandler("test", func(query *models.GetSignedInUserQuery) error {
|
||||
query.Result = &models.SignedInUser{OrgId: 2, UserId: 12}
|
||||
return nil
|
||||
})
|
||||
|
||||
sc.userAuthTokenService.LookupTokenProvider = func(ctx context.Context, unhashedToken string) (*models.UserToken, error) {
|
||||
return &models.UserToken{
|
||||
UserId: 12,
|
||||
UnhashedToken: "",
|
||||
}, nil
|
||||
}
|
||||
|
||||
bus.AddHandler("globalQuota", func(query *models.GetGlobalQuotaByTargetQuery) error {
|
||||
query.Result = &models.GlobalQuotaDTO{
|
||||
Target: query.Target,
|
||||
Limit: query.Default,
|
||||
Used: quotaUsed,
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
bus.AddHandler("userQuota", func(query *models.GetUserQuotaByTargetQuery) error {
|
||||
query.Result = &models.UserQuotaDTO{
|
||||
Target: query.Target,
|
||||
Limit: query.Default,
|
||||
Used: quotaUsed,
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
bus.AddHandler("orgQuota", func(query *models.GetOrgQuotaByTargetQuery) error {
|
||||
query.Result = &models.OrgQuotaDTO{
|
||||
Target: query.Target,
|
||||
Limit: query.Default,
|
||||
Used: quotaUsed,
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
middlewareScenario(t, "global datasource quota reached", func(t *testing.T, sc *scenarioContext) {
|
||||
setUp(sc)
|
||||
|
||||
quotaHandler := getQuotaHandler(sc, "data_source")
|
||||
sc.m.Get("/ds", quotaHandler, sc.defaultHandler)
|
||||
sc.fakeReq("GET", "/ds").exec()
|
||||
assert.Equal(t, 403, sc.resp.Code)
|
||||
}, func(cfg *setting.Cfg) {
|
||||
configure(cfg)
|
||||
|
||||
cfg.Quota.Global.DataSource = quotaUsed
|
||||
})
|
||||
|
||||
middlewareScenario(t, "user Org quota not reached", func(t *testing.T, sc *scenarioContext) {
|
||||
setUp(sc)
|
||||
|
||||
quotaHandler := getQuotaHandler(sc, "org")
|
||||
|
||||
sc.m.Get("/org", quotaHandler, sc.defaultHandler)
|
||||
sc.fakeReq("GET", "/org").exec()
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
}, func(cfg *setting.Cfg) {
|
||||
configure(cfg)
|
||||
|
||||
cfg.Quota.User.Org = quotaUsed + 1
|
||||
})
|
||||
|
||||
middlewareScenario(t, "user Org quota reached", func(t *testing.T, sc *scenarioContext) {
|
||||
setUp(sc)
|
||||
|
||||
quotaHandler := getQuotaHandler(sc, "org")
|
||||
sc.m.Get("/org", quotaHandler, sc.defaultHandler)
|
||||
sc.fakeReq("GET", "/org").exec()
|
||||
assert.Equal(t, 403, sc.resp.Code)
|
||||
}, func(cfg *setting.Cfg) {
|
||||
configure(cfg)
|
||||
|
||||
cfg.Quota.User.Org = quotaUsed
|
||||
})
|
||||
|
||||
middlewareScenario(t, "org dashboard quota not reached", func(t *testing.T, sc *scenarioContext) {
|
||||
setUp(sc)
|
||||
|
||||
quotaHandler := getQuotaHandler(sc, "dashboard")
|
||||
sc.m.Get("/dashboard", quotaHandler, sc.defaultHandler)
|
||||
sc.fakeReq("GET", "/dashboard").exec()
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
}, func(cfg *setting.Cfg) {
|
||||
configure(cfg)
|
||||
|
||||
cfg.Quota.Org.Dashboard = quotaUsed + 1
|
||||
})
|
||||
|
||||
middlewareScenario(t, "org dashboard quota reached", func(t *testing.T, sc *scenarioContext) {
|
||||
setUp(sc)
|
||||
|
||||
quotaHandler := getQuotaHandler(sc, "dashboard")
|
||||
sc.m.Get("/dashboard", quotaHandler, sc.defaultHandler)
|
||||
sc.fakeReq("GET", "/dashboard").exec()
|
||||
assert.Equal(t, 403, sc.resp.Code)
|
||||
}, func(cfg *setting.Cfg) {
|
||||
configure(cfg)
|
||||
|
||||
cfg.Quota.Org.Dashboard = quotaUsed
|
||||
})
|
||||
|
||||
middlewareScenario(t, "org dashboard quota reached, but quotas disabled", func(t *testing.T, sc *scenarioContext) {
|
||||
setUp(sc)
|
||||
|
||||
quotaHandler := getQuotaHandler(sc, "dashboard")
|
||||
sc.m.Get("/dashboard", quotaHandler, sc.defaultHandler)
|
||||
sc.fakeReq("GET", "/dashboard").exec()
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
}, func(cfg *setting.Cfg) {
|
||||
configure(cfg)
|
||||
|
||||
cfg.Quota.Org.Dashboard = quotaUsed
|
||||
cfg.Quota.Enabled = false
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func getQuotaHandler(sc *scenarioContext, target string) macaron.Handler {
|
||||
fakeAuthTokenService := auth.NewFakeUserAuthTokenService()
|
||||
qs := "a.QuotaService{
|
||||
AuthTokenService: fakeAuthTokenService,
|
||||
Cfg: sc.cfg,
|
||||
}
|
||||
|
||||
return Quota(qs)(target)
|
||||
}
|
||||
|
||||
func configure(cfg *setting.Cfg) {
|
||||
cfg.AnonymousEnabled = false
|
||||
cfg.Quota = setting.QuotaSettings{
|
||||
Enabled: true,
|
||||
Org: &setting.OrgQuota{
|
||||
User: 5,
|
||||
@ -34,166 +243,4 @@ func TestMiddlewareQuota(t *testing.T) {
|
||||
Session: 5,
|
||||
},
|
||||
}
|
||||
|
||||
fakeAuthTokenService := auth.NewFakeUserAuthTokenService()
|
||||
qs := "a.QuotaService{
|
||||
AuthTokenService: fakeAuthTokenService,
|
||||
}
|
||||
quotaFn := Quota(qs)
|
||||
|
||||
t.Run("With user not logged in", func(t *testing.T) {
|
||||
middlewareScenario(t, "and global quota not reached", func(t *testing.T, sc *scenarioContext) {
|
||||
bus.AddHandler("globalQuota", func(query *models.GetGlobalQuotaByTargetQuery) error {
|
||||
query.Result = &models.GlobalQuotaDTO{
|
||||
Target: query.Target,
|
||||
Limit: query.Default,
|
||||
Used: 4,
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
sc.m.Get("/user", quotaFn("user"), sc.defaultHandler)
|
||||
sc.fakeReq("GET", "/user").exec()
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
})
|
||||
|
||||
middlewareScenario(t, "and global quota reached", func(t *testing.T, sc *scenarioContext) {
|
||||
bus.AddHandler("globalQuota", func(query *models.GetGlobalQuotaByTargetQuery) error {
|
||||
query.Result = &models.GlobalQuotaDTO{
|
||||
Target: query.Target,
|
||||
Limit: query.Default,
|
||||
Used: 4,
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
origUser := setting.Quota.Global.User
|
||||
t.Cleanup(func() {
|
||||
setting.Quota.Global.User = origUser
|
||||
})
|
||||
setting.Quota.Global.User = 4
|
||||
|
||||
sc.m.Get("/user", quotaFn("user"), sc.defaultHandler)
|
||||
sc.fakeReq("GET", "/user").exec()
|
||||
assert.Equal(t, 403, sc.resp.Code)
|
||||
})
|
||||
|
||||
middlewareScenario(t, "and global session quota not reached", func(t *testing.T, sc *scenarioContext) {
|
||||
bus.AddHandler("globalQuota", func(query *models.GetGlobalQuotaByTargetQuery) error {
|
||||
query.Result = &models.GlobalQuotaDTO{
|
||||
Target: query.Target,
|
||||
Limit: query.Default,
|
||||
Used: 4,
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
origSession := setting.Quota.Global.Session
|
||||
t.Cleanup(func() {
|
||||
setting.Quota.Global.Session = origSession
|
||||
})
|
||||
setting.Quota.Global.Session = 10
|
||||
|
||||
sc.m.Get("/user", quotaFn("session"), sc.defaultHandler)
|
||||
sc.fakeReq("GET", "/user").exec()
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
})
|
||||
|
||||
middlewareScenario(t, "and global session quota reached", func(t *testing.T, sc *scenarioContext) {
|
||||
origSession := setting.Quota.Global.Session
|
||||
t.Cleanup(func() {
|
||||
setting.Quota.Global.Session = origSession
|
||||
})
|
||||
setting.Quota.Global.Session = 1
|
||||
|
||||
sc.m.Get("/user", quotaFn("session"), sc.defaultHandler)
|
||||
sc.fakeReq("GET", "/user").exec()
|
||||
assert.Equal(t, 403, sc.resp.Code)
|
||||
})
|
||||
})
|
||||
|
||||
middlewareScenario(t, "with user logged in", func(t *testing.T, sc *scenarioContext) {
|
||||
sc.withTokenSessionCookie("token")
|
||||
bus.AddHandler("test", func(query *models.GetSignedInUserQuery) error {
|
||||
query.Result = &models.SignedInUser{OrgId: 2, UserId: 12}
|
||||
return nil
|
||||
})
|
||||
|
||||
sc.userAuthTokenService.LookupTokenProvider = func(ctx context.Context, unhashedToken string) (*models.UserToken, error) {
|
||||
return &models.UserToken{
|
||||
UserId: 12,
|
||||
UnhashedToken: "",
|
||||
}, nil
|
||||
}
|
||||
|
||||
bus.AddHandler("globalQuota", func(query *models.GetGlobalQuotaByTargetQuery) error {
|
||||
query.Result = &models.GlobalQuotaDTO{
|
||||
Target: query.Target,
|
||||
Limit: query.Default,
|
||||
Used: 4,
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
bus.AddHandler("userQuota", func(query *models.GetUserQuotaByTargetQuery) error {
|
||||
query.Result = &models.UserQuotaDTO{
|
||||
Target: query.Target,
|
||||
Limit: query.Default,
|
||||
Used: 4,
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
bus.AddHandler("orgQuota", func(query *models.GetOrgQuotaByTargetQuery) error {
|
||||
query.Result = &models.OrgQuotaDTO{
|
||||
Target: query.Target,
|
||||
Limit: query.Default,
|
||||
Used: 4,
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
t.Run("global datasource quota reached", func(t *testing.T) {
|
||||
setting.Quota.Global.DataSource = 4
|
||||
sc.m.Get("/ds", quotaFn("data_source"), sc.defaultHandler)
|
||||
sc.fakeReq("GET", "/ds").exec()
|
||||
assert.Equal(t, 403, sc.resp.Code)
|
||||
})
|
||||
|
||||
t.Run("user Org quota not reached", func(t *testing.T) {
|
||||
setting.Quota.User.Org = 5
|
||||
sc.m.Get("/org", quotaFn("org"), sc.defaultHandler)
|
||||
sc.fakeReq("GET", "/org").exec()
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
})
|
||||
|
||||
t.Run("user Org quota reached", func(t *testing.T) {
|
||||
setting.Quota.User.Org = 4
|
||||
sc.m.Get("/org", quotaFn("org"), sc.defaultHandler)
|
||||
sc.fakeReq("GET", "/org").exec()
|
||||
assert.Equal(t, 403, sc.resp.Code)
|
||||
})
|
||||
|
||||
t.Run("org dashboard quota not reached", func(t *testing.T) {
|
||||
setting.Quota.Org.Dashboard = 10
|
||||
sc.m.Get("/dashboard", quotaFn("dashboard"), sc.defaultHandler)
|
||||
sc.fakeReq("GET", "/dashboard").exec()
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
})
|
||||
|
||||
t.Run("org dashboard quota reached", func(t *testing.T) {
|
||||
setting.Quota.Org.Dashboard = 4
|
||||
sc.m.Get("/dashboard", quotaFn("dashboard"), sc.defaultHandler)
|
||||
sc.fakeReq("GET", "/dashboard").exec()
|
||||
assert.Equal(t, 403, sc.resp.Code)
|
||||
})
|
||||
|
||||
t.Run("org dashboard quota reached but quotas disabled", func(t *testing.T) {
|
||||
setting.Quota.Org.Dashboard = 4
|
||||
setting.Quota.Enabled = false
|
||||
sc.m.Get("/dashboard", quotaFn("dashboard"), sc.defaultHandler)
|
||||
sc.fakeReq("GET", "/dashboard").exec()
|
||||
assert.Equal(t, 200, sc.resp.Code)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ import (
|
||||
func TestRecoveryMiddleware(t *testing.T) {
|
||||
t.Run("Given an API route that panics", func(t *testing.T) {
|
||||
apiURL := "/api/whatever"
|
||||
recoveryScenario(t, "recovery middleware should return json", apiURL, func(t *testing.T, sc *scenarioContext) {
|
||||
recoveryScenario(t, "recovery middleware should return JSON", apiURL, func(t *testing.T, sc *scenarioContext) {
|
||||
sc.handlerFunc = panicHandler
|
||||
sc.fakeReq("GET", apiURL).exec()
|
||||
sc.req.Header.Set("content-type", "application/json")
|
||||
@ -37,7 +37,7 @@ func TestRecoveryMiddleware(t *testing.T) {
|
||||
|
||||
assert.Equal(t, 500, sc.resp.Code)
|
||||
assert.Equal(t, "text/html; charset=UTF-8", sc.resp.Header().Get("content-type"))
|
||||
assert.True(t, strings.Contains(sc.resp.Body.String(), "<title>Grafana - Error</title>"))
|
||||
assert.Contains(t, sc.resp.Body.String(), "<title>Grafana - Error</title>")
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -76,7 +76,7 @@ func recoveryScenario(t *testing.T, desc string, url string, fn scenarioFunc) {
|
||||
contextHandler := getContextHandler(t, nil)
|
||||
sc.m.Use(contextHandler.Middleware)
|
||||
// mock out gc goroutine
|
||||
sc.m.Use(OrgRedirect())
|
||||
sc.m.Use(OrgRedirect(cfg))
|
||||
|
||||
sc.defaultHandler = func(c *models.ReqContext) {
|
||||
sc.context = c
|
||||
|
@ -67,6 +67,8 @@ func (sc *scenarioContext) fakeReqWithParams(method, url string, queryParams map
|
||||
|
||||
sc.resp = httptest.NewRecorder()
|
||||
req, err := http.NewRequest(method, url, nil)
|
||||
require.NoError(sc.t, err)
|
||||
|
||||
q := req.URL.Query()
|
||||
for k, v := range queryParams {
|
||||
q.Add(k, v)
|
||||
@ -78,11 +80,6 @@ func (sc *scenarioContext) fakeReqWithParams(method, url string, queryParams map
|
||||
return sc
|
||||
}
|
||||
|
||||
func (sc *scenarioContext) handler(fn handlerFunc) *scenarioContext {
|
||||
sc.handlerFunc = fn
|
||||
return sc
|
||||
}
|
||||
|
||||
func (sc *scenarioContext) exec() {
|
||||
sc.t.Helper()
|
||||
|
||||
@ -109,6 +106,9 @@ func (sc *scenarioContext) exec() {
|
||||
if sc.resp.Header().Get("Content-Type") == "application/json; charset=UTF-8" {
|
||||
err := json.NewDecoder(sc.resp.Body).Decode(&sc.respJson)
|
||||
require.NoError(sc.t, err)
|
||||
sc.t.Log("Decoded JSON", "json", sc.respJson)
|
||||
} else {
|
||||
sc.t.Log("Not decoding JSON")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
"gopkg.in/macaron.v1"
|
||||
)
|
||||
|
||||
func ValidateHostHeader(domain string) macaron.Handler {
|
||||
func ValidateHostHeader(cfg *setting.Cfg) macaron.Handler {
|
||||
return func(c *models.ReqContext) {
|
||||
// ignore local render calls
|
||||
if c.IsRenderCall {
|
||||
@ -20,8 +20,8 @@ func ValidateHostHeader(domain string) macaron.Handler {
|
||||
h = h[:i]
|
||||
}
|
||||
|
||||
if !strings.EqualFold(h, domain) {
|
||||
c.Redirect(strings.TrimSuffix(setting.AppUrl, "/")+c.Req.RequestURI, 301)
|
||||
if !strings.EqualFold(h, cfg.Domain) {
|
||||
c.Redirect(strings.TrimSuffix(cfg.AppURL, "/")+c.Req.RequestURI, 301)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ type ReqContext struct {
|
||||
}
|
||||
|
||||
// Handle handles and logs error by given status.
|
||||
func (ctx *ReqContext) Handle(status int, title string, err error) {
|
||||
func (ctx *ReqContext) Handle(cfg *setting.Cfg, status int, title string, err error) {
|
||||
if err != nil {
|
||||
ctx.Logger.Error(title, "error", err)
|
||||
if setting.Env != setting.Prod {
|
||||
@ -31,10 +31,10 @@ func (ctx *ReqContext) Handle(status int, title string, err error) {
|
||||
}
|
||||
|
||||
ctx.Data["Title"] = title
|
||||
ctx.Data["AppSubUrl"] = setting.AppSubUrl
|
||||
ctx.Data["AppSubUrl"] = cfg.AppSubURL
|
||||
ctx.Data["Theme"] = "dark"
|
||||
|
||||
ctx.HTML(status, setting.ErrTemplateName)
|
||||
ctx.HTML(status, cfg.ErrTemplateName)
|
||||
}
|
||||
|
||||
func (ctx *ReqContext) IsApiRequest() bool {
|
||||
|
@ -307,17 +307,17 @@ func GetDashboardFolderUrl(isFolder bool, uid string, slug string) string {
|
||||
return GetDashboardUrl(uid, slug)
|
||||
}
|
||||
|
||||
// GetDashboardUrl return the html url for a dashboard
|
||||
// GetDashboardUrl returns the HTML url for a dashboard.
|
||||
func GetDashboardUrl(uid string, slug string) string {
|
||||
return fmt.Sprintf("%s/d/%s/%s", setting.AppSubUrl, uid, slug)
|
||||
}
|
||||
|
||||
// GetFullDashboardUrl return the full url for a dashboard
|
||||
// GetFullDashboardUrl returns the full URL for a dashboard.
|
||||
func GetFullDashboardUrl(uid string, slug string) string {
|
||||
return fmt.Sprintf("%sd/%s/%s", setting.AppUrl, uid, slug)
|
||||
}
|
||||
|
||||
// GetFolderUrl return the html url for a folder
|
||||
// GetFolderUrl returns the HTML url for a folder.
|
||||
func GetFolderUrl(folderUid string, slug string) string {
|
||||
return fmt.Sprintf("%s/dashboards/f/%s/%s", setting.AppSubUrl, folderUid, slug)
|
||||
}
|
||||
|
@ -3,8 +3,6 @@ package models
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
var ErrInvalidQuotaTarget = errors.New("invalid quota target")
|
||||
@ -86,46 +84,3 @@ type UpdateUserQuotaCmd struct {
|
||||
Limit int64 `json:"limit"`
|
||||
UserId int64 `json:"-"`
|
||||
}
|
||||
|
||||
func GetQuotaScopes(target string) ([]QuotaScope, error) {
|
||||
scopes := make([]QuotaScope, 0)
|
||||
switch target {
|
||||
case "user":
|
||||
scopes = append(scopes,
|
||||
QuotaScope{Name: "global", Target: target, DefaultLimit: setting.Quota.Global.User},
|
||||
QuotaScope{Name: "org", Target: "org_user", DefaultLimit: setting.Quota.Org.User},
|
||||
)
|
||||
return scopes, nil
|
||||
case "org":
|
||||
scopes = append(scopes,
|
||||
QuotaScope{Name: "global", Target: target, DefaultLimit: setting.Quota.Global.Org},
|
||||
QuotaScope{Name: "user", Target: "org_user", DefaultLimit: setting.Quota.User.Org},
|
||||
)
|
||||
return scopes, nil
|
||||
case "dashboard":
|
||||
scopes = append(scopes,
|
||||
QuotaScope{Name: "global", Target: target, DefaultLimit: setting.Quota.Global.Dashboard},
|
||||
QuotaScope{Name: "org", Target: target, DefaultLimit: setting.Quota.Org.Dashboard},
|
||||
)
|
||||
return scopes, nil
|
||||
case "data_source":
|
||||
scopes = append(scopes,
|
||||
QuotaScope{Name: "global", Target: target, DefaultLimit: setting.Quota.Global.DataSource},
|
||||
QuotaScope{Name: "org", Target: target, DefaultLimit: setting.Quota.Org.DataSource},
|
||||
)
|
||||
return scopes, nil
|
||||
case "api_key":
|
||||
scopes = append(scopes,
|
||||
QuotaScope{Name: "global", Target: target, DefaultLimit: setting.Quota.Global.ApiKey},
|
||||
QuotaScope{Name: "org", Target: target, DefaultLimit: setting.Quota.Org.ApiKey},
|
||||
)
|
||||
return scopes, nil
|
||||
case "session":
|
||||
scopes = append(scopes,
|
||||
QuotaScope{Name: "global", Target: target, DefaultLimit: setting.Quota.Global.Session},
|
||||
)
|
||||
return scopes, nil
|
||||
default:
|
||||
return scopes, ErrInvalidQuotaTarget
|
||||
}
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ type Options struct {
|
||||
OrgID int64
|
||||
}
|
||||
|
||||
// New instance of the AuthProxy
|
||||
// New instance of the AuthProxy.
|
||||
func New(cfg *setting.Cfg, options *Options) *AuthProxy {
|
||||
header := options.Ctx.Req.Header.Get(cfg.AuthProxyHeaderName)
|
||||
return &AuthProxy{
|
||||
@ -93,7 +93,7 @@ func New(cfg *setting.Cfg, options *Options) *AuthProxy {
|
||||
}
|
||||
}
|
||||
|
||||
// IsEnabled checks if the proxy auth is enabled
|
||||
// IsEnabled checks if the auth proxy is enabled.
|
||||
func (auth *AuthProxy) IsEnabled() bool {
|
||||
// Bail if the setting is not enabled
|
||||
return auth.cfg.AuthProxyEnabled
|
||||
|
@ -350,13 +350,13 @@ func logUserIn(auth *authproxy.AuthProxy, username string, logger log.Logger, ig
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func handleError(ctx *models.ReqContext, err error, statusCode int, cb func(error)) {
|
||||
func (h *ContextHandler) handleError(ctx *models.ReqContext, err error, statusCode int, cb func(error)) {
|
||||
details := err
|
||||
var e authproxy.Error
|
||||
if errors.As(err, &e) {
|
||||
details = e.DetailsError
|
||||
}
|
||||
ctx.Handle(statusCode, err.Error(), details)
|
||||
ctx.Handle(h.Cfg, statusCode, err.Error(), details)
|
||||
|
||||
if cb != nil {
|
||||
cb(details)
|
||||
@ -385,7 +385,7 @@ func (h *ContextHandler) initContextWithAuthProxy(ctx *models.ReqContext, orgID
|
||||
|
||||
// Check if allowed to continue with this IP
|
||||
if err := auth.IsAllowedIP(); err != nil {
|
||||
handleError(ctx, err, 407, func(details error) {
|
||||
h.handleError(ctx, err, 407, func(details error) {
|
||||
logger.Error("Failed to check whitelisted IP addresses", "message", err.Error(), "error", details)
|
||||
})
|
||||
return true
|
||||
@ -393,7 +393,7 @@ func (h *ContextHandler) initContextWithAuthProxy(ctx *models.ReqContext, orgID
|
||||
|
||||
id, err := logUserIn(auth, username, logger, false)
|
||||
if err != nil {
|
||||
handleError(ctx, err, 407, nil)
|
||||
h.handleError(ctx, err, 407, nil)
|
||||
return true
|
||||
}
|
||||
|
||||
@ -414,13 +414,13 @@ func (h *ContextHandler) initContextWithAuthProxy(ctx *models.ReqContext, orgID
|
||||
}
|
||||
id, err = logUserIn(auth, username, logger, true)
|
||||
if err != nil {
|
||||
handleError(ctx, err, 407, nil)
|
||||
h.handleError(ctx, err, 407, nil)
|
||||
return true
|
||||
}
|
||||
|
||||
user, err = auth.GetSignedInUser(id)
|
||||
if err != nil {
|
||||
handleError(ctx, err, 407, nil)
|
||||
h.handleError(ctx, err, 407, nil)
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -433,7 +433,7 @@ func (h *ContextHandler) initContextWithAuthProxy(ctx *models.ReqContext, orgID
|
||||
|
||||
// Remember user data in cache
|
||||
if err := auth.Remember(id); err != nil {
|
||||
handleError(ctx, err, 500, func(details error) {
|
||||
h.handleError(ctx, err, 500, func(details error) {
|
||||
logger.Error(
|
||||
"Failed to store user in cache",
|
||||
"username", username,
|
||||
|
@ -11,7 +11,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/auth"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@ -22,7 +21,7 @@ func TestDontRotateTokensOnCancelledRequests(t *testing.T) {
|
||||
ctxHdlr := getContextHandler(t)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
reqContext, _, err := initTokenRotationScenario(ctx, t)
|
||||
reqContext, _, err := initTokenRotationScenario(ctx, t, ctxHdlr)
|
||||
require.NoError(t, err)
|
||||
|
||||
tryRotateCallCount := 0
|
||||
@ -46,7 +45,7 @@ func TestDontRotateTokensOnCancelledRequests(t *testing.T) {
|
||||
func TestTokenRotationAtEndOfRequest(t *testing.T) {
|
||||
ctxHdlr := getContextHandler(t)
|
||||
|
||||
reqContext, rr, err := initTokenRotationScenario(context.Background(), t)
|
||||
reqContext, rr, err := initTokenRotationScenario(context.Background(), t, ctxHdlr)
|
||||
require.NoError(t, err)
|
||||
|
||||
uts := &auth.FakeUserAuthTokenService{
|
||||
@ -80,18 +79,13 @@ func TestTokenRotationAtEndOfRequest(t *testing.T) {
|
||||
assert.True(t, foundLoginCookie, "Could not find cookie")
|
||||
}
|
||||
|
||||
func initTokenRotationScenario(ctx context.Context, t *testing.T) (*models.ReqContext, *httptest.ResponseRecorder, error) {
|
||||
func initTokenRotationScenario(ctx context.Context, t *testing.T, ctxHdlr *ContextHandler) (
|
||||
*models.ReqContext, *httptest.ResponseRecorder, error) {
|
||||
t.Helper()
|
||||
|
||||
origLoginCookieName := setting.LoginCookieName
|
||||
origLoginMaxLifetime := setting.LoginMaxLifetime
|
||||
t.Cleanup(func() {
|
||||
setting.LoginCookieName = origLoginCookieName
|
||||
setting.LoginMaxLifetime = origLoginMaxLifetime
|
||||
})
|
||||
setting.LoginCookieName = "login_token"
|
||||
ctxHdlr.Cfg.LoginCookieName = "login_token"
|
||||
var err error
|
||||
setting.LoginMaxLifetime, err = gtime.ParseDuration("7d")
|
||||
ctxHdlr.Cfg.LoginMaxLifetime, err = gtime.ParseDuration("7d")
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
@ -1,18 +1,23 @@
|
||||
package quota
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/registry"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
var ErrInvalidQuotaTarget = errors.New("invalid quota target")
|
||||
|
||||
func init() {
|
||||
registry.RegisterService(&QuotaService{})
|
||||
}
|
||||
|
||||
type QuotaService struct {
|
||||
AuthTokenService models.UserTokenService `inject:""`
|
||||
Cfg *setting.Cfg `inject:""`
|
||||
}
|
||||
|
||||
func (qs *QuotaService) Init() error {
|
||||
@ -20,7 +25,7 @@ func (qs *QuotaService) Init() error {
|
||||
}
|
||||
|
||||
func (qs *QuotaService) QuotaReached(c *models.ReqContext, target string) (bool, error) {
|
||||
if !setting.Quota.Enabled {
|
||||
if !qs.Cfg.Quota.Enabled {
|
||||
return false, nil
|
||||
}
|
||||
// No request context means this is a background service, like LDAP Background Sync.
|
||||
@ -29,8 +34,9 @@ func (qs *QuotaService) QuotaReached(c *models.ReqContext, target string) (bool,
|
||||
if c == nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// get the list of scopes that this target is valid for. Org, User, Global
|
||||
scopes, err := models.GetQuotaScopes(target)
|
||||
scopes, err := qs.getQuotaScopes(target)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@ -106,3 +112,46 @@ func (qs *QuotaService) QuotaReached(c *models.ReqContext, target string) (bool,
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (qs *QuotaService) getQuotaScopes(target string) ([]models.QuotaScope, error) {
|
||||
scopes := make([]models.QuotaScope, 0)
|
||||
switch target {
|
||||
case "user":
|
||||
scopes = append(scopes,
|
||||
models.QuotaScope{Name: "global", Target: target, DefaultLimit: qs.Cfg.Quota.Global.User},
|
||||
models.QuotaScope{Name: "org", Target: "org_user", DefaultLimit: qs.Cfg.Quota.Org.User},
|
||||
)
|
||||
return scopes, nil
|
||||
case "org":
|
||||
scopes = append(scopes,
|
||||
models.QuotaScope{Name: "global", Target: target, DefaultLimit: qs.Cfg.Quota.Global.Org},
|
||||
models.QuotaScope{Name: "user", Target: "org_user", DefaultLimit: qs.Cfg.Quota.User.Org},
|
||||
)
|
||||
return scopes, nil
|
||||
case "dashboard":
|
||||
scopes = append(scopes,
|
||||
models.QuotaScope{Name: "global", Target: target, DefaultLimit: qs.Cfg.Quota.Global.Dashboard},
|
||||
models.QuotaScope{Name: "org", Target: target, DefaultLimit: qs.Cfg.Quota.Org.Dashboard},
|
||||
)
|
||||
return scopes, nil
|
||||
case "data_source":
|
||||
scopes = append(scopes,
|
||||
models.QuotaScope{Name: "global", Target: target, DefaultLimit: qs.Cfg.Quota.Global.DataSource},
|
||||
models.QuotaScope{Name: "org", Target: target, DefaultLimit: qs.Cfg.Quota.Org.DataSource},
|
||||
)
|
||||
return scopes, nil
|
||||
case "api_key":
|
||||
scopes = append(scopes,
|
||||
models.QuotaScope{Name: "global", Target: target, DefaultLimit: qs.Cfg.Quota.Global.ApiKey},
|
||||
models.QuotaScope{Name: "org", Target: target, DefaultLimit: qs.Cfg.Quota.Org.ApiKey},
|
||||
)
|
||||
return scopes, nil
|
||||
case "session":
|
||||
scopes = append(scopes,
|
||||
models.QuotaScope{Name: "global", Target: target, DefaultLimit: qs.Cfg.Quota.Global.Session},
|
||||
)
|
||||
return scopes, nil
|
||||
default:
|
||||
return scopes, ErrInvalidQuotaTarget
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package sqlstore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
@ -275,14 +274,3 @@ func getOrCreateOrg(sess *DBSession, orgName string) (int64, error) {
|
||||
|
||||
return org.Id, nil
|
||||
}
|
||||
|
||||
func createDefaultOrg(ctx context.Context) error {
|
||||
return inTransactionCtx(ctx, func(sess *DBSession) error {
|
||||
_, err := getOrCreateOrg(sess, mainOrgName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
@ -118,10 +118,13 @@ func (ss *SQLStore) Init() error {
|
||||
|
||||
func (ss *SQLStore) ensureMainOrgAndAdminUser() error {
|
||||
err := ss.InTransaction(context.Background(), func(ctx context.Context) error {
|
||||
ss.log.Debug("Ensuring main org and admin user exist")
|
||||
var stats models.SystemUserCountStats
|
||||
err := ss.WithDbSession(ctx, func(sess *DBSession) error {
|
||||
var rawSql = `SELECT COUNT(id) AS Count FROM ` + dialect.Quote("user")
|
||||
if _, err := sess.SQL(rawSql).Get(&stats); err != nil {
|
||||
// TODO: Should be able to rename "Count" to "count", for more standard SQL style
|
||||
// Just have to make sure it gets deserialized properly into models.SystemUserCountStats
|
||||
rawSQL := `SELECT COUNT(id) AS Count FROM ` + dialect.Quote("user")
|
||||
if _, err := sess.SQL(rawSQL).Get(&stats); err != nil {
|
||||
return fmt.Errorf("could not determine if admin user exists: %w", err)
|
||||
}
|
||||
|
||||
@ -137,23 +140,27 @@ func (ss *SQLStore) ensureMainOrgAndAdminUser() error {
|
||||
|
||||
// ensure admin user
|
||||
if !ss.Cfg.DisableInitAdminCreation {
|
||||
cmd := models.CreateUserCommand{}
|
||||
cmd.Login = setting.AdminUser
|
||||
cmd.Email = setting.AdminUser + "@localhost"
|
||||
cmd.Password = setting.AdminPassword
|
||||
cmd.IsAdmin = true
|
||||
|
||||
ss.log.Debug("Creating default admin user")
|
||||
cmd := models.CreateUserCommand{
|
||||
Login: ss.Cfg.AdminUser,
|
||||
Email: ss.Cfg.AdminUser + "@localhost",
|
||||
Password: ss.Cfg.AdminPassword,
|
||||
IsAdmin: true,
|
||||
}
|
||||
if err := bus.DispatchCtx(ctx, &cmd); err != nil {
|
||||
return fmt.Errorf("failed to create admin user: %s", err)
|
||||
}
|
||||
|
||||
ss.log.Info("Created default admin", "user", setting.AdminUser)
|
||||
ss.log.Info("Created default admin", "user", ss.Cfg.AdminUser)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ensure default org if default admin user is disabled
|
||||
if err := createDefaultOrg(ctx); err != nil {
|
||||
return errutil.Wrap("Failed to create default organization", err)
|
||||
// ensure default org even if default admin user is disabled
|
||||
if err := inTransactionCtx(ctx, func(sess *DBSession) error {
|
||||
_, err := getOrCreateOrg(sess, mainOrgName)
|
||||
return err
|
||||
}); err != nil {
|
||||
return fmt.Errorf("failed to create default organization: %w", err)
|
||||
}
|
||||
|
||||
ss.log.Info("Created default organization")
|
||||
|
@ -40,10 +40,6 @@ const (
|
||||
Test = "test"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrTemplateName = "error"
|
||||
)
|
||||
|
||||
// This constant corresponds to the default value for ldap_sync_ttl in .ini files
|
||||
// it is used for comparison and has to be kept in sync
|
||||
const (
|
||||
@ -126,10 +122,6 @@ var (
|
||||
ViewersCanEdit bool
|
||||
|
||||
// HTTP auth
|
||||
AdminUser string
|
||||
AdminPassword string
|
||||
LoginCookieName string
|
||||
LoginMaxLifetime time.Duration
|
||||
SigV4AuthEnabled bool
|
||||
|
||||
AnonymousEnabled bool
|
||||
@ -271,6 +263,8 @@ type Cfg struct {
|
||||
TokenRotationIntervalMinutes int
|
||||
SigV4AuthEnabled bool
|
||||
BasicAuthEnabled bool
|
||||
AdminUser string
|
||||
AdminPassword string
|
||||
|
||||
// Auth proxy settings
|
||||
AuthProxyEnabled bool
|
||||
@ -724,7 +718,7 @@ func (cfg *Cfg) Load(args *CommandLineArgs) error {
|
||||
cfg.IsEnterprise = IsEnterprise
|
||||
cfg.Packaging = Packaging
|
||||
|
||||
cfg.ErrTemplateName = ErrTemplateName
|
||||
cfg.ErrTemplateName = "error"
|
||||
|
||||
ApplicationName = "Grafana"
|
||||
|
||||
@ -1013,8 +1007,8 @@ func readSecuritySettings(iniFile *ini.File, cfg *Cfg) error {
|
||||
|
||||
// admin
|
||||
cfg.DisableInitAdminCreation = security.Key("disable_initial_admin_creation").MustBool(false)
|
||||
AdminUser = valueAsString(security, "admin_user", "")
|
||||
AdminPassword = valueAsString(security, "admin_password", "")
|
||||
cfg.AdminUser = valueAsString(security, "admin_user", "")
|
||||
cfg.AdminPassword = valueAsString(security, "admin_password", "")
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -1022,8 +1016,7 @@ func readSecuritySettings(iniFile *ini.File, cfg *Cfg) error {
|
||||
func readAuthSettings(iniFile *ini.File, cfg *Cfg) (err error) {
|
||||
auth := iniFile.Section("auth")
|
||||
|
||||
LoginCookieName = valueAsString(auth, "login_cookie_name", "grafana_session")
|
||||
cfg.LoginCookieName = LoginCookieName
|
||||
cfg.LoginCookieName = valueAsString(auth, "login_cookie_name", "grafana_session")
|
||||
maxInactiveDaysVal := auth.Key("login_maximum_inactive_lifetime_days").MustString("")
|
||||
if maxInactiveDaysVal != "" {
|
||||
maxInactiveDaysVal = fmt.Sprintf("%sd", maxInactiveDaysVal)
|
||||
@ -1049,7 +1042,6 @@ func readAuthSettings(iniFile *ini.File, cfg *Cfg) (err error) {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
LoginMaxLifetime = cfg.LoginMaxLifetime
|
||||
|
||||
cfg.ApiKeyMaxSecondsToLive = auth.Key("api_key_max_seconds_to_live").MustInt64(-1)
|
||||
|
||||
|
@ -30,7 +30,7 @@ func TestLoadingSettings(t *testing.T) {
|
||||
err := cfg.Load(&CommandLineArgs{HomePath: "../../"})
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(AdminUser, ShouldEqual, "admin")
|
||||
So(cfg.AdminUser, ShouldEqual, "admin")
|
||||
So(cfg.RendererCallbackUrl, ShouldEqual, "http://localhost:3000/")
|
||||
})
|
||||
|
||||
@ -61,7 +61,7 @@ func TestLoadingSettings(t *testing.T) {
|
||||
err = cfg.Load(&CommandLineArgs{HomePath: "../../"})
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(AdminUser, ShouldEqual, "superduper")
|
||||
So(cfg.AdminUser, ShouldEqual, "superduper")
|
||||
So(cfg.DataPath, ShouldEqual, filepath.Join(HomePath, "data"))
|
||||
So(cfg.LogsPath, ShouldEqual, filepath.Join(cfg.DataPath, "log"))
|
||||
})
|
||||
|
@ -452,7 +452,7 @@ func isTerminated(queryStatus string) bool {
|
||||
return queryStatus == "Complete" || queryStatus == "Cancelled" || queryStatus == "Failed" || queryStatus == "Timeout"
|
||||
}
|
||||
|
||||
// CloudWatch client factory.
|
||||
// newCWClient is a CloudWatch client factory.
|
||||
//
|
||||
// Stubbable by tests.
|
||||
var newCWClient = func(sess *session.Session) cloudwatchiface.CloudWatchAPI {
|
||||
@ -464,7 +464,7 @@ var newCWClient = func(sess *session.Session) cloudwatchiface.CloudWatchAPI {
|
||||
return client
|
||||
}
|
||||
|
||||
// CloudWatch logs client factory.
|
||||
// newCWLogsClient is a CloudWatch logs client factory.
|
||||
//
|
||||
// Stubbable by tests.
|
||||
var newCWLogsClient = func(sess *session.Session) cloudwatchlogsiface.CloudWatchLogsAPI {
|
||||
|
Loading…
Reference in New Issue
Block a user