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:
@@ -242,3 +242,62 @@ func getStringClaim(claims jwt.MapClaims, key string) string {
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// JWTAuthWithFallback middleware för utveckling - stödjer både RS256 och HS256
|
||||
func JWTAuthWithFallback(jwtSecret string) func(http.Handler) http.Handler {
|
||||
validator := NewJWTValidator("http://localhost:3208/.well-known/jwks.json")
|
||||
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
authHeader := r.Header.Get("Authorization")
|
||||
if authHeader == "" {
|
||||
writeError(w, http.StatusUnauthorized, "missing authorization header")
|
||||
return
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(authHeader, "Bearer ") {
|
||||
writeError(w, http.StatusUnauthorized, "invalid authorization header format")
|
||||
return
|
||||
}
|
||||
|
||||
tokenString := strings.TrimPrefix(authHeader, "Bearer ")
|
||||
|
||||
// Försök validera med RS256 först
|
||||
_, claims, err := validator.ValidateToken(tokenString)
|
||||
if err != nil {
|
||||
// Fallback: Tillåt HS256 tokens för utveckling
|
||||
token, parseErr := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
|
||||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); ok {
|
||||
return []byte(jwtSecret), nil
|
||||
}
|
||||
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
|
||||
})
|
||||
if parseErr != nil || !token.Valid {
|
||||
log.Warn().Err(err).Str("path", r.URL.Path).Msg("JWT validation failed")
|
||||
writeError(w, http.StatusUnauthorized, "invalid token")
|
||||
return
|
||||
}
|
||||
claims = token.Claims.(jwt.MapClaims)
|
||||
}
|
||||
|
||||
// Extrahera claims
|
||||
userClaims := Claims{
|
||||
Sub: getStringClaim(claims, "sub"),
|
||||
Email: getStringClaim(claims, "email"),
|
||||
Name: getStringClaim(claims, "name"),
|
||||
}
|
||||
|
||||
// Hantera roles som kan vara []interface{}
|
||||
if roles, ok := claims["roles"].([]interface{}); ok {
|
||||
for _, r := range roles {
|
||||
if s, ok := r.(string); ok {
|
||||
userClaims.Roles = append(userClaims.Roles, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx := WithContext(r.Context(), &userClaims)
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user