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:
@@ -0,0 +1,212 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user