Skip to content

Commit 1b035f3

Browse files
committed
feat: Add local server for debug
1 parent 823fdbc commit 1b035f3

File tree

4 files changed

+191
-6
lines changed

4 files changed

+191
-6
lines changed

README.md

Lines changed: 128 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,128 @@
1-
# traefik-auth-middleware
2-
Keycloak gatekeeper middleware for traefik
1+
# Traefik Auth Middleware
2+
3+
This repository contains a Traefik middleware for authentication via Keycloak, with a **local debug server** to test it outside of Traefik.
4+
5+
---
6+
7+
## Structure
8+
9+
```
10+
traefik-auth-middleware/
11+
|── auth_test.go # Unit tests
12+
├── auth.go # Middleware code
13+
├── go.mod
14+
└── debug/
15+
└── main.go # Local debug server
16+
```
17+
18+
* `auth.go` → middleware used by Traefik.
19+
* `debug/main.go` → minimal HTTP server to test the middleware and view Keycloak responses.
20+
21+
---
22+
23+
## Dev setup
24+
25+
Install tools and dev dependencies
26+
27+
```bash
28+
mise install
29+
mise run install_yaegi
30+
```
31+
32+
### Run tests
33+
34+
```bash
35+
mise run test
36+
```
37+
38+
### Format and lint the code
39+
40+
```bash
41+
mise run format
42+
mise run lint
43+
```
44+
45+
## Running the debug server
46+
47+
1. Run the server:
48+
49+
```bash
50+
go run debug/.
51+
```
52+
53+
2. The server listens on port `8080`.
54+
55+
---
56+
57+
## Testing the middleware
58+
59+
Using `curl`:
60+
61+
```bash
62+
curl "http://localhost:8080?shop_name=test&api_key=secret"
63+
```
64+
65+
### Example response on success:
66+
67+
```json
68+
{
69+
"message": "OK - middleware passed",
70+
"token": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI..."
71+
}
72+
```
73+
74+
If the request is malformed or authentication fails, the middleware returns an appropriate HTTP status code and an error message.
75+
76+
---
77+
78+
## Logs
79+
80+
The middleware outputs JSON logs to standard output:
81+
82+
```json
83+
{
84+
"level": "INFO",
85+
"message": "Traefik-auth-middleware - Fetching auth token success for shop: test",
86+
"plugin_name": "sw-auth-plugin"
87+
}
88+
```
89+
90+
These logs allow you to track:
91+
92+
* The incoming request and its parameters
93+
* The HTTP request to Keycloak
94+
* Authentication success or failure
95+
96+
---
97+
98+
## Notes
99+
100+
* `main.go` is **only used for local debugging**.
101+
* When using Traefik, running this server is not necessary.
102+
* IAM variables must be configured in the Traefik config or via `CreateConfig()` for debugging.
103+
104+
---
105+
106+
## Debugging points
107+
108+
1. Ensure that the **query params** (`shop_name` and `api_key`) are present.
109+
2. Check that the **JSON logs** show the HTTP request to Keycloak and the `status code`.
110+
3. Using the debug server, you can directly see the Keycloak response in the HTTP response.
111+
112+
---
113+
114+
## Complete debug output example
115+
116+
```
117+
Middleware debug server started on :8080
118+
{"level":"INFO","message":"Traefik-auth-middleware - Fetching auth token success for shop: test","plugin_name":"sw-auth-plugin"}
119+
```
120+
121+
HTTP Response:
122+
123+
```json
124+
{
125+
"message": "OK - middleware passed",
126+
"token": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI..."
127+
}
128+
```

auth.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ import (
1212
)
1313

1414
type Config struct {
15-
IAM map[string]string
16-
httpClient *http.Client
15+
IAM map[string]string
16+
httpClient *http.Client
1717
}
1818

1919
func CreateConfig() *Config {
2020
return &Config{
21-
IAM: make(map[string]string),
21+
IAM: make(map[string]string),
2222
httpClient: http.DefaultClient,
2323
}
2424
}
@@ -89,6 +89,7 @@ func (cerbereConfig *Cerbere) ServeHTTP(rw http.ResponseWriter, req *http.Reques
8989
if authResponse.StatusCode != http.StatusOK {
9090
cerbereConfig.logInfo(fmt.Sprintf("Fetching auth token failed: %d", authResponse.StatusCode))
9191
http.Error(rw, "Forbidden", authResponse.StatusCode)
92+
9293
return
9394
}
9495
body, err := io.ReadAll(authResponse.Body)

auth_test.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,6 @@ func TestFailWithIamReturnUnauthorized(t *testing.T) {
108108

109109
handler.ServeHTTP(recorder, req)
110110
response := recorder.Result()
111-
112111
if response.StatusCode != http.StatusUnauthorized {
113112
t.Errorf("Expected status code 401, got %d", recorder.Code)
114113
}

debug/main.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"net/http"
7+
"time"
8+
9+
middleware "github.com/ZeroGachis/traefik-auth-middleware" //nolint:depguard
10+
)
11+
12+
func main() {
13+
// Crée la config avec valeurs par défaut
14+
config := middleware.CreateConfig()
15+
config.IAM = map[string]string{
16+
"ClientId": "devices",
17+
"Url": "https://auth.smartway-stage.tech/auth/realms/smartway/protocol/openid-connect/token",
18+
"UserQueryParamName": "shop_name",
19+
"PasswordQueryParamName": "api_key",
20+
}
21+
22+
// Wrap un handler simple pour tester
23+
handler, err := middleware.New(
24+
context.Background(),
25+
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
26+
token := r.Header.Get("Authorization")
27+
resp := map[string]string{
28+
"message": "OK - middleware passed",
29+
"token": token,
30+
}
31+
32+
w.Header().Set("Content-Type", "application/json")
33+
34+
if err := json.NewEncoder(w).Encode(resp); err != nil {
35+
http.Error(w, "Failed to encode JSON", http.StatusInternalServerError)
36+
37+
return
38+
}
39+
}),
40+
config,
41+
"sw-auth-plugin",
42+
)
43+
if err != nil {
44+
panic(err)
45+
}
46+
47+
// Lance un serveur local pour debug
48+
println("Middleware debug server started on :8080")
49+
server := &http.Server{
50+
Addr: ":8080",
51+
Handler: handler,
52+
ReadTimeout: 10 * time.Second,
53+
WriteTimeout: 10 * time.Second,
54+
IdleTimeout: 10 * time.Second,
55+
}
56+
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
57+
println("Server failed:", err)
58+
}
59+
}

0 commit comments

Comments
 (0)