waffle icon indicating copy to clipboard operation
waffle copied to clipboard

Internet Explorer bodyless POST optimization with SPNEGO header and accept-incomplete not handled

Open OlivierJaquemet opened this issue 8 years ago • 12 comments

For file upload, Internet Explorer may send a bodyless POST request under circumstances described in the following posts :

  • https://blogs.msdn.microsoft.com/ieinternals/2010/11/21/challenge-response-authentication-and-zero-length-posts/
  • http://stackoverflow.com/questions/20912663/ie10-ie11-upload-fail-not-sending-post-data

In such case, the behavior of the server as expected by IE is to send a 401 request to "re-establish" the authentication. However, in my observations, when this IE "optimization" occurs, the subsequent request

  • contains and HTTP header Authorization: Negotiate, with an SPNegoTokenTarg message with an accept-incomplete negResult
  • does not yet contains the file (even though the Content-Length / Content-Type indicates otherwise) (I suppose sent in a third request)

internet explorer accept-incomplete

Looking at the RFC : https://www.ietf.org/rfc/rfc4178.txt The accept-incomplete indicates the following : "At least one additional negotiation message from the peer is needed to establish the security context."

Indeed, the MSDN, documentation for AcceptSecurityContext indicates the possible SEC_I_COMPLETE_AND_CONTINUE or SEC_I_COMPLETE_NEEDED return value which requires additionnal processing : https://msdn.microsoft.com/en-us/library/windows/desktop/aa374705(v=vs.85).aspx

waffle-jna implementation in WindowsAuthProviderImpl.acceptSecurityToken does not seem to be handling such case : https://github.com/dblock/waffle/blob/60451c353916863d93073a32e88006af28c94412/Source/JNA/waffle-jna/src/main/java/waffle/windows/auth/impl/WindowsAuthProviderImpl.java#L134:L170

(The result for the end user is an upload failure)

OlivierJaquemet avatar Apr 19 '16 14:04 OlivierJaquemet

This looks like something we should implement, PRs with tests welcome!

dblock avatar Apr 21 '16 21:04 dblock

As far as I am concerned, there a lot of work before getting even near to a PR, I need to get familiar with the code base, the test suite, and most of all the build and process... This will not happen anytime soon. If you could pinpoint some documentation, thread, or anything describing the build process and potentialy some architecture choice of Waffle, It might speed up my learning.

OlivierJaquemet avatar Apr 22 '16 11:04 OlivierJaquemet

There's quite a bit in https://github.com/dblock/waffle/blob/master/Docs/SettingUpDevelopmentEnvironment.md, and maybe as you work through it you can contribute for the next person to get started.

dblock avatar Apr 22 '16 13:04 dblock

Shame on me, I did not find this doc previouly.

OlivierJaquemet avatar Apr 22 '16 13:04 OlivierJaquemet

No worries @OlivierJaquemet :)

dblock avatar Apr 22 '16 21:04 dblock

Any progress on this issue?

We've recently upgraded to IE11 in our company and XHR-based file uploads started to fail from time to time. As soon as I remove waffle from the filter-chain (JSF based application) it works all the time.

fanste avatar May 02 '16 11:05 fanste

@fanste the issue you are facing is probably not this one which happens only when using NTLMSSP (not kerberos), under very rare circumstances.

Issue #167 is certainly the source of the problem you are observing. I had a similar bug and I could test the solution implemented by @AriSuutariST in #338 and #339 with success . As far as I know #339 has not yet been merged due to unittest issues so it is probably not yet planned for 1.8.2. In the meantime you can checkout the corresponding branch to apply and test the fix (and it would be nice to do so as it would add a second confirmation of proper implementation).

OlivierJaquemet avatar May 02 '16 15:05 OlivierJaquemet

Thanks for your feedback. I will take a look at the referenced issue and patches.

fanste avatar May 02 '16 15:05 fanste

After you got me back to this issue, I have a question: What is your waffle filter configuration? I've tried to produce a capture that is similar to yours. But it always tries to use Kerberos if I enable Negotiation. This results in KRB5KRB_AP_ERR_MODIFIED as Kerberos is not configured.

<filter>
    <filter-name>NtlmHttpFilter</filter-name>
    <filter-class>waffle.servlet.NegotiateSecurityFilter</filter-class>
    <init-param>
        <param-name>waffle.servlet.spi.NegotiateSecurityFilterProvider/protocols</param-name>
        <param-value>Negotiate</param-value>
    </init-param>
</filter>

fanste avatar May 03 '16 11:05 fanste

  <init-param>
      <param-name>securityFilterProviders</param-name>
      <param-value>
          waffle.servlet.spi.NegotiateSecurityFilterProvider
      </param-value>
  </init-param>
  <init-param>
      <param-name>waffle.servlet.spi.NegotiateSecurityFilterProvider/protocols</param-name>
      <param-value>
          Negotiate
          NTLM
      </param-value>
  </init-param>

OlivierJaquemet avatar May 03 '16 12:05 OlivierJaquemet

NTLM is only used for the local server instance (negTokenInit > mechTypes has it as its first element). Our testserver (somewhere in the comanies network) has MS KRB5 as its first element. I'm now using RawCap to capture the traffic of the local server.

If I've understood your first post correctly, than we have the same issue. But I have a small difference: Wireshark does not show the parsed packet for POST NTLMSSP_AUTH. It gets confused by the Content-Length > 0 and missing POST body.

I've modified NegotiateSecurityFilterProvide#isPrincipalException so that the method consideres an previously cached ContinueContext for the current connectionId. It is then able to invoke the auth provider impl (resp. Secur32.INSTANCE.AcceptSecurityContext) one more time and the returned token contains negResult=accept-completed. I've never hit SEC_I_COMPLETE_AND_CONTINUE or SEC_I_COMPLETE_NEEDED. Then I modified the filter in a way, that the first ntlmPost will set a flag for the connectionId to true which is again used as soon as the negotiation succeeded (SEC_E_OK) to return back to the client without forwarding the request to the application (remember: Content-Length > 0 but no POST data). It doesn't matter if I return with status 200 or 401, IE will never send the next request. The IE network tab shows the request as pending... forever.

Either we've hit a serious bug within IE itself or the usage of the WinAPI is incorrect (missing flags or missing additional API calls). But I'm out of ideas and far away from being a pro in concerns of NTLM.

fanste avatar May 03 '16 15:05 fanste

I think we can stop digging around as the error is not only within waffle but also occurs with Microsoft IIS 7.5. Must be a bug inside IE...

I've found the following links from microsoft, but the don't fix it for me:

  • https://support.microsoft.com/en-us/kb/2980019
  • https://technet.microsoft.com/library/security/ms14-052
  • https://www.microsoft.com/en-us/download/details.aspx?id=44202

Edit 04.05.2016 11:03: I've had the possibility to test that feature on a windows 10 machine using IE11 and the new edge browser. It's working on both browsers. I can't tell you if it has something to do with the browser itself or if it is a windows internal thing (bug in the NTLM implementation or something like that). The same round-trips are done if IE expects a 401. It first sends a zero-length POST request followed by an request containing the POST data. This was tested using waffle 1.6.1224.

fanste avatar May 04 '16 08:05 fanste