| 
									
										
										
										
											2014-12-29 20:36:08 +08:00
										 |  |  | package api | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"net/http" | 
					
						
							|  |  |  | 	"net/http/httputil" | 
					
						
							|  |  |  | 	"net/url" | 
					
						
							| 
									
										
										
										
											2015-06-01 17:00:05 +08:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2014-12-29 20:36:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-02 17:10:21 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/api/cloudwatch" | 
					
						
							| 
									
										
										
										
											2015-02-05 17:37:13 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/bus" | 
					
						
							| 
									
										
										
										
											2016-06-03 15:17:36 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/metrics" | 
					
						
							| 
									
										
										
										
											2015-02-05 17:37:13 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/middleware" | 
					
						
							|  |  |  | 	m "github.com/grafana/grafana/pkg/models" | 
					
						
							| 
									
										
										
										
											2015-09-09 23:21:25 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/setting" | 
					
						
							| 
									
										
										
										
											2015-02-05 17:37:13 +08:00
										 |  |  | 	"github.com/grafana/grafana/pkg/util" | 
					
						
							| 
									
										
										
										
											2014-12-29 20:36:08 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-09 23:21:25 +08:00
										 |  |  | func NewReverseProxy(ds *m.DataSource, proxyPath string, targetUrl *url.URL) *httputil.ReverseProxy { | 
					
						
							| 
									
										
										
										
											2014-12-29 20:36:08 +08:00
										 |  |  | 	director := func(req *http.Request) { | 
					
						
							| 
									
										
										
										
											2015-09-09 23:21:25 +08:00
										 |  |  | 		req.URL.Scheme = targetUrl.Scheme | 
					
						
							|  |  |  | 		req.URL.Host = targetUrl.Host | 
					
						
							|  |  |  | 		req.Host = targetUrl.Host | 
					
						
							| 
									
										
										
										
											2014-12-29 20:36:08 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		reqQueryVals := req.URL.Query() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-28 15:25:13 +08:00
										 |  |  | 		if ds.Type == m.DS_INFLUXDB_08 { | 
					
						
							| 
									
										
										
										
											2015-09-09 23:21:25 +08:00
										 |  |  | 			req.URL.Path = util.JoinUrlFragments(targetUrl.Path, "db/"+ds.Database+"/"+proxyPath) | 
					
						
							| 
									
										
										
										
											2014-12-29 20:36:08 +08:00
										 |  |  | 			reqQueryVals.Add("u", ds.User) | 
					
						
							|  |  |  | 			reqQueryVals.Add("p", ds.Password) | 
					
						
							|  |  |  | 			req.URL.RawQuery = reqQueryVals.Encode() | 
					
						
							| 
									
										
										
										
											2015-02-28 15:25:13 +08:00
										 |  |  | 		} else if ds.Type == m.DS_INFLUXDB { | 
					
						
							| 
									
										
										
										
											2015-09-09 23:21:25 +08:00
										 |  |  | 			req.URL.Path = util.JoinUrlFragments(targetUrl.Path, proxyPath) | 
					
						
							| 
									
										
										
										
											2015-02-26 01:43:44 +08:00
										 |  |  | 			req.URL.RawQuery = reqQueryVals.Encode() | 
					
						
							| 
									
										
										
										
											2015-08-07 17:01:59 +08:00
										 |  |  | 			if !ds.BasicAuth { | 
					
						
							| 
									
										
										
										
											2015-09-19 18:32:35 +08:00
										 |  |  | 				req.Header.Del("Authorization") | 
					
						
							| 
									
										
										
										
											2015-08-07 17:01:59 +08:00
										 |  |  | 				req.Header.Add("Authorization", util.GetBasicAuthHeader(ds.User, ds.Password)) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2014-12-29 20:36:08 +08:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2015-09-09 23:21:25 +08:00
										 |  |  | 			req.URL.Path = util.JoinUrlFragments(targetUrl.Path, proxyPath) | 
					
						
							| 
									
										
										
										
											2014-12-29 20:36:08 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-03-02 16:58:35 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if ds.BasicAuth { | 
					
						
							| 
									
										
										
										
											2015-09-19 18:32:35 +08:00
										 |  |  | 			req.Header.Del("Authorization") | 
					
						
							| 
									
										
										
										
											2015-03-02 16:58:35 +08:00
										 |  |  | 			req.Header.Add("Authorization", util.GetBasicAuthHeader(ds.BasicAuthUser, ds.BasicAuthPassword)) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-08-10 18:11:18 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-26 13:13:29 +08:00
										 |  |  | 		dsAuth := req.Header.Get("X-DS-Authorization") | 
					
						
							|  |  |  | 		if len(dsAuth) > 0 { | 
					
						
							|  |  |  | 			req.Header.Del("X-DS-Authorization") | 
					
						
							|  |  |  | 			req.Header.Del("Authorization") | 
					
						
							|  |  |  | 			req.Header.Add("Authorization", dsAuth) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-10 18:11:18 +08:00
										 |  |  | 		// clear cookie headers
 | 
					
						
							|  |  |  | 		req.Header.Del("Cookie") | 
					
						
							|  |  |  | 		req.Header.Del("Set-Cookie") | 
					
						
							| 
									
										
										
										
											2014-12-29 20:36:08 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-19 18:09:26 +08:00
										 |  |  | 	return &httputil.ReverseProxy{Director: director, FlushInterval: time.Millisecond * 200} | 
					
						
							| 
									
										
										
										
											2014-12-29 20:36:08 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-08 23:30:13 +08:00
										 |  |  | func getDatasource(id int64, orgId int64) (*m.DataSource, error) { | 
					
						
							|  |  |  | 	query := m.GetDataSourceByIdQuery{Id: id, OrgId: orgId} | 
					
						
							| 
									
										
										
										
											2015-03-12 00:34:11 +08:00
										 |  |  | 	if err := bus.Dispatch(&query); err != nil { | 
					
						
							| 
									
										
										
										
											2015-10-08 23:30:13 +08:00
										 |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-06 23:11:46 +08:00
										 |  |  | 	return query.Result, nil | 
					
						
							| 
									
										
										
										
											2015-10-08 23:30:13 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func ProxyDataSourceRequest(c *middleware.Context) { | 
					
						
							| 
									
										
										
										
											2016-06-03 15:17:36 +08:00
										 |  |  | 	c.TimeRequest(metrics.M_DataSource_ProxyReq_Timer) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-08 23:30:13 +08:00
										 |  |  | 	ds, err := getDatasource(c.ParamsInt64(":id"), c.OrgId) | 
					
						
							| 
									
										
										
										
											2016-06-03 15:17:36 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-08 23:30:13 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2014-12-29 20:36:08 +08:00
										 |  |  | 		c.JsonApiErr(500, "Unable to load datasource meta data", err) | 
					
						
							| 
									
										
										
										
											2015-03-12 00:34:11 +08:00
										 |  |  | 		return | 
					
						
							| 
									
										
										
										
											2014-12-29 20:36:08 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-22 19:15:18 +08:00
										 |  |  | 	if ds.Type == m.DS_CLOUDWATCH { | 
					
						
							|  |  |  | 		cloudwatch.HandleRequest(c, ds) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-22 16:03:02 +08:00
										 |  |  | 	if ds.Type == m.DS_INFLUXDB { | 
					
						
							|  |  |  | 		if c.Query("db") != ds.Database { | 
					
						
							|  |  |  | 			c.JsonApiErr(403, "Datasource is not configured to allow this database", nil) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-09 23:21:25 +08:00
										 |  |  | 	targetUrl, _ := url.Parse(ds.Url) | 
					
						
							|  |  |  | 	if len(setting.DataProxyWhiteList) > 0 { | 
					
						
							|  |  |  | 		if _, exists := setting.DataProxyWhiteList[targetUrl.Host]; !exists { | 
					
						
							|  |  |  | 			c.JsonApiErr(403, "Data proxy hostname and ip are not included in whitelist", nil) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-22 19:15:18 +08:00
										 |  |  | 	proxyPath := c.Params("*") | 
					
						
							| 
									
										
										
										
											2016-09-13 21:04:21 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if ds.Type == m.DS_ES { | 
					
						
							|  |  |  | 		if c.Req.Request.Method == "DELETE" { | 
					
						
							|  |  |  | 			c.JsonApiErr(403, "Deletes not allowed on proxied Elasticsearch datasource", nil) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if c.Req.Request.Method == "PUT" { | 
					
						
							|  |  |  | 			c.JsonApiErr(403, "Puts not allowed on proxied Elasticsearch datasource", nil) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if c.Req.Request.Method == "POST" && proxyPath != "_msearch" { | 
					
						
							|  |  |  | 			c.JsonApiErr(403, "Posts not allowed on proxied Elasticsearch datasource except on /_msearch", nil) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-22 19:15:18 +08:00
										 |  |  | 	proxy := NewReverseProxy(ds, proxyPath, targetUrl) | 
					
						
							| 
									
										
										
										
											2016-12-07 18:10:42 +08:00
										 |  |  | 	proxy.Transport, err = ds.GetHttpTransport() | 
					
						
							| 
									
										
										
										
											2016-08-25 11:43:25 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		c.JsonApiErr(400, "Unable to load TLS certificate", err) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-07-22 19:15:18 +08:00
										 |  |  | 	proxy.ServeHTTP(c.Resp, c.Req.Request) | 
					
						
							|  |  |  | 	c.Resp.Header().Del("Set-Cookie") | 
					
						
							| 
									
										
										
										
											2014-12-29 20:36:08 +08:00
										 |  |  | } |