go first commit
This commit is contained in:
123
go_cloud/internal/middleware/middleware.go
Normal file
123
go_cloud/internal/middleware/middleware.go
Normal file
@@ -0,0 +1,123 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"go.b0esche.cloud/backend/internal/audit"
|
||||
"go.b0esche.cloud/backend/internal/database"
|
||||
"go.b0esche.cloud/backend/internal/org"
|
||||
"go.b0esche.cloud/backend/internal/permission"
|
||||
"go.b0esche.cloud/backend/pkg/jwt"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
var RequestID = middleware.RequestID
|
||||
var Logger = middleware.Logger
|
||||
var Recoverer = middleware.Recoverer
|
||||
|
||||
// TODO: Implement rate limiter
|
||||
var RateLimit = func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// Basic rate limiting logic here
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
type contextKey string
|
||||
|
||||
const (
|
||||
userKey contextKey = "user"
|
||||
sessionKey contextKey = "session"
|
||||
orgKey contextKey = "org"
|
||||
)
|
||||
|
||||
// Auth middleware
|
||||
func Auth(jwtManager *jwt.Manager, db *database.DB) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
authHeader := r.Header.Get("Authorization")
|
||||
if !strings.HasPrefix(authHeader, "Bearer ") {
|
||||
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
tokenString := strings.TrimPrefix(authHeader, "Bearer ")
|
||||
claims, session, err := jwtManager.ValidateWithSession(r.Context(), tokenString, db)
|
||||
if err != nil {
|
||||
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
ctx := context.WithValue(r.Context(), userKey, claims.UserID)
|
||||
ctx = context.WithValue(ctx, sessionKey, session)
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Org middleware
|
||||
func Org(db *database.DB, auditLogger *audit.Logger) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
userIDStr := r.Context().Value(userKey).(string)
|
||||
userID, _ := uuid.Parse(userIDStr)
|
||||
|
||||
orgIDStr := r.Header.Get("X-Org-ID")
|
||||
if orgIDStr == "" {
|
||||
orgIDStr = chi.URLParam(r, "orgId")
|
||||
}
|
||||
orgID, err := uuid.Parse(orgIDStr)
|
||||
if err != nil {
|
||||
http.Error(w, "Invalid org ID", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = org.CheckMembership(r.Context(), db, userID, orgID)
|
||||
if err != nil {
|
||||
auditLogger.Log(r.Context(), audit.Entry{
|
||||
UserID: &userID,
|
||||
Action: "org_access",
|
||||
Success: false,
|
||||
Metadata: map[string]interface{}{"org_id": orgID, "error": err.Error()},
|
||||
})
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
ctx := context.WithValue(r.Context(), orgKey, orgID)
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Permission middleware
|
||||
func Permission(db *database.DB, auditLogger *audit.Logger, perm permission.Permission) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
userIDStr := r.Context().Value(userKey).(string)
|
||||
userID, _ := uuid.Parse(userIDStr)
|
||||
orgID := r.Context().Value(orgKey).(uuid.UUID)
|
||||
|
||||
hasPerm, err := permission.HasPermission(r.Context(), db, userID, orgID, perm)
|
||||
if err != nil || !hasPerm {
|
||||
auditLogger.Log(r.Context(), audit.Entry{
|
||||
UserID: &userID,
|
||||
OrgID: &orgID,
|
||||
Action: "permission_check",
|
||||
Resource: &[]string{string(perm)}[0],
|
||||
Success: false,
|
||||
Metadata: map[string]interface{}{"permission": perm},
|
||||
})
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user