grafana/pkg/middleware/auth.go
Marcus Efraimsson 3be82ecd4e
Auth: Should redirect to login when anonymous enabled and URL with different org than anonymous specified (#28158)
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>
2020-10-23 16:34:35 +02:00

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)
}
}
}