mirror of
https://github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin.git
synced 2025-11-08 15:15:05 +01:00
Compare commits
11 Commits
3302bb5c36
...
80e1945633
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80e1945633 | ||
|
|
06a88c89ac | ||
|
|
18011fabe6 | ||
|
|
5b147c7b27 | ||
|
|
959b792111 | ||
|
|
ac317f45aa | ||
|
|
a35c74a31d | ||
|
|
60c5ae742d | ||
|
|
1ea6af5ee3 | ||
|
|
0ad6f13e34 | ||
|
|
6afff87214 |
4
ban.html
4
ban.html
@@ -281,7 +281,6 @@
|
||||
</head>
|
||||
|
||||
<body class="h-screen w-screen p-4">
|
||||
<script>var reason = "{{ .RemediationReason }}"</script>
|
||||
<div class="h-full w-full flex flex-col justify-center items-center">
|
||||
<div class="border-2 border-black rounded-xl p-4 text-center w-full sm:w-2/3 lg:w-1/2">
|
||||
<div class="flex flex-col items-center space-y-4">
|
||||
@@ -327,5 +326,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
||||
22
bouncer.go
22
bouncer.go
@@ -9,7 +9,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
httptemplate "html/template"
|
||||
htmltemplate "html/template"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -107,7 +107,7 @@ type Bouncer struct {
|
||||
crowdsecStreamRoute string
|
||||
crowdsecHeader string
|
||||
redisUnreachableBlock bool
|
||||
banTemplate *httptemplate.Template
|
||||
banTemplate *htmltemplate.Template
|
||||
clientPoolStrategy *ip.PoolStrategy
|
||||
serverPoolStrategy *ip.PoolStrategy
|
||||
httpClient *http.Client
|
||||
@@ -160,10 +160,10 @@ func New(_ context.Context, next http.Handler, config *configuration.Config, nam
|
||||
config.CrowdsecLapiKey = apiKey
|
||||
}
|
||||
|
||||
var banTemplate *httptemplate.Template
|
||||
if config.BanHTMLFilePath != "" {
|
||||
banTemplate, _ = configuration.GetHTMLTemplate(config.BanHTMLFilePath)
|
||||
}
|
||||
var banTemplate *htmltemplate.Template
|
||||
if config.BanHTMLFilePath != "" {
|
||||
banTemplate, _ = configuration.GetHTMLTemplate(config.BanHTMLFilePath)
|
||||
}
|
||||
|
||||
bouncer := &Bouncer{
|
||||
next: next,
|
||||
@@ -305,12 +305,12 @@ func (bouncer *Bouncer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
bouncer.next.ServeHTTP(rw, req)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
if bouncer.crowdsecMode == configuration.AppsecMode {
|
||||
handleNextServeHTTP(bouncer, remoteIP, rw, req)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// TODO This should be simplified
|
||||
if bouncer.crowdsecMode != configuration.NoneMode {
|
||||
value, cacheErr := bouncer.cacheClient.Get(remoteIP)
|
||||
@@ -331,13 +331,13 @@ func (bouncer *Bouncer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||
bouncer.log.Debug(fmt.Sprintf("ServeHTTP ip:%s cache:hit isBanned:%v", remoteIP, value))
|
||||
if value == cache.NoBannedValue {
|
||||
handleNextServeHTTP(bouncer, remoteIP, rw, req)
|
||||
} else {
|
||||
} else {
|
||||
handleRemediationServeHTTP(bouncer, remoteIP, value, rw, req)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Right here if we cannot join the stream we forbid the request to go on.
|
||||
if bouncer.crowdsecMode == configuration.StreamMode || bouncer.crowdsecMode == configuration.AloneMode {
|
||||
if isCrowdsecStreamHealthy {
|
||||
@@ -388,7 +388,7 @@ type Login struct {
|
||||
// To append Headers we need to call rw.WriteHeader after set any header.
|
||||
func handleBanServeHTTP(bouncer *Bouncer, rw http.ResponseWriter, method, reason string) {
|
||||
atomic.AddInt64(&blockedRequests, 1)
|
||||
|
||||
|
||||
if bouncer.remediationCustomHeader != "" {
|
||||
rw.Header().Set(bouncer.remediationCustomHeader, "ban")
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package crowdsec_bouncer_traefik_plugin //nolint:revive,stylecheck
|
||||
|
||||
import (
|
||||
"context"
|
||||
httptemplate "http/template"
|
||||
htmltemplate "html/template"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
@@ -189,11 +189,12 @@ func Test_crowdsecQuery(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestHandleBanServeHTTPWithDifferentMethods(t *testing.T) {
|
||||
banTemplate := httptemplate.New("html").parse("<html>You are banned</html>")
|
||||
html := "<html>You are banned</html>"
|
||||
banTemplate, _ := htmltemplate.New("html").Parse(html)
|
||||
tests := []struct {
|
||||
name string
|
||||
method string
|
||||
banTemplateString string
|
||||
banTemplate *htmltemplate.Template
|
||||
expectBodyContent bool
|
||||
}{
|
||||
{
|
||||
@@ -231,13 +232,13 @@ func TestHandleBanServeHTTPWithDifferentMethods(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bouncer := &Bouncer{
|
||||
remediationStatusCode: http.StatusForbidden,
|
||||
remediationStatusCode: http.StatusForbidden,
|
||||
remediationCustomHeader: "X-Test-Remediation",
|
||||
banTemplate: tt.banTemplateString,
|
||||
banTemplate: tt.banTemplate,
|
||||
}
|
||||
|
||||
rw := httptest.NewRecorder()
|
||||
handleBanServeHTTP(bouncer, rw, tt.method)
|
||||
handleBanServeHTTP(bouncer, rw, tt.method, "TEST")
|
||||
|
||||
// Check status code
|
||||
if rw.Code != http.StatusForbidden {
|
||||
@@ -260,8 +261,8 @@ func TestHandleBanServeHTTPWithDifferentMethods(t *testing.T) {
|
||||
}
|
||||
|
||||
// If we expect body content, verify it matches template
|
||||
if tt.expectBodyContent && body != tt.banTemplateString {
|
||||
t.Errorf("Expected body %q, got %q", tt.banTemplateString, body)
|
||||
if tt.expectBodyContent && body != html {
|
||||
t.Errorf("Expected body %q, got %q", html, body)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -45,3 +45,12 @@ To play the demo environment run:
|
||||
```bash
|
||||
make run_custom_ban_page
|
||||
```
|
||||
|
||||
## Another thing to note
|
||||
In the html of the ban page, you can use {{ .RemediationReason }} that convert on runtime into why the ban page is served.
|
||||
It's an enum with "APPSEC", "LAPI", "TECHNICAL_ISSUE".
|
||||
It is useful to help user understand why its request is blocked.
|
||||
```
|
||||
<script>var remediation = "{{ .RemediationReason }}"</script>
|
||||
```
|
||||
With the above tweak and some other js, you can customize your ban page on runtime.
|
||||
|
||||
Reference in New Issue
Block a user