c22b4a2613
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
270 lines
9.4 KiB
C#
270 lines
9.4 KiB
C#
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" }
|
|
}
|
|
}
|
|
};
|
|
}
|
|
}
|