| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | package api | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"net/http" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							|  |  |  | 	"testing" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/stretchr/testify/assert" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/services/accesscontrol" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/setting" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var ( | 
					
						
							|  |  |  | 	getCurrentOrgQuotasURL = "/api/org/quotas" | 
					
						
							|  |  |  | 	getOrgsQuotasURL       = "/api/orgs/%v/quotas" | 
					
						
							|  |  |  | 	putOrgsQuotasURL       = "/api/orgs/%v/quotas/%v" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	testUpdateOrgQuotaCmd = `{ "limit": 20 }` | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var testOrgQuota = setting.OrgQuota{ | 
					
						
							|  |  |  | 	User:       10, | 
					
						
							|  |  |  | 	DataSource: 10, | 
					
						
							|  |  |  | 	Dashboard:  10, | 
					
						
							|  |  |  | 	ApiKey:     10, | 
					
						
							|  |  |  | 	AlertRule:  10, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | // setupDBAndSettingsForAccessControlQuotaTests stores users and create two orgs
 | 
					
						
							|  |  |  | func setupDBAndSettingsForAccessControlQuotaTests(t *testing.T, sc accessControlScenarioContext) { | 
					
						
							|  |  |  | 	t.Helper() | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	sc.hs.Cfg.Quota.Enabled = true | 
					
						
							|  |  |  | 	sc.hs.Cfg.Quota.Org = &testOrgQuota | 
					
						
							|  |  |  | 	// Required while sqlstore quota.go relies on setting global variables
 | 
					
						
							|  |  |  | 	setting.Quota = sc.hs.Cfg.Quota | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | 	// Create two orgs with the context user
 | 
					
						
							| 
									
										
										
										
											2022-03-08 02:33:01 +08:00
										 |  |  | 	setupOrgsDBForAccessControlTests(t, sc.db, *sc.initCtx.SignedInUser, 2) | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestAPIEndpoint_GetCurrentOrgQuotas_LegacyAccessControl(t *testing.T) { | 
					
						
							|  |  |  | 	sc := setupHTTPServer(t, true, false) | 
					
						
							|  |  |  | 	setInitCtxSignedInViewer(sc.initCtx) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	setupDBAndSettingsForAccessControlQuotaTests(t, sc) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("Viewer can view CurrentOrgQuotas", func(t *testing.T) { | 
					
						
							|  |  |  | 		response := callAPI(sc.server, http.MethodGet, getCurrentOrgQuotasURL, nil, t) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusOK, response.Code) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sc.initCtx.IsSignedIn = false | 
					
						
							|  |  |  | 	t.Run("Unsigned user cannot view CurrentOrgQuotas", func(t *testing.T) { | 
					
						
							|  |  |  | 		response := callAPI(sc.server, http.MethodGet, getCurrentOrgQuotasURL, nil, t) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusUnauthorized, response.Code) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestAPIEndpoint_GetCurrentOrgQuotas_AccessControl(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | 	sc := setupHTTPServer(t, true, true) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 	setInitCtxSignedInViewer(sc.initCtx) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | 	setupDBAndSettingsForAccessControlQuotaTests(t, sc) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("AccessControl allows viewing CurrentOrgQuotas with correct permissions", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | 		setAccessControlPermissions(sc.acmock, []*accesscontrol.Permission{{Action: ActionOrgsQuotasRead}}, sc.initCtx.OrgId) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 		response := callAPI(sc.server, http.MethodGet, getCurrentOrgQuotasURL, nil, t) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusOK, response.Code) | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | 	t.Run("AccessControl prevents viewing CurrentOrgQuotas with correct permissions in another org", func(t *testing.T) { | 
					
						
							|  |  |  | 		setAccessControlPermissions(sc.acmock, []*accesscontrol.Permission{{Action: ActionOrgsQuotasRead}}, 2) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 		response := callAPI(sc.server, http.MethodGet, getCurrentOrgQuotasURL, nil, t) | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | 		assert.Equal(t, http.StatusForbidden, response.Code) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 	t.Run("AccessControl prevents viewing CurrentOrgQuotas with incorrect permissions", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | 		setAccessControlPermissions(sc.acmock, []*accesscontrol.Permission{{Action: "orgs:invalid"}}, sc.initCtx.OrgId) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 		response := callAPI(sc.server, http.MethodGet, getCurrentOrgQuotasURL, nil, t) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusForbidden, response.Code) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestAPIEndpoint_GetOrgQuotas_LegacyAccessControl(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | 	sc := setupHTTPServer(t, true, false) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 	setInitCtxSignedInViewer(sc.initCtx) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | 	setupDBAndSettingsForAccessControlQuotaTests(t, sc) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("Viewer cannot view another org quotas", func(t *testing.T) { | 
					
						
							|  |  |  | 		response := callAPI(sc.server, http.MethodGet, fmt.Sprintf(getOrgsQuotasURL, 2), nil, t) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusForbidden, response.Code) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sc.initCtx.SignedInUser.IsGrafanaAdmin = true | 
					
						
							|  |  |  | 	t.Run("Grafana admin viewer can view another org quotas", func(t *testing.T) { | 
					
						
							|  |  |  | 		response := callAPI(sc.server, http.MethodGet, fmt.Sprintf(getOrgsQuotasURL, 2), nil, t) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusOK, response.Code) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestAPIEndpoint_GetOrgQuotas_AccessControl(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | 	sc := setupHTTPServer(t, true, true) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 	setInitCtxSignedInViewer(sc.initCtx) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | 	setupDBAndSettingsForAccessControlQuotaTests(t, sc) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("AccessControl allows viewing another org quotas with correct permissions", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | 		setAccessControlPermissions(sc.acmock, []*accesscontrol.Permission{{Action: ActionOrgsQuotasRead}}, 2) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 		response := callAPI(sc.server, http.MethodGet, fmt.Sprintf(getOrgsQuotasURL, 2), nil, t) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusOK, response.Code) | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | 	t.Run("AccessControl prevents viewing another org quotas with correct permissions in another org", func(t *testing.T) { | 
					
						
							|  |  |  | 		setAccessControlPermissions(sc.acmock, []*accesscontrol.Permission{{Action: ActionOrgsQuotasRead}}, 1) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 		response := callAPI(sc.server, http.MethodGet, fmt.Sprintf(getOrgsQuotasURL, 2), nil, t) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusForbidden, response.Code) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	t.Run("AccessControl prevents viewing another org quotas with incorrect permissions", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | 		setAccessControlPermissions(sc.acmock, []*accesscontrol.Permission{{Action: "orgs:invalid"}}, 2) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 		response := callAPI(sc.server, http.MethodGet, fmt.Sprintf(getOrgsQuotasURL, 2), nil, t) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusForbidden, response.Code) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestAPIEndpoint_PutOrgQuotas_LegacyAccessControl(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | 	sc := setupHTTPServer(t, true, false) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 	setInitCtxSignedInViewer(sc.initCtx) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | 	setupDBAndSettingsForAccessControlQuotaTests(t, sc) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	input := strings.NewReader(testUpdateOrgQuotaCmd) | 
					
						
							|  |  |  | 	t.Run("Viewer cannot update another org quotas", func(t *testing.T) { | 
					
						
							|  |  |  | 		response := callAPI(sc.server, http.MethodPut, fmt.Sprintf(putOrgsQuotasURL, 2, "org_user"), input, t) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusForbidden, response.Code) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sc.initCtx.SignedInUser.IsGrafanaAdmin = true | 
					
						
							|  |  |  | 	input = strings.NewReader(testUpdateOrgQuotaCmd) | 
					
						
							|  |  |  | 	t.Run("Grafana admin viewer can update another org quotas", func(t *testing.T) { | 
					
						
							|  |  |  | 		response := callAPI(sc.server, http.MethodPut, fmt.Sprintf(putOrgsQuotasURL, 2, "org_user"), input, t) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusOK, response.Code) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestAPIEndpoint_PutOrgQuotas_AccessControl(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | 	sc := setupHTTPServer(t, true, true) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 	setInitCtxSignedInViewer(sc.initCtx) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | 	setupDBAndSettingsForAccessControlQuotaTests(t, sc) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	input := strings.NewReader(testUpdateOrgQuotaCmd) | 
					
						
							|  |  |  | 	t.Run("AccessControl allows updating another org quotas with correct permissions", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | 		setAccessControlPermissions(sc.acmock, []*accesscontrol.Permission{{Action: ActionOrgsQuotasWrite}}, 2) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 		response := callAPI(sc.server, http.MethodPut, fmt.Sprintf(putOrgsQuotasURL, 2, "org_user"), input, t) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusOK, response.Code) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	input = strings.NewReader(testUpdateOrgQuotaCmd) | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | 	t.Run("AccessControl prevents updating another org quotas with correct permissions in another org", func(t *testing.T) { | 
					
						
							|  |  |  | 		setAccessControlPermissions(sc.acmock, []*accesscontrol.Permission{{Action: ActionOrgsQuotasWrite}}, 1) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 		response := callAPI(sc.server, http.MethodPut, fmt.Sprintf(putOrgsQuotasURL, 2, "org_user"), input, t) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusForbidden, response.Code) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	input = strings.NewReader(testUpdateOrgQuotaCmd) | 
					
						
							|  |  |  | 	t.Run("AccessControl prevents updating another org quotas with incorrect permissions", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | 		setAccessControlPermissions(sc.acmock, []*accesscontrol.Permission{{Action: "orgs:invalid"}}, 2) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 		response := callAPI(sc.server, http.MethodPut, fmt.Sprintf(putOrgsQuotasURL, 2, "org_user"), input, t) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusForbidden, response.Code) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | } |