Skip to content

Commit 521a111

Browse files
committed
* Added AzureManagedServiceAuthenticator real implementation which is used on supported target platforms (net472, netcoreapp2.2) to perform Azure managed identities token gathering.
* Added AzureManagedServiceAuthenticator stub implementation which does nothing for target frameworks not supporting this * Added unit tests * Use AzureManagedServiceAuthenticator in SqlConnectionFactory to set token on connection * Initialization in the sink and audit siink classes still set the azure msi auth to disabled. It will be activated according to passed parameters in the next commits.
1 parent d474e71 commit 521a111

File tree

12 files changed

+244
-15
lines changed

12 files changed

+244
-15
lines changed

src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/Microsoft.Extensions.Configuration/MicrosoftExtensionsConnectionStringProvider.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using Microsoft.Extensions.Configuration;
1+
using System;
2+
using Microsoft.Extensions.Configuration;
23
using Serilog.Debugging;
34

45
namespace Serilog.Sinks.MSSqlServer.Configuration
@@ -9,8 +10,8 @@ public string GetConnectionString(string nameOrConnectionString, IConfiguration
910
{
1011
// If there is an `=`, we assume this is a raw connection string not a named value
1112
// If there are no `=`, attempt to pull the named value from config
12-
if (nameOrConnectionString.IndexOf('=') > -1) return nameOrConnectionString;
13-
string cs = appConfiguration?.GetConnectionString(nameOrConnectionString);
13+
if (nameOrConnectionString.IndexOf("=", StringComparison.InvariantCultureIgnoreCase) > -1) return nameOrConnectionString;
14+
var cs = appConfiguration?.GetConnectionString(nameOrConnectionString);
1415
if (string.IsNullOrEmpty(cs))
1516
{
1617
SelfLog.WriteLine("MSSqlServer sink configured value {0} is not found in ConnectionStrings settings and does not appear to be a raw connection string.",

src/Serilog.Sinks.MSSqlServer/Configuration/Implementations/System.Configuration/SystemConfigurationConnectionStringProvider.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Configuration;
1+
using System;
2+
using System.Configuration;
23
using Serilog.Debugging;
34

45
namespace Serilog.Sinks.MSSqlServer.Configuration
@@ -9,7 +10,7 @@ public string GetConnectionString(string nameOrConnectionString)
910
{
1011
// If there is an `=`, we assume this is a raw connection string not a named value
1112
// If there are no `=`, attempt to pull the named value from config
12-
if (nameOrConnectionString.IndexOf('=') < 0)
13+
if (nameOrConnectionString.IndexOf("=", StringComparison.InvariantCultureIgnoreCase) < 0)
1314
{
1415
var cs = ConfigurationManager.ConnectionStrings[nameOrConnectionString];
1516
if (cs != null)

src/Serilog.Sinks.MSSqlServer/Serilog.Sinks.MSSqlServer.csproj

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<Description>A Serilog sink that writes events to Microsoft SQL Server</Description>
55
<VersionPrefix>5.3.0</VersionPrefix>
66
<Authors>Michiel van Oudheusden;Serilog Contributors</Authors>
7-
<TargetFrameworks>netstandard2.0;net452;netcoreapp2.0;net461</TargetFrameworks>
7+
<TargetFrameworks>netstandard2.0;net452;net461;net472;netcoreapp2.0;netcoreapp2.2</TargetFrameworks>
88
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
99
<GenerateDocumentationFile>true</GenerateDocumentationFile>
1010
<AssemblyName>Serilog.Sinks.MSSqlServer</AssemblyName>
@@ -41,12 +41,16 @@
4141
<Compile Remove="Configuration\Extensions\System.Configuration\**\*.*" />
4242
<Compile Remove="Configuration\Implementations\Microsoft.Extensions.Configuration\**\*.*" />
4343
<Compile Remove="Configuration\Implementations\System.Configuration\**\*.*" />
44+
<Compile Remove="Sinks\MSSqlServer\Platform\AzureManagedServiceAuthenticator.cs" />
45+
<Compile Remove="Sinks\MSSqlServer\Platform\AzureManagedServiceAuthenticator.Stub.cs" />
4446
<!-- Show in VStudio, but MSBuild ignores these (indicates files are not code, non-published-content, etc.) -->
4547
<None Include="Configuration\Extensions\Hybrid\**\*.*" />
4648
<None Include="Configuration\Extensions\Microsoft.Extensions.Configuration\**\*.*" />
4749
<None Include="Configuration\Extensions\System.Configuration\**\*.*" />
4850
<None Include="Configuration\Implementations\Microsoft.Extensions.Configuration\**\*.*" />
4951
<None Include="Configuration\Implementations\System.Configuration\**\*.*" />
52+
<None Include="Sinks\MSSqlServer\Platform\AzureManagedServiceAuthenticator.cs" />
53+
<None Include="Sinks\MSSqlServer\Platform\AzureManagedServiceAuthenticator.Stub.cs" />
5054
<!-- ItemGroups below with TFM conditions will re-include the compile targets -->
5155
</ItemGroup>
5256

@@ -56,6 +60,7 @@
5660
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.0.0" />
5761
<Compile Include="Configuration\Extensions\Microsoft.Extensions.Configuration\**\*.cs" />
5862
<Compile Include="Configuration\Implementations\Microsoft.Extensions.Configuration\**\*.cs" />
63+
<Compile Include="Sinks\MSSqlServer\Platform\AzureManagedServiceAuthenticator.Stub.cs" />
5964
</ItemGroup>
6065

6166
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.0' Or '$(TargetFramework)' == 'net461' ">
@@ -66,6 +71,19 @@
6671
<Compile Include="Configuration\Extensions\Hybrid\**\*.cs" />
6772
<Compile Include="Configuration\Implementations\Microsoft.Extensions.Configuration\**\*.cs" />
6873
<Compile Include="Configuration\Implementations\System.Configuration\**\*.cs" />
74+
<Compile Include="Sinks\MSSqlServer\Platform\AzureManagedServiceAuthenticator.Stub.cs" />
75+
</ItemGroup>
76+
77+
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.2' Or '$(TargetFramework)' == 'net472' ">
78+
<PackageReference Include="System.Configuration.ConfigurationManager" Version="4.5.0" />
79+
<PackageReference Include="System.Data.SqlClient" Version="4.6.0" />
80+
<PackageReference Include="Microsoft.Azure.Services.AppAuthentication" Version="1.4.0" />
81+
<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.0.0" />
82+
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.0.0" />
83+
<Compile Include="Configuration\Extensions\Hybrid\**\*.cs" />
84+
<Compile Include="Configuration\Implementations\Microsoft.Extensions.Configuration\**\*.cs" />
85+
<Compile Include="Configuration\Implementations\System.Configuration\**\*.cs" />
86+
<Compile Include="Sinks\MSSqlServer\Platform\AzureManagedServiceAuthenticator.cs" />
6987
</ItemGroup>
7088

7189
<ItemGroup Condition=" '$(TargetFramework)' == 'net452' ">
@@ -77,6 +95,7 @@
7795
<Reference Include="Microsoft.CSharp" />
7896
<Compile Include="Configuration\Extensions\System.Configuration\**\*.cs" />
7997
<Compile Include="Configuration\Implementations\System.Configuration\**\*.cs" />
98+
<Compile Include="Sinks\MSSqlServer\Platform\AzureManagedServiceAuthenticator.Stub.cs" />
8099
</ItemGroup>
81100

82101
<ItemGroup>

src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/MSSqlServerAuditSink.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,10 @@ public MSSqlServerAuditSink(
6060
throw new NotSupportedException($"The {nameof(ColumnOptions.DisableTriggers)} option is not supported for auditing.");
6161
}
6262

63-
_sqlConnectionFactory = new SqlConnectionFactory(connectionString);
63+
// TODO initialize authenticator from parameters
64+
var azureManagedServiceAuthenticator = new AzureManagedServiceAuthenticator(false, null);
65+
66+
_sqlConnectionFactory = new SqlConnectionFactory(connectionString, azureManagedServiceAuthenticator);
6467
_traits = new MSSqlServerSinkTraits(_sqlConnectionFactory, tableName, schemaName, columnOptions, formatProvider, autoCreateSqlTable, logEventFormatter);
6568
}
6669

src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/MSSqlServerSink.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,10 @@ public MSSqlServerSink(
7272
{
7373
columnOptions?.FinalizeConfigurationForSinkConstructor();
7474

75-
_sqlConnectionFactory = new SqlConnectionFactory(connectionString);
75+
// TODO initialize authenticator from parameters
76+
var azureManagedServiceAuthenticator = new AzureManagedServiceAuthenticator(false, null);
77+
78+
_sqlConnectionFactory = new SqlConnectionFactory(connectionString, azureManagedServiceAuthenticator);
7679
_traits = new MSSqlServerSinkTraits(_sqlConnectionFactory, tableName, schemaName, columnOptions, formatProvider, autoCreateSqlTable, logEventFormatter);
7780
}
7881

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System.Data.SqlClient;
2+
3+
// This is an empty implementaion of IAzureManagedServiceAuthenticator for the target
4+
// frameworks that don't support azure managed identities (net452, net461, netstandard2.0, netcoreapp2.0).
5+
namespace Serilog.Sinks.MSSqlServer.Sinks.MSSqlServer.Platform
6+
{
7+
internal class AzureManagedServiceAuthenticator : IAzureManagedServiceAuthenticator
8+
{
9+
private readonly bool _useAzureManagedIdentity;
10+
private readonly string _azureServiceTokenProviderResource;
11+
12+
public AzureManagedServiceAuthenticator(bool useAzureManagedIdentity, string azureServiceTokenProviderResource)
13+
{
14+
_useAzureManagedIdentity = useAzureManagedIdentity;
15+
_azureServiceTokenProviderResource = azureServiceTokenProviderResource;
16+
}
17+
18+
public void SetAuthenticationToken(SqlConnection sqlConnection)
19+
{
20+
}
21+
}
22+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using System;
2+
using System.Data.SqlClient;
3+
using Microsoft.Azure.Services.AppAuthentication;
4+
5+
namespace Serilog.Sinks.MSSqlServer.Sinks.MSSqlServer.Platform
6+
{
7+
internal class AzureManagedServiceAuthenticator : IAzureManagedServiceAuthenticator
8+
{
9+
private readonly bool _useAzureManagedIdentity;
10+
private readonly string _azureServiceTokenProviderResource;
11+
private readonly AzureServiceTokenProvider _azureServiceTokenProvider;
12+
13+
public AzureManagedServiceAuthenticator(bool useAzureManagedIdentity, string azureServiceTokenProviderResource)
14+
{
15+
if (useAzureManagedIdentity && string.IsNullOrWhiteSpace(azureServiceTokenProviderResource))
16+
{
17+
throw new ArgumentNullException(nameof(azureServiceTokenProviderResource));
18+
}
19+
20+
_useAzureManagedIdentity = useAzureManagedIdentity;
21+
_azureServiceTokenProviderResource = azureServiceTokenProviderResource;
22+
_azureServiceTokenProvider = new AzureServiceTokenProvider();
23+
}
24+
25+
public void SetAuthenticationToken(SqlConnection sqlConnection)
26+
{
27+
if (!_useAzureManagedIdentity)
28+
{
29+
return;
30+
}
31+
32+
// TODO make the whole call hierarchy async
33+
sqlConnection.AccessToken = _azureServiceTokenProvider.GetAccessTokenAsync(
34+
_azureServiceTokenProviderResource).GetAwaiter().GetResult();
35+
}
36+
}
37+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using System.Data.SqlClient;
2+
3+
namespace Serilog.Sinks.MSSqlServer.Sinks.MSSqlServer.Platform
4+
{
5+
internal interface IAzureManagedServiceAuthenticator
6+
{
7+
void SetAuthenticationToken(SqlConnection sqlConnection);
8+
}
9+
}

src/Serilog.Sinks.MSSqlServer/Sinks/MSSqlServer/Platform/SqlConnectionFactory.cs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,31 @@ namespace Serilog.Sinks.MSSqlServer.Sinks.MSSqlServer.Platform
66
internal class SqlConnectionFactory : ISqlConnectionFactory
77
{
88
private readonly string _connectionString;
9+
private readonly IAzureManagedServiceAuthenticator _azureManagedServiceAuthenticator;
910

10-
public SqlConnectionFactory(string connectionString)
11+
public SqlConnectionFactory(string connectionString, IAzureManagedServiceAuthenticator azureManagedServiceAuthenticator)
1112
{
1213
if (string.IsNullOrWhiteSpace(connectionString))
1314
{
1415
throw new ArgumentNullException(nameof(connectionString));
1516
}
1617

18+
if (azureManagedServiceAuthenticator == null)
19+
{
20+
throw new ArgumentNullException(nameof(azureManagedServiceAuthenticator));
21+
}
22+
1723
_connectionString = connectionString;
24+
_azureManagedServiceAuthenticator = azureManagedServiceAuthenticator;
1825
}
1926

20-
public SqlConnection Create() => new SqlConnection(_connectionString);
27+
public SqlConnection Create()
28+
{
29+
var sqlConnection = new SqlConnection(_connectionString);
30+
31+
_azureManagedServiceAuthenticator.SetAuthenticationToken(sqlConnection);
32+
33+
return sqlConnection;
34+
}
2135
}
2236
}

test/Serilog.Sinks.MSSqlServer.Tests/Serilog.Sinks.MSSqlServer.Tests.csproj

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
-->
1414

1515
<PropertyGroup>
16-
<TargetFrameworks>netcoreapp2.0;net452</TargetFrameworks>
16+
<TargetFrameworks>net452;netcoreapp2.0;netcoreapp2.2</TargetFrameworks>
1717
<TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">netstandard2.0</TargetFrameworks>
1818
<AssemblyName>Serilog.Sinks.MSSqlServer.Tests</AssemblyName>
1919
<AssemblyOriginatorKeyFile>../../assets/Serilog.snk</AssemblyOriginatorKeyFile>
@@ -41,8 +41,10 @@
4141
<ItemGroup>
4242
<!-- Ensure MSBuild ignores all build-target-specific files by default -->
4343
<Compile Remove="Configuration\**\*.*" />
44+
<Compile Remove="Sinks\MSSqlServer\Platform\AzureManagedServiceAuthenticatorTests.cs" />
4445
<!-- Show in VStudio, but MSBuild ignores these (indicates files are not code, non-published-content, etc.) -->
4546
<None Include="Configuration\**\*.*" />
47+
<None Include="Sinks\MSSqlServer\Platform\AzureManagedServiceAuthenticatorTests.cs" />
4648
<!-- ItemGroups below with TFM conditions will re-include the compile targets -->
4749
</ItemGroup>
4850

@@ -55,6 +57,17 @@
5557
<Compile Include="Configuration\Implementations\System.Configuration\**\*.cs" />
5658
</ItemGroup>
5759

60+
<!--<ItemGroup Condition=" '$(TargetFramework)' == 'net472' ">
61+
<Reference Include="System" />
62+
<Reference Include="Microsoft.CSharp" />
63+
<PackageReference Include="xunit" Version="2.4.1" />
64+
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
65+
<Compile Remove="**\*.*" />
66+
<Compile Include="GlobalSuppressions.cs" />
67+
<Compile Include="TestUtils\**\*.cs" />
68+
<Compile Include="Sinks\MSSqlServer\Platform\AzureManagedServiceAuthenticatorTests.cs" />
69+
</ItemGroup>-->
70+
5871
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.0' ">
5972
<PackageReference Include="System.Collections" Version="4.3.0" />
6073
<PackageReference Include="System.Runtime.InteropServices" Version="4.3.0" />
@@ -73,6 +86,25 @@
7386
<Compile Include="Configuration\Implementations\System.Configuration\**\*.cs" />
7487
</ItemGroup>
7588

89+
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.2' ">
90+
<PackageReference Include="System.Collections" Version="4.3.0" />
91+
<PackageReference Include="System.Runtime.InteropServices" Version="4.3.0" />
92+
<PackageReference Include="System.Runtime.Extensions" Version="4.3.1" />
93+
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
94+
<PackageReference Include="System.Resources.ResourceManager" Version="4.3.0" />
95+
<PackageReference Include="System.Text.Encoding.Extensions" Version="4.3.0" />
96+
<PackageReference Include="xunit" Version="2.4.1" />
97+
<PackageReference Include="xunit.core" Version="2.4.1" />
98+
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
99+
<PrivateAssets>all</PrivateAssets>
100+
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
101+
</PackageReference>
102+
<Compile Remove="**\*.*" />
103+
<Compile Include="GlobalSuppressions.cs" />
104+
<Compile Include="TestUtils\**\*.cs" />
105+
<Compile Include="Sinks\MSSqlServer\Platform\AzureManagedServiceAuthenticatorTests.cs" />
106+
</ItemGroup>
107+
76108
<ItemGroup>
77109
<None Update="App.config">
78110
<CopyToOutputDirectory>Always</CopyToOutputDirectory>

0 commit comments

Comments
 (0)