mirror of
https://github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin.git
synced 2026-10-17 23:19:37 +02:00
🐛 forward client HTTP version to AppSec via X-Crowdsec-Appsec-Http-Version (#400)
This commit is contained in:
1 parent
710e88808b
commit
bd94fb0c2b
2 files changed
+90
-18
No files matched your search
+22
-18
@@ -27,24 +27,25 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
crowdsecAppsecIPHeader = "X-Crowdsec-Appsec-Ip"
|
||||
crowdsecAppsecURIHeader = "X-Crowdsec-Appsec-Uri"
|
||||
crowdsecAppsecHostHeader = "X-Crowdsec-Appsec-Host"
|
||||
crowdsecAppsecVerbHeader = "X-Crowdsec-Appsec-Verb"
|
||||
crowdsecAppsecHeader = "X-Crowdsec-Appsec-Api-Key"
|
||||
crowdsecAppsecUserAgent = "X-Crowdsec-Appsec-User-Agent"
|
||||
crowdsecLapiHeader = "X-Api-Key"
|
||||
crowdsecLapiRoute = "v1/decisions"
|
||||
crowdsecLapiStreamRoute = "v1/decisions/stream"
|
||||
crowdsecLapiMetricsRoute = "v1/usage-metrics"
|
||||
crowdsecCapiHost = "api.crowdsec.net"
|
||||
crowdsecCapiHeader = "Authorization"
|
||||
crowdsecCapiLoginRoute = "v2/watchers/login"
|
||||
crowdsecCapiStreamRoute = "v2/decisions/stream"
|
||||
cacheTimeoutKey = "updated"
|
||||
appsecAllowAction = "allow"
|
||||
appsecChallengeAction = "challenge"
|
||||
appsecResponseBodyLimit = 1 << 20 // 1 MiB
|
||||
crowdsecAppsecIPHeader = "X-Crowdsec-Appsec-Ip"
|
||||
crowdsecAppsecURIHeader = "X-Crowdsec-Appsec-Uri"
|
||||
crowdsecAppsecHostHeader = "X-Crowdsec-Appsec-Host"
|
||||
crowdsecAppsecVerbHeader = "X-Crowdsec-Appsec-Verb"
|
||||
crowdsecAppsecHeader = "X-Crowdsec-Appsec-Api-Key"
|
||||
crowdsecAppsecUserAgent = "X-Crowdsec-Appsec-User-Agent"
|
||||
crowdsecAppsecHTTPVersionHeader = "X-Crowdsec-Appsec-Http-Version"
|
||||
crowdsecLapiHeader = "X-Api-Key"
|
||||
crowdsecLapiRoute = "v1/decisions"
|
||||
crowdsecLapiStreamRoute = "v1/decisions/stream"
|
||||
crowdsecLapiMetricsRoute = "v1/usage-metrics"
|
||||
crowdsecCapiHost = "api.crowdsec.net"
|
||||
crowdsecCapiHeader = "Authorization"
|
||||
crowdsecCapiLoginRoute = "v2/watchers/login"
|
||||
crowdsecCapiStreamRoute = "v2/decisions/stream"
|
||||
cacheTimeoutKey = "updated"
|
||||
appsecAllowAction = "allow"
|
||||
appsecChallengeAction = "challenge"
|
||||
appsecResponseBodyLimit = 1 << 20 // 1 MiB
|
||||
)
|
||||
|
||||
// ##############################################################
|
||||
@@ -841,6 +842,9 @@ func appsecQuery(bouncer *Bouncer, ip string, httpReq *http.Request) (*AppSecRes
|
||||
req.Header.Set(crowdsecAppsecHostHeader, httpReq.Host)
|
||||
req.Header.Set(crowdsecAppsecURIHeader, httpReq.URL.String())
|
||||
req.Header.Set(crowdsecAppsecUserAgent, httpReq.Header.Get("User-Agent"))
|
||||
if httpReq.ProtoMajor > 0 {
|
||||
req.Header.Set(crowdsecAppsecHTTPVersionHeader, fmt.Sprintf("%d%d", httpReq.ProtoMajor, httpReq.ProtoMinor))
|
||||
}
|
||||
req.Header.Set("User-Agent", "Crowdsec-Bouncer-Traefik-Plugin/"+pluginVersion)
|
||||
|
||||
res, err := bouncer.httpAppsecClient.Do(req)
|
||||
|
||||
@@ -885,3 +885,71 @@ func Test_appsecQuery_unreadableBodyMethods(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Test_appsecQuery_forwardsHTTPVersion verifies that the client HTTP version
|
||||
// is forwarded to CrowdSec AppSec via X-Crowdsec-Appsec-Http-Version.
|
||||
func Test_appsecQuery_forwardsHTTPVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
protoMajor int
|
||||
protoMinor int
|
||||
expectedHdr string
|
||||
}{
|
||||
{
|
||||
name: "HTTP/1.0",
|
||||
protoMajor: 1,
|
||||
protoMinor: 0,
|
||||
expectedHdr: "10",
|
||||
},
|
||||
{
|
||||
name: "HTTP/1.1",
|
||||
protoMajor: 1,
|
||||
protoMinor: 1,
|
||||
expectedHdr: "11",
|
||||
},
|
||||
{
|
||||
name: "HTTP/2.0",
|
||||
protoMajor: 2,
|
||||
protoMinor: 0,
|
||||
expectedHdr: "20",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var capturedVersion string
|
||||
appsecServer := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
capturedVersion = r.Header.Get(crowdsecAppsecHTTPVersionHeader)
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
if _, err := rw.Write([]byte(`{"action":"allow"}`)); err != nil {
|
||||
t.Errorf("write response: %v", err)
|
||||
}
|
||||
}))
|
||||
defer appsecServer.Close()
|
||||
|
||||
appsecURL, _ := url.Parse(appsecServer.URL)
|
||||
bouncer := &Bouncer{
|
||||
appsecScheme: appsecURL.Scheme,
|
||||
appsecHost: appsecURL.Host,
|
||||
appsecPath: "/",
|
||||
appsecBodyLimit: 10485760,
|
||||
appsecFailureBlock: false,
|
||||
httpAppsecClient: appsecServer.Client(),
|
||||
log: logger.New("INFO", ""),
|
||||
}
|
||||
|
||||
req, _ := http.NewRequest(http.MethodGet, "http://localhost/", nil)
|
||||
req.ProtoMajor = tt.protoMajor
|
||||
req.ProtoMinor = tt.protoMinor
|
||||
|
||||
_, err := appsecQuery(bouncer, "1.2.3.4", req)
|
||||
if err != nil {
|
||||
t.Fatalf("appsecQuery() unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if capturedVersion != tt.expectedHdr {
|
||||
t.Errorf("expected %s header %q, got %q", crowdsecAppsecHTTPVersionHeader, tt.expectedHdr, capturedVersion)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user