feat: Integrazione completa gestione credenziali per database e REST API con supporto SAP B1 e Salesforce

NUOVE FUNZIONALITÀ:
- Aggiunto modulo CredentialManager per gestione centralizzata credenziali
- Implementata UI Blazor per gestione credenziali (CredentialManagement.razor)
- Supporto completo per credenziali database (SQL Server, MySQL, PostgreSQL, Oracle, SQLite, DB2, SAP HANA)
- Gestione unificata REST API con supporto specifico per SAP B1 Service Layer e Salesforce
- Test reali di connessione per database, SAP B1 e Salesforce OAuth2
- Selezione dinamica tipo servizio REST (Generico, SAP B1, Salesforce) con campi specifici
- Persistenza sicura di credenziali con crittografia password e campi sensibili

COMPONENTI AGGIUNTI:
- CredentialManager/Models/: CredentialEntity, CredentialModels (DatabaseCredential, RestApiCredential, SapB1ServiceLayerCredential, SalesforceCredential)
- CredentialManager/Services/: CredentialService, EncryptionService, DatabaseInitializer
- CredentialManager/Data/: CredentialDbContext con Entity Framework
- DataConnection/CredentialManagement/: Interfacce e servizi di integrazione
- Data_Coupler/Pages/CredentialManagement.razor: UI completa per gestione credenziali

MIGLIORAMENTI UI:
- Form dinamica per REST API con campi specifici per tipo servizio
- Validazione campi obbligatori per Salesforce (ClientId, ClientSecret, SecurityToken)
- Test connessione in tempo reale dalla modale di inserimento/modifica
- Rimozione sezioni separate per SAP B1 e Salesforce (ora unificate in REST API)
- Gestione stato loading durante operazioni async

PERSISTENZA AVANZATA:
- Campo RestServiceType aggiunto a CredentialEntity con migrazione automatica
- Serializzazione campi specifici Salesforce/SAP B1 in AdditionalParameters JSON
- Mapping bidirezionale tra entità database e modelli business
- Gestione nullability e conversioni tipo sicure

SICUREZZA:
- Crittografia AES-256 per password e token sensibili
- Gestione sicura ConnectionString database
- Validazione input e sanitizzazione dati

TESTING E CONNETTIVITÀ:
- Test autenticazione reale SAP B1 Service Layer
- Test OAuth2 Salesforce con supporto Connected App
- Test connettività database multi-provider
- Logging dettagliato per debugging e monitoraggio

CONFIGURAZIONE:
- Dependency injection per tutti i servizi
- Configurazione Entity Framework con SQLite
- Tasks VS Code per build e run
- Gestione connection string centralizzata

CORREZIONI:
- Risolti errori nullability in CredentialService
- Aggiunto using Microsoft.JSInterop per IJSRuntime
- Fix compilazione e warning

Files modificati: 35+ file tra nuovi e aggiornati
This commit is contained in:
2025-06-17 01:43:17 +02:00
parent 09d07db2ba
commit c22b4a2613
38 changed files with 5002 additions and 27 deletions
@@ -0,0 +1,269 @@
using CredentialManager.Models;
using System.Text.Json;
namespace CredentialManager.Utilities;
/// <summary>
/// Metodi di utilità per la validazione delle credenziali
/// </summary>
public static class CredentialValidator
{
/// <summary>
/// Valida una credenziale database
/// </summary>
/// <param name="credential">La credenziale da validare</param>
/// <returns>Risultato della validazione</returns>
public static ValidationResult ValidateDatabaseCredential(DatabaseCredential credential)
{
var errors = new List<string>();
if (string.IsNullOrWhiteSpace(credential.Name))
errors.Add("Name is required");
if (string.IsNullOrWhiteSpace(credential.Host))
errors.Add("Host is required");
if (credential.Port <= 0)
errors.Add("Port must be greater than 0");
if (string.IsNullOrWhiteSpace(credential.DatabaseName))
errors.Add("Database name is required");
if (string.IsNullOrWhiteSpace(credential.Username))
errors.Add("Username is required");
if (string.IsNullOrWhiteSpace(credential.Password))
errors.Add("Password is required");
// Validate port ranges for specific database types
switch (credential.DatabaseType)
{
case DatabaseType.SqlServer:
if (credential.Port < 1 || credential.Port > 65535)
errors.Add("SQL Server port must be between 1 and 65535");
break;
case DatabaseType.MySql:
if (credential.Port < 1 || credential.Port > 65535)
errors.Add("MySQL port must be between 1 and 65535");
break;
case DatabaseType.PostgreSql:
if (credential.Port < 1 || credential.Port > 65535)
errors.Add("PostgreSQL port must be between 1 and 65535");
break;
case DatabaseType.Oracle:
if (credential.Port < 1 || credential.Port > 65535)
errors.Add("Oracle port must be between 1 and 65535");
break;
}
return new ValidationResult { IsValid = errors.Count == 0, Errors = errors };
}
/// <summary>
/// Valida una credenziale REST API
/// </summary>
/// <param name="credential">La credenziale da validare</param>
/// <returns>Risultato della validazione</returns>
public static ValidationResult ValidateRestApiCredential(RestApiCredential credential)
{
var errors = new List<string>();
if (string.IsNullOrWhiteSpace(credential.Name))
errors.Add("Name is required");
if (string.IsNullOrWhiteSpace(credential.BaseUrl))
errors.Add("Base URL is required");
if (!string.IsNullOrWhiteSpace(credential.BaseUrl) && !Uri.IsWellFormedUriString(credential.BaseUrl, UriKind.Absolute))
errors.Add("Base URL must be a valid absolute URI");
if (credential.TimeoutSeconds <= 0)
errors.Add("Timeout must be greater than 0 seconds");
// Check that at least one authentication method is provided
bool hasAuth = !string.IsNullOrWhiteSpace(credential.ApiKey) ||
!string.IsNullOrWhiteSpace(credential.AuthToken) ||
!string.IsNullOrWhiteSpace(credential.BearerToken) ||
(!string.IsNullOrWhiteSpace(credential.Username) && !string.IsNullOrWhiteSpace(credential.Password));
if (!hasAuth)
errors.Add("At least one authentication method must be provided (ApiKey, AuthToken, BearerToken, or Username/Password)");
return new ValidationResult { IsValid = errors.Count == 0, Errors = errors };
}
}
/// <summary>
/// Risultato di una validazione
/// </summary>
public class ValidationResult
{
public bool IsValid { get; set; }
public List<string> Errors { get; set; } = new();
}
/// <summary>
/// Metodi di utilità per l'import/export delle credenziali
/// </summary>
public static class CredentialImportExport
{
/// <summary>
/// Esporta le credenziali in formato JSON
/// </summary>
/// <param name="databaseCredentials">Credenziali database</param>
/// <param name="restApiCredentials">Credenziali REST API</param>
/// <returns>JSON string</returns>
public static string ExportToJson(
IEnumerable<DatabaseCredential> databaseCredentials,
IEnumerable<RestApiCredential> restApiCredentials)
{
var export = new
{
ExportDate = DateTime.UtcNow,
DatabaseCredentials = databaseCredentials,
RestApiCredentials = restApiCredentials
};
var options = new JsonSerializerOptions
{
WriteIndented = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
return JsonSerializer.Serialize(export, options);
}
/// <summary>
/// Importa le credenziali da formato JSON
/// </summary>
/// <param name="json">JSON string</param>
/// <returns>Tuple con le credenziali importate</returns>
public static (List<DatabaseCredential> DatabaseCredentials, List<RestApiCredential> RestApiCredentials) ImportFromJson(string json)
{
var options = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
using var document = JsonDocument.Parse(json);
var root = document.RootElement;
var databaseCredentials = new List<DatabaseCredential>();
var restApiCredentials = new List<RestApiCredential>();
if (root.TryGetProperty("databaseCredentials", out var dbElement))
{
databaseCredentials = JsonSerializer.Deserialize<List<DatabaseCredential>>(dbElement.GetRawText(), options) ?? new();
}
if (root.TryGetProperty("restApiCredentials", out var restElement))
{
restApiCredentials = JsonSerializer.Deserialize<List<RestApiCredential>>(restElement.GetRawText(), options) ?? new();
}
return (databaseCredentials, restApiCredentials);
}
}
/// <summary>
/// Metodi di utilità per la generazione di credenziali di test
/// </summary>
public static class CredentialTestDataGenerator
{
/// <summary>
/// Genera credenziali database di esempio per testing
/// </summary>
/// <returns>Lista di credenziali database di test</returns>
public static List<DatabaseCredential> GenerateTestDatabaseCredentials()
{
return new List<DatabaseCredential>
{
new DatabaseCredential
{
Name = "Test SQL Server",
DatabaseType = DatabaseType.SqlServer,
Host = "localhost",
Port = 1433,
DatabaseName = "TestDB",
Username = "testuser",
Password = "testpass123",
CommandTimeout = 30
},
new DatabaseCredential
{
Name = "Test MySQL",
DatabaseType = DatabaseType.MySql,
Host = "localhost",
Port = 3306,
DatabaseName = "testdb",
Username = "testuser",
Password = "testpass123",
CommandTimeout = 30
},
new DatabaseCredential
{
Name = "Test PostgreSQL",
DatabaseType = DatabaseType.PostgreSql,
Host = "localhost",
Port = 5432,
DatabaseName = "testdb",
Username = "testuser",
Password = "testpass123",
CommandTimeout = 30
},
new DatabaseCredential
{
Name = "Test SQLite",
DatabaseType = DatabaseType.Sqlite,
Host = "",
Port = 0,
DatabaseName = "test.db",
Username = "",
Password = "",
CommandTimeout = 30
}
};
}
/// <summary>
/// Genera credenziali REST API di esempio per testing
/// </summary>
/// <returns>Lista di credenziali REST API di test</returns>
public static List<RestApiCredential> GenerateTestRestApiCredentials()
{
return new List<RestApiCredential>
{
new RestApiCredential
{
Name = "Test API with API Key",
BaseUrl = "https://api.example.com/v1",
ApiKey = "test_api_key_123",
TimeoutSeconds = 60,
Headers = new Dictionary<string, string>
{
{ "Accept", "application/json" },
{ "Content-Type", "application/json" }
}
},
new RestApiCredential
{
Name = "Test API with Bearer Token",
BaseUrl = "https://api.another-example.com",
BearerToken = "bearer_token_xyz789",
TimeoutSeconds = 120
},
new RestApiCredential
{
Name = "Test API with Basic Auth",
BaseUrl = "https://api.basic-auth-example.com",
Username = "testuser",
Password = "testpassword",
TimeoutSeconds = 90,
Headers = new Dictionary<string, string>
{
{ "User-Agent", "CredentialManager-Test/1.0" }
}
}
};
}
}