Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion middleware/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import (
"github.com/platform-mesh/golang-commons/context"
)

// StoreAuthHeader stores the Authorization header within the request context
// StoreAuthHeader returns HTTP middleware that reads the request's Authorization header and stores it in the request context.
// The middleware wraps a handler, extracts the Authorization header (using headers.Authorization), calls
// context.AddAuthHeaderToContext with the existing request context and the header value, and invokes the next handler
// with the request updated to use that context. If the Authorization header is absent, an empty string is stored.
func StoreAuthHeader() func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(responseWriter http.ResponseWriter, request *http.Request) {
Expand Down
10 changes: 10 additions & 0 deletions middleware/authzMiddlewares.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ import (
"github.com/platform-mesh/golang-commons/policy_services"
)

// CreateAuthMiddleware returns a slice of HTTP middleware constructors that populate
// authentication-related request context and headers.
//
// The returned middlewares, applied in order, are:
// 1. StoreWebToken()
// 2. StoreAuthHeader()
// 3. StoreSpiffeHeader()
//
// The `retriever` parameter is accepted for compatibility with caller signatures but is
// not used by this implementation.
func CreateAuthMiddleware(retriever policy_services.TenantRetriever) []func(http.Handler) http.Handler {
mws := make([]func(http.Handler) http.Handler, 0, 5)

Expand Down
3 changes: 2 additions & 1 deletion middleware/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import (
"github.com/platform-mesh/golang-commons/logger"
)

// StoreLoggerMiddleware is a middleware that stores a given Logger in the request context
// StoreLoggerMiddleware returns an HTTP middleware that injects the provided
// logger into each request's context so downstream handlers can retrieve it.
func StoreLoggerMiddleware(log *logger.Logger) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
Expand Down
1 change: 1 addition & 0 deletions middleware/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/platform-mesh/golang-commons/logger"
)

// attaches a request-scoped logger (using the provided logger), assigns a request ID, and propagates that ID into the logger.
func CreateMiddleware(log *logger.Logger) []func(http.Handler) http.Handler {
return []func(http.Handler) http.Handler{
SetOtelTracingContext(),
Expand Down
8 changes: 8 additions & 0 deletions middleware/otel.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ import (
"go.opentelemetry.io/otel/propagation"
)

// SetOtelTracingContext returns an HTTP middleware that extracts OpenTelemetry
// tracing context from incoming request headers and injects it into the request's
// context before passing the request to the next handler.
//
// The middleware uses the global OpenTelemetry text map propagator and
// propagation.HeaderCarrier to read trace/span context from the request headers.
// Any extraction behavior (including failure handling) is delegated to the
// propagator implementation.
func SetOtelTracingContext() func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(responseWriter http.ResponseWriter, request *http.Request) {
Expand Down
11 changes: 11 additions & 0 deletions middleware/requestid.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import (

const requestIdHeader = "X-Request-Id"

// SetRequestId returns an HTTP middleware that ensures each request has a request ID.
// It reads the `X-Request-Id` header (used only if exactly one value is present); otherwise
// it generates a new UUID. The request ID is stored in the request context under
// keys.RequestIdCtxKey and the request is forwarded to the next handler with the updated context.
func SetRequestId() func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(responseWriter http.ResponseWriter, request *http.Request) {
Expand All @@ -28,6 +32,11 @@ func SetRequestId() func(http.Handler) http.Handler {
}
}

// SetRequestIdInLogger returns HTTP middleware that injects a request-scoped logger into the request context.
//
// The middleware loads the current logger from the request context, creates a per-request logger using
// logger.NewRequestLoggerFromZerolog(ctx, log.Logger), and stores the resulting logger back into the context
// before calling the next handler. This ensures handlers downstream receive a logger enriched for the current request.
func SetRequestIdInLogger() func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(responseWriter http.ResponseWriter, request *http.Request) {
Expand All @@ -40,6 +49,8 @@ func SetRequestIdInLogger() func(http.Handler) http.Handler {
}
}

// GetRequestId returns the request ID stored in ctx under keys.RequestIdCtxKey.
// If the value is missing or not a string, it returns the empty string.
func GetRequestId(ctx context.Context) string {
if val, ok := ctx.Value(keys.RequestIdCtxKey).(string); ok {
return val
Expand Down
7 changes: 6 additions & 1 deletion middleware/sentry.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ import (
)

// Recoverer implements a middleware that recover from panics, sends them to Sentry
// log the panic together with a stack trace and sends HTTP status 500
// SentryRecoverer returns an http.Handler that wraps next and recovers from panics.
//
// If a panic occurs (except http.ErrAbortHandler) the middleware logs the panic and stack
// trace, reports the error to the current Sentry hub, flushes Sentry events (up to 5s),
// and responds with HTTP 500 Internal Server Error. The returned handler otherwise
// delegates to next.ServeHTTP.
func SentryRecoverer(next http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
defer func() {
Expand Down
5 changes: 5 additions & 0 deletions middleware/spiffe.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ import (
"github.com/platform-mesh/golang-commons/jwt"
)

// StoreSpiffeHeader returns an HTTP middleware that extracts a SPIFFE URL from the request headers
// and, if present, inserts it into the request context for downstream handlers.
//
// The middleware always calls the next handler; when a SPIFFE URL is found it updates the request's
// context with that value so subsequent handlers can retrieve it.
func StoreSpiffeHeader() func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(responseWriter http.ResponseWriter, request *http.Request) {
Expand Down
4 changes: 4 additions & 0 deletions middleware/test_support/local_middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import (
"github.com/platform-mesh/golang-commons/context"
)

// LocalMiddleware returns an HTTP middleware factory that injects a test JWT and tenant ID into each request's context.
// The returned middleware creates a lightweight, unsigned JWT whose subject is set to userId and whose issuer is "localhost:8080",
// stores that token (allowed signature algorithm "none") and the provided tenantId in the request context, then calls the next handler.
// This middleware is intended for local/test use; it will panic if token creation fails.
func LocalMiddleware(tenantId string, userId string) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(responseWriter http.ResponseWriter, request *http.Request) {
Expand Down
8 changes: 7 additions & 1 deletion middleware/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,13 @@ const tokenAuthPrefix = "BEARER"

var SignatureAlgorithms = []jose.SignatureAlgorithm{jose.RS256}

// StoreWebToken retrieves the actual JWT Token within the Authorization header, and it stores it in the context as a struct
// StoreWebToken returns middleware that extracts a JWT from the HTTP `Authorization` header
// and stores it in the request context for downstream handlers.
//
// The middleware looks for an Authorization header of the form `Bearer <token>` (scheme match is
// case-insensitive). When present, the token is added to the context via
// context.AddWebTokenToContext using the package's SignatureAlgorithms. If the header is absent,
// malformed, or not a Bearer token, the request context is left unchanged.
func StoreWebToken() func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(responseWriter http.ResponseWriter, request *http.Request) {
Expand Down