Skip to content

Commit 4ae27cd

Browse files
authored
implement password manager support for connection strings (#107)
1 parent 96c8a99 commit 4ae27cd

15 files changed

+80
-21
lines changed

.editorconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,8 @@ dotnet_diagnostic.MA0006.severity = none
249249
dotnet_diagnostic.MA0007.severity = none
250250
# MA0009: Add regex evaluation timeout
251251
dotnet_diagnostic.MA0009.severity = none
252+
# MA0023: Add RegexOptions.ExplicitCapture
253+
dotnet_diagnostic.MA0023.severity = none
252254
# MA0026: Fix TODO comment
253255
dotnet_diagnostic.MA0026.severity = none
254256
# MA0038: Make method static (deprecated, use CA1822 instead)

Source/Configuration/AppConfig.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public static ILinqToDBSettings LoadJson(string configPath)
2626
if (cn.Key.EndsWith("_ProviderName", StringComparison.InvariantCultureIgnoreCase))
2727
continue;
2828

29-
connections.Add(cn.Key, new ConnectionStringSettings(cn.Key, cn.Value));
29+
connections.Add(cn.Key, new ConnectionStringSettings(cn.Key, PasswordManager.ResolvePasswordManagerFields(cn.Value)));
3030
}
3131

3232
foreach (var cn in config.ConnectionStrings)
@@ -64,7 +64,7 @@ public static ILinqToDBSettings LoadAppConfig(string configPath)
6464
var providerName = node.Attributes["providerName" ]?.Value;
6565

6666
if (name != null && connectionString != null)
67-
settings.Add(new ConnectionStringSettings(name, connectionString) { ProviderName = providerName });
67+
settings.Add(new ConnectionStringSettings(name, PasswordManager.ResolvePasswordManagerFields(connectionString)) { ProviderName = providerName });
6868
}
6969

7070
return new AppConfig(settings.ToArray());
@@ -82,11 +82,13 @@ private sealed class JsonConfig
8282
public IDictionary<string, string>? ConnectionStrings { get; set; }
8383
}
8484

85+
/// <param name="name">Connection name.</param>
86+
/// <param name="connectionString">Must be connection string without password manager tokens.</param>
8587
private sealed class ConnectionStringSettings(string name, string connectionString) : IConnectionStringSettings
8688
{
8789
string IConnectionStringSettings.ConnectionString => connectionString;
88-
string IConnectionStringSettings.Name => name;
89-
bool IConnectionStringSettings.IsGlobal => false;
90+
string IConnectionStringSettings.Name => name;
91+
bool IConnectionStringSettings.IsGlobal => false;
9092

9193
public string? ProviderName { get; set; }
9294
}

Source/Configuration/ConnectionSettings.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,18 @@ public string? ProviderPath
387387
[JsonIgnore]
388388
public string? ConnectionString { get; set; }
389389

390+
/// <summary>
391+
/// Returns <see cref="ConnectionString"/> property value with resolved LINQPad password manager tokens.
392+
/// </summary>
393+
/// <returns></returns>
394+
public string? GetFullConnectionString () => PasswordManager.ResolvePasswordManagerFields(ConnectionString);
395+
396+
/// <summary>
397+
/// Returns <see cref="SecondaryConnectionString"/> property value with resolved LINQPad password manager tokens.
398+
/// </summary>
399+
/// <returns></returns>
400+
public string? GetFullSecondaryConnectionString() => PasswordManager.ResolvePasswordManagerFields(SecondaryConnectionString);
401+
390402
/// <summary>
391403
/// Stored in <see cref="IDatabaseInfo.Provider"/>.
392404
/// </summary>

Source/DatabaseProviders/AccessProvider.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ public override void ClearAllPools(string providerName)
4040
public override DateTime? GetLastSchemaUpdate(ConnectionSettings settings)
4141
{
4242
var connectionString = settings.Connection.Provider == ProviderName.Access
43-
? settings.Connection.ConnectionString
43+
? settings.Connection.GetFullConnectionString()
4444
: settings.Connection.SecondaryProvider == ProviderName.Access
45-
? settings.Connection.SecondaryConnectionString
45+
? settings.Connection.GetFullSecondaryConnectionString()
4646
: null;
4747

4848
if (connectionString == null || !RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
@@ -53,7 +53,7 @@ public override void ClearAllPools(string providerName)
5353
if (settings.Connection.Provider == ProviderName.Access)
5454
provider = DatabaseProviders.GetDataProvider(settings);
5555
else
56-
provider = DatabaseProviders.GetDataProvider(settings.Connection.SecondaryProvider, settings.Connection.SecondaryConnectionString, null);
56+
provider = DatabaseProviders.GetDataProvider(settings.Connection.SecondaryProvider, connectionString, null);
5757

5858
using var cn = (OleDbConnection)provider.CreateConnection(connectionString);
5959
cn.Open();
@@ -65,6 +65,8 @@ public override void ClearAllPools(string providerName)
6565

6666
public override ProviderInfo? GetProviderByConnectionString(string connectionString)
6767
{
68+
connectionString = PasswordManager.ResolvePasswordManagerFields(connectionString);
69+
6870
var isOleDb = connectionString.IndexOf("Microsoft.Jet.OLEDB", StringComparison.OrdinalIgnoreCase) != -1
6971
|| connectionString.IndexOf("Microsoft.ACE.OLEDB", StringComparison.OrdinalIgnoreCase) != -1;
7072

Source/DatabaseProviders/DatabaseProviderBase.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ public virtual void Unload (
3030
public abstract DateTime? GetLastSchemaUpdate(ConnectionSettings settings);
3131
public abstract DbProviderFactory GetProviderFactory (string providerName );
3232

33+
/// <param name="providerName">Provider name.</param>
34+
/// <param name="connectionString">Connection string must be resolved against password manager already.</param>
35+
/// <returns></returns>
3336
public virtual IDataProvider GetDataProvider(string providerName, string connectionString)
3437
{
3538
return DataConnection.GetDataProvider(providerName, connectionString)

Source/DatabaseProviders/DatabaseProviders.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,21 @@ public static void Init()
6464
// trigger .cctors
6565
}
6666

67-
public static DbConnection CreateConnection (ConnectionSettings settings) => GetDataProvider(settings).CreateConnection(settings.Connection.ConnectionString!);
67+
public static DbConnection CreateConnection(ConnectionSettings settings)
68+
{
69+
return GetDataProvider(settings).CreateConnection(settings.Connection.GetFullConnectionString()!);
70+
}
6871

6972
public static DbProviderFactory GetProviderFactory(ConnectionSettings settings) => GetProviderByName(settings.Connection.Provider!).GetProviderFactory(settings.Connection.Provider!);
7073

71-
public static IDataProvider GetDataProvider(ConnectionSettings settings) => GetDataProvider(settings.Connection.Provider, settings.Connection.ConnectionString, settings.Connection.ProviderPath);
74+
public static IDataProvider GetDataProvider(ConnectionSettings settings)
75+
{
76+
return GetDataProvider(settings.Connection.Provider, settings.Connection.GetFullConnectionString(), settings.Connection.ProviderPath);
77+
}
7278

79+
/// <param name="providerName">Provider name.</param>
80+
/// <param name="connectionString">Connection string must be already resolved against password manager.</param>
81+
/// <param name="providerPath">Optional path to provider assembly.</param>
7382
public static IDataProvider GetDataProvider(string? providerName, string? connectionString, string? providerPath)
7483
{
7584
if (string.IsNullOrWhiteSpace(providerName))

Source/DatabaseProviders/IDatabaseProvider.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ internal interface IDatabaseProvider
5353
/// <summary>
5454
/// Tries to infer provider by database connection string.
5555
/// </summary>
56+
/// <param name="connectionString">Connection string could contain password manager tokens.</param>
57+
/// <returns></returns>
5658
ProviderInfo? GetProviderByConnectionString(string connectionString);
5759

5860
/// <summary>
@@ -95,6 +97,8 @@ internal interface IDatabaseProvider
9597
/// <summary>
9698
/// Returns linq2db data provider.
9799
/// </summary>
100+
/// <param name="providerName">Provider name.</param>
101+
/// <param name="connectionString">Connection string must be already resolved against password manager.</param>
98102
IDataProvider GetDataProvider(string providerName, string connectionString);
99103

100104
#if NETFRAMEWORK

Source/DatabaseProviders/SqlServerProvider.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@ public override DbProviderFactory GetProviderFactory(string providerName)
9292
return SqlClientFactory.Instance;
9393
}
9494

95-
9695
public override IDataProvider GetDataProvider(string providerName, string connectionString)
9796
{
9897
// provider detector fails to detect Microsoft.Data.SqlClient

Source/Drivers/DriverHelper.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -266,17 +266,18 @@ public static bool ShowConnectionDialog(IConnectionInfo cxInfo, ConnectionDialog
266266
throw new LinqToDBLinqPadException($"Cannot access provider assembly at {model.DynamicConnection.ProviderPath}");
267267
}
268268

269-
var provider = DatabaseProviders.GetDataProvider(model.DynamicConnection.Provider.Name, model.DynamicConnection.ConnectionString, model.DynamicConnection.ProviderPath);
270-
271-
using (var con = provider.CreateConnection(model.DynamicConnection.ConnectionString))
269+
var connectionString = PasswordManager.ResolvePasswordManagerFields(model.DynamicConnection.ConnectionString);
270+
var provider = DatabaseProviders.GetDataProvider(model.DynamicConnection.Provider.Name, connectionString, model.DynamicConnection.ProviderPath);
271+
using (var con = provider.CreateConnection(connectionString))
272272
con.Open();
273273

274274
if (model.DynamicConnection.Database.SupportsSecondaryConnection
275275
&& model.DynamicConnection.SecondaryProvider != null
276276
&& model.DynamicConnection.SecondaryConnectionString != null)
277277
{
278-
var secondaryProvider = DatabaseProviders.GetDataProvider(model.DynamicConnection.SecondaryProvider.Name, model.DynamicConnection.SecondaryConnectionString, null);
279-
using var con = secondaryProvider.CreateConnection(model.DynamicConnection.SecondaryConnectionString);
278+
var secondaryConnectionString = PasswordManager.ResolvePasswordManagerFields(model.DynamicConnection.SecondaryConnectionString);
279+
var secondaryProvider = DatabaseProviders.GetDataProvider(model.DynamicConnection.SecondaryProvider.Name, secondaryConnectionString, null);
280+
using var con = secondaryProvider.CreateConnection(secondaryConnectionString);
280281
con.Open();
281282
}
282283

Source/Drivers/DynamicLinqToDBDriver.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ public override List<ExplorerItem> GetSchemaAndBuildAssembly(IConnectionInfo cxI
197197
[
198198
settings.Connection.Provider,
199199
settings.Connection.ProviderPath,
200-
settings.Connection.ConnectionString
200+
settings.Connection.GetFullConnectionString()
201201
];
202202
}
203203
catch (Exception ex)

0 commit comments

Comments
 (0)