0

See updates for updated question

I am using AFNetworking's AFHTTPClient for my app's service calls. My server uses HTTP digest authentication to authenticate. The service call is returning a 401 HTTP error with WWW-Authenticate header in its response as a challenge like this:

HTTP/1.1 401 
WWW-Authenticate: Digest realm="user@myserver.com",
    qop="auth",
    nonce="059c37d0e654fdba9c606f35ce84741998"
Content-Type: text/html; charset=utf-8

The connection:didReceiveAuthenticationChallenge: method is never called in AFURLConnectionOperation, which is the NSURLConnectionDelegate in this situation and would then call my block set in setAuthenticationChallengeBlock:. Instead, I just get the error: Error Expected status code in (200-299), got 401 in my AFHTTPRequestOperation failure block.

As far as I understand, these are the only required fields in the WWW-Authenticate header for HTTP digest authentication. It's very similar to the response in this example on Wikipedia. I don't have any actual body of the response since I'm not displaying any HTML to the user anyway. Should this matter? I'm not using the opaque field, but this should be optional. I don't support the "auth-int" quality of protection. Other than that, I don't return a Server or Date header. Are either of these required?

What is it I'm doing wrong here?

UPDATE: I am now logging the response headers on the client side (Apple doesn't provide a nice way to simply print the plain text response that I know of). The response as shown above is as it's logged on the server. The result of NSHTTPURLResponse allHeaders is:

{
    "Alternate-Protocol" = "80:quic";
    "Cache-Control" = private;
    "Content-Type" = "text/html; charset=utf-8";
    Date = "Mon, 09 Sep 2013 20:24:00 GMT";
    Server = "Google Frontend";
    "Transfer-Encoding" = Identity;
    Vary = "Accept-Encoding";
    "Www-Authenticate" = "Digest realm=\"user@myserver.com\",__    qop=\"auth\",__    nonce=\"f36dc1b8abc342d5c1cbad22a533d3868c\"";
}

The Server and Date headers are actually included by the server, as well as a few others. The server is Google App Engine.

But the issue seems to be that my \r\n CR+LF is being converted to __ for some reason, which messes up the header syntax. Looking into why this is...

UPDATE 2: Using only \n results in _. The HTTP requirement is to use CR+LF+SPACE for dividing lines within a header. So now my question becomes, how do I properly include this CR+LF+SPACE in my HttpServletResponse header string so that it's encoded correctly? Where in the server response process is the encoding being changed, resulting in the _ character I'm getting?

This is the server code which is creating the response:

public static void sendUnauthorizedResponse(HttpServletResponse resp, String realm, boolean isStale) throws IOException {
    String s = ",\r\n    ";
    String header = "Digest realm=\"" + realm + "\"" + s + "qop=\"auth\"" + s + "nonce=\"" + createNonce() + "\"";
    if (isStale) {
        header += s + "stale=TRUE";
    }
    resp.setHeader("WWW-Authenticate", header);
    resp.sendError(HttpServletResponse.SC_UNAUTHORIZED);
    log.info("Sent 401 Unauthorized Response:\n" + resp.toString());
}

The last line is what logs the response as shown first above, which is formatted correctly at this point.

Both the carriage return \r 0x0D and line feed \n 0x0A are being changed to the ASCII underscore _ 0x5F.

UPDATE 3: I can confirm this is not a client issue, but must be caused by the Google App Engine server. I get the same result when posting the service call in a poster tool.

UPDATE 4: Removing the CR+LF characters and including the comma separated attributes all on one line seems to work, but according to RFC 2047, lines should not be longer than 75 characters long, which it would now be:

An 'encoded-word' may not be more than 75 characters long, including 'charset', 'encoding', 'encoded-text', and delimiters. If it is desirable to encode more text than will fit in an 'encoded-word' of 75 characters, multiple 'encoded-word's (separated by CRLF SPACE) may be used.

While there is no limit to the length of a multiple-line header field, each line of a header field that contains one or more 'encoded-word's is limited to 76 characters.

So I still need to figure out how to correctly put CR+LF characters in my header string.

UPDATE 5: So it seems the maximum characters allowed per line of an HTTP header is server dependent and likely in the thousands of bytes range, which should be sufficient for the WWW-Authenticate header. But this still doesn't answer the question as to why "\r\n" characters in my header string are converted to "__". Is this a bug in Google App Engine? Hard to imagine I'm the only person to have used CR+LF+SPACE to separate my header attributes on new lines in HTTP responses.

Community
  • 1
  • 1
Jeff Lockhart
  • 5,379
  • 4
  • 36
  • 51
  • Mayby I'm missing something, but RFC2047 is talking about MIME headers. here you talking about HTTP headers. Apples and Oranges. See also http://stackoverflow.com/questions/1097651/is-there-a-practical-http-header-length-limit – barryhunter Sep 10 '13 at 11:25
  • I don't remember what lead me to that standard being relevant for HTTP headers. But that's helpful to know it is likely a much higher limit. But it should still be possible to use CR+LF to separate header attributes and I would like to know why this isn't working on GAE. – Jeff Lockhart Sep 10 '13 at 18:35
  • Why? I would think its a crude method of preventing header injections. AppEngine doesnt allow you to set some headers, so by preventing newlines, stops you piggybacking on other valid headers. Also helps if the developer is careless in outputting user supplied variables in headers. – barryhunter Sep 10 '13 at 20:11
  • I could see where this might be trying to solve some of these potential issues. But I don't see how you could piggyback on another header since the header name will always precede the value. It should be enough to trim whitespace on the header name to prevent this. Also, if a developer blindly dumps user supplied variables into a header, I don't see how converting CR and LF to _ fixes anything, it just messes up syntax. If anything, they should be removed completely or replaced by whitespace. Better though, just check that CR+LF is always followed by SPACE or TAB, in which case it's valid. – Jeff Lockhart Sep 10 '13 at 20:22
  • I did say it was a crude method. effective, but not particularly elegant. – barryhunter Sep 10 '13 at 20:50

0 Answers0