| 
									
										
										
										
											2018-01-30 20:17:48 +08:00
										 |  |  | package api | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2021-11-29 17:18:01 +08:00
										 |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2021-09-27 22:43:16 +08:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2021-11-29 17:18:01 +08:00
										 |  |  | 	"encoding/json" | 
					
						
							| 
									
										
										
										
											2020-05-12 19:04:18 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2018-01-30 20:17:48 +08:00
										 |  |  | 	"net/http" | 
					
						
							|  |  |  | 	"net/http/httptest" | 
					
						
							|  |  |  | 	"path/filepath" | 
					
						
							| 
									
										
										
										
											2020-05-12 19:04:18 +08:00
										 |  |  | 	"testing" | 
					
						
							| 
									
										
										
										
											2018-01-30 20:17:48 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-18 02:52:22 +08:00
										 |  |  | 	"github.com/stretchr/testify/require" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/api/response" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/api/routing" | 
					
						
							| 
									
										
										
										
											2020-12-16 02:09:04 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/infra/fs" | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/infra/log" | 
					
						
							| 
									
										
										
										
											2020-12-11 18:44:44 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/infra/remotecache" | 
					
						
							| 
									
										
										
										
											2022-01-20 18:10:12 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/infra/tracing" | 
					
						
							| 
									
										
										
										
											2020-03-04 19:57:20 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/models" | 
					
						
							| 
									
										
										
										
											2021-08-24 17:36:28 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/accesscontrol" | 
					
						
							| 
									
										
										
										
											2022-01-26 22:48:41 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/accesscontrol/database" | 
					
						
							| 
									
										
										
										
											2021-08-25 02:12:48 +08:00
										 |  |  | 	accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock" | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/accesscontrol/ossaccesscontrol" | 
					
						
							| 
									
										
										
										
											2019-03-08 22:15:38 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/auth" | 
					
						
							| 
									
										
										
										
											2020-12-11 18:44:44 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/contexthandler" | 
					
						
							| 
									
										
										
										
											2022-03-30 23:01:24 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/contexthandler/authproxy" | 
					
						
							| 
									
										
										
										
											2022-05-21 00:45:18 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/contexthandler/ctxkey" | 
					
						
							| 
									
										
										
										
											2022-02-16 21:15:44 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/dashboards" | 
					
						
							|  |  |  | 	dashboardsstore "github.com/grafana/grafana/pkg/services/dashboards/database" | 
					
						
							| 
									
										
										
										
											2022-05-18 02:52:22 +08:00
										 |  |  | 	dashboardservice "github.com/grafana/grafana/pkg/services/dashboards/service" | 
					
						
							| 
									
										
										
										
											2022-01-27 01:44:20 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/featuremgmt" | 
					
						
							| 
									
										
										
										
											2022-02-01 19:03:21 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/ldap" | 
					
						
							| 
									
										
										
										
											2022-03-30 23:01:24 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/login/loginservice" | 
					
						
							| 
									
										
										
										
											2022-04-05 02:36:15 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/login/logintest" | 
					
						
							| 
									
										
										
										
											2022-04-21 21:03:17 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/preference/preftest" | 
					
						
							| 
									
										
										
										
											2021-08-25 21:11:22 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/quota" | 
					
						
							| 
									
										
										
										
											2020-12-11 18:44:44 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/rendering" | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/searchusers" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/services/searchusers/filters" | 
					
						
							| 
									
										
										
										
											2020-12-11 18:44:44 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/sqlstore" | 
					
						
							| 
									
										
										
										
											2022-05-18 06:11:55 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/sqlstore/mockstore" | 
					
						
							| 
									
										
										
										
											2020-12-11 18:44:44 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/setting" | 
					
						
							| 
									
										
										
										
											2021-10-11 20:30:59 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/web" | 
					
						
							| 
									
										
										
										
											2022-03-11 01:38:04 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/web/webtest" | 
					
						
							| 
									
										
										
										
											2018-01-30 20:17:48 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-03 16:20:20 +08:00
										 |  |  | func loggedInUserScenario(t *testing.T, desc string, url string, routePattern string, fn scenarioFunc, sqlStore sqlstore.Store) { | 
					
						
							|  |  |  | 	loggedInUserScenarioWithRole(t, desc, "GET", url, routePattern, models.ROLE_EDITOR, fn, sqlStore) | 
					
						
							| 
									
										
										
										
											2018-01-30 20:17:48 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-03 16:20:20 +08:00
										 |  |  | func loggedInUserScenarioWithRole(t *testing.T, desc string, method string, url string, routePattern string, role models.RoleType, fn scenarioFunc, sqlStore sqlstore.Store) { | 
					
						
							| 
									
										
										
										
											2020-11-13 16:52:38 +08:00
										 |  |  | 	t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) { | 
					
						
							|  |  |  | 		sc := setupScenarioContext(t, url) | 
					
						
							| 
									
										
										
										
											2022-02-03 16:20:20 +08:00
										 |  |  | 		sc.sqlStore = sqlStore | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | 		sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { | 
					
						
							| 
									
										
										
										
											2018-01-30 20:17:48 +08:00
										 |  |  | 			sc.context = c | 
					
						
							| 
									
										
										
										
											2020-11-13 16:52:38 +08:00
										 |  |  | 			sc.context.UserId = testUserID | 
					
						
							|  |  |  | 			sc.context.OrgId = testOrgID | 
					
						
							| 
									
										
										
										
											2020-11-24 19:10:32 +08:00
										 |  |  | 			sc.context.Login = testUserLogin | 
					
						
							| 
									
										
										
										
											2018-01-30 20:17:48 +08:00
										 |  |  | 			sc.context.OrgRole = role | 
					
						
							|  |  |  | 			if sc.handlerFunc != nil { | 
					
						
							|  |  |  | 				return sc.handlerFunc(sc.context) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			return nil | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		switch method { | 
					
						
							|  |  |  | 		case "GET": | 
					
						
							|  |  |  | 			sc.m.Get(routePattern, sc.defaultHandler) | 
					
						
							|  |  |  | 		case "DELETE": | 
					
						
							|  |  |  | 			sc.m.Delete(routePattern, sc.defaultHandler) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		fn(sc) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-13 16:52:38 +08:00
										 |  |  | func anonymousUserScenario(t *testing.T, desc string, method string, url string, routePattern string, fn scenarioFunc) { | 
					
						
							|  |  |  | 	t.Run(fmt.Sprintf("%s %s", desc, url), func(t *testing.T) { | 
					
						
							|  |  |  | 		sc := setupScenarioContext(t, url) | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | 		sc.defaultHandler = routing.Wrap(func(c *models.ReqContext) response.Response { | 
					
						
							| 
									
										
										
										
											2018-05-24 14:55:16 +08:00
										 |  |  | 			sc.context = c | 
					
						
							|  |  |  | 			if sc.handlerFunc != nil { | 
					
						
							|  |  |  | 				return sc.handlerFunc(sc.context) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			return nil | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		switch method { | 
					
						
							|  |  |  | 		case "GET": | 
					
						
							|  |  |  | 			sc.m.Get(routePattern, sc.defaultHandler) | 
					
						
							|  |  |  | 		case "DELETE": | 
					
						
							|  |  |  | 			sc.m.Delete(routePattern, sc.defaultHandler) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		fn(sc) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-30 20:17:48 +08:00
										 |  |  | func (sc *scenarioContext) fakeReq(method, url string) *scenarioContext { | 
					
						
							|  |  |  | 	sc.resp = httptest.NewRecorder() | 
					
						
							|  |  |  | 	req, err := http.NewRequest(method, url, nil) | 
					
						
							| 
									
										
										
										
											2020-11-13 16:52:38 +08:00
										 |  |  | 	require.NoError(sc.t, err) | 
					
						
							| 
									
										
										
										
											2022-02-09 20:44:38 +08:00
										 |  |  | 	req.Header.Add("Content-Type", "application/json") | 
					
						
							| 
									
										
										
										
											2018-01-30 20:17:48 +08:00
										 |  |  | 	sc.req = req | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return sc | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (sc *scenarioContext) fakeReqWithParams(method, url string, queryParams map[string]string) *scenarioContext { | 
					
						
							|  |  |  | 	sc.resp = httptest.NewRecorder() | 
					
						
							|  |  |  | 	req, err := http.NewRequest(method, url, nil) | 
					
						
							| 
									
										
										
										
											2020-05-12 19:04:18 +08:00
										 |  |  | 	// TODO: Depend on sc.t
 | 
					
						
							|  |  |  | 	if sc.t != nil { | 
					
						
							|  |  |  | 		require.NoError(sc.t, err) | 
					
						
							|  |  |  | 	} else if err != nil { | 
					
						
							|  |  |  | 		panic(fmt.Sprintf("Making request failed: %s", err)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-09 20:44:38 +08:00
										 |  |  | 	req.Header.Add("Content-Type", "application/json") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-30 20:17:48 +08:00
										 |  |  | 	q := req.URL.Query() | 
					
						
							|  |  |  | 	for k, v := range queryParams { | 
					
						
							|  |  |  | 		q.Add(k, v) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	req.URL.RawQuery = q.Encode() | 
					
						
							|  |  |  | 	sc.req = req | 
					
						
							|  |  |  | 	return sc | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-09 14:37:24 +08:00
										 |  |  | func (sc *scenarioContext) fakeReqNoAssertions(method, url string) *scenarioContext { | 
					
						
							|  |  |  | 	sc.resp = httptest.NewRecorder() | 
					
						
							|  |  |  | 	req, _ := http.NewRequest(method, url, nil) | 
					
						
							| 
									
										
										
										
											2022-02-09 20:44:38 +08:00
										 |  |  | 	req.Header.Add("Content-Type", "application/json") | 
					
						
							| 
									
										
										
										
											2019-07-09 14:37:24 +08:00
										 |  |  | 	sc.req = req | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return sc | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (sc *scenarioContext) fakeReqNoAssertionsWithCookie(method, url string, cookie http.Cookie) *scenarioContext { | 
					
						
							|  |  |  | 	sc.resp = httptest.NewRecorder() | 
					
						
							|  |  |  | 	http.SetCookie(sc.resp, &cookie) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	req, _ := http.NewRequest(method, url, nil) | 
					
						
							|  |  |  | 	req.Header = http.Header{"Cookie": sc.resp.Header()["Set-Cookie"]} | 
					
						
							| 
									
										
										
										
											2022-02-09 20:44:38 +08:00
										 |  |  | 	req.Header.Add("Content-Type", "application/json") | 
					
						
							| 
									
										
										
										
											2019-07-09 14:37:24 +08:00
										 |  |  | 	sc.req = req | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return sc | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-30 20:17:48 +08:00
										 |  |  | type scenarioContext struct { | 
					
						
							| 
									
										
										
										
											2020-05-12 19:04:18 +08:00
										 |  |  | 	t                    *testing.T | 
					
						
							| 
									
										
										
										
											2020-12-16 02:09:04 +08:00
										 |  |  | 	cfg                  *setting.Cfg | 
					
						
							| 
									
										
										
										
											2021-10-11 20:30:59 +08:00
										 |  |  | 	m                    *web.Mux | 
					
						
							| 
									
										
										
										
											2020-03-04 19:57:20 +08:00
										 |  |  | 	context              *models.ReqContext | 
					
						
							| 
									
										
										
										
											2019-03-08 22:15:38 +08:00
										 |  |  | 	resp                 *httptest.ResponseRecorder | 
					
						
							|  |  |  | 	handlerFunc          handlerFunc | 
					
						
							| 
									
										
										
										
											2021-10-11 20:30:59 +08:00
										 |  |  | 	defaultHandler       web.Handler | 
					
						
							| 
									
										
										
										
											2019-03-08 22:15:38 +08:00
										 |  |  | 	req                  *http.Request | 
					
						
							|  |  |  | 	url                  string | 
					
						
							|  |  |  | 	userAuthTokenService *auth.FakeUserAuthTokenService | 
					
						
							| 
									
										
										
										
											2022-02-03 16:20:20 +08:00
										 |  |  | 	sqlStore             sqlstore.Store | 
					
						
							| 
									
										
										
										
											2022-04-05 02:36:15 +08:00
										 |  |  | 	authInfoService      *logintest.AuthInfoServiceFake | 
					
						
							| 
									
										
										
										
											2018-01-30 20:17:48 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (sc *scenarioContext) exec() { | 
					
						
							|  |  |  | 	sc.m.ServeHTTP(sc.resp, sc.req) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type scenarioFunc func(c *scenarioContext) | 
					
						
							| 
									
										
										
										
											2021-01-15 21:43:20 +08:00
										 |  |  | type handlerFunc func(c *models.ReqContext) response.Response | 
					
						
							| 
									
										
										
										
											2018-01-30 20:17:48 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-16 02:09:04 +08:00
										 |  |  | func getContextHandler(t *testing.T, cfg *setting.Cfg) *contexthandler.ContextHandler { | 
					
						
							| 
									
										
										
										
											2020-12-11 18:44:44 +08:00
										 |  |  | 	t.Helper() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-16 02:09:04 +08:00
										 |  |  | 	if cfg == nil { | 
					
						
							|  |  |  | 		cfg = setting.NewCfg() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-11 18:44:44 +08:00
										 |  |  | 	sqlStore := sqlstore.InitTestDB(t) | 
					
						
							|  |  |  | 	remoteCacheSvc := &remotecache.RemoteCache{} | 
					
						
							|  |  |  | 	cfg.RemoteCacheOptions = &setting.RemoteCacheOptions{ | 
					
						
							|  |  |  | 		Name: "database", | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	userAuthTokenSvc := auth.NewFakeUserAuthTokenService() | 
					
						
							|  |  |  | 	renderSvc := &fakeRenderService{} | 
					
						
							| 
									
										
										
										
											2021-03-31 23:40:44 +08:00
										 |  |  | 	authJWTSvc := models.NewFakeJWTService() | 
					
						
							| 
									
										
										
										
											2022-01-20 18:10:12 +08:00
										 |  |  | 	tracer, err := tracing.InitializeTracerForTest() | 
					
						
							|  |  |  | 	require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2022-03-30 23:01:24 +08:00
										 |  |  | 	authProxy := authproxy.ProvideAuthProxy(cfg, remoteCacheSvc, loginservice.LoginServiceMock{}, sqlStore) | 
					
						
							| 
									
										
										
										
											2022-04-08 16:33:19 +08:00
										 |  |  | 	loginService := &logintest.LoginServiceFake{} | 
					
						
							|  |  |  | 	authenticator := &logintest.AuthenticatorFake{} | 
					
						
							|  |  |  | 	ctxHdlr := contexthandler.ProvideService(cfg, userAuthTokenSvc, authJWTSvc, remoteCacheSvc, renderSvc, sqlStore, tracer, authProxy, loginService, authenticator) | 
					
						
							| 
									
										
										
										
											2020-12-11 18:44:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return ctxHdlr | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-13 16:52:38 +08:00
										 |  |  | func setupScenarioContext(t *testing.T, url string) *scenarioContext { | 
					
						
							| 
									
										
										
										
											2020-12-16 02:09:04 +08:00
										 |  |  | 	cfg := setting.NewCfg() | 
					
						
							| 
									
										
										
										
											2018-01-30 20:17:48 +08:00
										 |  |  | 	sc := &scenarioContext{ | 
					
						
							|  |  |  | 		url: url, | 
					
						
							| 
									
										
										
										
											2020-11-13 16:52:38 +08:00
										 |  |  | 		t:   t, | 
					
						
							| 
									
										
										
										
											2020-12-16 02:09:04 +08:00
										 |  |  | 		cfg: cfg, | 
					
						
							| 
									
										
										
										
											2018-01-30 20:17:48 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-12-11 18:44:44 +08:00
										 |  |  | 	viewsPath, err := filepath.Abs("../../public/views") | 
					
						
							|  |  |  | 	require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2020-12-16 02:09:04 +08:00
										 |  |  | 	exists, err := fs.Exists(viewsPath) | 
					
						
							|  |  |  | 	require.NoError(t, err) | 
					
						
							|  |  |  | 	require.Truef(t, exists, "Views should be in %q", viewsPath) | 
					
						
							| 
									
										
										
										
											2018-01-30 20:17:48 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-11 20:30:59 +08:00
										 |  |  | 	sc.m = web.New() | 
					
						
							|  |  |  | 	sc.m.UseMiddleware(web.Renderer(viewsPath, "[[", "]]")) | 
					
						
							| 
									
										
										
										
											2020-12-16 02:09:04 +08:00
										 |  |  | 	sc.m.Use(getContextHandler(t, cfg).Middleware) | 
					
						
							| 
									
										
										
										
											2018-01-30 20:17:48 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return sc | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2020-12-11 18:44:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | type fakeRenderService struct { | 
					
						
							|  |  |  | 	rendering.Service | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s *fakeRenderService) Init() error { | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-06-11 21:58:18 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-14 23:36:48 +08:00
										 |  |  | func setupAccessControlScenarioContext(t *testing.T, cfg *setting.Cfg, url string, permissions []*accesscontrol.Permission) (*scenarioContext, *HTTPServer) { | 
					
						
							| 
									
										
										
										
											2021-09-01 21:18:17 +08:00
										 |  |  | 	cfg.Quota.Enabled = false | 
					
						
							| 
									
										
										
										
											2021-06-11 21:58:18 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-23 03:48:32 +08:00
										 |  |  | 	store := sqlstore.InitTestDB(t) | 
					
						
							| 
									
										
										
										
											2021-06-11 21:58:18 +08:00
										 |  |  | 	hs := &HTTPServer{ | 
					
						
							| 
									
										
										
										
											2021-09-29 18:51:49 +08:00
										 |  |  | 		Cfg:                cfg, | 
					
						
							| 
									
										
										
										
											2022-03-23 03:48:32 +08:00
										 |  |  | 		Live:               newTestLive(t, store), | 
					
						
							| 
									
										
										
										
											2022-05-05 23:31:14 +08:00
										 |  |  | 		Features:           featuremgmt.WithFeatures(), | 
					
						
							| 
									
										
										
										
											2021-09-29 18:51:49 +08:00
										 |  |  | 		QuotaService:       "a.QuotaService{Cfg: cfg}, | 
					
						
							|  |  |  | 		RouteRegister:      routing.NewRouteRegister(), | 
					
						
							|  |  |  | 		AccessControl:      accesscontrolmock.New().WithPermissions(permissions), | 
					
						
							| 
									
										
										
										
											2022-03-23 03:48:32 +08:00
										 |  |  | 		searchUsersService: searchusers.ProvideUsersService(store, filters.ProvideOSSSearchUserFilter()), | 
					
						
							| 
									
										
										
										
											2022-02-01 19:03:21 +08:00
										 |  |  | 		ldapGroups:         ldap.ProvideGroupsService(), | 
					
						
							| 
									
										
										
										
											2021-06-11 21:58:18 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sc := setupScenarioContext(t, url) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	hs.registerRoutes() | 
					
						
							|  |  |  | 	hs.RouteRegister.Register(sc.m.Router) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-14 23:36:48 +08:00
										 |  |  | 	return sc, hs | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type accessControlTestCase struct { | 
					
						
							|  |  |  | 	expectedCode int | 
					
						
							|  |  |  | 	desc         string | 
					
						
							|  |  |  | 	url          string | 
					
						
							|  |  |  | 	method       string | 
					
						
							|  |  |  | 	permissions  []*accesscontrol.Permission | 
					
						
							| 
									
										
										
										
											2021-06-11 21:58:18 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // accessControlScenarioContext contains the setups for accesscontrol tests
 | 
					
						
							|  |  |  | type accessControlScenarioContext struct { | 
					
						
							|  |  |  | 	// server we registered hs routes on.
 | 
					
						
							|  |  |  | 	server *web.Mux | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// initCtx is used in a middleware to set the initial context
 | 
					
						
							|  |  |  | 	// of the request server side. Can be used to pretend sign in.
 | 
					
						
							|  |  |  | 	initCtx *models.ReqContext | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// hs is a minimal HTTPServer for the accesscontrol tests to pass.
 | 
					
						
							|  |  |  | 	hs *HTTPServer | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// acmock is an accesscontrol mock used to fake users rights.
 | 
					
						
							|  |  |  | 	acmock *accesscontrolmock.Mock | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// db is a test database initialized with InitTestDB
 | 
					
						
							| 
									
										
										
										
											2022-03-08 02:33:01 +08:00
										 |  |  | 	db sqlstore.Store | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// cfg is the setting provider
 | 
					
						
							|  |  |  | 	cfg *setting.Cfg | 
					
						
							| 
									
										
										
										
											2022-02-16 21:15:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	dashboardsStore dashboards.Store | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | func setAccessControlPermissions(acmock *accesscontrolmock.Mock, perms []*accesscontrol.Permission, org int64) { | 
					
						
							| 
									
										
										
										
											2022-02-12 00:40:43 +08:00
										 |  |  | 	acmock.GetUserPermissionsFunc = | 
					
						
							|  |  |  | 		func(_ context.Context, u *models.SignedInUser, _ accesscontrol.Options) ([]*accesscontrol.Permission, error) { | 
					
						
							|  |  |  | 			if u.OrgId == org { | 
					
						
							|  |  |  | 				return perms, nil | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return nil, nil | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | // setInitCtxSignedInUser sets a copy of the user in initCtx
 | 
					
						
							|  |  |  | func setInitCtxSignedInUser(initCtx *models.ReqContext, user models.SignedInUser) { | 
					
						
							|  |  |  | 	initCtx.IsSignedIn = true | 
					
						
							|  |  |  | 	initCtx.SignedInUser = &user | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | func setInitCtxSignedInViewer(initCtx *models.ReqContext) { | 
					
						
							|  |  |  | 	initCtx.IsSignedIn = true | 
					
						
							|  |  |  | 	initCtx.SignedInUser = &models.SignedInUser{UserId: testUserID, OrgId: 1, OrgRole: models.ROLE_VIEWER, Login: testUserLogin} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-11 01:05:53 +08:00
										 |  |  | func setInitCtxSignedInEditor(initCtx *models.ReqContext) { | 
					
						
							|  |  |  | 	initCtx.IsSignedIn = true | 
					
						
							|  |  |  | 	initCtx.SignedInUser = &models.SignedInUser{UserId: testUserID, OrgId: 1, OrgRole: models.ROLE_EDITOR, Login: testUserLogin} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | func setInitCtxSignedInOrgAdmin(initCtx *models.ReqContext) { | 
					
						
							|  |  |  | 	initCtx.IsSignedIn = true | 
					
						
							|  |  |  | 	initCtx.SignedInUser = &models.SignedInUser{UserId: testUserID, OrgId: 1, OrgRole: models.ROLE_ADMIN, Login: testUserLogin} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-27 01:44:20 +08:00
										 |  |  | func setupSimpleHTTPServer(features *featuremgmt.FeatureManager) *HTTPServer { | 
					
						
							|  |  |  | 	if features == nil { | 
					
						
							|  |  |  | 		features = featuremgmt.WithFeatures() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	cfg := setting.NewCfg() | 
					
						
							|  |  |  | 	cfg.IsFeatureToggleEnabled = features.IsEnabled | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return &HTTPServer{ | 
					
						
							| 
									
										
										
										
											2022-02-04 00:49:39 +08:00
										 |  |  | 		Cfg:           cfg, | 
					
						
							|  |  |  | 		Features:      features, | 
					
						
							|  |  |  | 		AccessControl: accesscontrolmock.New().WithDisabled(), | 
					
						
							| 
									
										
										
										
											2022-01-27 01:44:20 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | func setupHTTPServer(t *testing.T, useFakeAccessControl bool, enableAccessControl bool) accessControlScenarioContext { | 
					
						
							| 
									
										
										
										
											2022-05-05 23:31:14 +08:00
										 |  |  | 	return setupHTTPServerWithCfg(t, useFakeAccessControl, enableAccessControl, setting.NewCfg()) | 
					
						
							| 
									
										
										
										
											2022-01-11 01:05:53 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func setupHTTPServerWithCfg(t *testing.T, useFakeAccessControl, enableAccessControl bool, cfg *setting.Cfg) accessControlScenarioContext { | 
					
						
							| 
									
										
										
										
											2022-05-16 18:45:41 +08:00
										 |  |  | 	db := sqlstore.InitTestDB(t, sqlstore.InitTestDBOpt{}) | 
					
						
							| 
									
										
										
										
											2022-05-18 06:11:55 +08:00
										 |  |  | 	return setupHTTPServerWithCfgDb(t, useFakeAccessControl, enableAccessControl, cfg, db, db, featuremgmt.WithFeatures()) | 
					
						
							| 
									
										
										
										
											2022-03-08 02:33:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-18 06:11:55 +08:00
										 |  |  | func setupHTTPServerWithMockDb(t *testing.T, useFakeAccessControl, enableAccessControl bool, features *featuremgmt.FeatureManager) accessControlScenarioContext { | 
					
						
							|  |  |  | 	// Use a new conf
 | 
					
						
							|  |  |  | 	cfg := setting.NewCfg() | 
					
						
							|  |  |  | 	db := sqlstore.InitTestDB(t) | 
					
						
							|  |  |  | 	db.Cfg = setting.NewCfg() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return setupHTTPServerWithCfgDb(t, useFakeAccessControl, enableAccessControl, cfg, db, mockstore.NewSQLStoreMock(), features) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func setupHTTPServerWithCfgDb(t *testing.T, useFakeAccessControl, enableAccessControl bool, cfg *setting.Cfg, db *sqlstore.SQLStore, store sqlstore.Store, features *featuremgmt.FeatureManager) accessControlScenarioContext { | 
					
						
							| 
									
										
										
										
											2022-01-11 01:05:53 +08:00
										 |  |  | 	t.Helper() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-16 18:45:41 +08:00
										 |  |  | 	if enableAccessControl { | 
					
						
							|  |  |  | 		cfg.RBACEnabled = true | 
					
						
							|  |  |  | 		db.Cfg.RBACEnabled = true | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		cfg.RBACEnabled = false | 
					
						
							|  |  |  | 		db.Cfg.RBACEnabled = false | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-01-27 01:44:20 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-11 01:05:53 +08:00
										 |  |  | 	var acmock *accesscontrolmock.Mock | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-16 21:15:44 +08:00
										 |  |  | 	dashboardsStore := dashboardsstore.ProvideDashboardStore(db) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-26 22:48:41 +08:00
										 |  |  | 	routeRegister := routing.NewRouteRegister() | 
					
						
							| 
									
										
										
										
											2022-03-08 02:33:01 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 	// Create minimal HTTP Server
 | 
					
						
							|  |  |  | 	hs := &HTTPServer{ | 
					
						
							|  |  |  | 		Cfg:                cfg, | 
					
						
							| 
									
										
										
										
											2022-01-27 01:44:20 +08:00
										 |  |  | 		Features:           features, | 
					
						
							| 
									
										
										
										
											2022-03-23 03:48:32 +08:00
										 |  |  | 		Live:               newTestLive(t, db), | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 		QuotaService:       "a.QuotaService{Cfg: cfg}, | 
					
						
							| 
									
										
										
										
											2022-01-26 22:48:41 +08:00
										 |  |  | 		RouteRegister:      routeRegister, | 
					
						
							| 
									
										
										
										
											2022-03-08 02:33:01 +08:00
										 |  |  | 		SQLStore:           store, | 
					
						
							| 
									
										
										
										
											2022-03-02 18:05:31 +08:00
										 |  |  | 		searchUsersService: searchusers.ProvideUsersService(db, filters.ProvideOSSSearchUserFilter()), | 
					
						
							| 
									
										
										
										
											2022-05-10 21:48:47 +08:00
										 |  |  | 		dashboardService: dashboardservice.ProvideDashboardService( | 
					
						
							|  |  |  | 			cfg, dashboardsStore, nil, features, | 
					
						
							|  |  |  | 			accesscontrolmock.NewMockedPermissionsService(), accesscontrolmock.NewMockedPermissionsService(), | 
					
						
							|  |  |  | 		), | 
					
						
							|  |  |  | 		preferenceService: preftest.NewPreferenceServiceFake(), | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | 	// Defining the accesscontrol service has to be done before registering routes
 | 
					
						
							|  |  |  | 	if useFakeAccessControl { | 
					
						
							|  |  |  | 		acmock = accesscontrolmock.New() | 
					
						
							|  |  |  | 		if !enableAccessControl { | 
					
						
							|  |  |  | 			acmock = acmock.WithDisabled() | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		hs.AccessControl = acmock | 
					
						
							| 
									
										
										
										
											2022-03-07 20:28:39 +08:00
										 |  |  | 		teamPermissionService, err := ossaccesscontrol.ProvideTeamPermissions(cfg, routeRegister, db, acmock, database.ProvideService(db)) | 
					
						
							| 
									
										
										
										
											2022-01-26 22:48:41 +08:00
										 |  |  | 		require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2022-02-17 21:03:45 +08:00
										 |  |  | 		hs.teamPermissionsService = teamPermissionService | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2022-05-16 18:45:41 +08:00
										 |  |  | 		ac, errInitAc := ossaccesscontrol.ProvideService(hs.Features, hs.Cfg, database.ProvideService(db), routing.NewRouteRegister()) | 
					
						
							| 
									
										
										
										
											2022-04-06 15:31:14 +08:00
										 |  |  | 		require.NoError(t, errInitAc) | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | 		hs.AccessControl = ac | 
					
						
							|  |  |  | 		// Perform role registration
 | 
					
						
							|  |  |  | 		err := hs.declareFixedRoles() | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2022-04-12 15:53:43 +08:00
										 |  |  | 		err = ac.RegisterFixedRoles(context.Background()) | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | 		require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2022-03-07 20:28:39 +08:00
										 |  |  | 		teamPermissionService, err := ossaccesscontrol.ProvideTeamPermissions(cfg, routeRegister, db, ac, database.ProvideService(db)) | 
					
						
							| 
									
										
										
										
											2022-01-26 22:48:41 +08:00
										 |  |  | 		require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2022-02-17 21:03:45 +08:00
										 |  |  | 		hs.teamPermissionsService = teamPermissionService | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 	// Instantiate a new Server
 | 
					
						
							|  |  |  | 	m := web.New() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// middleware to set the test initial context
 | 
					
						
							|  |  |  | 	initCtx := &models.ReqContext{} | 
					
						
							|  |  |  | 	m.Use(func(c *web.Context) { | 
					
						
							|  |  |  | 		initCtx.Context = c | 
					
						
							|  |  |  | 		initCtx.Logger = log.New("api-test") | 
					
						
							|  |  |  | 		c.Map(initCtx) | 
					
						
							| 
									
										
										
										
											2022-05-21 00:45:18 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		c.Req = c.Req.WithContext(ctxkey.Set(c.Req.Context(), initCtx)) | 
					
						
							|  |  |  | 		c.Map(c.Req) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-28 16:46:18 +08:00
										 |  |  | 	m.Use(accesscontrol.LoadPermissionsMiddleware(hs.AccessControl)) | 
					
						
							| 
									
										
										
										
											2022-01-13 21:40:32 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 	// Register all routes
 | 
					
						
							|  |  |  | 	hs.registerRoutes() | 
					
						
							|  |  |  | 	hs.RouteRegister.Register(m.Router) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return accessControlScenarioContext{ | 
					
						
							| 
									
										
										
										
											2022-02-16 21:15:44 +08:00
										 |  |  | 		server:          m, | 
					
						
							|  |  |  | 		initCtx:         initCtx, | 
					
						
							|  |  |  | 		hs:              hs, | 
					
						
							|  |  |  | 		acmock:          acmock, | 
					
						
							|  |  |  | 		db:              db, | 
					
						
							|  |  |  | 		cfg:             cfg, | 
					
						
							|  |  |  | 		dashboardsStore: dashboardsStore, | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func callAPI(server *web.Mux, method, path string, body io.Reader, t *testing.T) *httptest.ResponseRecorder { | 
					
						
							|  |  |  | 	req, err := http.NewRequest(method, path, body) | 
					
						
							|  |  |  | 	require.NoError(t, err) | 
					
						
							|  |  |  | 	req.Header.Set("Content-Type", "application/json") | 
					
						
							|  |  |  | 	recorder := httptest.NewRecorder() | 
					
						
							|  |  |  | 	server.ServeHTTP(recorder, req) | 
					
						
							|  |  |  | 	return recorder | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-11-29 17:18:01 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func mockRequestBody(v interface{}) io.ReadCloser { | 
					
						
							|  |  |  | 	b, _ := json.Marshal(v) | 
					
						
							|  |  |  | 	return io.NopCloser(bytes.NewReader(b)) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-03-11 01:38:04 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // APITestServerOption option func for customizing HTTPServer configuration
 | 
					
						
							|  |  |  | // when setting up an API test server via SetupAPITestServer.
 | 
					
						
							|  |  |  | type APITestServerOption func(hs *HTTPServer) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // SetupAPITestServer sets up a webtest.Server ready for testing all
 | 
					
						
							|  |  |  | // routes registered via HTTPServer.registerRoutes().
 | 
					
						
							|  |  |  | // Optionally customize HTTPServer configuration by providing APITestServerOption
 | 
					
						
							|  |  |  | // option(s).
 | 
					
						
							|  |  |  | func SetupAPITestServer(t *testing.T, opts ...APITestServerOption) *webtest.Server { | 
					
						
							|  |  |  | 	t.Helper() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	hs := &HTTPServer{ | 
					
						
							|  |  |  | 		RouteRegister:      routing.NewRouteRegister(), | 
					
						
							|  |  |  | 		Cfg:                setting.NewCfg(), | 
					
						
							|  |  |  | 		AccessControl:      accesscontrolmock.New().WithDisabled(), | 
					
						
							|  |  |  | 		Features:           featuremgmt.WithFeatures(), | 
					
						
							|  |  |  | 		searchUsersService: &searchusers.OSSService{}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, opt := range opts { | 
					
						
							|  |  |  | 		opt(hs) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	hs.registerRoutes() | 
					
						
							|  |  |  | 	s := webtest.NewServer(t, hs.RouteRegister) | 
					
						
							|  |  |  | 	return s | 
					
						
							|  |  |  | } |