| 
									
										
										
										
											2014-10-06 03:13:01 +08:00
										 |  |  | package middleware | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2021-03-17 00:44:02 +08:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2015-01-27 19:05:23 +08:00
										 |  |  | 	"net/url" | 
					
						
							| 
									
										
										
										
											2020-11-21 02:30:37 +08:00
										 |  |  | 	"regexp" | 
					
						
							| 
									
										
										
										
											2020-07-06 20:59:00 +08:00
										 |  |  | 	"strconv" | 
					
						
							| 
									
										
										
										
											2015-01-14 16:33:34 +08:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2014-11-20 22:19:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-05 19:41:01 +08:00
										 |  |  | 	macaron "gopkg.in/macaron.v1" | 
					
						
							| 
									
										
										
										
											2015-01-14 21:25:12 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-11 18:44:44 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/middleware/cookies" | 
					
						
							| 
									
										
										
										
											2020-02-28 19:50:58 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/models" | 
					
						
							| 
									
										
										
										
											2015-02-05 17:37:13 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/setting" | 
					
						
							| 
									
										
										
										
											2014-10-06 03:13:01 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-15 19:16:54 +08:00
										 |  |  | type AuthOptions struct { | 
					
						
							| 
									
										
										
										
											2015-01-16 21:32:18 +08:00
										 |  |  | 	ReqGrafanaAdmin bool | 
					
						
							|  |  |  | 	ReqSignedIn     bool | 
					
						
							| 
									
										
										
										
											2021-02-28 01:04:28 +08:00
										 |  |  | 	ReqNoAnonynmous bool | 
					
						
							| 
									
										
										
										
											2015-01-15 19:16:54 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-28 19:50:58 +08:00
										 |  |  | func accessForbidden(c *models.ReqContext) { | 
					
						
							| 
									
										
										
										
											2015-01-14 21:25:12 +08:00
										 |  |  | 	if c.IsApiRequest() { | 
					
						
							| 
									
										
										
										
											2015-09-08 16:46:31 +08:00
										 |  |  | 		c.JsonApiErr(403, "Permission denied", nil) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-06 01:17:47 +08:00
										 |  |  | 	c.Redirect(setting.AppSubUrl + "/") | 
					
						
							| 
									
										
										
										
											2015-09-08 16:46:31 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-28 19:50:58 +08:00
										 |  |  | func notAuthorized(c *models.ReqContext) { | 
					
						
							| 
									
										
										
										
											2015-09-08 16:46:31 +08:00
										 |  |  | 	if c.IsApiRequest() { | 
					
						
							|  |  |  | 		c.JsonApiErr(401, "Unauthorized", nil) | 
					
						
							| 
									
										
										
										
											2015-01-27 19:05:23 +08:00
										 |  |  | 		return | 
					
						
							| 
									
										
										
										
											2015-01-14 21:25:12 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-17 00:44:02 +08:00
										 |  |  | 	writeRedirectCookie(c) | 
					
						
							|  |  |  | 	c.Redirect(setting.AppSubUrl + "/login") | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func tokenRevoked(c *models.ReqContext, err *models.TokenRevokedError) { | 
					
						
							|  |  |  | 	if c.IsApiRequest() { | 
					
						
							|  |  |  | 		c.JSON(401, map[string]interface{}{ | 
					
						
							|  |  |  | 			"message": "Token revoked", | 
					
						
							|  |  |  | 			"error": map[string]interface{}{ | 
					
						
							|  |  |  | 				"id":                    "ERR_TOKEN_REVOKED", | 
					
						
							|  |  |  | 				"maxConcurrentSessions": err.MaxConcurrentSessions, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	writeRedirectCookie(c) | 
					
						
							|  |  |  | 	c.Redirect(setting.AppSubUrl + "/login") | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func writeRedirectCookie(c *models.ReqContext) { | 
					
						
							| 
									
										
										
										
											2020-03-11 17:04:48 +08:00
										 |  |  | 	redirectTo := c.Req.RequestURI | 
					
						
							|  |  |  | 	if setting.AppSubUrl != "" && !strings.HasPrefix(redirectTo, setting.AppSubUrl) { | 
					
						
							|  |  |  | 		redirectTo = setting.AppSubUrl + c.Req.RequestURI | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-02-15 17:56:29 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-21 02:30:37 +08:00
										 |  |  | 	// remove any forceLogin=true params
 | 
					
						
							|  |  |  | 	redirectTo = removeForceLoginParams(redirectTo) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-11 18:44:44 +08:00
										 |  |  | 	cookies.WriteCookie(c.Resp, "redirect_to", url.QueryEscape(redirectTo), 0, nil) | 
					
						
							| 
									
										
										
										
											2014-10-06 03:13:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-21 02:30:37 +08:00
										 |  |  | var forceLoginParamsRegexp = regexp.MustCompile(`&?forceLogin=true`) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func removeForceLoginParams(str string) string { | 
					
						
							|  |  |  | 	return forceLoginParamsRegexp.ReplaceAllString(str, "") | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-28 19:50:58 +08:00
										 |  |  | func EnsureEditorOrViewerCanEdit(c *models.ReqContext) { | 
					
						
							|  |  |  | 	if !c.SignedInUser.HasRole(models.ROLE_EDITOR) && !setting.ViewersCanEdit { | 
					
						
							| 
									
										
										
										
											2019-03-05 19:41:01 +08:00
										 |  |  | 		accessForbidden(c) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-28 19:50:58 +08:00
										 |  |  | func RoleAuth(roles ...models.RoleType) macaron.Handler { | 
					
						
							|  |  |  | 	return func(c *models.ReqContext) { | 
					
						
							| 
									
										
										
										
											2015-01-16 22:28:44 +08:00
										 |  |  | 		ok := false | 
					
						
							|  |  |  | 		for _, role := range roles { | 
					
						
							| 
									
										
										
										
											2015-02-24 03:07:49 +08:00
										 |  |  | 			if role == c.OrgRole { | 
					
						
							| 
									
										
										
										
											2015-01-16 22:28:44 +08:00
										 |  |  | 				ok = true | 
					
						
							|  |  |  | 				break | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if !ok { | 
					
						
							| 
									
										
										
										
											2015-09-08 16:46:31 +08:00
										 |  |  | 			accessForbidden(c) | 
					
						
							| 
									
										
										
										
											2015-01-16 22:28:44 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-15 19:16:54 +08:00
										 |  |  | func Auth(options *AuthOptions) macaron.Handler { | 
					
						
							| 
									
										
										
										
											2020-02-28 19:50:58 +08:00
										 |  |  | 	return func(c *models.ReqContext) { | 
					
						
							| 
									
										
										
										
											2020-07-06 20:59:00 +08:00
										 |  |  | 		forceLogin := false | 
					
						
							|  |  |  | 		if c.AllowAnonymous { | 
					
						
							| 
									
										
										
										
											2021-03-16 23:46:34 +08:00
										 |  |  | 			forceLogin = shouldForceLogin(c) | 
					
						
							| 
									
										
										
										
											2020-10-23 22:34:35 +08:00
										 |  |  | 			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 | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2020-07-06 20:59:00 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-02-28 01:04:28 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		requireLogin := !c.AllowAnonymous || forceLogin || options.ReqNoAnonynmous | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-16 21:33:44 +08:00
										 |  |  | 		if !c.IsSignedIn && options.ReqSignedIn && requireLogin { | 
					
						
							| 
									
										
										
										
											2021-03-17 00:44:02 +08:00
										 |  |  | 			lookupTokenErr, hasTokenErr := c.Data["lookupTokenErr"].(error) | 
					
						
							|  |  |  | 			var revokedErr *models.TokenRevokedError | 
					
						
							|  |  |  | 			if hasTokenErr && errors.As(lookupTokenErr, &revokedErr) { | 
					
						
							|  |  |  | 				tokenRevoked(c, revokedErr) | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-08 16:46:31 +08:00
										 |  |  | 			notAuthorized(c) | 
					
						
							| 
									
										
										
										
											2015-01-15 19:16:54 +08:00
										 |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-01-14 16:33:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-08 16:46:31 +08:00
										 |  |  | 		if !c.IsGrafanaAdmin && options.ReqGrafanaAdmin { | 
					
						
							|  |  |  | 			accessForbidden(c) | 
					
						
							| 
									
										
										
										
											2015-01-15 19:16:54 +08:00
										 |  |  | 			return | 
					
						
							| 
									
										
										
										
											2015-01-14 16:33:34 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-10-06 03:13:01 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-03-06 17:27:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-14 17:02:46 +08:00
										 |  |  | // 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 { | 
					
						
							| 
									
										
										
										
											2020-02-28 19:50:58 +08:00
										 |  |  | 	return func(c *models.ReqContext) { | 
					
						
							|  |  |  | 		if c.OrgRole == models.ROLE_ADMIN { | 
					
						
							| 
									
										
										
										
											2019-03-13 17:38:09 +08:00
										 |  |  | 			return | 
					
						
							| 
									
										
										
										
											2019-03-06 17:27:38 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-13 17:38:09 +08:00
										 |  |  | 		if !enabled { | 
					
						
							| 
									
										
										
										
											2019-03-06 17:27:38 +08:00
										 |  |  | 			accessForbidden(c) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-09-02 21:15:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-17 16:51:50 +08:00
										 |  |  | // SnapshotPublicModeOrSignedIn creates a middleware that allows access
 | 
					
						
							|  |  |  | // if snapshot public mode is enabled or if user is signed in.
 | 
					
						
							| 
									
										
										
										
											2020-12-11 18:44:44 +08:00
										 |  |  | func SnapshotPublicModeOrSignedIn(cfg *setting.Cfg) macaron.Handler { | 
					
						
							| 
									
										
										
										
											2020-02-28 19:50:58 +08:00
										 |  |  | 	return func(c *models.ReqContext) { | 
					
						
							| 
									
										
										
										
											2020-12-11 18:44:44 +08:00
										 |  |  | 		if cfg.SnapshotPublicMode { | 
					
						
							| 
									
										
										
										
											2019-09-02 21:15:46 +08:00
										 |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-17 16:51:50 +08:00
										 |  |  | 		if !c.IsSignedIn { | 
					
						
							|  |  |  | 			notAuthorized(c) | 
					
						
							|  |  |  | 			return | 
					
						
							| 
									
										
										
										
											2019-09-02 21:15:46 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-03-16 23:46:34 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // NoAuth creates a middleware that doesn't require any authentication.
 | 
					
						
							|  |  |  | // If forceLogin param is set it will redirect the user to the login page.
 | 
					
						
							|  |  |  | func NoAuth() macaron.Handler { | 
					
						
							|  |  |  | 	return func(c *models.ReqContext) { | 
					
						
							|  |  |  | 		if shouldForceLogin(c) { | 
					
						
							|  |  |  | 			notAuthorized(c) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // shouldForceLogin checks if user should be enforced to login.
 | 
					
						
							|  |  |  | // Returns true if forceLogin parameter is set.
 | 
					
						
							|  |  |  | func shouldForceLogin(c *models.ReqContext) bool { | 
					
						
							|  |  |  | 	forceLogin := false | 
					
						
							|  |  |  | 	forceLoginParam, err := strconv.ParseBool(c.Req.URL.Query().Get("forceLogin")) | 
					
						
							|  |  |  | 	if err == nil { | 
					
						
							|  |  |  | 		forceLogin = forceLoginParam | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return forceLogin | 
					
						
							|  |  |  | } |