diff --git a/DataConnection/REST/Implementations/SalesforceServiceClient.cs b/DataConnection/REST/Implementations/SalesforceServiceClient.cs
index dd3308e..c20586d 100644
--- a/DataConnection/REST/Implementations/SalesforceServiceClient.cs
+++ b/DataConnection/REST/Implementations/SalesforceServiceClient.cs
@@ -132,13 +132,13 @@ namespace DataConnection.REST.Implementations
if (string.IsNullOrEmpty(_options.Username) || string.IsNullOrEmpty(_options.Password))
{
- Console.WriteLine("Salesforce authentication requires username and password in options");
+ Console.WriteLine($"Salesforce authentication requires username and password in options. Username: '{_options.Username}', Password: '{(!string.IsNullOrEmpty(_options.Password) ? "***SET***" : "***NULL***")}'");
return false;
}
if (string.IsNullOrEmpty(_options.ApiKey) || string.IsNullOrEmpty(_options.AuthToken))
{
- Console.WriteLine("Salesforce authentication requires ApiKey (ClientId) and AuthToken (ClientSecret) in options");
+ Console.WriteLine($"Salesforce authentication requires ApiKey (ClientId) and AuthToken (ClientSecret) in options. ApiKey: '{_options.ApiKey}', AuthToken: '{(!string.IsNullOrEmpty(_options.AuthToken) ? "***SET***" : "***NULL***")}'");
return false;
}
diff --git a/Data_Coupler/Services/DataConnectionFactory.cs b/Data_Coupler/Services/DataConnectionFactory.cs
index 819669c..1717aa2 100644
--- a/Data_Coupler/Services/DataConnectionFactory.cs
+++ b/Data_Coupler/Services/DataConnectionFactory.cs
@@ -7,9 +7,21 @@ using DataConnection.REST.Configuration;
using DataConnection.CredentialManagement.Interfaces;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
+using System.Security.Cryptography;
+using System.Text;
namespace Data_Coupler.Services
{
+ ///
+ /// Classe per tracciare i client REST cached con le loro credenziali
+ ///
+ internal class CachedRestClient
+ {
+ public IRestServiceClient Client { get; set; } = null!;
+ public string CredentialsHash { get; set; } = string.Empty;
+ public DateTime CachedAt { get; set; }
+ }
+
///
/// Factory service per creare istanze di DatabaseManager e RestClient
///
@@ -46,8 +58,8 @@ namespace Data_Coupler.Services
private readonly ILogger _logger;
private readonly IDataConnectionCredentialService _credentialService;
- // Cache per mantenere le istanze dei client REST autenticati
- private readonly Dictionary _restClientCache = new();
+ // Cache intelligente per client REST che mantiene lo stato di autenticazione ma verifica le credenziali
+ private readonly Dictionary _restClientCache = new();
public DataConnectionFactory(IServiceProvider serviceProvider, ILogger logger, IDataConnectionCredentialService credentialService)
{
@@ -76,17 +88,29 @@ namespace Data_Coupler.Services
{
try
{
- // Controlla se abbiamo già un client cached per questa credenziale
- if (_restClientCache.TryGetValue(credentialName, out var cachedClient))
- {
- _logger.LogInformation("Utilizzando client REST cached per {CredentialName}", credentialName);
- return cachedClient;
- }
-
+ // SEMPRE recupera le credenziali fresh dal database per assicurare che siano aggiornate
var credential = await _credentialService.GetRestApiCredentialAsync(credentialName);
if (credential == null)
{
throw new ArgumentException($"Credenziale REST API '{credentialName}' non trovata");
+ }
+
+ // Calcola l'hash delle credenziali correnti
+ var currentCredentialsHash = CalculateCredentialsHash(credential);
+
+ // Controlla se abbiamo un client cached con le stesse credenziali
+ if (_restClientCache.TryGetValue(credentialName, out var cachedClient))
+ {
+ if (cachedClient.CredentialsHash == currentCredentialsHash)
+ {
+ _logger.LogInformation("Utilizzando client REST cached con credenziali verificate per {CredentialName}", credentialName);
+ return cachedClient.Client;
+ }
+ else
+ {
+ _logger.LogInformation("Credenziali cambiate, rimuovendo client cached per {CredentialName}", credentialName);
+ _restClientCache.Remove(credentialName);
+ }
} var options = new RestServiceOptions
{
BaseUrl = credential.BaseUrl,
@@ -101,8 +125,11 @@ namespace Data_Coupler.Services
// Per Salesforce usiamo i campi specifici ClientId e ClientSecret
options.ApiKey = credential.ClientId; // ClientId -> ApiKey
options.AuthToken = credential.ClientSecret; // ClientSecret -> AuthToken
- _logger.LogInformation("Salesforce mapping - ClientId: {ClientId}, ClientSecret: {HasSecret}, Username: {Username}",
- credential.ClientId, !string.IsNullOrEmpty(credential.ClientSecret), credential.Username);
+ _logger.LogInformation("Salesforce mapping - ClientId: '{ClientId}', ClientSecret: {HasSecret}, Username: '{Username}', Password: {HasPassword}",
+ credential.ClientId,
+ !string.IsNullOrEmpty(credential.ClientSecret),
+ credential.Username,
+ !string.IsNullOrEmpty(credential.Password));
break;
case RestServiceType.SapB1ServiceLayer:
// Per SAP B1 usiamo il CompanyDatabase come ApiKey
@@ -128,9 +155,15 @@ namespace Data_Coupler.Services
_ => throw new NotSupportedException($"Tipo di servizio REST non supportato: {credential.ServiceType}")
};
- // Salva il client nella cache
- _restClientCache[credentialName] = client;
- _logger.LogInformation("Client REST creato e cached per {CredentialName}", credentialName);
+ // Salva il client nella cache con l'hash delle credenziali
+ _restClientCache[credentialName] = new CachedRestClient
+ {
+ Client = client,
+ CredentialsHash = currentCredentialsHash,
+ CachedAt = DateTime.UtcNow
+ };
+
+ _logger.LogInformation("Client REST creato e cached con credenziali aggiornate per {CredentialName}", credentialName);
return client;
}
@@ -143,13 +176,13 @@ namespace Data_Coupler.Services
{
try
{
- // Utilizza lo stesso client REST cached (che è già autenticato)
+ // Crea un nuovo client REST con credenziali aggiornate
var restClient = await CreateRestServiceClientAsync(credentialName);
// I service client già implementano IRestMetadataDiscovery
if (restClient is IRestMetadataDiscovery metadataDiscovery)
{
- _logger.LogInformation("Utilizzando lo stesso client REST per metadata discovery per {CredentialName}", credentialName);
+ _logger.LogInformation("Utilizzando client REST per metadata discovery con credenziali aggiornate per {CredentialName}", credentialName);
return metadataDiscovery;
}
@@ -178,7 +211,17 @@ namespace Data_Coupler.Services
}
///
- /// Pulisce la cache del client REST per una credenziale specifica
+ /// Calcola un hash delle credenziali per rilevare cambiamenti
+ ///
+ private string CalculateCredentialsHash(RestApiCredential credential)
+ {
+ var credentialString = $"{credential.BaseUrl}|{credential.Username}|{credential.Password}|{credential.ApiKey}|{credential.AuthToken}|{credential.ClientId}|{credential.ClientSecret}|{credential.CompanyDatabase}";
+ var bytes = SHA256.HashData(Encoding.UTF8.GetBytes(credentialString));
+ return Convert.ToBase64String(bytes);
+ }
+
+ ///
+ /// Pulisce la cache del client REST per una credenziale specifica.
///
public void ClearRestClientCache(string credentialName)
{
@@ -189,7 +232,7 @@ namespace Data_Coupler.Services
}
///
- /// Pulisce tutta la cache dei client REST
+ /// Pulisce tutta la cache dei client REST.
///
public void ClearAllRestClientCache()
{