Files
Torkel Ödegaard 1076f47509 Dashboard: Fixes kiosk state after being redirected to login page and back (#29273)
* Login: Fixes issue where url parameters where modified by golang url code

* Add tests

* Fix test cases

* Update pkg/middleware/auth_test.go

Co-authored-by: Sofia Papagiannaki <papagian@users.noreply.github.com>

* fixed formatting

Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>
Co-authored-by: Sofia Papagiannaki <papagian@users.noreply.github.com>
2020-11-20 19:30:37 +01:00

150 lines
3.3 KiB
Go

package middleware
import (
"net/url"
"regexp"
"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 any forceLogin=true params
redirectTo = removeForceLoginParams(redirectTo)
WriteCookie(c.Resp, "redirect_to", url.QueryEscape(redirectTo), 0, newCookieOptions)
c.Redirect(setting.AppSubUrl + "/login")
}
var forceLoginParamsRegexp = regexp.MustCompile(`&?forceLogin=true`)
func removeForceLoginParams(str string) string {
return forceLoginParamsRegexp.ReplaceAllString(str, "")
}
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)
}
}
}