110 lines
3.2 KiB
Go
110 lines
3.2 KiB
Go
package auth
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"strings"
|
|
)
|
|
|
|
// ContextKey is a type for context keys to avoid collisions
|
|
type ContextKey string
|
|
|
|
const (
|
|
// ContextKeyUsername is the context key for storing the authenticated username
|
|
ContextKeyUsername ContextKey = "username"
|
|
// ContextKeyAuthUser is the context key for storing the raw auth username
|
|
ContextKeyAuthUser ContextKey = "auth_user"
|
|
// ContextKeyAuthPass is the context key for storing the raw auth password
|
|
ContextKeyAuthPass ContextKey = "auth_pass"
|
|
)
|
|
|
|
// Credentials holds authentication credentials
|
|
type Credentials struct {
|
|
Username string
|
|
Password string
|
|
}
|
|
|
|
// GetCredentials extracts authentication credentials from the request
|
|
// This is the single point where auth mechanism is defined
|
|
func GetCredentials(r *http.Request) (*Credentials, bool) {
|
|
username, password, ok := r.BasicAuth()
|
|
if !ok || username == "" {
|
|
return nil, false
|
|
}
|
|
return &Credentials{
|
|
Username: username,
|
|
Password: password,
|
|
}, true
|
|
}
|
|
|
|
// GetUsername extracts and formats the username for display
|
|
func GetUsername(r *http.Request) string {
|
|
creds, ok := GetCredentials(r)
|
|
if !ok {
|
|
return "Guest"
|
|
}
|
|
// Capitalize the username for display
|
|
return strings.Title(creds.Username)
|
|
}
|
|
|
|
// GetUsernameFromContext retrieves the username from the request context
|
|
func GetUsernameFromContext(ctx context.Context) string {
|
|
if username, ok := ctx.Value(ContextKeyUsername).(string); ok {
|
|
return username
|
|
}
|
|
return "Guest"
|
|
}
|
|
|
|
// GetCredentialsFromContext retrieves credentials from the request context
|
|
func GetCredentialsFromContext(ctx context.Context) (*Credentials, bool) {
|
|
username, okUser := ctx.Value(ContextKeyAuthUser).(string)
|
|
password, okPass := ctx.Value(ContextKeyAuthPass).(string)
|
|
if !okUser || !okPass {
|
|
return nil, false
|
|
}
|
|
return &Credentials{
|
|
Username: username,
|
|
Password: password,
|
|
}, true
|
|
}
|
|
|
|
// AddAuthToRequest adds authentication credentials to an HTTP request
|
|
// This should be used when making authenticated requests to internal services
|
|
func AddAuthToRequest(req *http.Request, creds *Credentials) {
|
|
if creds != nil {
|
|
req.SetBasicAuth(creds.Username, creds.Password)
|
|
}
|
|
}
|
|
|
|
// NewAuthenticatedRequest creates a new HTTP request with authentication from the source request
|
|
// This is a convenience method that extracts auth from sourceReq and applies it to the new request
|
|
func NewAuthenticatedRequest(method, url string, sourceReq *http.Request) (*http.Request, error) {
|
|
req, err := http.NewRequest(method, url, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Copy authentication from source request
|
|
if creds, ok := GetCredentials(sourceReq); ok {
|
|
AddAuthToRequest(req, creds)
|
|
}
|
|
|
|
return req, nil
|
|
}
|
|
|
|
// Middleware adds authentication information to the request context
|
|
// This allows handlers to access auth info without parsing headers repeatedly
|
|
func Middleware(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
creds, ok := GetCredentials(r)
|
|
if ok {
|
|
ctx := r.Context()
|
|
ctx = context.WithValue(ctx, ContextKeyUsername, strings.Title(creds.Username))
|
|
ctx = context.WithValue(ctx, ContextKeyAuthUser, creds.Username)
|
|
ctx = context.WithValue(ctx, ContextKeyAuthPass, creds.Password)
|
|
r = r.WithContext(ctx)
|
|
}
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|