You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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
Configure a SQL Server instance to run under a specific domain account.
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).
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.
usingMicrosoft.Data.SqlClient;namespaceTestCSharpConnection{internalclassProgram{staticvoidMain(){// Define your connection stringvarconnectionString=newSqlConnectionStringBuilder{DataSource="myserver.mycompany.com,1033",// Server name and portIntegratedSecurity=true,// Enables Windows Authentication (Kerberos)TrustServerCertificate=true,// Trust the server certificateServerSPN="svc-myuser@REALM"}.ConnectionString;try{// Establish connectionusing(varconnection=newSqlConnection(connectionString)){connection.Open();Console.WriteLine("Connected successfully!");// Create a command to execute a queryusing(varcommand=newSqlCommand("SELECT auth_scheme, * FROM sys.dm_exec_connections WHERE session_id = @@SPID",connection)){// Execute the queryusing(varreader=command.ExecuteReader()){if(reader.Read()){Console.WriteLine($"SQL Server Auth Scheme: {reader["auth_scheme"]}");}}}}}catch(Exceptionex){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
The text was updated successfully, but these errors were encountered:
Another observation is that on Windows, it's possible to specify the Kerberos realm in the ServerSPN as follows:
ServerSPN = "MSSQLSvc/fqdn:port@REALM"
However, on Linux, specifying the @REALM in the ServerSPN causes the connection to fail with the same exception as mentioned earlier:
Microsoft.Data.SqlClient.SqlException (0x80131904): The target principal name is incorrect. Cannot generate SSPI context.
Tt's important to note that specifying the ServerSPN in the format "MSSQLSvc/fqdn:port@REALM" or "user@REALM" is successful across multiple platforms and drivers, I have successfully tested it with:
pyodbc with DRIVER={ODBC Driver 18 for SQL Server} on Linux
Java com.microsoft.sqlserver.jdbc.SQLServerDataSource on both Windows and Linux
C# Microsoft.Data.SqlClient on Windows
The discrepancy arises specifically with C# Microsoft.Data.SqlClient on Linux only, where specifying the ServerSPN in this manner results in a connection failure.
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:To reproduce
ServerSPN
attribute, specifying the account in the formatUsername@Domain
(example: svc-myuser@REALM).The following code snippet works on Windows but doesn't work on Linux without any single change.
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.
Expected behavior
The connection should succeed in both Windows and Linux.
Further technical details
5.4.249-1.el8.x86_64
2.4.11.0
with kernel version5.15.167.4-1
on Windows10.0.22631.4890
runningUbuntu 22.04
The text was updated successfully, but these errors were encountered: