Sfoglia il codice sorgente

Bug 1420: SSPI/NTLM/Negotiate authentication not working

https://winscp.net/tracker/1420

Source commit: 64f4a7f0dadfc10c834df7415c9e55344dc5f92e
Martin Prikryl 9 anni fa
parent
commit
bee66b5539
2 ha cambiato i file con 20 aggiunte e 10 eliminazioni
  1. 19 10
      source/core/WebDAVFileSystem.cpp
  2. 1 0
      source/core/WebDAVFileSystem.h

+ 19 - 10
source/core/WebDAVFileSystem.cpp

@@ -1742,6 +1742,7 @@ void TWebDAVFileSystem::NeonCreateRequest(
   TWebDAVFileSystem * FileSystem = static_cast<TWebDAVFileSystem *>(UserData);
   ne_set_request_private(Request, SESSION_FS_KEY, FileSystem);
   ne_add_response_body_reader(Request, NeonBodyAccepter, NeonBodyReader, Request);
+  FileSystem->FNtlmAuthenticationFailed = false;
 }
 //---------------------------------------------------------------------------
 void TWebDAVFileSystem::NeonPreSend(
@@ -1824,16 +1825,24 @@ void __fastcall TWebDAVFileSystem::HttpAuthenticationFailed()
   // NTLM/GSSAPI failed
   if (IsNtlmAuthentication())
   {
-    // Next time do not try Negotiate (NTLM/GSSAPI),
-    // otherwise we end up in an endless loop.
-    // If the server returns all other challenges in the response, removing the Negotiate
-    // protocol will itself ensure that other protocols are tried (we haven't seen this behaviour).
-    // IIS will return only Negotiate response if the request was Negotiate, so there's no fallback.
-    // We have to retry with a fresh request. That's what FAuthenticationRetry does.
-    FTerminal->LogEvent(FORMAT(L"%s challenge failed, will try different challenge", (FAuthorizationProtocol)));
-    ne_remove_server_auth(FNeonSession);
-    NeonAddAuthentiation(false);
-    FAuthenticationRetry = true;
+    if (FNtlmAuthenticationFailed)
+    {
+      // Next time do not try Negotiate (NTLM/GSSAPI),
+      // otherwise we end up in an endless loop.
+      // If the server returns all other challenges in the response, removing the Negotiate
+      // protocol will itself ensure that other protocols are tried (we haven't seen this behaviour).
+      // IIS will return only Negotiate response if the request was Negotiate, so there's no fallback.
+      // We have to retry with a fresh request. That's what FAuthenticationRetry does.
+      FTerminal->LogEvent(FORMAT(L"%s challenge failed, will try different challenge", (FAuthorizationProtocol)));
+      ne_remove_server_auth(FNeonSession);
+      NeonAddAuthentiation(false);
+      FAuthenticationRetry = true;
+    }
+    else
+    {
+      // The first 401 is expected, the server is using it to send WWW-Authenticate header with data.
+      FNtlmAuthenticationFailed = true;
+    }
   }
 }
 //---------------------------------------------------------------------------

+ 1 - 0
source/core/WebDAVFileSystem.h

@@ -174,6 +174,7 @@ private:
   enum TIgnoreAuthenticationFailure { iafNo, iafWaiting, iafPasswordFailed } FIgnoreAuthenticationFailure;
   UnicodeString FAuthorizationProtocol;
   bool FAuthenticationRetry;
+  bool FNtlmAuthenticationFailed;
 
   void __fastcall CustomReadFile(UnicodeString FileName,
     TRemoteFile *& File, TRemoteFile * ALinkedByFile);