cmc-sales/go/internal/cmc/auth/auth.go

110 lines
3.2 KiB
Go
Raw Normal View History

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)
})
}