Skip to content

Specifying Domain Account in ServerSPN Causes Connection Failure on Linux #3165

Open
@AbbasLB

Description

@AbbasLB

When attempting to set the ServerSPN attribute in a connection string to specify the account under which a SQL Server instance is running (Username@Domain), as described in the SQL Server Native Client documentation, the connection succeeds on Windows but fails on Linux with the following exception:

Exception thrown: 'Microsoft.Data.SqlClient.SqlException' in Microsoft.Data.SqlClient.dll
Connection failed: The target principal name is incorrect.  Cannot generate SSPI context.
GenericFailure
   at Microsoft.Data.SqlClient.SNI.TdsParserStateObjectManaged.GenerateSspiClientContext(Byte[] receivedBuff, UInt32 receivedLength, Byte[]& sendBuff, UInt32& sendLength, Byte[][] _sniSpnBuffer)
   at Microsoft.Data.SqlClient.TdsParser.SSPIData(Byte[] receivedBuff, UInt32 receivedLength, Byte[]& sendBuff, UInt32& sendLength)
 at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, SqlCommand command, Boolean callerHasConnectionLock, Boolean asyncClose)
   at Microsoft.Data.SqlClient.TdsParser.SSPIError(String error, String procedure)
   at Microsoft.Data.SqlClient.TdsParser.SSPIData(Byte[] receivedBuff, UInt32 receivedLength, Byte[]& sendBuff, UInt32& sendLength)
   at Microsoft.Data.SqlClient.TdsParser.TdsLogin(SqlLogin rec, FeatureExtension requestedFeatures, SessionData recoverySessionData, FederatedAuthenticationFeatureExtensionData fedAuthFeatureExtensionData, SqlConnectionEncryptOption encrypt)
   at Microsoft.Data.SqlClient.SqlInternalConnectionTds.Login(ServerInfo server, TimeoutTimer timeout, String newPassword, SecureString newSecurePassword, SqlConnectionEncryptOption encrypt)
   at Microsoft.Data.SqlClient.SqlInternalConnectionTds.AttemptOneLogin(ServerInfo serverInfo, String newPassword, SecureString newSecurePassword, TimeoutTimer timeout, Boolean withFailover)
   at Microsoft.Data.SqlClient.SqlInternalConnectionTds.LoginNoFailover(ServerInfo serverInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString connectionOptions, SqlCredential credential, TimeoutTimer timeout)
   at Microsoft.Data.SqlClient.SqlInternalConnectionTds.OpenLoginEnlist(TimeoutTimer timeout, SqlConnectionString connectionOptions, SqlCredential credential, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance)
   at Microsoft.Data.SqlClient.SqlInternalConnectionTds..ctor(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, SqlCredential credential, Object providerInfo, String newPassword, SecureString newSecurePassword, Boolean redirectedUserInstance, SqlConnectionString userConnectionOptions, SessionData reconnectSessionData, Boolean applyTransientFaultHandling, String accessToken, DbConnectionPool pool, Func`3 accessTokenCallback)
   at Microsoft.Data.SqlClient.SqlConnectionFactory.CreateConnection(DbConnectionOptions options, DbConnectionPoolKey poolKey, Object poolGroupProviderInfo, DbConnectionPool pool, DbConnection owningConnection, DbConnectionOptions userOptions)
   at Microsoft.Data.ProviderBase.DbConnectionFactory.CreatePooledConnection(DbConnectionPool pool, DbConnection owningObject, DbConnectionOptions options, DbConnectionPoolKey poolKey, DbConnectionOptions userOptions)
   at Microsoft.Data.ProviderBase.DbConnectionPool.CreateObject(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
   at Microsoft.Data.ProviderBase.DbConnectionPool.UserCreateRequest(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection)
   at Microsoft.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
   at Microsoft.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection)
   at Microsoft.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection)
   at Microsoft.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
   at Microsoft.Data.ProviderBase.DbConnectionClosed.TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
   at Microsoft.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry, SqlConnectionOverrides overrides)
   at Microsoft.Data.SqlClient.SqlConnection.Open(SqlConnectionOverrides overrides)
   at Microsoft.Data.SqlClient.SqlConnection.Open()
   at TestCSharpConnection.Program.Main() in ....

To reproduce

  1. Configure a SQL Server instance to run under a specific domain account.
  2. On a Linux client, setup Kerberos authentication, and set up a connection string that includes the ServerSPN attribute, specifying the account in the format Username@Domain (example: svc-myuser@REALM).
  3. Attempt to establish a connection to the SQL Server instance using this connection string.

The following code snippet works on Windows but doesn't work on Linux without any single change.

using Microsoft.Data.SqlClient;

namespace TestCSharpConnection
{
    internal class Program
    {
        static void Main()
        {
            // Define your connection string
            var connectionString = new SqlConnectionStringBuilder
            {
                DataSource = "myserver.mycompany.com,1033", // Server name and port
                IntegratedSecurity = true, // Enables Windows Authentication (Kerberos)
                TrustServerCertificate = true, // Trust the server certificate
                ServerSPN = "svc-myuser@REALM"
            }.ConnectionString;

            try
            {
                // Establish connection
                using (var connection = new SqlConnection(connectionString))
                {
                    connection.Open();
                    Console.WriteLine("Connected successfully!");

                    // Create a command to execute a query
                    using (var command = new SqlCommand(
                        "SELECT auth_scheme, * FROM sys.dm_exec_connections WHERE session_id = @@SPID", connection))
                    {
                        // Execute the query
                        using (var reader = command.ExecuteReader())
                        {
                            if (reader.Read())
                            {
                                Console.WriteLine($"SQL Server Auth Scheme: {reader["auth_scheme"]}");
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Connection failed: {ex.Message}");
            }
        }
    }
}

Note that if we remove ServerSPN = "svc-myuser@REALM" then the connection succeeds on both Windows and Linux using Kerberos. (This indicate that Kerbros is setup correctly on the Linux Client)

Observed Behavior

The connection attempt results in the exception mentioned above, indicating that the target principal name is incorrect and the SSPI context cannot be generated.

  • The issue does not occur when the same connection string is used on a Windows client; the connection is established successfully.

Expected behavior

The connection should succeed in both Windows and Linux.

Further technical details

  • Microsoft.Data.SqlClient version: 5.2.2 and 6.0.1
  • .NET target: .NET 8.0
  • SQL Server version: SQL Server 2022 CU11 Linux and SQL Server 2022 CU11 Windows
  • Client Operating Systems Tested where it is failing:
    • Rocky Linux release 8.10 (Green Obsidian) with kernel version 5.4.249-1.el8.x86_64
    • WSL version 2.4.11.0 with kernel version 5.15.167.4-1 on Windows 10.0.22631.4890 running Ubuntu 22.04

Metadata

Metadata

Assignees

Labels

Bug! 🐛Issues that are bugs in the drivers we maintain.P2Use to label moderate priority issue - impacts atleast more than 1 customer.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions