From 1c32076fcf038ab4826bd63ba76bd2504d20e227 Mon Sep 17 00:00:00 2001 From: David Shulman Date: Sun, 31 Mar 2019 14:40:57 -0700 Subject: [PATCH] Fix SqlClient Kerberos on Linux This PR is a follow-up to PR #36329. In that previous PR, I changed to use the GSS_C_NT_HOSTBASED_SERVICE format for the SPN. That requires using a '@' separator character instead of a "/". I had assumed since System.Data.SqlClient was including the source files from Common for SafeDeleteNegoContext.cs that it would have the corresponding change to use the proper separator character. However, it appears that the file was only included to get the project building. It was using a separate file to calculate the SPN. The customer requiring these fixes reported that Kerberos was working properly now for HttpClient and NegotiateStream. But SqlClient was still broken. This PR completes the fix so that SqlClient will work properly with Kerberos especially in multiple domain/realm environments. This fix was manually tested in the enterprise scenario test lab. --- .../src/System.Data.SqlClient.csproj | 2 ++ .../System/Data/SqlClient/SNI/SNIProxy.Unix.cs | 16 ++++++++++++++++ .../Data/SqlClient/SNI/SNIProxy.Windows.cs | 16 ++++++++++++++++ .../src/System/Data/SqlClient/SNI/SNIProxy.cs | 4 ++-- 4 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIProxy.Unix.cs create mode 100644 src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIProxy.Windows.cs diff --git a/src/System.Data.SqlClient/src/System.Data.SqlClient.csproj b/src/System.Data.SqlClient/src/System.Data.SqlClient.csproj index 0058e7c0cacc..3228a3b32b5b 100644 --- a/src/System.Data.SqlClient/src/System.Data.SqlClient.csproj +++ b/src/System.Data.SqlClient/src/System.Data.SqlClient.csproj @@ -205,6 +205,8 @@ + + diff --git a/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIProxy.Unix.cs b/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIProxy.Unix.cs new file mode 100644 index 000000000000..b587dedee32a --- /dev/null +++ b/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIProxy.Unix.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Data.SqlClient.SNI +{ + /// + /// Managed SNI proxy implementation. Contains many SNI entry points used by SqlClient. + /// + internal partial class SNIProxy + { + // On Unix/Linux the format for the SPN is SERVICE@HOST. This is because the System.Net.Security.Native + // GSS-API layer uses GSS_C_NT_HOSTBASED_SERVICE format for the SPN. + private const string SpnServiceHostSeparator = "@"; + } +} diff --git a/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIProxy.Windows.cs b/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIProxy.Windows.cs new file mode 100644 index 000000000000..581056643151 --- /dev/null +++ b/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIProxy.Windows.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace System.Data.SqlClient.SNI +{ + /// + /// Managed SNI proxy implementation. Contains many SNI entry points used by SqlClient. + /// + internal partial class SNIProxy + { + // On Windows the format for the SPN is SERVICE/HOST. So the separator character between the + // SERVICE and HOST components is "/". + private const string SpnServiceHostSeparator = "/"; + } +} diff --git a/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIProxy.cs b/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIProxy.cs index 9c778972e49a..92b8ffeca4ea 100644 --- a/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIProxy.cs +++ b/src/System.Data.SqlClient/src/System/Data/SqlClient/SNI/SNIProxy.cs @@ -18,7 +18,7 @@ namespace System.Data.SqlClient.SNI /// /// Managed SNI proxy implementation. Contains many SNI entry points used by SqlClient. /// - internal class SNIProxy + internal partial class SNIProxy { private const int DefaultSqlServerPort = 1433; private const int DefaultSqlServerDacPort = 1434; @@ -342,7 +342,7 @@ private static byte[] GetSqlServerSPN(string hostNameOrAddress, string portOrIns // If the DNS lookup failed, then resort to using the user provided hostname to construct the SPN. fullyQualifiedDomainName = hostEntry?.HostName ?? hostNameOrAddress; } - string serverSpn = SqlServerSpnHeader + "/" + fullyQualifiedDomainName; + string serverSpn = SqlServerSpnHeader + SpnServiceHostSeparator + fullyQualifiedDomainName; if (!string.IsNullOrWhiteSpace(portOrInstanceName)) { serverSpn += ":" + portOrInstanceName;