-
Notifications
You must be signed in to change notification settings - Fork 148
Open
Labels
Description
Feature Proposal Description
Add Enterprise-Grade SPNEGO Authentication Middleware
This middleware provides Kerberos-based authentication for Fiber v3:
- Handles full SPNEGO protocol (
WWW-Authenticate
challenges +Authorization
validation) - Dynamic keytab loading via callback functions (files, secrets managers, databases)
- Sets authenticated principal in
c.Locals("user")
- System credential cache fallback
- Automatic SPN/realm resolution
- Customizable unauthorized responses
Workflow:
- Client accesses protected route
- Middleware returns
401 + WWW-Authenticate: Negotiate
- Client provides Kerberos ticket (browser auto-completes)
- Middleware validates ticket and decrypt request user info
- Success: Continue route with
c.Locals("user")
set
Alignment with Express API
This implementation follows Express patterns
authMiddleware, err := NewSpnegoKrb5AuthenticateMiddleware(&Config{
KeytabLookup: keytabLookup,
})
app.Use("/protected", authMiddleware)
app.Get("/protected/resource", func(c fiber.Ctx) error {
identity, ok := GetAuthenticatedIdentityFromContext(c)
if !ok {
return c.Status(fiber.StatusUnauthorized).SendString("Unauthorized")
}
return c.SendString(fmt.Sprintf("Hello, %s!", identity.UserName()))
})
HTTP RFC Standards Compliance
Fully compliant with:
- RFC 4559 (SPNEGO-based Kerberos HTTP Authentication)
- Section 4.1:
Negotiate
scheme implementation - Section 4.2: GSS-API message encapsulation
- Section 4.1:
- RFC 4120 (Kerberos V5)
- AP-REQ/AP-REP validation
- Service ticket verification
- RFC 7235 (HTTP/1.1 Authentication)
WWW-Authenticate
challenge generationAuthorization
header processing
Compliance ensured through:
- Standardized gokrb5 implementation
- Test coverage for all authentication flows
- Support for MIT Kerberos and Active Directory
API Stability
// KeytabLookupFunc is a function type that returns a keytab or an error
// It's used to look up the keytab dynamically when needed
// This design allows for extensibility, enabling keytab retrieval from various sources
// such as databases, remote services, or other custom implementations beyond static files
type KeytabLookupFunc func() (*keytab.Keytab, error)
// Config holds the configuration for the SPNEGO middleware
// It includes the keytab lookup function and a logger
type Config struct {
// KeytabLookup is a function that retrieves the keytab
KeytabLookup KeytabLookupFunc
// Log is the logger used for middleware logging
Log *log.Logger
}
Feature Examples
This just a example server
1. user should use `kinit` login to kerberos at first and use `klist` check session.
2. use `curl --negotiate ` to trigger spnego authenticate
app := fiber.New()
keytabLookup, err := NewKeytabFileLookupFunc("/keytabFile/one.keytab", "/keytabFile/two.keyta")
if err != nil {
panic(fmt.Errorf("create keytab lookup function failed: %w", err))
}
authMiddleware, err := NewSpnegoKrb5AuthenticateMiddleware(&Config{
KeytabLookup: keytabLookup,
})
if err != nil {
panic(fmt.Errorf("create spnego middleware failed: %w", err))
}
// Apply the middleware to protected routes
app.Use("/protected", authMiddleware)
// Access authenticated identity
app.Get("/protected/resource", func(c fiber.Ctx) error {
identity, ok := GetAuthenticatedIdentityFromContext(c)
if !ok {
return c.Status(fiber.StatusUnauthorized).SendString("Unauthorized")
}
return c.SendString(fmt.Sprintf("Hello, %s!", identity.UserName()))
})
log.Info("Server is running on :3000")
go func() {
<-time.After(time.Second * 1)
fmt.Println("use curl -kv --negotiate http://sso.example.local:3000/protected/resource")
fmt.Println("if response is 401, execute `klist` to check use kerberos session")
<-time.After(time.Second * 2)
fmt.Println("close server")
if err = app.Shutdown(); err != nil {
panic(fmt.Errorf("shutdown server failed: %w", err))
}
}()
if err := app.Listen("sso.example.local:3000"); err != nil {
panic(fmt.Errorf("start server failed: %w", err))
}
Checklist:
- I agree to follow Fiber's Code of Conduct.
- I have searched for existing issues that describe my proposal before opening this one.
- I understand that a proposal that does not meet these guidelines may be closed without explanation.