fix(middlewares): failure to detect remote ip (#5339)

This fixes an edge case where the RemoteIP detection could safely fail with an error, and instead defaults to the TCP packet information.

Signed-off-by: James Elliott <james-d-elliott@users.noreply.github.com>
pull/5340/head
James Elliott 2023-04-30 10:52:45 +10:00 committed by GitHub
parent c3cc4061b8
commit 34ec813370
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 38 additions and 5 deletions

View File

@ -452,12 +452,13 @@ func (ctx *AutheliaCtx) SetJSONBody(value any) error {
// RemoteIP return the remote IP taking X-Forwarded-For header into account if provided. // RemoteIP return the remote IP taking X-Forwarded-For header into account if provided.
func (ctx *AutheliaCtx) RemoteIP() net.IP { func (ctx *AutheliaCtx) RemoteIP() net.IP {
XForwardedFor := ctx.Request.Header.PeekBytes(headerXForwardedFor) if header := ctx.Request.Header.PeekBytes(headerXForwardedFor); len(header) != 0 {
if XForwardedFor != nil { ips := strings.SplitN(string(header), ",", 2)
ips := strings.Split(string(XForwardedFor), ",")
if len(ips) > 0 { if len(ips) != 0 {
return net.ParseIP(strings.Trim(ips[0], " ")) if ip := net.ParseIP(strings.Trim(ips[0], " ")); ip != nil {
return ip
}
} }
} }

View File

@ -1,6 +1,7 @@
package middlewares_test package middlewares_test
import ( import (
"net"
"net/url" "net/url"
"testing" "testing"
@ -17,6 +18,37 @@ import (
"github.com/authelia/authelia/v4/internal/session" "github.com/authelia/authelia/v4/internal/session"
) )
func TestAutheliaCtx_RemoteIP(t *testing.T) {
testCases := []struct {
name string
have []byte
expected net.IP
}{
{"ShouldDefaultToRemoteAddr", nil, net.ParseIP("127.0.0.127")},
{"ShouldParseProperlyFormattedXFFWithIPv4", []byte("192.168.1.1, 127.0.0.1"), net.ParseIP("192.168.1.1")},
{"ShouldParseProperlyFormattedXFFWithIPv6", []byte("2001:db8:85a3:8d3:1319:8a2e:370:7348, 127.0.0.1"), net.ParseIP("2001:db8:85a3:8d3:1319:8a2e:370:7348")},
{"ShouldFallbackToRemoteAddrOnImproperlyFormattedXFFWithIPv6", []byte("[2001:db8:85a3:8d3:1319:8a2e:370:7348], 127.0.0.1"), net.ParseIP("127.0.0.127")},
{"ShouldFallbackToRemoteAddrOnBlankXFFHeader", []byte(""), net.ParseIP("127.0.0.127")},
{"ShouldFallbackToRemoteAddrOnBlankXFFEntry", []byte(", 127.0.0.1"), net.ParseIP("127.0.0.127")},
{"ShouldFallbackToRemoteAddrOnBadXFFEntry", []byte("abc, 127.0.0.1"), net.ParseIP("127.0.0.127")},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
mock := mocks.NewMockAutheliaCtx(t)
defer mock.Close()
mock.Ctx.SetRemoteAddr(&net.TCPAddr{Port: 80, IP: net.ParseIP("127.0.0.127")})
if tc.have != nil {
mock.Ctx.RequestCtx.Request.Header.SetBytesV(fasthttp.HeaderXForwardedFor, tc.have)
}
assert.Equal(t, tc.expected, mock.Ctx.RemoteIP())
})
}
}
func TestContentTypes(t *testing.T) { func TestContentTypes(t *testing.T) {
testCases := []struct { testCases := []struct {
name string name string