mirror of
https://github.com/grafana/grafana.git
synced 2025-02-13 00:55:47 -06:00
If anonymous access is enabled for an org and there are multiple orgs. When requesting a page that requires user to be logged in and orgId query string is set in the request url to an org not equal the anonymous org, if the user is not logged in should be redirected to the login page. Fixes #26120 Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com> Co-authored-by: Sofia Papagiannaki <papagian@users.noreply.github.com>
148 lines
3.4 KiB
Go
148 lines
3.4 KiB
Go
package middleware
|
|
|
|
import (
|
|
"net/url"
|
|
"strconv"
|
|
"strings"
|
|
|
|
macaron "gopkg.in/macaron.v1"
|
|
|
|
"github.com/grafana/grafana/pkg/models"
|
|
"github.com/grafana/grafana/pkg/setting"
|
|
"github.com/grafana/grafana/pkg/util"
|
|
)
|
|
|
|
type AuthOptions struct {
|
|
ReqGrafanaAdmin bool
|
|
ReqSignedIn bool
|
|
}
|
|
|
|
func getApiKey(c *models.ReqContext) string {
|
|
header := c.Req.Header.Get("Authorization")
|
|
parts := strings.SplitN(header, " ", 2)
|
|
if len(parts) == 2 && parts[0] == "Bearer" {
|
|
key := parts[1]
|
|
return key
|
|
}
|
|
|
|
username, password, err := util.DecodeBasicAuthHeader(header)
|
|
if err == nil && username == "api_key" {
|
|
return password
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
func accessForbidden(c *models.ReqContext) {
|
|
if c.IsApiRequest() {
|
|
c.JsonApiErr(403, "Permission denied", nil)
|
|
return
|
|
}
|
|
|
|
c.Redirect(setting.AppSubUrl + "/")
|
|
}
|
|
|
|
func notAuthorized(c *models.ReqContext) {
|
|
if c.IsApiRequest() {
|
|
c.JsonApiErr(401, "Unauthorized", nil)
|
|
return
|
|
}
|
|
|
|
redirectTo := c.Req.RequestURI
|
|
if setting.AppSubUrl != "" && !strings.HasPrefix(redirectTo, setting.AppSubUrl) {
|
|
redirectTo = setting.AppSubUrl + c.Req.RequestURI
|
|
}
|
|
|
|
// remove forceLogin query param if it exists
|
|
if parsed, err := url.ParseRequestURI(redirectTo); err == nil {
|
|
params := parsed.Query()
|
|
params.Del("forceLogin")
|
|
parsed.RawQuery = params.Encode()
|
|
WriteCookie(c.Resp, "redirect_to", url.QueryEscape(parsed.String()), 0, newCookieOptions)
|
|
} else {
|
|
c.Logger.Debug("Failed parsing request URI; redirect cookie will not be set", "redirectTo", redirectTo, "error", err)
|
|
}
|
|
c.Redirect(setting.AppSubUrl + "/login")
|
|
}
|
|
|
|
func EnsureEditorOrViewerCanEdit(c *models.ReqContext) {
|
|
if !c.SignedInUser.HasRole(models.ROLE_EDITOR) && !setting.ViewersCanEdit {
|
|
accessForbidden(c)
|
|
}
|
|
}
|
|
|
|
func RoleAuth(roles ...models.RoleType) macaron.Handler {
|
|
return func(c *models.ReqContext) {
|
|
ok := false
|
|
for _, role := range roles {
|
|
if role == c.OrgRole {
|
|
ok = true
|
|
break
|
|
}
|
|
}
|
|
if !ok {
|
|
accessForbidden(c)
|
|
}
|
|
}
|
|
}
|
|
|
|
func Auth(options *AuthOptions) macaron.Handler {
|
|
return func(c *models.ReqContext) {
|
|
forceLogin := false
|
|
if c.AllowAnonymous {
|
|
forceLoginParam, err := strconv.ParseBool(c.Req.URL.Query().Get("forceLogin"))
|
|
if err == nil {
|
|
forceLogin = forceLoginParam
|
|
}
|
|
|
|
if !forceLogin {
|
|
orgIDValue := c.Req.URL.Query().Get("orgId")
|
|
orgID, err := strconv.ParseInt(orgIDValue, 10, 64)
|
|
if err == nil && orgID > 0 && orgID != c.OrgId {
|
|
forceLogin = true
|
|
}
|
|
}
|
|
}
|
|
requireLogin := !c.AllowAnonymous || forceLogin
|
|
if !c.IsSignedIn && options.ReqSignedIn && requireLogin {
|
|
notAuthorized(c)
|
|
return
|
|
}
|
|
|
|
if !c.IsGrafanaAdmin && options.ReqGrafanaAdmin {
|
|
accessForbidden(c)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// AdminOrFeatureEnabled creates a middleware that allows access
|
|
// if the signed in user is either an Org Admin or if the
|
|
// feature flag is enabled.
|
|
// Intended for when feature flags open up access to APIs that
|
|
// are otherwise only available to admins.
|
|
func AdminOrFeatureEnabled(enabled bool) macaron.Handler {
|
|
return func(c *models.ReqContext) {
|
|
if c.OrgRole == models.ROLE_ADMIN {
|
|
return
|
|
}
|
|
|
|
if !enabled {
|
|
accessForbidden(c)
|
|
}
|
|
}
|
|
}
|
|
|
|
func SnapshotPublicModeOrSignedIn() macaron.Handler {
|
|
return func(c *models.ReqContext) {
|
|
if setting.SnapshotPublicMode {
|
|
return
|
|
}
|
|
|
|
_, err := c.Invoke(ReqSignedIn)
|
|
if err != nil {
|
|
c.JsonApiErr(500, "Failed to invoke required signed in middleware", err)
|
|
}
|
|
}
|
|
}
|