fix(auth): exempt swagger ui path in authentik middleware
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
b8fd020bb2
commit
dd834211d8
3 changed files with 40 additions and 3 deletions
12
authentik.go
12
authentik.go
|
|
@ -26,7 +26,7 @@ type AuthentikConfig struct {
|
|||
TrustedProxy bool
|
||||
|
||||
// PublicPaths lists additional paths that do not require authentication.
|
||||
// /health and /swagger are always public.
|
||||
// /health and the configured Swagger UI path are always public.
|
||||
PublicPaths []string
|
||||
}
|
||||
|
||||
|
|
@ -134,7 +134,7 @@ func validateJWT(ctx context.Context, cfg AuthentikConfig, rawToken string) (*Au
|
|||
// The middleware is PERMISSIVE: it populates the context when credentials are
|
||||
// present but never rejects unauthenticated requests. Downstream handlers
|
||||
// use GetUser to check authentication.
|
||||
func authentikMiddleware(cfg AuthentikConfig) gin.HandlerFunc {
|
||||
func authentikMiddleware(cfg AuthentikConfig, publicPaths func() []string) gin.HandlerFunc {
|
||||
// Build the set of public paths that skip header extraction entirely.
|
||||
public := map[string]bool{
|
||||
"/health": true,
|
||||
|
|
@ -153,6 +153,14 @@ func authentikMiddleware(cfg AuthentikConfig) gin.HandlerFunc {
|
|||
return
|
||||
}
|
||||
}
|
||||
if publicPaths != nil {
|
||||
for _, p := range publicPaths() {
|
||||
if isPublicPath(path, p) {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Block 1: Extract user from X-authentik-* forward-auth headers.
|
||||
if cfg.TrustedProxy {
|
||||
|
|
|
|||
|
|
@ -343,6 +343,33 @@ func TestBearerAndAuthentikCoexist_Good(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestAuthentik_Good_CustomSwaggerPathBypassesAuth(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
cfg := api.AuthentikConfig{TrustedProxy: true}
|
||||
e, err := api.New(
|
||||
api.WithAuthentik(cfg),
|
||||
api.WithSwagger("Test API", "A test API service", "1.0.0"),
|
||||
api.WithSwaggerPath("/docs"),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
srv := httptest.NewServer(e.Handler())
|
||||
defer srv.Close()
|
||||
|
||||
resp, err := http.Get(srv.URL + "/docs/doc.json")
|
||||
if err != nil {
|
||||
t.Fatalf("request failed: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
t.Fatalf("expected 200 for custom swagger path without auth, got %d", resp.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
// ── RequireAuth / RequireGroup ────────────────────────────────────────
|
||||
|
||||
func TestRequireAuth_Good(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -140,7 +140,9 @@ func WithWSPath(path string) Option {
|
|||
// The middleware is permissive: unauthenticated requests are allowed through.
|
||||
func WithAuthentik(cfg AuthentikConfig) Option {
|
||||
return func(e *Engine) {
|
||||
e.middlewares = append(e.middlewares, authentikMiddleware(cfg))
|
||||
e.middlewares = append(e.middlewares, authentikMiddleware(cfg, func() []string {
|
||||
return []string{resolveSwaggerPath(e.swaggerPath)}
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue