| 
									
										
										
										
											2016-02-10 23:43:35 +08:00
										 |  |  | package pluginproxy | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2021-10-07 22:33:50 +08:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2022-08-23 19:05:31 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2022-08-10 21:37:51 +08:00
										 |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2019-03-14 20:04:47 +08:00
										 |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2022-02-09 20:44:38 +08:00
										 |  |  | 	"net/http/httptest" | 
					
						
							| 
									
										
										
										
											2022-08-23 19:05:31 +08:00
										 |  |  | 	"net/url" | 
					
						
							| 
									
										
										
										
											2016-02-10 23:43:35 +08:00
										 |  |  | 	"testing" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-23 19:05:31 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/infra/tracing" | 
					
						
							| 
									
										
										
										
											2020-03-04 19:57:20 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/models" | 
					
						
							| 
									
										
										
										
											2016-02-10 23:43:35 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/plugins" | 
					
						
							| 
									
										
										
										
											2022-08-10 17:56:48 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/org" | 
					
						
							| 
									
										
										
										
											2022-02-25 18:29:18 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/pluginsettings" | 
					
						
							| 
									
										
										
										
											2021-11-05 00:47:21 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/secrets" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/services/secrets/fakes" | 
					
						
							|  |  |  | 	secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager" | 
					
						
							| 
									
										
										
										
											2022-08-10 17:56:48 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/services/user" | 
					
						
							| 
									
										
										
										
											2016-02-10 23:43:35 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/setting" | 
					
						
							| 
									
										
										
										
											2021-12-13 22:56:14 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/web" | 
					
						
							| 
									
										
										
										
											2020-11-17 18:31:35 +08:00
										 |  |  | 	"github.com/stretchr/testify/assert" | 
					
						
							|  |  |  | 	"github.com/stretchr/testify/require" | 
					
						
							| 
									
										
										
										
											2016-02-10 23:43:35 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestPluginProxy(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2021-11-05 00:47:21 +08:00
										 |  |  | 	setting.SecretKey = "password" | 
					
						
							|  |  |  | 	secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore()) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-17 18:31:35 +08:00
										 |  |  | 	t.Run("When getting proxy headers", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2021-11-01 17:53:33 +08:00
										 |  |  | 		route := &plugins.Route{ | 
					
						
							|  |  |  | 			Headers: []plugins.Header{ | 
					
						
							| 
									
										
										
										
											2016-02-10 23:43:35 +08:00
										 |  |  | 				{Name: "x-header", Content: "my secret {{.SecureJsonData.key}}"}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-02-25 18:29:18 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-23 19:05:31 +08:00
										 |  |  | 		key, err := secretsService.Encrypt(context.Background(), []byte("123"), secrets.WithoutScope()) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2016-02-10 23:43:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-07 22:33:50 +08:00
										 |  |  | 		httpReq, err := http.NewRequest(http.MethodGet, "", nil) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-17 17:56:42 +08:00
										 |  |  | 		req := getPluginProxiedRequest( | 
					
						
							| 
									
										
										
										
											2020-11-17 18:31:35 +08:00
										 |  |  | 			t, | 
					
						
							| 
									
										
										
										
											2022-08-23 19:05:31 +08:00
										 |  |  | 			&pluginsettings.DTO{ | 
					
						
							|  |  |  | 				SecureJSONData: map[string][]byte{ | 
					
						
							|  |  |  | 					"key": key, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2021-11-05 00:47:21 +08:00
										 |  |  | 			secretsService, | 
					
						
							| 
									
										
										
										
											2020-11-17 17:56:42 +08:00
										 |  |  | 			&models.ReqContext{ | 
					
						
							| 
									
										
										
										
											2022-08-10 17:56:48 +08:00
										 |  |  | 				SignedInUser: &user.SignedInUser{ | 
					
						
							| 
									
										
										
										
											2020-11-17 17:56:42 +08:00
										 |  |  | 					Login: "test_user", | 
					
						
							|  |  |  | 				}, | 
					
						
							| 
									
										
										
										
											2021-12-13 22:56:14 +08:00
										 |  |  | 				Context: &web.Context{ | 
					
						
							| 
									
										
										
										
											2021-10-07 22:33:50 +08:00
										 |  |  | 					Req: httpReq, | 
					
						
							|  |  |  | 				}, | 
					
						
							| 
									
										
										
										
											2020-11-17 17:56:42 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			&setting.Cfg{SendUserHeader: true}, | 
					
						
							|  |  |  | 			route, | 
					
						
							|  |  |  | 		) | 
					
						
							| 
									
										
										
										
											2016-02-10 23:43:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-17 18:31:35 +08:00
										 |  |  | 		assert.Equal(t, "my secret 123", req.Header.Get("x-header")) | 
					
						
							| 
									
										
										
										
											2016-02-10 23:43:35 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-17 18:31:35 +08:00
										 |  |  | 	t.Run("When SendUserHeader config is enabled", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2021-10-07 22:33:50 +08:00
										 |  |  | 		httpReq, err := http.NewRequest(http.MethodGet, "", nil) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2022-02-25 18:29:18 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-14 20:04:47 +08:00
										 |  |  | 		req := getPluginProxiedRequest( | 
					
						
							| 
									
										
										
										
											2020-11-17 18:31:35 +08:00
										 |  |  | 			t, | 
					
						
							| 
									
										
										
										
											2022-08-23 19:05:31 +08:00
										 |  |  | 			&pluginsettings.DTO{}, | 
					
						
							| 
									
										
										
										
											2021-11-05 00:47:21 +08:00
										 |  |  | 			secretsService, | 
					
						
							| 
									
										
										
										
											2020-03-04 19:57:20 +08:00
										 |  |  | 			&models.ReqContext{ | 
					
						
							| 
									
										
										
										
											2022-08-10 17:56:48 +08:00
										 |  |  | 				SignedInUser: &user.SignedInUser{ | 
					
						
							| 
									
										
										
										
											2019-03-14 20:04:47 +08:00
										 |  |  | 					Login: "test_user", | 
					
						
							|  |  |  | 				}, | 
					
						
							| 
									
										
										
										
											2021-12-13 22:56:14 +08:00
										 |  |  | 				Context: &web.Context{ | 
					
						
							| 
									
										
										
										
											2021-10-07 22:33:50 +08:00
										 |  |  | 					Req: httpReq, | 
					
						
							|  |  |  | 				}, | 
					
						
							| 
									
										
										
										
											2019-03-14 20:04:47 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			&setting.Cfg{SendUserHeader: true}, | 
					
						
							| 
									
										
										
										
											2019-05-08 00:55:39 +08:00
										 |  |  | 			nil, | 
					
						
							| 
									
										
										
										
											2019-03-14 20:04:47 +08:00
										 |  |  | 		) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-17 18:31:35 +08:00
										 |  |  | 		// Get will return empty string even if header is not set
 | 
					
						
							|  |  |  | 		assert.Equal(t, "test_user", req.Header.Get("X-Grafana-User")) | 
					
						
							| 
									
										
										
										
											2019-03-14 20:04:47 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-17 18:31:35 +08:00
										 |  |  | 	t.Run("When SendUserHeader config is disabled", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2021-10-07 22:33:50 +08:00
										 |  |  | 		httpReq, err := http.NewRequest(http.MethodGet, "", nil) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2022-02-25 18:29:18 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-14 20:04:47 +08:00
										 |  |  | 		req := getPluginProxiedRequest( | 
					
						
							| 
									
										
										
										
											2020-11-17 18:31:35 +08:00
										 |  |  | 			t, | 
					
						
							| 
									
										
										
										
											2022-08-23 19:05:31 +08:00
										 |  |  | 			&pluginsettings.DTO{}, | 
					
						
							| 
									
										
										
										
											2021-11-05 00:47:21 +08:00
										 |  |  | 			secretsService, | 
					
						
							| 
									
										
										
										
											2020-03-04 19:57:20 +08:00
										 |  |  | 			&models.ReqContext{ | 
					
						
							| 
									
										
										
										
											2022-08-10 17:56:48 +08:00
										 |  |  | 				SignedInUser: &user.SignedInUser{ | 
					
						
							| 
									
										
										
										
											2019-03-14 20:04:47 +08:00
										 |  |  | 					Login: "test_user", | 
					
						
							|  |  |  | 				}, | 
					
						
							| 
									
										
										
										
											2021-12-13 22:56:14 +08:00
										 |  |  | 				Context: &web.Context{ | 
					
						
							| 
									
										
										
										
											2021-10-07 22:33:50 +08:00
										 |  |  | 					Req: httpReq, | 
					
						
							|  |  |  | 				}, | 
					
						
							| 
									
										
										
										
											2019-03-14 20:04:47 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			&setting.Cfg{SendUserHeader: false}, | 
					
						
							| 
									
										
										
										
											2019-05-08 00:55:39 +08:00
										 |  |  | 			nil, | 
					
						
							| 
									
										
										
										
											2019-03-14 20:04:47 +08:00
										 |  |  | 		) | 
					
						
							| 
									
										
										
										
											2020-11-17 18:31:35 +08:00
										 |  |  | 		// Get will return empty string even if header is not set
 | 
					
						
							|  |  |  | 		assert.Equal(t, "", req.Header.Get("X-Grafana-User")) | 
					
						
							| 
									
										
										
										
											2019-03-14 20:04:47 +08:00
										 |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2019-03-14 23:28:32 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-17 18:31:35 +08:00
										 |  |  | 	t.Run("When SendUserHeader config is enabled but user is anonymous", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2021-10-07 22:33:50 +08:00
										 |  |  | 		httpReq, err := http.NewRequest(http.MethodGet, "", nil) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2022-02-25 18:29:18 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-14 23:28:32 +08:00
										 |  |  | 		req := getPluginProxiedRequest( | 
					
						
							| 
									
										
										
										
											2020-11-17 18:31:35 +08:00
										 |  |  | 			t, | 
					
						
							| 
									
										
										
										
											2022-08-23 19:05:31 +08:00
										 |  |  | 			&pluginsettings.DTO{}, | 
					
						
							| 
									
										
										
										
											2021-11-05 00:47:21 +08:00
										 |  |  | 			secretsService, | 
					
						
							| 
									
										
										
										
											2020-03-04 19:57:20 +08:00
										 |  |  | 			&models.ReqContext{ | 
					
						
							| 
									
										
										
										
											2022-08-10 17:56:48 +08:00
										 |  |  | 				SignedInUser: &user.SignedInUser{IsAnonymous: true}, | 
					
						
							| 
									
										
										
										
											2021-12-13 22:56:14 +08:00
										 |  |  | 				Context: &web.Context{ | 
					
						
							| 
									
										
										
										
											2021-10-07 22:33:50 +08:00
										 |  |  | 					Req: httpReq, | 
					
						
							|  |  |  | 				}, | 
					
						
							| 
									
										
										
										
											2019-03-14 23:28:32 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			&setting.Cfg{SendUserHeader: true}, | 
					
						
							| 
									
										
										
										
											2019-05-08 00:55:39 +08:00
										 |  |  | 			nil, | 
					
						
							| 
									
										
										
										
											2019-03-14 23:28:32 +08:00
										 |  |  | 		) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-17 18:31:35 +08:00
										 |  |  | 		// Get will return empty string even if header is not set
 | 
					
						
							|  |  |  | 		assert.Equal(t, "", req.Header.Get("X-Grafana-User")) | 
					
						
							| 
									
										
										
										
											2019-03-14 23:28:32 +08:00
										 |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2019-05-08 00:55:39 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-17 18:31:35 +08:00
										 |  |  | 	t.Run("When getting templated url", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2021-11-01 17:53:33 +08:00
										 |  |  | 		route := &plugins.Route{ | 
					
						
							| 
									
										
										
										
											2020-04-24 16:32:13 +08:00
										 |  |  | 			URL:    "{{.JsonData.dynamicUrl}}", | 
					
						
							| 
									
										
										
										
											2019-05-08 00:55:39 +08:00
										 |  |  | 			Method: "GET", | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-02-25 18:29:18 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-07 22:33:50 +08:00
										 |  |  | 		httpReq, err := http.NewRequest(http.MethodGet, "", nil) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-08 00:55:39 +08:00
										 |  |  | 		req := getPluginProxiedRequest( | 
					
						
							| 
									
										
										
										
											2020-11-17 18:31:35 +08:00
										 |  |  | 			t, | 
					
						
							| 
									
										
										
										
											2022-08-23 19:05:31 +08:00
										 |  |  | 			&pluginsettings.DTO{ | 
					
						
							|  |  |  | 				JSONData: map[string]interface{}{ | 
					
						
							|  |  |  | 					"dynamicUrl": "https://dynamic.grafana.com", | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2021-11-05 00:47:21 +08:00
										 |  |  | 			secretsService, | 
					
						
							| 
									
										
										
										
											2020-03-04 19:57:20 +08:00
										 |  |  | 			&models.ReqContext{ | 
					
						
							| 
									
										
										
										
											2022-08-10 17:56:48 +08:00
										 |  |  | 				SignedInUser: &user.SignedInUser{ | 
					
						
							| 
									
										
										
										
											2019-05-08 00:55:39 +08:00
										 |  |  | 					Login: "test_user", | 
					
						
							|  |  |  | 				}, | 
					
						
							| 
									
										
										
										
											2021-12-13 22:56:14 +08:00
										 |  |  | 				Context: &web.Context{ | 
					
						
							| 
									
										
										
										
											2021-10-07 22:33:50 +08:00
										 |  |  | 					Req: httpReq, | 
					
						
							|  |  |  | 				}, | 
					
						
							| 
									
										
										
										
											2019-05-08 00:55:39 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			&setting.Cfg{SendUserHeader: true}, | 
					
						
							|  |  |  | 			route, | 
					
						
							|  |  |  | 		) | 
					
						
							| 
									
										
										
										
											2020-11-17 18:31:35 +08:00
										 |  |  | 		assert.Equal(t, "https://dynamic.grafana.com", req.URL.String()) | 
					
						
							|  |  |  | 		assert.Equal(t, "{{.JsonData.dynamicUrl}}", route.URL) | 
					
						
							| 
									
										
										
										
											2019-05-08 00:55:39 +08:00
										 |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2020-11-17 17:56:42 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-17 18:31:35 +08:00
										 |  |  | 	t.Run("When getting complex templated url", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2021-11-01 17:53:33 +08:00
										 |  |  | 		route := &plugins.Route{ | 
					
						
							| 
									
										
										
										
											2020-11-17 17:56:42 +08:00
										 |  |  | 			URL:    "{{if .JsonData.apiHost}}{{.JsonData.apiHost}}{{else}}https://example.com{{end}}", | 
					
						
							|  |  |  | 			Method: "GET", | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-02-25 18:29:18 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-07 22:33:50 +08:00
										 |  |  | 		httpReq, err := http.NewRequest(http.MethodGet, "", nil) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-17 17:56:42 +08:00
										 |  |  | 		req := getPluginProxiedRequest( | 
					
						
							| 
									
										
										
										
											2020-11-17 18:31:35 +08:00
										 |  |  | 			t, | 
					
						
							| 
									
										
										
										
											2022-08-23 19:05:31 +08:00
										 |  |  | 			&pluginsettings.DTO{}, | 
					
						
							| 
									
										
										
										
											2021-11-05 00:47:21 +08:00
										 |  |  | 			secretsService, | 
					
						
							| 
									
										
										
										
											2020-11-17 17:56:42 +08:00
										 |  |  | 			&models.ReqContext{ | 
					
						
							| 
									
										
										
										
											2022-08-10 17:56:48 +08:00
										 |  |  | 				SignedInUser: &user.SignedInUser{ | 
					
						
							| 
									
										
										
										
											2020-11-17 17:56:42 +08:00
										 |  |  | 					Login: "test_user", | 
					
						
							|  |  |  | 				}, | 
					
						
							| 
									
										
										
										
											2021-12-13 22:56:14 +08:00
										 |  |  | 				Context: &web.Context{ | 
					
						
							| 
									
										
										
										
											2021-10-07 22:33:50 +08:00
										 |  |  | 					Req: httpReq, | 
					
						
							|  |  |  | 				}, | 
					
						
							| 
									
										
										
										
											2020-11-17 17:56:42 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			&setting.Cfg{SendUserHeader: true}, | 
					
						
							|  |  |  | 			route, | 
					
						
							|  |  |  | 		) | 
					
						
							| 
									
										
										
										
											2020-11-17 18:31:35 +08:00
										 |  |  | 		assert.Equal(t, "https://example.com", req.URL.String()) | 
					
						
							| 
									
										
										
										
											2020-11-17 17:56:42 +08:00
										 |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2021-03-31 22:38:35 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("When getting templated body", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2021-11-01 17:53:33 +08:00
										 |  |  | 		route := &plugins.Route{ | 
					
						
							| 
									
										
										
										
											2021-03-31 22:38:35 +08:00
										 |  |  | 			Path: "api/body", | 
					
						
							|  |  |  | 			URL:  "http://www.test.com", | 
					
						
							|  |  |  | 			Body: []byte(`{ "url": "{{.JsonData.dynamicUrl}}", "secret": "{{.SecureJsonData.key}}"	}`), | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-23 19:05:31 +08:00
										 |  |  | 		encryptedJsonData, err := secretsService.EncryptJsonData( | 
					
						
							| 
									
										
										
										
											2022-02-05 00:35:00 +08:00
										 |  |  | 			context.Background(), | 
					
						
							|  |  |  | 			map[string]string{"key": "123"}, | 
					
						
							|  |  |  | 			secrets.WithoutScope(), | 
					
						
							|  |  |  | 		) | 
					
						
							| 
									
										
										
										
											2022-08-23 19:05:31 +08:00
										 |  |  | 		require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2021-03-31 22:38:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-07 22:33:50 +08:00
										 |  |  | 		httpReq, err := http.NewRequest(http.MethodGet, "", nil) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-31 22:38:35 +08:00
										 |  |  | 		req := getPluginProxiedRequest( | 
					
						
							|  |  |  | 			t, | 
					
						
							| 
									
										
										
										
											2022-08-23 19:05:31 +08:00
										 |  |  | 			&pluginsettings.DTO{ | 
					
						
							|  |  |  | 				JSONData:       map[string]interface{}{"dynamicUrl": "https://dynamic.grafana.com"}, | 
					
						
							|  |  |  | 				SecureJSONData: encryptedJsonData, | 
					
						
							|  |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2021-11-05 00:47:21 +08:00
										 |  |  | 			secretsService, | 
					
						
							| 
									
										
										
										
											2021-03-31 22:38:35 +08:00
										 |  |  | 			&models.ReqContext{ | 
					
						
							| 
									
										
										
										
											2022-08-10 17:56:48 +08:00
										 |  |  | 				SignedInUser: &user.SignedInUser{ | 
					
						
							| 
									
										
										
										
											2021-03-31 22:38:35 +08:00
										 |  |  | 					Login: "test_user", | 
					
						
							|  |  |  | 				}, | 
					
						
							| 
									
										
										
										
											2021-12-13 22:56:14 +08:00
										 |  |  | 				Context: &web.Context{ | 
					
						
							| 
									
										
										
										
											2021-10-07 22:33:50 +08:00
										 |  |  | 					Req: httpReq, | 
					
						
							|  |  |  | 				}, | 
					
						
							| 
									
										
										
										
											2021-03-31 22:38:35 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			&setting.Cfg{SendUserHeader: true}, | 
					
						
							|  |  |  | 			route, | 
					
						
							|  |  |  | 		) | 
					
						
							| 
									
										
										
										
											2022-08-10 21:37:51 +08:00
										 |  |  | 		content, err := io.ReadAll(req.Body) | 
					
						
							| 
									
										
										
										
											2021-03-31 22:38:35 +08:00
										 |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		require.Equal(t, `{ "url": "https://dynamic.grafana.com", "secret": "123"	}`, string(content)) | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2022-02-09 20:44:38 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("When proxying a request should set expected response headers", func(t *testing.T) { | 
					
						
							|  |  |  | 		requestHandled := false | 
					
						
							|  |  |  | 		backendServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | 
					
						
							|  |  |  | 			w.WriteHeader(200) | 
					
						
							|  |  |  | 			_, _ = w.Write([]byte("I am the backend")) | 
					
						
							|  |  |  | 			requestHandled = true | 
					
						
							|  |  |  | 		})) | 
					
						
							|  |  |  | 		t.Cleanup(backendServer.Close) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		responseWriter := web.NewResponseWriter("GET", httptest.NewRecorder()) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-23 19:05:31 +08:00
										 |  |  | 		routes := []*plugins.Route{ | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				Path: "/", | 
					
						
							|  |  |  | 				URL:  backendServer.URL, | 
					
						
							|  |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2022-02-09 20:44:38 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ctx := &models.ReqContext{ | 
					
						
							| 
									
										
										
										
											2022-08-10 17:56:48 +08:00
										 |  |  | 			SignedInUser: &user.SignedInUser{}, | 
					
						
							| 
									
										
										
										
											2022-02-09 20:44:38 +08:00
										 |  |  | 			Context: &web.Context{ | 
					
						
							|  |  |  | 				Req:  httptest.NewRequest("GET", "/", nil), | 
					
						
							|  |  |  | 				Resp: responseWriter, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-08-23 19:05:31 +08:00
										 |  |  | 		ps := &pluginsettings.DTO{ | 
					
						
							|  |  |  | 			SecureJSONData: map[string][]byte{}, | 
					
						
							| 
									
										
										
										
											2022-02-09 20:44:38 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-08-23 19:05:31 +08:00
										 |  |  | 		proxy, err := NewPluginProxy(ps, routes, ctx, "", &setting.Cfg{}, secretsService, tracing.InitializeTracerForTest(), &http.Transport{}) | 
					
						
							|  |  |  | 		require.NoError(t, err) | 
					
						
							|  |  |  | 		proxy.HandleRequest() | 
					
						
							| 
									
										
										
										
											2022-02-09 20:44:38 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		for { | 
					
						
							|  |  |  | 			if requestHandled { | 
					
						
							|  |  |  | 				break | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		require.Equal(t, "sandbox", ctx.Resp.Header().Get("Content-Security-Policy")) | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2019-03-14 20:04:47 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-23 19:05:31 +08:00
										 |  |  | func TestPluginProxyRoutes(t *testing.T) { | 
					
						
							|  |  |  | 	routes := []*plugins.Route{ | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			Path:   "", | 
					
						
							|  |  |  | 			Method: "GET", | 
					
						
							|  |  |  | 			URL:    "http://localhost", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			Path:   "some-api", | 
					
						
							|  |  |  | 			Method: "GET", | 
					
						
							|  |  |  | 			URL:    "http://localhost/api", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			Path:   "some-api/instances", | 
					
						
							|  |  |  | 			Method: "GET", | 
					
						
							|  |  |  | 			URL:    "http://localhost/api/instances/", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			Path:   "some-api/*", | 
					
						
							|  |  |  | 			Method: "GET", | 
					
						
							|  |  |  | 			URL:    "http://localhost/api", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			Path:   "some-api/instances/*", | 
					
						
							|  |  |  | 			Method: "GET", | 
					
						
							|  |  |  | 			URL:    "http://localhost/api/instances", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			Path:   "some-other-api/*", | 
					
						
							|  |  |  | 			Method: "GET", | 
					
						
							|  |  |  | 			URL:    "http://localhost/api/v2", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			Path:   "some-other-api/instances/*", | 
					
						
							|  |  |  | 			Method: "GET", | 
					
						
							|  |  |  | 			URL:    "http://localhost/api/v2/instances", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tcs := []struct { | 
					
						
							|  |  |  | 		proxyPath       string | 
					
						
							|  |  |  | 		expectedURLPath string | 
					
						
							|  |  |  | 		expectedStatus  int | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			proxyPath:      "/notexists", | 
					
						
							|  |  |  | 			expectedStatus: http.StatusNotFound, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			proxyPath:       "/", | 
					
						
							|  |  |  | 			expectedURLPath: "/", | 
					
						
							|  |  |  | 			expectedStatus:  http.StatusOK, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			proxyPath:       "/some-api", | 
					
						
							|  |  |  | 			expectedURLPath: "/api", | 
					
						
							|  |  |  | 			expectedStatus:  http.StatusOK, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			proxyPath:       "/some-api/instances", | 
					
						
							|  |  |  | 			expectedURLPath: "/api/instances/", | 
					
						
							|  |  |  | 			expectedStatus:  http.StatusOK, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			proxyPath:       "/some-api/some/thing", | 
					
						
							|  |  |  | 			expectedURLPath: "/api/some/thing", | 
					
						
							|  |  |  | 			expectedStatus:  http.StatusOK, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			proxyPath:       "/some-api/instances/instance-one", | 
					
						
							|  |  |  | 			expectedURLPath: "/api/instances/instance-one", | 
					
						
							|  |  |  | 			expectedStatus:  http.StatusOK, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			proxyPath:       "/some-other-api/some/thing", | 
					
						
							|  |  |  | 			expectedURLPath: "/api/v2/some/thing", | 
					
						
							|  |  |  | 			expectedStatus:  http.StatusOK, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			proxyPath:       "/some-other-api/instances/instance-one", | 
					
						
							|  |  |  | 			expectedURLPath: "/api/v2/instances/instance-one", | 
					
						
							|  |  |  | 			expectedStatus:  http.StatusOK, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, tc := range tcs { | 
					
						
							|  |  |  | 		t.Run(fmt.Sprintf("When proxying path %q should call expected URL", tc.proxyPath), func(t *testing.T) { | 
					
						
							|  |  |  | 			secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore()) | 
					
						
							|  |  |  | 			requestHandled := false | 
					
						
							|  |  |  | 			requestURL := "" | 
					
						
							|  |  |  | 			backendServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | 
					
						
							|  |  |  | 				requestURL = r.URL.RequestURI() | 
					
						
							|  |  |  | 				w.WriteHeader(200) | 
					
						
							|  |  |  | 				_, _ = w.Write([]byte("I am the backend")) | 
					
						
							|  |  |  | 				requestHandled = true | 
					
						
							|  |  |  | 			})) | 
					
						
							|  |  |  | 			t.Cleanup(backendServer.Close) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			backendURL, err := url.Parse(backendServer.URL) | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			testRoutes := make([]*plugins.Route, len(routes)) | 
					
						
							|  |  |  | 			for i, r := range routes { | 
					
						
							|  |  |  | 				u, err := url.Parse(r.URL) | 
					
						
							|  |  |  | 				require.NoError(t, err) | 
					
						
							|  |  |  | 				u.Scheme = backendURL.Scheme | 
					
						
							|  |  |  | 				u.Host = backendURL.Host | 
					
						
							|  |  |  | 				testRoute := *r | 
					
						
							|  |  |  | 				testRoute.URL = u.String() | 
					
						
							|  |  |  | 				testRoutes[i] = &testRoute | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			responseWriter := web.NewResponseWriter("GET", httptest.NewRecorder()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			ctx := &models.ReqContext{ | 
					
						
							|  |  |  | 				SignedInUser: &user.SignedInUser{}, | 
					
						
							|  |  |  | 				Context: &web.Context{ | 
					
						
							|  |  |  | 					Req:  httptest.NewRequest("GET", tc.proxyPath, nil), | 
					
						
							|  |  |  | 					Resp: responseWriter, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			ps := &pluginsettings.DTO{ | 
					
						
							|  |  |  | 				SecureJSONData: map[string][]byte{}, | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			proxy, err := NewPluginProxy(ps, testRoutes, ctx, tc.proxyPath, &setting.Cfg{}, secretsService, tracing.InitializeTracerForTest(), &http.Transport{}) | 
					
						
							|  |  |  | 			require.NoError(t, err) | 
					
						
							|  |  |  | 			proxy.HandleRequest() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			for { | 
					
						
							|  |  |  | 				if requestHandled || ctx.Resp.Written() { | 
					
						
							|  |  |  | 					break | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			require.Equal(t, tc.expectedStatus, ctx.Resp.Status()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if tc.expectedStatus == http.StatusNotFound { | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			require.Equal(t, tc.expectedURLPath, requestURL) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-14 20:04:47 +08:00
										 |  |  | // getPluginProxiedRequest is a helper for easier setup of tests based on global config and ReqContext.
 | 
					
						
							| 
									
										
										
										
											2022-08-23 19:05:31 +08:00
										 |  |  | func getPluginProxiedRequest(t *testing.T, ps *pluginsettings.DTO, secretsService secrets.Service, ctx *models.ReqContext, cfg *setting.Cfg, route *plugins.Route) *http.Request { | 
					
						
							| 
									
										
										
										
											2019-05-08 00:55:39 +08:00
										 |  |  | 	// insert dummy route if none is specified
 | 
					
						
							|  |  |  | 	if route == nil { | 
					
						
							| 
									
										
										
										
											2021-11-01 17:53:33 +08:00
										 |  |  | 		route = &plugins.Route{ | 
					
						
							| 
									
										
										
										
											2019-05-08 00:55:39 +08:00
										 |  |  | 			Path:    "api/v4/", | 
					
						
							| 
									
										
										
										
											2020-04-24 16:32:13 +08:00
										 |  |  | 			URL:     "https://www.google.com", | 
					
						
							| 
									
										
										
										
											2022-08-10 17:56:48 +08:00
										 |  |  | 			ReqRole: org.RoleEditor, | 
					
						
							| 
									
										
										
										
											2019-05-08 00:55:39 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-08-23 19:05:31 +08:00
										 |  |  | 	proxy, err := NewPluginProxy(ps, []*plugins.Route{}, ctx, "", cfg, secretsService, tracing.InitializeTracerForTest(), &http.Transport{}) | 
					
						
							|  |  |  | 	require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2019-03-14 20:04:47 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-17 17:56:42 +08:00
										 |  |  | 	req, err := http.NewRequest(http.MethodGet, "/api/plugin-proxy/grafana-simple-app/api/v4/alerts", nil) | 
					
						
							| 
									
										
										
										
											2020-11-17 18:31:35 +08:00
										 |  |  | 	require.NoError(t, err) | 
					
						
							| 
									
										
										
										
											2022-08-23 19:05:31 +08:00
										 |  |  | 	proxy.matchedRoute = route | 
					
						
							|  |  |  | 	proxy.director(req) | 
					
						
							| 
									
										
										
										
											2019-03-14 20:04:47 +08:00
										 |  |  | 	return req | 
					
						
							| 
									
										
										
										
											2016-02-10 23:43:35 +08:00
										 |  |  | } |