mirror of https://github.com/grafana/grafana
Backend plugins: Prepare and clean request headers before resource calls (#22321)
Moves common request proxy utilities to proxyutil package with support for removing X-Forwarded-Host, X-Forwarded-Port, X-Forwarded-Proto headers, setting X-Forwarded-For header and cleaning Cookie header. Using the proxyutil package to prepare and clean request headers before resource calls. Closes #21512pull/22538/head
parent
8b122ee464
commit
e6cec8dbdc
@ -0,0 +1,44 @@ |
||||
package proxyutil |
||||
|
||||
import ( |
||||
"net" |
||||
"net/http" |
||||
) |
||||
|
||||
// PrepareProxyRequest prepares a request for being proxied.
|
||||
// Removes X-Forwarded-Host, X-Forwarded-Port, X-Forwarded-Proto headers.
|
||||
// Set X-Forwarded-For headers.
|
||||
func PrepareProxyRequest(req *http.Request) { |
||||
req.Header.Del("X-Forwarded-Host") |
||||
req.Header.Del("X-Forwarded-Port") |
||||
req.Header.Del("X-Forwarded-Proto") |
||||
|
||||
if req.RemoteAddr != "" { |
||||
remoteAddr, _, err := net.SplitHostPort(req.RemoteAddr) |
||||
if err != nil { |
||||
remoteAddr = req.RemoteAddr |
||||
} |
||||
if req.Header.Get("X-Forwarded-For") != "" { |
||||
req.Header.Set("X-Forwarded-For", req.Header.Get("X-Forwarded-For")+", "+remoteAddr) |
||||
} else { |
||||
req.Header.Set("X-Forwarded-For", remoteAddr) |
||||
} |
||||
} |
||||
} |
||||
|
||||
// ClearCookieHeader clear cookie header, except for cookies specified to be kept.
|
||||
func ClearCookieHeader(req *http.Request, keepCookiesNames []string) { |
||||
var keepCookies []*http.Cookie |
||||
for _, c := range req.Cookies() { |
||||
for _, v := range keepCookiesNames { |
||||
if c.Name == v { |
||||
keepCookies = append(keepCookies, c) |
||||
} |
||||
} |
||||
} |
||||
|
||||
req.Header.Del("Cookie") |
||||
for _, c := range keepCookies { |
||||
req.AddCookie(c) |
||||
} |
||||
} |
||||
@ -0,0 +1,67 @@ |
||||
package proxyutil |
||||
|
||||
import ( |
||||
"net/http" |
||||
"testing" |
||||
|
||||
"github.com/stretchr/testify/require" |
||||
) |
||||
|
||||
func TestPrepareProxyRequest(t *testing.T) { |
||||
t.Run("Prepare proxy request should clear X-Forwarded headers", func(t *testing.T) { |
||||
req, err := http.NewRequest(http.MethodGet, "/", nil) |
||||
require.NoError(t, err) |
||||
req.Header.Add("X-Forwarded-Host", "host") |
||||
req.Header.Add("X-Forwarded-Port", "123") |
||||
req.Header.Add("X-Forwarded-Proto", "http1") |
||||
|
||||
PrepareProxyRequest(req) |
||||
require.NotContains(t, req.Header, "X-Forwarded-Host") |
||||
require.NotContains(t, req.Header, "X-Forwarded-Port") |
||||
require.NotContains(t, req.Header, "X-Forwarded-Proto") |
||||
}) |
||||
|
||||
t.Run("Prepare proxy request should set X-Forwarded-For", func(t *testing.T) { |
||||
req, err := http.NewRequest(http.MethodGet, "/", nil) |
||||
req.RemoteAddr = "127.0.0.1:1234" |
||||
require.NoError(t, err) |
||||
|
||||
PrepareProxyRequest(req) |
||||
require.Contains(t, req.Header, "X-Forwarded-For") |
||||
require.Equal(t, "127.0.0.1", req.Header.Get("X-Forwarded-For")) |
||||
}) |
||||
|
||||
t.Run("Prepare proxy request should appent client ip at the end of X-Forwarded-For", func(t *testing.T) { |
||||
req, err := http.NewRequest(http.MethodGet, "/", nil) |
||||
req.RemoteAddr = "127.0.0.1:1234" |
||||
req.Header.Add("X-Forwarded-For", "192.168.0.1") |
||||
require.NoError(t, err) |
||||
|
||||
PrepareProxyRequest(req) |
||||
require.Contains(t, req.Header, "X-Forwarded-For") |
||||
require.Equal(t, "192.168.0.1, 127.0.0.1", req.Header.Get("X-Forwarded-For")) |
||||
}) |
||||
} |
||||
|
||||
func TestClearCookieHeader(t *testing.T) { |
||||
t.Run("Clear cookie header should clear Cookie header", func(t *testing.T) { |
||||
req, err := http.NewRequest(http.MethodGet, "/", nil) |
||||
require.NoError(t, err) |
||||
req.AddCookie(&http.Cookie{Name: "cookie"}) |
||||
|
||||
ClearCookieHeader(req, nil) |
||||
require.NotContains(t, req.Header, "Cookie") |
||||
}) |
||||
|
||||
t.Run("Clear cookie header with cookies to keep should clear Cookie header and keep cookies", func(t *testing.T) { |
||||
req, err := http.NewRequest(http.MethodGet, "/", nil) |
||||
require.NoError(t, err) |
||||
req.AddCookie(&http.Cookie{Name: "cookie1"}) |
||||
req.AddCookie(&http.Cookie{Name: "cookie2"}) |
||||
req.AddCookie(&http.Cookie{Name: "cookie3"}) |
||||
|
||||
ClearCookieHeader(req, []string{"cookie1", "cookie3"}) |
||||
require.Contains(t, req.Header, "Cookie") |
||||
require.Equal(t, "cookie1=; cookie3=", req.Header.Get("Cookie")) |
||||
}) |
||||
} |
||||
Loading…
Reference in new issue