Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
N
nexpie-grafana-theme
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Registry
Registry
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Kornkitt Poolsup
nexpie-grafana-theme
Commits
dd2d206d
Unverified
Commit
dd2d206d
authored
Dec 15, 2020
by
Arve Knudsen
Committed by
GitHub
Dec 15, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Backend: Remove more globals (#29644)
Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>
parent
aa8fb1ae
Hide whitespace changes
Inline
Side-by-side
Showing
35 changed files
with
463 additions
and
421 deletions
+463
-421
pkg/api/api.go
+2
-2
pkg/api/common_test.go
+14
-4
pkg/api/dashboard_test.go
+10
-3
pkg/api/frontendsettings_test.go
+1
-1
pkg/api/http_server.go
+2
-2
pkg/api/index.go
+2
-2
pkg/api/ldap_debug.go
+1
-2
pkg/api/ldap_debug_test.go
+8
-10
pkg/api/login.go
+2
-2
pkg/api/login_oauth.go
+1
-1
pkg/api/login_test.go
+31
-42
pkg/api/render.go
+9
-9
pkg/middleware/cookies/cookies.go
+1
-1
pkg/middleware/dashboard_redirect.go
+20
-18
pkg/middleware/dashboard_redirect_test.go
+56
-51
pkg/middleware/gziper.go
+0
-0
pkg/middleware/middleware_test.go
+35
-35
pkg/middleware/org_redirect.go
+2
-2
pkg/middleware/quota.go
+2
-2
pkg/middleware/quota_test.go
+152
-105
pkg/middleware/recovery_test.go
+3
-3
pkg/middleware/testing.go
+5
-5
pkg/middleware/validate_host.go
+3
-3
pkg/models/context.go
+3
-3
pkg/models/dashboards.go
+3
-3
pkg/models/quotas.go
+0
-45
pkg/services/contexthandler/authproxy/authproxy.go
+2
-2
pkg/services/contexthandler/contexthandler.go
+7
-7
pkg/services/contexthandler/contexthandler_test.go
+6
-12
pkg/services/quota/quota.go
+51
-2
pkg/services/sqlstore/org.go
+0
-12
pkg/services/sqlstore/sqlstore.go
+19
-12
pkg/setting/setting.go
+6
-14
pkg/setting/setting_test.go
+2
-2
pkg/tsdb/cloudwatch/cloudwatch.go
+2
-2
No files found.
pkg/api/api.go
View file @
dd2d206d
...
...
@@ -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
...
...
pkg/api/common_test.go
View file @
dd2d206d
...
...
@@ -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
}
...
...
pkg/api/dashboard_test.go
View file @
dd2d206d
...
...
@@ -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
:
&
quota
.
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
:
&
quota
.
QuotaService
{
Cfg
:
cfg
},
}
sc
:=
setupScenarioContext
(
t
,
url
)
...
...
pkg/api/frontendsettings_test.go
View file @
dd2d206d
...
...
@@ -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
,
...
...
pkg/api/http_server.go
View file @
dd2d206d
...
...
@@ -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
())
...
...
pkg/api/index.go
View file @
dd2d206d
...
...
@@ -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
}
...
...
pkg/api/ldap_debug.go
View file @
dd2d206d
...
...
@@ -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
settin
g
.
AdminUser
==
query
.
Result
.
Login
{
// User is *the* Grafana Admin. We cannot disable it.
if
hs
.
Cf
g
.
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
)
...
...
pkg/api/ldap_debug_test.go
View file @
dd2d206d
...
...
@@ -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
:
s
etting
.
NewCfg
()
,
Cfg
:
s
c
.
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
}
...
...
pkg/api/login.go
View file @
dd2d206d
...
...
@@ -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
}
}
...
...
pkg/api/login_oauth.go
View file @
dd2d206d
...
...
@@ -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
{
...
...
pkg/api/login_test.go
View file @
dd2d206d
...
...
@@ -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
)
})
settin
g
.
LoginCookieName
=
"grafana_session"
cf
g
.
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
:
s
etting
.
NewCfg
()
,
Cfg
:
s
c
.
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
.
C
fg
.
AuthProxyEnabled
=
true
hs
.
C
fg
.
AuthProxyEnableLoginToken
=
enableLoginToken
sc
.
c
fg
.
AuthProxyEnabled
=
true
sc
.
c
fg
.
AuthProxyEnableLoginToken
=
enableLoginToken
sc
.
m
.
Get
(
sc
.
url
,
sc
.
defaultHandler
)
sc
.
fakeReqNoAssertions
(
"GET"
,
sc
.
url
)
.
exec
()
...
...
pkg/api/render.go
View file @
dd2d206d
...
...
@@ -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
}
...
...
pkg/middleware/cookies/cookies.go
View file @
dd2d206d
...
...
@@ -67,5 +67,5 @@ func WriteSessionCookie(ctx *models.ReqContext, cfg *setting.Cfg, value string,
maxAge
=
int
(
maxLifetime
.
Seconds
())
}
WriteCookie
(
ctx
.
Resp
,
settin
g
.
LoginCookieName
,
url
.
QueryEscape
(
value
),
maxAge
,
nil
)
WriteCookie
(
ctx
.
Resp
,
cf
g
.
LoginCookieName
,
url
.
QueryEscape
(
value
),
maxAge
,
nil
)
}
pkg/middleware/dashboard_redirect.go
View file @
dd2d206d
...
...
@@ -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
()
panelI
d
,
hasPanelId
:=
queryParams
[
"panelId"
]
panelI
D
,
hasPanelID
:=
queryParams
[
"panelId"
]
_
,
hasFullscreen
:=
queryParams
[
"fullscreen"
]
_
,
hasEdit
:=
queryParams
[
"edit"
]
if
hasPanelI
d
&&
hasFullscreen
{
if
hasPanelI
D
&&
hasFullscreen
{
delete
(
queryParams
,
"panelId"
)
delete
(
queryParams
,
"fullscreen"
)
delete
(
queryParams
,
"edit"
)
if
hasEdit
{
queryParams
[
"editPanel"
]
=
panelI
d
queryParams
[
"editPanel"
]
=
panelI
D
}
else
{
queryParams
[
"viewPanel"
]
=
panelI
d
queryParams
[
"viewPanel"
]
=
panelI
D
}
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
}
}
}
pkg/middleware/dashboard_redirect_test.go
View file @
dd2d206d
...
...
@@ -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
)
bus
.
AddHandler
(
"test"
,
func
(
query
*
models
.
GetDashboardQuery
)
error
{
t
.
Log
(
"Returning fake dashboard"
)
query
.
Result
=
fakeDash
return
nil
})
sc
.
fakeReqWithParams
(
"GET"
,
"/dashboard/db/dash?orgId=1&panelId=2"
,
map
[
string
]
string
{})
.
exec
()
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
()
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
()))
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 solo by legacy url"
,
func
(
t
*
testing
.
T
,
sc
*
scenarioContext
)
{
bus
.
AddHandler
(
"test"
,
func
(
query
*
models
.
GetDashboardQuery
)
error
{
query
.
Result
=
fakeDash
return
nil
})
middlewareScenario
(
t
,
"GET dashboard solo by legacy url"
,
func
(
t
*
testing
.
T
,
sc
*
scenarioContext
)
{
redirectFromLegacyDashboardSoloURL
:=
RedirectFromLegacyDashboardSoloURL
(
sc
.
cfg
)
sc
.
m
.
Get
(
"/dashboard-solo/db/:slug"
,
redirectFromLegacyDashboardSoloUrl
,
sc
.
defaultHandler
)
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
()
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
()))
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
)
})
}
middlewareScenario
(
t
,
"GET dashboard by legacy edit url"
,
func
(
t
*
testing
.
T
,
sc
*
scenarioContext
)
{
sc
.
m
.
Get
(
"/d/:uid/:slug"
,
RedirectFromLegacyPanelEditURL
(),
sc
.
defaultHandler
)
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
()
...
...
pkg/middleware/
util
.go
→
pkg/middleware/
gziper
.go
View file @
dd2d206d
File moved
pkg/middleware/middleware_test.go
View file @
dd2d206d
...
...
@@ -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
.
E
qual
(
t
,
""
,
sc
.
resp
.
Header
()
.
Get
(
"Set-Cookie"
))
assert
.
E
mpty
(
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
(
s
ettin
g
.
LoginMaxLifetime
.
Seconds
())
maxAge
:=
int
(
s
c
.
cf
g
.
LoginMaxLifetime
.
Seconds
())
sameSiteModes
:=
[]
http
.
SameSite
{
http
.
SameSiteNoneMode
,
...
...
@@ -269,11 +263,11 @@ func TestMiddlewareContext(t *testing.T) {
setting
.
CookieSameSiteMode
=
sameSiteMode
expectedCookiePath
:=
"/"
if
len
(
s
etting
.
AppSubUrl
)
>
0
{
expectedCookiePath
=
s
etting
.
AppSubUrl
if
len
(
s
c
.
cfg
.
AppSubURL
)
>
0
{
expectedCookiePath
=
s
c
.
cfg
.
AppSubURL
}
expectedCookie
:=
&
http
.
Cookie
{
Name
:
s
ettin
g
.
LoginCookieName
,
Name
:
s
c
.
cf
g
.
LoginCookieName
,
Value
:
"rotated"
,
Path
:
expectedCookiePath
,
HttpOnly
:
true
,
...
...
@@ -303,11 +297,11 @@ func TestMiddlewareContext(t *testing.T) {
setting
.
CookieSameSiteMode
=
http
.
SameSiteLaxMode
expectedCookiePath
:=
"/"
if
len
(
s
etting
.
AppSubUrl
)
>
0
{
expectedCookiePath
=
s
etting
.
AppSubUrl
if
len
(
s
c
.
cfg
.
AppSubURL
)
>
0
{
expectedCookiePath
=
s
c
.
cfg
.
AppSubURL
}
expectedCookie
:=
&
http
.
Cookie
{
Name
:
s
ettin
g
.
LoginCookieName
,
Name
:
s
c
.
cf
g
.
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
)
...
...
pkg/middleware/org_redirect.go
View file @
dd2d206d
...
...
@@ -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
)
}
}
pkg/middleware/quota.go
View file @
dd2d206d
...
...
@@ -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
,
"
f
ailed to get quota"
,
err
)
c
.
JsonApiErr
(
500
,
"
F
ailed to get quota"
,
err
)
return
}
if
limitReached
{
...
...
pkg/middleware/quota_test.go
View file @
dd2d206d
...
...
@@ -10,37 +10,10 @@ 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
{
Enabled
:
true
,
Org
:
&
setting
.
OrgQuota
{
User
:
5
,
Dashboard
:
5
,
DataSource
:
5
,
ApiKey
:
5
,
},
User
:
&
setting
.
UserQuota
{
Org
:
5
,
},
Global
:
&
setting
.
GlobalQuota
{
Org
:
5
,
User
:
5
,
Dashboard
:
5
,
DataSource
:
5
,
ApiKey
:
5
,
Session
:
5
,
},
}
fakeAuthTokenService
:=
auth
.
NewFakeUserAuthTokenService
()
qs
:=
&
quota
.
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
{
...
...
@@ -52,10 +25,12 @@ func TestMiddlewareQuota(t *testing.T) {
return
nil
})
sc
.
m
.
Get
(
"/user"
,
quotaFn
(
"user"
),
sc
.
defaultHandler
)
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
{
...
...
@@ -67,15 +42,14 @@ func TestMiddlewareQuota(t *testing.T) {
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
)
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
)
{
...
...
@@ -88,112 +62,185 @@ func TestMiddlewareQuota(t *testing.T) {
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
)
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
)
{
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
)
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
})
})
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
})
t
.
Run
(
"with user logged in"
,
func
(
t
*
testing
.
T
)
{
const
quotaUsed
=
4
s
c
.
userAuthTokenService
.
LookupTokenProvider
=
func
(
ctx
context
.
Context
,
unhashedToken
string
)
(
*
models
.
UserToken
,
error
)
{
return
&
models
.
UserToken
{
UserId
:
12
,
UnhashedToken
:
""
,
},
nil
}
s
etUp
:=
func
(
sc
*
scenarioContext
)
{
sc
.
withTokenSessionCookie
(
"token"
)
bus
.
AddHandler
(
"test"
,
func
(
query
*
models
.
GetSignedInUserQuery
)
error
{
query
.
Result
=
&
models
.
SignedInUser
{
OrgId
:
2
,
UserId
:
12
}
return
nil
})
bus
.
AddHandler
(
"globalQuota"
,
func
(
query
*
models
.
GetGlobalQuotaByTargetQuery
)
error
{
query
.
Result
=
&
models
.
GlobalQuotaDTO
{
Target
:
query
.
Target
,
Limit
:
query
.
Default
,
Used
:
4
,
sc
.
userAuthTokenService
.
LookupTokenProvider
=
func
(
ctx
context
.
Context
,
unhashedToken
string
)
(
*
models
.
UserToken
,
error
)
{
return
&
models
.
UserToken
{
UserId
:
12
,
UnhashedToken
:
""
,
},
nil
}
return
nil
})
bus
.
AddHandler
(
"userQuota"
,
func
(
query
*
models
.
GetUser
QuotaByTargetQuery
)
error
{
query
.
Result
=
&
models
.
User
QuotaDTO
{
Target
:
query
.
Target
,
Limit
:
query
.
Default
,
Used
:
4
,
}
return
nil
})
bus
.
AddHandler
(
"globalQuota"
,
func
(
query
*
models
.
GetGlobal
QuotaByTargetQuery
)
error
{
query
.
Result
=
&
models
.
Global
QuotaDTO
{
Target
:
query
.
Target
,
Limit
:
query
.
Default
,
Used
:
quotaUsed
,
}
return
nil
})
bus
.
AddHandler
(
"orgQuota"
,
func
(
query
*
models
.
GetOrg
QuotaByTargetQuery
)
error
{
query
.
Result
=
&
models
.
Org
QuotaDTO
{
Target
:
query
.
Target
,
Limit
:
query
.
Default
,
Used
:
4
,
}
return
nil
})
bus
.
AddHandler
(
"userQuota"
,
func
(
query
*
models
.
GetUser
QuotaByTargetQuery
)
error
{
query
.
Result
=
&
models
.
User
QuotaDTO
{
Target
:
query
.
Target
,
Limit
:
query
.
Default
,
Used
:
quotaUsed
,
}
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
)
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
})
t
.
Run
(
"user Org quota not reached"
,
func
(
t
*
testing
.
T
)
{
setting
.
Quota
.
User
.
Org
=
5
sc
.
m
.
Get
(
"/org"
,
quotaFn
(
"org"
),
sc
.
defaultHandler
)
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
})
t
.
Run
(
"user Org quota reached"
,
func
(
t
*
testing
.
T
)
{
setting
.
Quota
.
User
.
Org
=
4
sc
.
m
.
Get
(
"/org"
,
quotaFn
(
"org"
),
sc
.
defaultHandler
)
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
})
t
.
Run
(
"org dashboard quota not reached"
,
func
(
t
*
testing
.
T
)
{
setting
.
Quota
.
Org
.
Dashboard
=
10
sc
.
m
.
Get
(
"/dashboard"
,
quotaFn
(
"dashboard"
),
sc
.
defaultHandler
)
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
})
t
.
Run
(
"org dashboard quota reached"
,
func
(
t
*
testing
.
T
)
{
setting
.
Quota
.
Org
.
Dashboard
=
4
sc
.
m
.
Get
(
"/dashboard"
,
quotaFn
(
"dashboard"
),
sc
.
defaultHandler
)
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
})
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
)
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
:=
&
quota
.
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
,
Dashboard
:
5
,
DataSource
:
5
,
ApiKey
:
5
,
},
User
:
&
setting
.
UserQuota
{
Org
:
5
,
},
Global
:
&
setting
.
GlobalQuota
{
Org
:
5
,
User
:
5
,
Dashboard
:
5
,
DataSource
:
5
,
ApiKey
:
5
,
Session
:
5
,
},
}
}
pkg/middleware/recovery_test.go
View file @
dd2d206d
...
...
@@ -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
...
...
pkg/middleware/testing.go
View file @
dd2d206d
...
...
@@ -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"
)
}
}
...
...
pkg/middleware/validate_host.go
View file @
dd2d206d
...
...
@@ -8,7 +8,7 @@ import (
"gopkg.in/macaron.v1"
)
func
ValidateHostHeader
(
domain
strin
g
)
macaron
.
Handler
{
func
ValidateHostHeader
(
cfg
*
setting
.
Cf
g
)
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
,
d
omain
)
{
c
.
Redirect
(
strings
.
TrimSuffix
(
setting
.
AppUrl
,
"/"
)
+
c
.
Req
.
RequestURI
,
301
)
if
!
strings
.
EqualFold
(
h
,
cfg
.
D
omain
)
{
c
.
Redirect
(
strings
.
TrimSuffix
(
cfg
.
AppURL
,
"/"
)
+
c
.
Req
.
RequestURI
,
301
)
return
}
}
...
...
pkg/models/context.go
View file @
dd2d206d
...
...
@@ -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
,
settin
g
.
ErrTemplateName
)
ctx
.
HTML
(
status
,
cf
g
.
ErrTemplateName
)
}
func
(
ctx
*
ReqContext
)
IsApiRequest
()
bool
{
...
...
pkg/models/dashboards.go
View file @
dd2d206d
...
...
@@ -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 return
s 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 return
s 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 return
s 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
)
}
...
...
pkg/models/quotas.go
View file @
dd2d206d
...
...
@@ -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
}
}
pkg/services/contexthandler/authproxy/authproxy.go
View file @
dd2d206d
...
...
@@ -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
...
...
pkg/services/contexthandler/contexthandler.go
View file @
dd2d206d
...
...
@@ -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
.
h
andleError
(
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
.
h
andleError
(
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
.
h
andleError
(
ctx
,
err
,
407
,
nil
)
return
true
}
user
,
err
=
auth
.
GetSignedInUser
(
id
)
if
err
!=
nil
{
handleError
(
ctx
,
err
,
407
,
nil
)
h
.
h
andleError
(
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
.
h
andleError
(
ctx
,
err
,
500
,
func
(
details
error
)
{
logger
.
Error
(
"Failed to store user in cache"
,
"username"
,
username
,
...
...
pkg/services/contexthandler/contexthandler_test.go
View file @
dd2d206d
...
...
@@ -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
settin
g
.
LoginMaxLifetime
,
err
=
gtime
.
ParseDuration
(
"7d"
)
ctxHdlr
.
Cf
g
.
LoginMaxLifetime
,
err
=
gtime
.
ParseDuration
(
"7d"
)
if
err
!=
nil
{
return
nil
,
nil
,
err
}
...
...
pkg/services/quota/quota.go
View file @
dd2d206d
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
!
settin
g
.
Quota
.
Enabled
{
if
!
qs
.
Cf
g
.
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
.
G
etQuotaScopes
(
target
)
scopes
,
err
:=
qs
.
g
etQuotaScopes
(
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
}
}
pkg/services/sqlstore/org.go
View file @
dd2d206d
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
})
}
pkg/services/sqlstore/sqlstore.go
View file @
dd2d206d
...
...
@@ -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"
,
s
ettin
g
.
AdminUser
)
ss
.
log
.
Info
(
"Created default admin"
,
"user"
,
s
s
.
Cf
g
.
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"
)
...
...
pkg/setting/setting.go
View file @
dd2d206d
...
...
@@ -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
)
...
...
pkg/setting/setting_test.go
View file @
dd2d206d
...
...
@@ -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"
))
})
...
...
pkg/tsdb/cloudwatch/cloudwatch.go
View file @
dd2d206d
...
...
@@ -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
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment