#7 WWW-Authenticate only being sent on first attempt

open
nobody
None
5
2010-06-21
2010-06-21
Mockodin
No

Issue:
When Automatic Credentials fail logging via NTLM user is prompted for user/pass
If the user fails to enter credentials correctly a 401 page and no re-prompt for credentials.
Refreshing the page likewise will display 401 but no re-prompt. Looking at headers it appears that WWW-Authenticate is only sent on the first response.

A WWW-Authenticate header should be sent with every 401, or optionally a max attempts within x minutes should be configurable.

Occurs under IE and FireFox.

Discussion

  • Ilguiz Latypov
    Ilguiz Latypov
    2010-08-25

    Here are 2 suggestions. The first may stop IE8 from sending empty POST requests on submitting full forms. The second will inform the user in case the browser still mis-behaves.

    * Add the following SSPI options to Apache configuration,
    [code]
    SSPIUsernameCase lower
    SSPIPerRequestAuth On # http://archiver.mailfighter.net/tortoisesvn-users/2008/July/30/0021.html
    [/code]

    * In CGI scripts, intercept possible misbehaviour by IE,
    [code]
    content_length = os.getenv( "CONTENT_LENGTH", None )
    request_method = os.getenv( "REQUEST_METHOD", None )
    if content_length == "0" and request_method == "POST":
    # Work around Internet Explorer requesting a new authentication session from us.
    # See "Form submission error with MSIE 6.0 (post data)",
    # http://www.websina.com/bugzero/kb/browser-ie.html
    # Replying with an authentication query may result in password prompts after each restart of IE.
    #
    # The issue may be avoided altogether by adding these lines to Apache
    # SSPI configuration, according to a post by Simon Berry,
    # http://archiver.mailfighter.net/tortoisesvn-users/2008/July/30/0021.html
    #
    # SSPIPerRequestAuth On
    # SSPIUsernameCase lower

    sys.stdout.write( "Status: 401 Unauthorized\r\n" ) # This should result in "HTTP/1.1 401 Unauthorized\r\n"
    sys.stdout.write( "WWW-Authenticate: NTLM\r\n" )
    sys.stdout.write( "\r\n" )
    raise SystemExit( )

    # sys.stdout.write( """Content-Type: text/plain\r\n\r\n""" )
    # sys.stdout.write( """stdin "%s"\n""" % ( sys.stdin.read(), ), )
    # raise SystemExit( )
    [/code]

     

    Related

    Code: code

  • Try to disable ntlm preauth. there is a registry key to fix it. Sorry I lost the url. Use google further instructions.

    Greetings
    Alex

     
  • David Simmons
    David Simmons
    2012-12-06

    I've encountered a similar problem due to the WWW-Authenticate header not being sent upon "login denied":

    If Safari users on Macs select "Remember this password in my keychain," so that Safari will automatically send their credentials, they will be in trouble if they ever change their password. When they go to the page, Safari will try to send their old credentials, authentication will fail, but they will not be presented with a dialog box to enter their new password! They will be unable to use the page again without knowing how to use the Keychain Access program to manually clear the stored password.

    Chrome users don't have this problem, because Chrome doesn't believe the sudden lack of a WWW-Authenticate header, and presents the username/password dialog box anyway.

    I've studied the source code and found that the WWW-Authenticate header is actually suppressed when one of two error conditions occurs: 1. The OS's SSPI system returns SEC_E_LOGON_DENIED (i.e. bad username and/or password), or 2. the OS's SSPI returns SEC_E_INVALID_TOKEN (perhaps due to corrupted input, or an incorrect authentication method?). I'm not sure why the author made this decision, but perhaps there was some concern of browsers getting into an endless loop if some errant code was sending bad or malformed credentials.

    I've fixed the problem on my customer's server by commenting out the line of code that triggers the suppression of WWW-Authenticate when the user's credentials are rejected (case #1 above). Safari users are now properly presented with a dialog box so they can enter a new username and password. This diff shows the change I made:

    --- src/authentication.c (revision 17)
    +++ src/authentication.c (working copy)
    @@ -403,7 +403,6 @@

    case SEC_E_LOGON_DENIED:
    log_sspi_logon_denied(ctx->r, &ctx->hdr, APR_FROM_OS_ERROR(GetLastError()));
    - ctx->scr->sspi_failing = 1;
    ctx->scr->package = 0;
    note_sspi_auth_failure(ctx->r);
    cleanup_sspi_connection(ctx->scr);