security: Add proper authentication, RBAC, and tenant isolation
- Add password hashing with bcrypt - Add AuthService with proper login - Add password strength validation - Add RBAC middleware (AdminOnly, ManagerOrAdmin) - Add tenant isolation middleware - Update CRM handler with tenant filtering - Add JWT fallback for development mode - Add user context helpers - Build successful
This commit is contained in:
+30
-22
@@ -122,9 +122,20 @@ func main() {
|
||||
jwtService := auth.NewJWTService(cfg.JWTSecret, "boc-auth", "boc")
|
||||
_ = jwtService
|
||||
|
||||
// För utveckling: använd öppen auth
|
||||
authMiddleware := middleware.APIKeyAuth("")
|
||||
logger.Info().Msg("Development auth initialized (open access)")
|
||||
// Auth service med databas
|
||||
authService := auth.NewAuthService(database, cfg.JWTSecret, "boc-auth", "boc")
|
||||
|
||||
// Auth middleware - RS256 för produktion, HS256 för utveckling
|
||||
var authMiddleware func(http.Handler) http.Handler
|
||||
if cfg.Port == "9092" {
|
||||
// Utveckling: tillåt HS256
|
||||
authMiddleware = middleware.JWTAuthWithFallback(cfg.JWTSecret)
|
||||
logger.Info().Msg("Development auth initialized (HS256 + RS256)")
|
||||
} else {
|
||||
// Produktion: endast RS256
|
||||
authMiddleware = middleware.JWTAuth("http://localhost:3208/.well-known/jwks.json")
|
||||
logger.Info().Msg("Production auth initialized (RS256 only)")
|
||||
}
|
||||
|
||||
// Prometheus metrics
|
||||
requestDuration := prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
||||
@@ -176,42 +187,38 @@ func main() {
|
||||
|
||||
// Auth endpoints (no auth required)
|
||||
r.Post("/api/v1/auth/login", func(w http.ResponseWriter, r *http.Request) {
|
||||
var req struct {
|
||||
Email string `json:"email"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
var req auth.LoginRequest
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
http.Error(w, `{"error":"invalid request"}`, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: Implement proper password verification against database
|
||||
// For now, reject all login attempts in production
|
||||
if cfg.Port != "9092" {
|
||||
http.Error(w, `{"error":"authentication service unavailable"}`, http.StatusServiceUnavailable)
|
||||
// Validera input
|
||||
if req.Email == "" || req.Password == "" {
|
||||
http.Error(w, `{"error":"email and password required"}`, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Development only - generate token without password check
|
||||
token, err := jwtService.GenerateToken("3847477b-3d56-4975-9157-ae8f9ce52aa7", req.Email, "admin")
|
||||
// Försök logga in
|
||||
resp, err := authService.Login(r.Context(), req)
|
||||
if err != nil {
|
||||
http.Error(w, `{"error":"token generation failed"}`, http.StatusInternalServerError)
|
||||
// Generiskt felmeddelande för att inte avslöja om email finns
|
||||
http.Error(w, `{"error":"invalid email or password"}`, http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||
"ok": true,
|
||||
"token": token,
|
||||
"token_type": "Bearer",
|
||||
"expires_in": 3600, // 1 hour - reduced from 30 days
|
||||
"algorithm": "HS256",
|
||||
"token": resp.Token,
|
||||
"token_type": resp.TokenType,
|
||||
"expires_in": resp.ExpiresIn,
|
||||
"user": map[string]string{
|
||||
"id": "3847477b-3d56-4975-9157-ae8f9ce52aa7",
|
||||
"email": req.Email,
|
||||
"name": "Erik Svensson",
|
||||
"role": "admin",
|
||||
"id": resp.User.ID,
|
||||
"email": resp.User.Email,
|
||||
"name": resp.User.Name,
|
||||
"role": resp.User.Role,
|
||||
},
|
||||
})
|
||||
})
|
||||
@@ -219,6 +226,7 @@ func main() {
|
||||
// Protected routes
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(authMiddleware)
|
||||
r.Use(middleware.TenantIsolation)
|
||||
|
||||
// Auth me
|
||||
r.Get("/api/v1/auth/me", func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
Reference in New Issue
Block a user