Setting trusted platform using an enum-like (#2739)

This commit is contained in:
Alessandro (Ale) Segala 2021-06-23 17:58:10 -07:00 committed by GitHub
parent fb8a113f8d
commit dd8a27c0b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 43 additions and 13 deletions

View File

@ -9,6 +9,7 @@ import (
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"log"
"math" "math"
"mime/multipart" "mime/multipart"
"net" "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, // 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. // the remote IP (coming form Request.RemoteAddr) is returned.
func (c *Context) ClientIP() string { func (c *Context) ClientIP() string {
switch { // Check if we're running on a tursted platform
case c.engine.AppEngine: switch c.engine.TrustedPlatform {
case PlatformGoogleAppEngine:
if addr := c.requestHeader("X-Appengine-Remote-Addr"); addr != "" { if addr := c.requestHeader("X-Appengine-Remote-Addr"); addr != "" {
return addr return addr
} }
case c.engine.CloudflareProxy: case PlatformCloudflare:
if addr := c.requestHeader("CF-Connecting-IP"); addr != "" { if addr := c.requestHeader("CF-Connecting-IP"); addr != "" {
return 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() remoteIP, trusted := c.RemoteIP()
if remoteIP == nil { if remoteIP == nil {
return "" return ""

View File

@ -8,5 +8,5 @@
package gin package gin
func init() { func init() {
defaultAppEngine = true defaultPlatform = PlatformGoogleAppEngine
} }

View File

@ -1410,7 +1410,7 @@ func TestContextClientIP(t *testing.T) {
c.Request.Header.Del("X-Forwarded-For") c.Request.Header.Del("X-Forwarded-For")
c.Request.Header.Del("X-Real-IP") c.Request.Header.Del("X-Real-IP")
c.engine.AppEngine = true c.engine.TrustedPlatform = PlatformGoogleAppEngine
assert.Equal(t, "50.50.50.50", c.ClientIP()) assert.Equal(t, "50.50.50.50", c.ClientIP())
c.Request.Header.Del("X-Appengine-Remote-Addr") 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()) assert.Equal(t, "10.10.10.10", c.ClientIP())
c.engine.RemoteIPHeaders = []string{} 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 c.engine.AppEngine = true
assert.Equal(t, "50.50.50.50", c.ClientIP()) 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") c.Request.Header.Del("X-Appengine-Remote-Addr")
assert.Equal(t, "40.40.40.40", c.ClientIP()) assert.Equal(t, "40.40.40.40", c.ClientIP())
c.engine.AppEngine = false c.engine.TrustedPlatform = PlatformCloudflare
c.engine.CloudflareProxy = true
assert.Equal(t, "60.60.60.60", c.ClientIP()) assert.Equal(t, "60.60.60.60", c.ClientIP())
c.Request.Header.Del("CF-Connecting-IP") c.Request.Header.Del("CF-Connecting-IP")
assert.Equal(t, "40.40.40.40", c.ClientIP()) assert.Equal(t, "40.40.40.40", c.ClientIP())
c.engine.TrustedPlatform = ""
// no port // no port
c.Request.RemoteAddr = "50.50.50.50" c.Request.RemoteAddr = "50.50.50.50"
assert.Empty(t, c.ClientIP()) 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("X-Appengine-Remote-Addr", "50.50.50.50")
c.Request.Header.Set("CF-Connecting-IP", "60.60.60.60") c.Request.Header.Set("CF-Connecting-IP", "60.60.60.60")
c.Request.RemoteAddr = " 40.40.40.40:42123 " c.Request.RemoteAddr = " 40.40.40.40:42123 "
c.engine.TrustedPlatform = ""
c.engine.AppEngine = false c.engine.AppEngine = false
} }

23
gin.go
View File

@ -25,7 +25,7 @@ var (
default405Body = []byte("405 method not allowed") default405Body = []byte("405 method not allowed")
) )
var defaultAppEngine bool var defaultPlatform string
// HandlerFunc defines the handler used by gin middleware as return value. // HandlerFunc defines the handler used by gin middleware as return value.
type HandlerFunc func(*Context) type HandlerFunc func(*Context)
@ -52,6 +52,16 @@ type RouteInfo struct {
// RoutesInfo defines a RouteInfo array. // RoutesInfo defines a RouteInfo array.
type RoutesInfo []RouteInfo 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. // Engine is the framework's instance, it contains the muxer, middleware and configuration settings.
// Create an instance of Engine, by using New() or Default() // Create an instance of Engine, by using New() or Default()
type Engine struct { type Engine struct {
@ -101,14 +111,15 @@ type Engine struct {
// `true`. // `true`.
TrustedProxies []string 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 // #726 #755 If enabled, it will trust some headers starting with
// 'X-AppEngine...' for better integration with that PaaS. // 'X-AppEngine...' for better integration with that PaaS.
AppEngine bool 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. // If enabled, the url.RawPath will be used to find parameters.
UseRawPath bool UseRawPath bool
@ -164,7 +175,7 @@ func New() *Engine {
ForwardedByClientIP: true, ForwardedByClientIP: true,
RemoteIPHeaders: []string{"X-Forwarded-For", "X-Real-IP"}, RemoteIPHeaders: []string{"X-Forwarded-For", "X-Real-IP"},
TrustedProxies: []string{"0.0.0.0/0"}, TrustedProxies: []string{"0.0.0.0/0"},
AppEngine: defaultAppEngine, TrustedPlatform: defaultPlatform,
UseRawPath: false, UseRawPath: false,
RemoveExtraSlash: false, RemoveExtraSlash: false,
UnescapePathValues: true, UnescapePathValues: true,