| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | package api | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"net/http" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							|  |  |  | 	"testing" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/stretchr/testify/assert" | 
					
						
							| 
									
										
										
										
											2023-01-17 18:33:01 +08:00
										 |  |  | 	"github.com/stretchr/testify/require" | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/services/accesscontrol" | 
					
						
							| 
									
										
										
										
											2023-01-17 18:33:01 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/org" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/services/user" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/services/user/usertest" | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/setting" | 
					
						
							| 
									
										
										
										
											2023-01-17 18:33:01 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/web/webtest" | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var ( | 
					
						
							|  |  |  | 	getCurrentOrgQuotasURL = "/api/org/quotas" | 
					
						
							|  |  |  | 	getOrgsQuotasURL       = "/api/orgs/%v/quotas" | 
					
						
							|  |  |  | 	putOrgsQuotasURL       = "/api/orgs/%v/quotas/%v" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	testUpdateOrgQuotaCmd = `{ "limit": 20 }` | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | func TestAPIEndpoint_GetCurrentOrgQuotas_LegacyAccessControl(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2022-08-11 21:37:31 +08:00
										 |  |  | 	cfg := setting.NewCfg() | 
					
						
							| 
									
										
										
										
											2022-11-15 03:08:10 +08:00
										 |  |  | 	cfg.Quota.Enabled = true | 
					
						
							| 
									
										
										
										
											2022-08-11 21:37:31 +08:00
										 |  |  | 	cfg.RBACEnabled = false | 
					
						
							| 
									
										
										
										
											2023-01-17 18:33:01 +08:00
										 |  |  | 	server := SetupAPITestServer(t, func(hs *HTTPServer) { | 
					
						
							|  |  |  | 		hs.Cfg = cfg | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("Unsigned user cannot view CurrentOrgQuotas", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-01-17 18:33:01 +08:00
										 |  |  | 		req := server.NewGetRequest(getCurrentOrgQuotasURL) | 
					
						
							|  |  |  | 		res, err := server.Send(req) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusUnauthorized, res.StatusCode) | 
					
						
							|  |  |  | 		require.NoError(t, res.Body.Close()) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	t.Run("Viewer can view CurrentOrgQuotas", func(t *testing.T) { | 
					
						
							|  |  |  | 		req := webtest.RequestWithSignedInUser(server.NewGetRequest(getCurrentOrgQuotasURL), &user.SignedInUser{OrgID: 1, OrgRole: org.RoleViewer}) | 
					
						
							|  |  |  | 		res, err := server.Send(req) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusOK, res.StatusCode) | 
					
						
							|  |  |  | 		require.NoError(t, res.Body.Close()) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestAPIEndpoint_GetCurrentOrgQuotas_AccessControl(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2022-11-15 03:08:10 +08:00
										 |  |  | 	cfg := setting.NewCfg() | 
					
						
							|  |  |  | 	cfg.Quota.Enabled = true | 
					
						
							| 
									
										
										
										
											2023-01-17 18:33:01 +08:00
										 |  |  | 	server := SetupAPITestServer(t, func(hs *HTTPServer) { | 
					
						
							|  |  |  | 		hs.Cfg = cfg | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("AccessControl allows viewing CurrentOrgQuotas with correct permissions", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-01-17 18:33:01 +08:00
										 |  |  | 		req := webtest.RequestWithSignedInUser(server.NewGetRequest(getCurrentOrgQuotasURL), userWithPermissions(1, []accesscontrol.Permission{{Action: accesscontrol.ActionOrgsQuotasRead}})) | 
					
						
							|  |  |  | 		res, err := server.Send(req) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusOK, res.StatusCode) | 
					
						
							|  |  |  | 		require.NoError(t, res.Body.Close()) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2021-11-17 17:12:28 +08:00
										 |  |  | 	t.Run("AccessControl prevents viewing CurrentOrgQuotas with correct permissions in another org", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-01-17 18:33:01 +08:00
										 |  |  | 		// Set permissions in org 2, but set current org to org 1
 | 
					
						
							|  |  |  | 		user := userWithPermissions(2, []accesscontrol.Permission{{Action: accesscontrol.ActionOrgsQuotasRead}}) | 
					
						
							|  |  |  | 		user.OrgID = 1 | 
					
						
							|  |  |  | 		req := webtest.RequestWithSignedInUser(server.NewGetRequest(getCurrentOrgQuotasURL), user) | 
					
						
							|  |  |  | 		res, err := server.Send(req) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusForbidden, res.StatusCode) | 
					
						
							|  |  |  | 		require.NoError(t, res.Body.Close()) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 	t.Run("AccessControl prevents viewing CurrentOrgQuotas with incorrect permissions", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-01-17 18:33:01 +08:00
										 |  |  | 		req := webtest.RequestWithSignedInUser(server.NewGetRequest(getCurrentOrgQuotasURL), userWithPermissions(1, []accesscontrol.Permission{{Action: "orgs:invalid"}})) | 
					
						
							|  |  |  | 		res, err := server.Send(req) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusForbidden, res.StatusCode) | 
					
						
							|  |  |  | 		require.NoError(t, res.Body.Close()) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestAPIEndpoint_GetOrgQuotas_LegacyAccessControl(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2022-08-11 21:37:31 +08:00
										 |  |  | 	cfg := setting.NewCfg() | 
					
						
							| 
									
										
										
										
											2022-11-15 03:08:10 +08:00
										 |  |  | 	cfg.Quota.Enabled = true | 
					
						
							| 
									
										
										
										
											2022-08-11 21:37:31 +08:00
										 |  |  | 	cfg.RBACEnabled = false | 
					
						
							| 
									
										
										
										
											2023-01-17 18:33:01 +08:00
										 |  |  | 	server := SetupAPITestServer(t, func(hs *HTTPServer) { | 
					
						
							|  |  |  | 		hs.Cfg = cfg | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("Viewer cannot view another org quotas", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-01-17 18:33:01 +08:00
										 |  |  | 		req := webtest.RequestWithSignedInUser(server.NewGetRequest(fmt.Sprintf(getOrgsQuotasURL, 2)), &user.SignedInUser{OrgID: 1, OrgRole: org.RoleViewer}) | 
					
						
							|  |  |  | 		res, err := server.Send(req) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusForbidden, res.StatusCode) | 
					
						
							|  |  |  | 		require.NoError(t, res.Body.Close()) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("Grafana admin viewer can view another org quotas", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-01-17 18:33:01 +08:00
										 |  |  | 		req := webtest.RequestWithSignedInUser(server.NewGetRequest(fmt.Sprintf(getOrgsQuotasURL, 2)), &user.SignedInUser{OrgID: 1, OrgRole: org.RoleViewer, IsGrafanaAdmin: true}) | 
					
						
							|  |  |  | 		res, err := server.Send(req) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusOK, res.StatusCode) | 
					
						
							|  |  |  | 		require.NoError(t, res.Body.Close()) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestAPIEndpoint_GetOrgQuotas_AccessControl(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2022-11-15 03:08:10 +08:00
										 |  |  | 	cfg := setting.NewCfg() | 
					
						
							|  |  |  | 	cfg.Quota.Enabled = true | 
					
						
							| 
									
										
										
										
											2023-01-17 18:33:01 +08:00
										 |  |  | 	server := SetupAPITestServer(t, func(hs *HTTPServer) { | 
					
						
							|  |  |  | 		hs.Cfg = cfg | 
					
						
							|  |  |  | 		hs.userService = &usertest.FakeUserService{ | 
					
						
							|  |  |  | 			ExpectedSignedInUser: &user.SignedInUser{OrgID: 2}, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("AccessControl allows viewing another org quotas with correct permissions", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-01-17 18:33:01 +08:00
										 |  |  | 		req := webtest.RequestWithSignedInUser(server.NewGetRequest(fmt.Sprintf(getOrgsQuotasURL, 2)), userWithPermissions(2, []accesscontrol.Permission{{Action: accesscontrol.ActionOrgsQuotasRead}})) | 
					
						
							|  |  |  | 		res, err := server.Send(req) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusOK, res.StatusCode) | 
					
						
							|  |  |  | 		require.NoError(t, res.Body.Close()) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 	}) | 
					
						
							| 
									
										
										
										
											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) { | 
					
						
							| 
									
										
										
										
											2023-01-17 18:33:01 +08:00
										 |  |  | 		// Set correct permissions in org 1 and empty permissions in org 2
 | 
					
						
							|  |  |  | 		user := userWithPermissions(1, []accesscontrol.Permission{{Action: accesscontrol.ActionOrgsQuotasRead}}) | 
					
						
							|  |  |  | 		user.Permissions[2] = map[string][]string{} | 
					
						
							|  |  |  | 		req := webtest.RequestWithSignedInUser(server.NewGetRequest(fmt.Sprintf(getOrgsQuotasURL, 2)), user) | 
					
						
							|  |  |  | 		res, err := server.Send(req) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusForbidden, res.StatusCode) | 
					
						
							|  |  |  | 		require.NoError(t, res.Body.Close()) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 	t.Run("AccessControl prevents viewing another org quotas with incorrect permissions", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-01-17 18:33:01 +08:00
										 |  |  | 		req := webtest.RequestWithSignedInUser(server.NewGetRequest(fmt.Sprintf(getOrgsQuotasURL, 2)), userWithPermissions(2, []accesscontrol.Permission{{Action: "orgs:invalid"}})) | 
					
						
							|  |  |  | 		res, err := server.Send(req) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusForbidden, res.StatusCode) | 
					
						
							|  |  |  | 		require.NoError(t, res.Body.Close()) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestAPIEndpoint_PutOrgQuotas_LegacyAccessControl(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2022-08-11 21:37:31 +08:00
										 |  |  | 	cfg := setting.NewCfg() | 
					
						
							| 
									
										
										
										
											2022-11-15 03:08:10 +08:00
										 |  |  | 	cfg.Quota.Enabled = true | 
					
						
							| 
									
										
										
										
											2022-08-11 21:37:31 +08:00
										 |  |  | 	cfg.RBACEnabled = false | 
					
						
							| 
									
										
										
										
											2023-01-17 18:33:01 +08:00
										 |  |  | 	server := SetupAPITestServer(t, func(hs *HTTPServer) { | 
					
						
							|  |  |  | 		hs.Cfg = cfg | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	input := strings.NewReader(testUpdateOrgQuotaCmd) | 
					
						
							|  |  |  | 	t.Run("Viewer cannot update another org quotas", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-01-17 18:33:01 +08:00
										 |  |  | 		req := webtest.RequestWithSignedInUser(server.NewRequest(http.MethodPut, fmt.Sprintf(putOrgsQuotasURL, 2, "org_user"), input), &user.SignedInUser{ | 
					
						
							|  |  |  | 			OrgID:   1, | 
					
						
							|  |  |  | 			OrgRole: org.RoleViewer, | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		response, err := server.SendJSON(req) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusForbidden, response.StatusCode) | 
					
						
							|  |  |  | 		require.NoError(t, response.Body.Close()) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	input = strings.NewReader(testUpdateOrgQuotaCmd) | 
					
						
							|  |  |  | 	t.Run("Grafana admin viewer can update another org quotas", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-01-17 18:33:01 +08:00
										 |  |  | 		req := webtest.RequestWithSignedInUser(server.NewRequest(http.MethodPut, fmt.Sprintf(putOrgsQuotasURL, 2, "org_user"), input), &user.SignedInUser{ | 
					
						
							|  |  |  | 			OrgID:          1, | 
					
						
							|  |  |  | 			OrgRole:        org.RoleViewer, | 
					
						
							|  |  |  | 			IsGrafanaAdmin: true, | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		response, err := server.SendJSON(req) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusOK, response.StatusCode) | 
					
						
							|  |  |  | 		require.NoError(t, response.Body.Close()) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestAPIEndpoint_PutOrgQuotas_AccessControl(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2022-11-15 03:08:10 +08:00
										 |  |  | 	cfg := setting.NewCfg() | 
					
						
							|  |  |  | 	cfg.Quota = setting.QuotaSettings{ | 
					
						
							|  |  |  | 		Enabled: true, | 
					
						
							|  |  |  | 		Global: setting.GlobalQuota{ | 
					
						
							|  |  |  | 			Org: 5, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		Org: setting.OrgQuota{ | 
					
						
							|  |  |  | 			User: 5, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		User: setting.UserQuota{ | 
					
						
							|  |  |  | 			Org: 5, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-01-17 18:33:01 +08:00
										 |  |  | 	server := SetupAPITestServer(t, func(hs *HTTPServer) { | 
					
						
							|  |  |  | 		hs.Cfg = cfg | 
					
						
							|  |  |  | 		hs.userService = &usertest.FakeUserService{ | 
					
						
							|  |  |  | 			ExpectedSignedInUser: &user.SignedInUser{OrgID: 2}, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											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) { | 
					
						
							| 
									
										
										
										
											2023-01-17 18:33:01 +08:00
										 |  |  | 		user := userWithPermissions(2, []accesscontrol.Permission{{Action: accesscontrol.ActionOrgsQuotasWrite}}) | 
					
						
							|  |  |  | 		user.OrgID = 1 | 
					
						
							|  |  |  | 		req := webtest.RequestWithSignedInUser(server.NewRequest(http.MethodPut, fmt.Sprintf(putOrgsQuotasURL, 2, "org_user"), input), user) | 
					
						
							|  |  |  | 		response, err := server.SendJSON(req) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusOK, response.StatusCode) | 
					
						
							|  |  |  | 		require.NoError(t, response.Body.Close()) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	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) { | 
					
						
							| 
									
										
										
										
											2023-01-17 18:33:01 +08:00
										 |  |  | 		user := userWithPermissions(1, []accesscontrol.Permission{{Action: accesscontrol.ActionOrgsQuotasWrite}}) | 
					
						
							|  |  |  | 		user.Permissions[2] = map[string][]string{} | 
					
						
							|  |  |  | 		req := webtest.RequestWithSignedInUser(server.NewRequest(http.MethodPut, fmt.Sprintf(putOrgsQuotasURL, 2, "org_user"), input), user) | 
					
						
							|  |  |  | 		response, err := server.SendJSON(req) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusForbidden, response.StatusCode) | 
					
						
							|  |  |  | 		require.NoError(t, response.Body.Close()) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	input = strings.NewReader(testUpdateOrgQuotaCmd) | 
					
						
							|  |  |  | 	t.Run("AccessControl prevents updating another org quotas with incorrect permissions", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-01-17 18:33:01 +08:00
										 |  |  | 		user := userWithPermissions(2, []accesscontrol.Permission{{Action: "orgs:invalid"}}) | 
					
						
							|  |  |  | 		req := webtest.RequestWithSignedInUser(server.NewRequest(http.MethodPut, fmt.Sprintf(putOrgsQuotasURL, 2, "org_user"), input), user) | 
					
						
							|  |  |  | 		response, err := server.SendJSON(req) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		assert.Equal(t, http.StatusForbidden, response.StatusCode) | 
					
						
							|  |  |  | 		require.NoError(t, response.Body.Close()) | 
					
						
							| 
									
										
										
										
											2021-10-27 19:13:59 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | } |