fix(bearer): key the failure tracker by IPv6 /64

The bearer failure tracker keyed entries by the full source address.
One IPv6 host could create a new entry per request and grow the map for
window plus penalty seconds. It now shares one entry per /64, like the
login limiter. IPv4 keys do not change.
This commit is contained in:
2026-11-03 00:59:16 +00:00
parent b1cf524bb4
commit 9ecd987416
2 changed files with 27 additions and 2 deletions
+3 -2
View File
@@ -558,9 +558,10 @@ func clientIPForBearer(req *http.Request) string {
}
host, _, err := net.SplitHostPort(req.RemoteAddr)
if err != nil {
return req.RemoteAddr
host = req.RemoteAddr
}
return host
// One IPv6 /64 shares a key, so a single host cannot mint 2^64 entries.
return limiterKey(host)
}
// --- Bearer auth entrypoint ---
+24
View File
@@ -0,0 +1,24 @@
package traefikoidc
import (
"net/http/httptest"
"testing"
)
// Addresses in one IPv6 /64 must share one failure-tracker key.
func TestClientIPForBearerCollapsesIPv6Prefix(t *testing.T) {
key := func(addr string) string {
r := httptest.NewRequest("GET", "/", nil)
r.RemoteAddr = addr
return clientIPForBearer(r)
}
if a, b := key("[2001:db8:1:2::1]:1"), key("[2001:db8:1:2:ffff::9]:2"); a != b {
t.Fatalf("same /64 got different keys: %q vs %q", a, b)
}
if a, b := key("[2001:db8:1:2::1]:1"), key("[2001:db8:1:3::1]:1"); a == b {
t.Fatalf("different /64 shared key %q", a)
}
if got := key("192.0.2.7:80"); got != "192.0.2.7" {
t.Fatalf("ipv4 key = %q", got)
}
}