Files
Data-Coupler/CredentialManager/Integration/DataConnectionHelper.cs
T
Alessio c22b4a2613 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
2025-06-17 01:43:17 +02:00

213 lines
8.3 KiB
C#

using CredentialManager.Models;
using CredentialManager.Services;
namespace CredentialManager.Integration;
/// <summary>
/// Metodi di utilità per l'integrazione con DataConnection
/// </summary>
public static class DataConnectionHelper
{
/// <summary>
/// Converte una DatabaseCredential in una stringa di connessione
/// </summary>
/// <param name="credential">La credenziale database</param>
/// <returns>Stringa di connessione pronta per l'uso</returns>
public static string ToConnectionString(this DatabaseCredential credential)
{
return ConnectionStringBuilder.BuildConnectionString(credential);
}
/// <summary>
/// Crea le opzioni per RestServiceOptions dal progetto DataConnection
/// </summary>
/// <param name="credential">La credenziale REST API</param>
/// <returns>Oggetto con le opzioni per REST service</returns>
public static object ToRestServiceOptions(this RestApiCredential credential)
{
return new
{
BaseUrl = credential.BaseUrl,
ApiKey = credential.ApiKey,
Username = credential.Username,
Password = credential.Password,
AuthToken = credential.AuthToken,
TimeoutSeconds = credential.TimeoutSeconds,
IgnoreSslErrors = credential.IgnoreSslErrors
};
}
/// <summary>
/// Crea le opzioni per DbManagerOptions dal progetto DataConnection
/// </summary>
/// <param name="credential">La credenziale database</param>
/// <returns>Oggetto con le opzioni per DB manager</returns>
public static object ToDbManagerOptions(this DatabaseCredential credential)
{
return new
{
ServerConnectionString = credential.ToConnectionString(),
DatabaseName = credential.DatabaseName,
DatabaseType = credential.DatabaseType.ToString(),
CommandTimeout = credential.CommandTimeout
};
}
/// <summary>
/// Ottiene la porta predefinita per un tipo di database
/// </summary>
/// <param name="databaseType">Tipo di database</param>
/// <returns>Porta predefinita</returns>
public static int GetDefaultPort(DatabaseType databaseType)
{
return databaseType switch
{
DatabaseType.SqlServer => 1433,
DatabaseType.MySql => 3306,
DatabaseType.PostgreSql => 5432,
DatabaseType.Oracle => 1521,
DatabaseType.DB2 => 50000,
DatabaseType.SapHana => 30015,
DatabaseType.Sqlite => 0, // Non applicabile
_ => 0
};
}
/// <summary>
/// Valida una credenziale database
/// </summary>
/// <param name="credential">La credenziale da validare</param>
/// <returns>Lista di errori di validazione (vuota se valida)</returns>
public static List<string> ValidateDatabaseCredential(DatabaseCredential credential)
{
var errors = new List<string>();
if (string.IsNullOrWhiteSpace(credential.Name))
errors.Add("Il nome della credenziale è obbligatorio");
if (string.IsNullOrWhiteSpace(credential.Host) && credential.DatabaseType != DatabaseType.Sqlite)
errors.Add("L'host è obbligatorio per questo tipo di database");
if (string.IsNullOrWhiteSpace(credential.DatabaseName))
errors.Add("Il nome del database è obbligatorio");
if (string.IsNullOrWhiteSpace(credential.Username) && credential.DatabaseType != DatabaseType.Sqlite)
errors.Add("Il nome utente è obbligatorio per questo tipo di database");
if (string.IsNullOrWhiteSpace(credential.Password) && credential.DatabaseType != DatabaseType.Sqlite)
errors.Add("La password è obbligatoria per questo tipo di database");
if (credential.Port <= 0 && credential.DatabaseType != DatabaseType.Sqlite)
{
// Assegna porta predefinita se non specificata
credential.Port = GetDefaultPort(credential.DatabaseType);
}
return errors;
}
/// <summary>
/// Valida una credenziale REST API
/// </summary>
/// <param name="credential">La credenziale da validare</param>
/// <returns>Lista di errori di validazione (vuota se valida)</returns>
public static List<string> ValidateRestApiCredential(RestApiCredential credential)
{
var errors = new List<string>();
if (string.IsNullOrWhiteSpace(credential.Name))
errors.Add("Il nome della credenziale è obbligatorio");
if (string.IsNullOrWhiteSpace(credential.BaseUrl))
errors.Add("L'URL base è obbligatorio");
else if (!Uri.TryCreate(credential.BaseUrl, UriKind.Absolute, out _))
errors.Add("L'URL base non è valido");
// Almeno uno tra ApiKey, Username/Password, o AuthToken deve essere specificato
var hasApiKey = !string.IsNullOrWhiteSpace(credential.ApiKey);
var hasUserPass = !string.IsNullOrWhiteSpace(credential.Username) && !string.IsNullOrWhiteSpace(credential.Password);
var hasAuthToken = !string.IsNullOrWhiteSpace(credential.AuthToken);
if (!hasApiKey && !hasUserPass && !hasAuthToken)
errors.Add("Deve essere specificato almeno un metodo di autenticazione (API Key, Username/Password, o Auth Token)");
return errors;
}
}
/// <summary>
/// Estensioni per la gestione asincrona delle credenziali
/// </summary>
public static class CredentialServiceExtensions
{
/// <summary>
/// Ottiene una credenziale database validata
/// </summary>
/// <param name="service">Il servizio credenziali</param>
/// <param name="name">Nome della credenziale</param>
/// <returns>Credenziale validata o null se non trovata</returns>
public static async Task<DatabaseCredential?> GetValidatedDatabaseCredentialAsync(
this ICredentialService service, string name)
{
var credential = await service.GetDatabaseCredentialAsync(name);
if (credential == null) return null;
var errors = DataConnectionHelper.ValidateDatabaseCredential(credential);
if (errors.Any())
throw new ArgumentException($"Credenziale non valida: {string.Join(", ", errors)}");
return credential;
}
/// <summary>
/// Ottiene una credenziale REST API validata
/// </summary>
/// <param name="service">Il servizio credenziali</param>
/// <param name="name">Nome della credenziale</param>
/// <returns>Credenziale validata o null se non trovata</returns>
public static async Task<RestApiCredential?> GetValidatedRestApiCredentialAsync(
this ICredentialService service, string name)
{
var credential = await service.GetRestApiCredentialAsync(name);
if (credential == null) return null;
var errors = DataConnectionHelper.ValidateRestApiCredential(credential);
if (errors.Any())
throw new ArgumentException($"Credenziale non valida: {string.Join(", ", errors)}");
return credential;
}
/// <summary>
/// Salva una credenziale database con validazione
/// </summary>
/// <param name="service">Il servizio credenziali</param>
/// <param name="credential">La credenziale da salvare</param>
/// <returns>ID della credenziale salvata</returns>
public static async Task<int> SaveValidatedDatabaseCredentialAsync(
this ICredentialService service, DatabaseCredential credential)
{
var errors = DataConnectionHelper.ValidateDatabaseCredential(credential);
if (errors.Any())
throw new ArgumentException($"Credenziale non valida: {string.Join(", ", errors)}");
return await service.SaveDatabaseCredentialAsync(credential);
}
/// <summary>
/// Salva una credenziale REST API con validazione
/// </summary>
/// <param name="service">Il servizio credenziali</param>
/// <param name="credential">La credenziale da salvare</param>
/// <returns>ID della credenziale salvata</returns>
public static async Task<int> SaveValidatedRestApiCredentialAsync(
this ICredentialService service, RestApiCredential credential)
{
var errors = DataConnectionHelper.ValidateRestApiCredential(credential);
if (errors.Any())
throw new ArgumentException($"Credenziale non valida: {string.Join(", ", errors)}");
return await service.SaveRestApiCredentialAsync(credential);
}
}