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