From dd8a27c0b6fbbfd192c5586ba3165700f535ac7f Mon Sep 17 00:00:00 2001 From: "Alessandro (Ale) Segala" <43508+ItalyPaleAle@users.noreply.github.com> Date: Wed, 23 Jun 2021 17:58:10 -0700 Subject: [PATCH] Setting trusted platform using an enum-like (#2739) --- context.go | 16 +++++++++++++--- context_appengine.go | 2 +- context_test.go | 15 ++++++++++++--- gin.go | 23 +++++++++++++++++------ 4 files changed, 43 insertions(+), 13 deletions(-) diff --git a/context.go b/context.go index 0c1fb07f..5c1aba5e 100644 --- a/context.go +++ b/context.go @@ -9,6 +9,7 @@ import ( "fmt" "io" "io/ioutil" + "log" "math" "mime/multipart" "net" @@ -731,17 +732,26 @@ func (c *Context) ShouldBindBodyWith(obj interface{}, bb binding.BindingBody) (e // If the headers are nots syntactically valid OR the remote IP does not correspong to a trusted proxy, // the remote IP (coming form Request.RemoteAddr) is returned. func (c *Context) ClientIP() string { - switch { - case c.engine.AppEngine: + // Check if we're running on a tursted platform + switch c.engine.TrustedPlatform { + case PlatformGoogleAppEngine: if addr := c.requestHeader("X-Appengine-Remote-Addr"); addr != "" { return addr } - case c.engine.CloudflareProxy: + case PlatformCloudflare: if addr := c.requestHeader("CF-Connecting-IP"); addr != "" { return addr } } + // Legacy "AppEngine" flag + if c.engine.AppEngine { + log.Println(`The AppEngine flag is going to be deprecated. Please check issues #2723 and #2739 and use 'TrustedPlatform: gin.PlatformGoogleAppEngine' instead.`) + if addr := c.requestHeader("X-Appengine-Remote-Addr"); addr != "" { + return addr + } + } + remoteIP, trusted := c.RemoteIP() if remoteIP == nil { return "" diff --git a/context_appengine.go b/context_appengine.go index d5658434..8bf93896 100644 --- a/context_appengine.go +++ b/context_appengine.go @@ -8,5 +8,5 @@ package gin func init() { - defaultAppEngine = true + defaultPlatform = PlatformGoogleAppEngine } diff --git a/context_test.go b/context_test.go index e0de717e..93b58ee8 100644 --- a/context_test.go +++ b/context_test.go @@ -1410,7 +1410,7 @@ func TestContextClientIP(t *testing.T) { c.Request.Header.Del("X-Forwarded-For") c.Request.Header.Del("X-Real-IP") - c.engine.AppEngine = true + c.engine.TrustedPlatform = PlatformGoogleAppEngine assert.Equal(t, "50.50.50.50", c.ClientIP()) c.Request.Header.Del("X-Appengine-Remote-Addr") @@ -1470,19 +1470,27 @@ func TestContextClientIP(t *testing.T) { assert.Equal(t, "10.10.10.10", c.ClientIP()) c.engine.RemoteIPHeaders = []string{} + c.engine.TrustedPlatform = PlatformGoogleAppEngine + assert.Equal(t, "50.50.50.50", c.ClientIP()) + + // Test the legacy flag + c.engine.TrustedPlatform = "" c.engine.AppEngine = true assert.Equal(t, "50.50.50.50", c.ClientIP()) + c.engine.AppEngine = false + c.engine.TrustedPlatform = PlatformGoogleAppEngine c.Request.Header.Del("X-Appengine-Remote-Addr") assert.Equal(t, "40.40.40.40", c.ClientIP()) - c.engine.AppEngine = false - c.engine.CloudflareProxy = true + c.engine.TrustedPlatform = PlatformCloudflare assert.Equal(t, "60.60.60.60", c.ClientIP()) c.Request.Header.Del("CF-Connecting-IP") assert.Equal(t, "40.40.40.40", c.ClientIP()) + c.engine.TrustedPlatform = "" + // no port c.Request.RemoteAddr = "50.50.50.50" assert.Empty(t, c.ClientIP()) @@ -1494,6 +1502,7 @@ func resetContextForClientIPTests(c *Context) { c.Request.Header.Set("X-Appengine-Remote-Addr", "50.50.50.50") c.Request.Header.Set("CF-Connecting-IP", "60.60.60.60") c.Request.RemoteAddr = " 40.40.40.40:42123 " + c.engine.TrustedPlatform = "" c.engine.AppEngine = false } diff --git a/gin.go b/gin.go index 00686e77..fd4fa512 100644 --- a/gin.go +++ b/gin.go @@ -25,7 +25,7 @@ var ( default405Body = []byte("405 method not allowed") ) -var defaultAppEngine bool +var defaultPlatform string // HandlerFunc defines the handler used by gin middleware as return value. type HandlerFunc func(*Context) @@ -52,6 +52,16 @@ type RouteInfo struct { // RoutesInfo defines a RouteInfo array. type RoutesInfo []RouteInfo +// Trusted platforms +const ( + // When running on Google App Engine. Trust X-Appengine-Remote-Addr + // for determining the client's IP + PlatformGoogleAppEngine = "google-app-engine" + // When using Cloudflare's CDN. Trust CF-Connecting-IP for determining + // the client's IP + PlatformCloudflare = "cloudflare" +) + // Engine is the framework's instance, it contains the muxer, middleware and configuration settings. // Create an instance of Engine, by using New() or Default() type Engine struct { @@ -101,14 +111,15 @@ type Engine struct { // `true`. TrustedProxies []string + // If set to a constant of value gin.Platform*, trusts the headers set by + // that platform, for example to determine the client IP + TrustedPlatform string + + // DEPRECATED: USE `TrustedPlatform` WITH VALUE `gin.GoogleAppEngine` INSTEAD // #726 #755 If enabled, it will trust some headers starting with // 'X-AppEngine...' for better integration with that PaaS. AppEngine bool - // If enabled, it will trust the CF-Connecting-IP header to determine the - // IP of the client. - CloudflareProxy bool - // If enabled, the url.RawPath will be used to find parameters. UseRawPath bool @@ -164,7 +175,7 @@ func New() *Engine { ForwardedByClientIP: true, RemoteIPHeaders: []string{"X-Forwarded-For", "X-Real-IP"}, TrustedProxies: []string{"0.0.0.0/0"}, - AppEngine: defaultAppEngine, + TrustedPlatform: defaultPlatform, UseRawPath: false, RemoveExtraSlash: false, UnescapePathValues: true,