namespace CredentialManager.Models; /// /// Tipi di credenziali supportate /// public enum CredentialType { Database, RestApi, OAuth, ApiKey, BasicAuth } /// /// Tipi di servizi REST specifici /// public enum RestServiceType { Generic, SapB1ServiceLayer, Salesforce } /// /// Tipo di flusso OAuth2 per Salesforce /// public enum SalesforceGrantType { /// /// Flusso Username/Password (grant_type=password). /// Richiede: ClientId, ClientSecret, Username, Password (+SecurityToken se non IP-trusted). /// URL di login: https://login.salesforce.com o https://test.salesforce.com. /// Password, /// /// Flusso Client Credentials (grant_type=client_credentials) — server-to-server, senza utente. /// Richiede: ClientId, ClientSecret. /// URL obbligatorio: My Domain URL (es. https://myorg.my.salesforce.com). /// La Connected App deve avere "Enable Client Credentials Flow" attivato e un Integration User assegnato. /// ClientCredentials } /// /// Tipi di database supportati (allineato con DataConnection.Enums.DatabaseType) /// public enum DatabaseType { SqlServer, MySql, PostgreSql, Oracle, Sqlite, DB2, SapHana, Odbc, OleDb } /// /// Modalità di connessione ODBC /// public enum OdbcConnectionMode { /// /// Utilizzo di un DSN (Data Source Name) configurato /// Dsn, /// /// Costruzione manuale della connection string /// Custom } /// /// DTO per le credenziali database - completo per tutti i tipi di DB supportati /// public class DatabaseCredential { public string Name { get; set; } = string.Empty; public DatabaseType DatabaseType { get; set; } public string Host { get; set; } = string.Empty; public int Port { get; set; } public string? DatabaseName { get; set; } = string.Empty; // Ora opzionale public string Username { get; set; } = string.Empty; public string Password { get; set; } = string.Empty; public string? ConnectionString { get; set; } public int CommandTimeout { get; set; } = 30; public bool IgnoreSslErrors { get; set; } = false; public Dictionary? AdditionalParameters { get; set; } // ODBC specific properties public string? OdbcDsnName { get; set; } // Nome del DSN ODBC (se utilizzato) public OdbcConnectionMode OdbcMode { get; set; } = OdbcConnectionMode.Dsn; // Modalità ODBC (DSN o Custom) } /// /// DTO per le credenziali REST API - allineato con RestServiceOptions e esteso per servizi specifici /// public class RestApiCredential { public string Name { get; set; } = string.Empty; public RestServiceType ServiceType { get; set; } = RestServiceType.Generic; public string BaseUrl { get; set; } = string.Empty; public string? ApiKey { get; set; } public string? Username { get; set; } public string? Password { get; set; } public string? AuthToken { get; set; } public string? BearerToken { get; set; } public int TimeoutSeconds { get; set; } = 100; public bool IgnoreSslErrors { get; set; } = false; public Dictionary? Headers { get; set; } public Dictionary? AdditionalParameters { get; set; } // Campi specifici per SAP B1 Service Layer public string? CompanyDatabase { get; set; } public string? Language { get; set; } = "en-US"; public string? Version { get; set; } = "v1"; public bool UseTrustedConnection { get; set; } = false; // Campi specifici per Salesforce public string? SecurityToken { get; set; } public string? ClientId { get; set; } public string? ClientSecret { get; set; } public string? ApiVersion { get; set; } = "59.0"; public bool IsSandbox { get; set; } = false; public bool UseSoapApi { get; set; } = false; public SalesforceGrantType GrantType { get; set; } = SalesforceGrantType.Password; public string? RefreshToken { get; set; } public string? AccessToken { get; set; } public DateTime? TokenExpiry { get; set; } } /// /// Credenziali specifiche per SAP Business One Service Layer /// public class SapB1ServiceLayerCredential { public string Name { get; set; } = string.Empty; public string ServerUrl { get; set; } = string.Empty; // es: https://server:50000/b1s/v1/ public string CompanyDatabase { get; set; } = string.Empty; // Database dell'azienda SAP public string Username { get; set; } = string.Empty; public string Password { get; set; } = string.Empty; public string? Language { get; set; } = "en-US"; // Lingua per la sessione public int TimeoutSeconds { get; set; } = 300; // Timeout per le chiamate API public bool IgnoreSslErrors { get; set; } = false; public string? Version { get; set; } = "v1"; // Versione del Service Layer (v1, v2, etc.) public bool UseTrustedConnection { get; set; } = false; // Per autenticazione Windows public Dictionary? AdditionalHeaders { get; set; } } /// /// Credenziali specifiche per Salesforce /// public class SalesforceCredential { public string Name { get; set; } = string.Empty; public string LoginUrl { get; set; } = "https://login.salesforce.com"; // o https://test.salesforce.com per sandbox public string Username { get; set; } = string.Empty; public string Password { get; set; } = string.Empty; public string SecurityToken { get; set; } = string.Empty; // Token di sicurezza Salesforce public string? ClientId { get; set; } = string.Empty; // Consumer Key per Connected App public string? ClientSecret { get; set; } = string.Empty; // Consumer Secret per Connected App public string ApiVersion { get; set; } = "59.0"; // Versione API Salesforce public bool IsSandbox { get; set; } = false; // Se è un ambiente sandbox public int TimeoutSeconds { get; set; } = 120; public bool UseSoapApi { get; set; } = false; // Se usare SOAP invece di REST /// Tipo di flusso OAuth2 da utilizzare. Default: Password (retrocompatibile). public SalesforceGrantType GrantType { get; set; } = SalesforceGrantType.Password; public string? RefreshToken { get; set; } public string? AccessToken { get; set; } public DateTime? TokenExpiry { get; set; } } /// /// Factory per creare connection string per i diversi tipi di database /// public static class ConnectionStringBuilder { public static string BuildConnectionString(DatabaseCredential credential) { if (!string.IsNullOrEmpty(credential.ConnectionString)) return credential.ConnectionString; return credential.DatabaseType switch { DatabaseType.SqlServer => BuildSqlServerConnectionString(credential), DatabaseType.MySql => BuildMySqlConnectionString(credential), DatabaseType.PostgreSql => BuildPostgreSqlConnectionString(credential), DatabaseType.Oracle => BuildOracleConnectionString(credential), DatabaseType.Sqlite => BuildSqliteConnectionString(credential), DatabaseType.DB2 => BuildDb2ConnectionString(credential), DatabaseType.SapHana => BuildSapHanaConnectionString(credential), DatabaseType.Odbc => BuildOdbcConnectionString(credential), DatabaseType.OleDb => BuildOleDbConnectionString(credential), _ => throw new NotSupportedException($"Database type {credential.DatabaseType} not supported") }; } private static string BuildSqlServerConnectionString(DatabaseCredential credential) { var builder = new List(); // Gestione speciale per SQL Server locale e named instances // Se l'host contiene '\' (instance name) o '(localdb)', non aggiungere la porta bool hasInstanceName = credential.Host.Contains('\\') || credential.Host.StartsWith("(localdb)", StringComparison.OrdinalIgnoreCase); if (hasInstanceName) { // Per named instances e LocalDB, non includere la porta builder.Add($"Server={credential.Host}"); } else { // Per connessioni TCP/IP standard, include host e porta // Ma solo se la porta non è la default (1433) per localhost if ((credential.Host.Equals("localhost", StringComparison.OrdinalIgnoreCase) || credential.Host == "." || credential.Host == "127.0.0.1") && credential.Port == 1433) { // Per localhost con porta default, ometti la porta per usare Named Pipes builder.Add($"Server={credential.Host}"); } else { // Per altri casi, usa host,porta builder.Add($"Server={credential.Host},{credential.Port}"); } } // Se username è vuoto o è "Integrated", usa Windows Authentication if (string.IsNullOrWhiteSpace(credential.Username) || credential.Username.Equals("Integrated", StringComparison.OrdinalIgnoreCase) || credential.Username.Equals("Windows", StringComparison.OrdinalIgnoreCase)) { builder.Add("Integrated Security=True"); } else { // Usa SQL Server Authentication builder.Add($"User Id={credential.Username}"); builder.Add($"Password={credential.Password}"); } builder.Add($"Connection Timeout={credential.CommandTimeout}"); // Aggiungi Database solo se specificato if (!string.IsNullOrEmpty(credential.DatabaseName)) builder.Add($"Database={credential.DatabaseName}"); if (credential.IgnoreSslErrors) builder.Add("TrustServerCertificate=True"); AddAdditionalParameters(builder, credential.AdditionalParameters); return string.Join(";", builder); } private static string BuildMySqlConnectionString(DatabaseCredential credential) { var builder = new List { $"Server={credential.Host}", $"Port={credential.Port}", $"Uid={credential.Username}", $"Pwd={credential.Password}", $"Connection Timeout={credential.CommandTimeout}" }; // Aggiungi Database solo se specificato if (!string.IsNullOrEmpty(credential.DatabaseName)) builder.Add($"Database={credential.DatabaseName}"); if (credential.IgnoreSslErrors) builder.Add("SslMode=None"); AddAdditionalParameters(builder, credential.AdditionalParameters); return string.Join(";", builder); } private static string BuildPostgreSqlConnectionString(DatabaseCredential credential) { var builder = new List { $"Host={credential.Host}", $"Port={credential.Port}", $"Username={credential.Username}", $"Password={credential.Password}", $"Timeout={credential.CommandTimeout}" }; // Aggiungi Database solo se specificato if (!string.IsNullOrEmpty(credential.DatabaseName)) builder.Add($"Database={credential.DatabaseName}"); if (credential.IgnoreSslErrors) builder.Add("SSL Mode=Disable"); AddAdditionalParameters(builder, credential.AdditionalParameters); return string.Join(";", builder); } private static string BuildOracleConnectionString(DatabaseCredential credential) { var builder = new List(); // Per Oracle, il formato cambia se c'è o meno un database specificato if (!string.IsNullOrEmpty(credential.DatabaseName)) { builder.Add($"Data Source={credential.Host}:{credential.Port}/{credential.DatabaseName}"); } else { builder.Add($"Data Source={credential.Host}:{credential.Port}"); } builder.AddRange(new[] { $"User Id={credential.Username}", $"Password={credential.Password}", $"Connection Timeout={credential.CommandTimeout}" }); AddAdditionalParameters(builder, credential.AdditionalParameters); return string.Join(";", builder); } private static string BuildSqliteConnectionString(DatabaseCredential credential) { var builder = new List { $"Data Source={credential.DatabaseName}" }; AddAdditionalParameters(builder, credential.AdditionalParameters); return string.Join(";", builder); } private static string BuildDb2ConnectionString(DatabaseCredential credential) { var builder = new List { $"Server={credential.Host}:{credential.Port}", $"Database={credential.DatabaseName}", $"UID={credential.Username}", $"PWD={credential.Password}", $"Connection Timeout={credential.CommandTimeout}" }; AddAdditionalParameters(builder, credential.AdditionalParameters); return string.Join(";", builder); } private static string BuildSapHanaConnectionString(DatabaseCredential credential) { var builder = new List { $"Server={credential.Host}:{credential.Port}", $"DatabaseName={credential.DatabaseName}", $"UserID={credential.Username}", $"Password={credential.Password}", $"Connection Timeout={credential.CommandTimeout}" }; AddAdditionalParameters(builder, credential.AdditionalParameters); return string.Join(";", builder); } private static string BuildOdbcConnectionString(DatabaseCredential credential) { // Se è già presente una connection string personalizzata, utilizzala if (!string.IsNullOrEmpty(credential.ConnectionString)) return credential.ConnectionString; var builder = new List(); // Modalità DSN: usa il DSN configurato if (credential.OdbcMode == OdbcConnectionMode.Dsn && !string.IsNullOrEmpty(credential.OdbcDsnName)) { builder.Add($"DSN={credential.OdbcDsnName}"); // Aggiungi credenziali se fornite if (!string.IsNullOrEmpty(credential.Username)) builder.Add($"UID={credential.Username}"); if (!string.IsNullOrEmpty(credential.Password)) builder.Add($"PWD={credential.Password}"); } // Modalità Custom: costruisci manualmente la connection string else { // Driver (se specificato nei parametri aggiuntivi) if (credential.AdditionalParameters?.ContainsKey("Driver") == true) { builder.Add($"Driver={{{credential.AdditionalParameters["Driver"]}}}"); } // Server/Host if (!string.IsNullOrEmpty(credential.Host)) { builder.Add($"Server={credential.Host}"); // Porta (se diversa da 0) if (credential.Port > 0) builder.Add($"Port={credential.Port}"); } // Database if (!string.IsNullOrEmpty(credential.DatabaseName)) builder.Add($"Database={credential.DatabaseName}"); // Credenziali if (!string.IsNullOrEmpty(credential.Username)) builder.Add($"UID={credential.Username}"); if (!string.IsNullOrEmpty(credential.Password)) builder.Add($"PWD={credential.Password}"); } // Timeout if (credential.CommandTimeout > 0) builder.Add($"Connection Timeout={credential.CommandTimeout}"); // Parametri aggiuntivi (escludendo Driver se già aggiunto) if (credential.AdditionalParameters != null) { foreach (var param in credential.AdditionalParameters) { if (param.Key != "Driver") // Driver già gestito sopra builder.Add($"{param.Key}={param.Value}"); } } return string.Join(";", builder); } private static string BuildOleDbConnectionString(DatabaseCredential credential) { // Se è già presente una connection string personalizzata, utilizzala if (!string.IsNullOrEmpty(credential.ConnectionString)) return credential.ConnectionString; var builder = new List(); // Provider OLE DB (obbligatorio) var provider = credential.AdditionalParameters?.GetValueOrDefault("Provider") ?? "VFPOLEDB.1"; builder.Add($"Provider={provider}"); // Data Source: per VFP e Access è il percorso file/cartella // DatabaseName è il campo principale (come per SQLite) var dataSource = !string.IsNullOrEmpty(credential.DatabaseName) ? credential.DatabaseName : credential.Host; if (!string.IsNullOrEmpty(dataSource)) builder.Add($"Data Source={dataSource}"); // Credenziali (opzionali per VFP file-based) if (!string.IsNullOrEmpty(credential.Username)) builder.Add($"User ID={credential.Username}"); if (!string.IsNullOrEmpty(credential.Password)) builder.Add($"Password={credential.Password}"); // Parametri aggiuntivi specifici (es. Collating Sequence, Exclusive, DELETED per VFP) if (credential.AdditionalParameters != null) { foreach (var param in credential.AdditionalParameters) { if (param.Key != "Provider") // Provider già gestito sopra builder.Add($"{param.Key}={param.Value}"); } } return string.Join(";", builder); } private static void AddAdditionalParameters(List builder, Dictionary? additionalParams) { if (additionalParams != null) { foreach (var param in additionalParams) { builder.Add($"{param.Key}={param.Value}"); } } } }