@@ -61,7 +61,8 @@ await AuthenticateSASL(((AuthenticationSASLMessage)msg).Mechanisms, username, as
6161 case AuthenticationRequestType . GSS :
6262 case AuthenticationRequestType . SSPI :
6363 ThrowIfNotAllowed ( requiredAuthModes , msg . AuthRequestType == AuthenticationRequestType . GSS ? RequireAuthMode . GSS : RequireAuthMode . SSPI ) ;
64- await DataSource . IntegratedSecurityHandler . NegotiateAuthentication ( async , this , cancellationToken ) . ConfigureAwait( false ) ;
64+ var isKerberos = msg . AuthRequestType == AuthenticationRequestType . GSS ;
65+ await DataSource . IntegratedSecurityHandler . NegotiateAuthentication ( async , isKerberos , this , cancellationToken ) . ConfigureAwait( false ) ;
6566 return ;
6667
6768 case AuthenticationRequestType . GSSContinue :
@@ -327,7 +328,7 @@ async Task AuthenticateMD5(string username, byte[] salt, bool async, Cancellatio
327328 await Flush ( async , cancellationToken ) . ConfigureAwait( false ) ;
328329 }
329330
330- internal async ValueTask AuthenticateGSS ( bool async , CancellationToken cancellationToken )
331+ internal async ValueTask AuthenticateGSS ( bool async , bool isKerberos , CancellationToken cancellationToken )
331332 {
332333 var targetName = $ "{ KerberosServiceName } /{ Host } ";
333334 // See https://github.com/postgres/postgres/blob/a0dd0702e464f206b08c99a74cb58809c51aafa5/src/interfaces/libpq/fe-auth.c#L111-L123
@@ -337,15 +338,24 @@ internal async ValueTask AuthenticateGSS(bool async, CancellationToken cancellat
337338 TargetName = targetName ,
338339 RequireMutualAuthentication = true
339340 } ;
341+ // If postgres requests GSS, we explicitly ask for Kerberos
342+ // Instead of relying on SSPI on windows to pick the correct protocol (Kerberos instead of NTLM)
343+ // Otherwise, leave Negotiate to allow SSPI to pick whatever it thinks is correct
344+ // This behavior differs from libpq, which prefers SSPI to pick the protocol
345+ // But mimics PGJDBC
346+ // On UNIX only Kerberos is supported, so no need to differentiate between OSes
347+ // TODO: PGJBC has a parameter to force SSPI. Not sure we need something like this.
348+ if ( isKerberos )
349+ clientOptions . Package = "Kerberos" ;
340350
341351 NegotiateOptionsCallback ? . Invoke ( clientOptions ) ;
342352
343353 using var authContext = new NegotiateAuthentication ( clientOptions ) ;
344354 var data = authContext . GetOutgoingBlob ( ReadOnlySpan < byte > . Empty , out var statusCode ) ! ;
345- if ( statusCode != NegotiateAuthenticationStatusCode . ContinueNeeded )
355+ if ( statusCode is not NegotiateAuthenticationStatusCode . Completed and not NegotiateAuthenticationStatusCode . ContinueNeeded )
346356 {
347357 // Unable to retrieve credentials or some other issue
348- throw new NpgsqlException ( $ "Unable to authenticate with GSS: received { statusCode } instead of the expected ContinueNeeded") ;
358+ throw new NpgsqlException ( $ "Unable to authenticate with GSS: received { statusCode } instead of the expected ContinueNeeded or Completed ") ;
349359 }
350360 await WritePassword ( data , 0 , data . Length , async, cancellationToken ) . ConfigureAwait ( false ) ;
351361 await Flush ( async , cancellationToken ) . ConfigureAwait( false ) ;
0 commit comments