Authorization header not sent using AFNetworking - heroku

I'm developing an iOS app that makes frequent requests to a web server, and I'm using AFNetworking (which I very much like). However, I'm running into a problem with authorization that I just can't solve.
The server requires me to provide an authorization header in order to get the response that I want. Specifically, the authorization headers should be like so:
Authorization = "ApiKey some-user-name:someNumericalApiKey"
I'm using AFNetworking throughout the project, and everything works fine, except for this authorization issue. I'm using the following code:
[myClient setDefaultHeader:#"Authorization" value:#"ApiKey some-user-name:someNumericalApiKey"];
where myClient points to an AFHTTPClient object. Strange enough, when I log the request in XCode using AFHTTPRequestOperationLogger, the logger claims that I have the correct headers set. However, the authorization header does not seem to reach the server - I can't see it in the server log.
To isolate the problem, I've tried to make the exact same request using good old NSURLRequest, as well as curl, and the requests library in Python - all of these work fine, i.e. the authorization header is sent & received (i.e. I can see it in the server log), and the server response is what it should be.
If anyone has run into the same problem (and has found a solution) I would very much appreciate to hear from you.
Thanks.

Sometimes (especially with Django) this is caused by redirection stripping of header parameters. For instance, /Object redirects to /Object/ in the background and removes the necessary auth parameter during the switch.
If you're using AFNetworkActivityLogger with level AFLoggerLevelDebug then you should be able to check this out in the console. If you see a POST request with /Object and the response with /Object/ then this might indicate redirection stripping is taking place.

If you construct your operation manually then the defaultHeaders are not applied, that might be the cause of your problem.

Related

How can I get more verbose debugging information from hammerhead?

I am running into an issue where my web code is invoking an ajax call to another endpoint on the same server that is not completing. I can see in the server logs that the request is processed and the response is sent, but the network tool shows the response as not finished (stalled) even after several minutes.
I am looking for more details on what is happening in the proxy (perhaps it is waiting on more data from the server, etc). But I cannot find any logging from the proxy to assist in debugging.
EDIT:
I have noticed this happens on all proxy requests with isXhr set.
OK, so to answer the original question regarding verbose logging, there isn't any. I had to sprinkle logging through the hammerhead code to get anything more meaningful than testcafe timing out on a selector.
Regarding the underlying issue (which would have been obvious long ago with decent proxy logging), I finally uncovered a node.js http module "Parse Error". While the browsers are more forgiving, node's http module will barf on a Content-Length header along with 'Transfer-Encoding : chunked'. Chunked encoding creats additional overhead and the Content-Length does not match the payload size any longer.
This would normally not have happened, but in our server implementation, the API calls are proxied and the far end headers were being passed on to the response leading to a collision in the headers.
Hopefully this will be useful for someone else.
You need to inspect the RequestPipeline module. It controls the procedures of sending the request, processing the response, and sending the modified response to the client.

Cross Domain request for service using SproutCore

I have been trying to get this resolved, without any success.
I have a webapp residing on my domain, say www.myDomain.com. I need to call a service which is present on another domain, say www.anotherDomain.com/service.do?
I'm using SproutCore's SC.Request.getUrl(www.anotherDomain.com/service.do?) to call that service.
I get an error that says, Origin www.myDomain.com is not allowed by access-control-allow-origin.
When I was in dev stages, and using sc-server, the issue was resolved using proxies. Now that I have deployed the app to an actual server, I replaced all the lines where I had set up the proxy with the actual domain name. I have started getting that error again.
The problem is that I CANNOT MAKE ANY CHANGES to the server on the other domain. All the posts that I have come across state that the other server on the other domain ought to provide access-control-allow-origin header and that it ought to support the OPTIONS verb.
My question is, is it possible for me to connect to that service using SproutCore's SC.Request.getUrl() method?
Additionally, the other posts that I have read mentioned that a simple GET request ought not to be preflighted. Why then are my requests going as OPTION instead of GET?
Thanks a ton in advance! :D
This is not a Sproutcore issue; it's a javascript Same Origin Policy issue.
If you can't modify the production server, you have no option but to develop your own proxy server, and have your proxy hit the real service.
This is effectively replacing sc-server in your production environment.
All this server would do is take the incoming request and pass it along to www.anotherDomain.com/?service.do.
You would need to make sure you passed all parameters, cookies, headers, the http verb, etc....
This is far from ideal, because now errors can occur in more places. Did the real service fail? Did the proxy fail? etc.
If you could modify the other domain, you could
1) deploy your SC app there.
2) put in the CORS headers so you could make cross domain requests

HTTP digest authentication for AJAX requests

Hey SO, so I've got an API I'm making calls to in a browser application. Said API lives on a server that requires whitelisting and HTTP Digest Authentication.
To meet the whitelisting requirement, I'm running all API calls through a proxy, which is whitelisted. The calls are originating from an iFrame, currently populated by an index.html file.
What I need to know is how I can authenticate via HTTP Digest in the background. Most of the resources I can find online seem to involve the original HTTP Digest Authentication setup, but what I'm looking to do is automate login.
Despite the non-secretive subject matter, it is somehow critical that I keep the digest parameters obfuscated from users. Perhaps I could change the served file to index.php and then somehow set the magic headers? Even then, if the calls made via XHR, would the index.php headers authenticate the separate request?
Overall, I'm just lost, and the API developers in question are not exactly responsive, so thought I'd turn here.
It appears that in the end, this was not possible. I had to switch to building a thin back-end to route requests through.

Eradicating 401 "Unauthorised" responses followed by 200 "Ok" responses

I’ve got a situation with a large internal corporate web based application running ASP.NET 3.5 on IIS6 generating 401 “Unauthorised” responses followed by 200 “Ok” responses (as profiled by Fiddler). I’m aware of why this happening (integrated auth forcing the browser to resend credentials) but I’m looking for some thoughts on how to minimise or eradicate the situation. The application in question is running in the WAN with some users experiencing latency of up to 250ms so forcing a subsequent request can have a noticeable impact on page load time, particularly when there are a number of cascading drop down lists on the pages making.
The users of the application are internal within a managed desktop environment so mechanisms to force the browser to send credentials on the first request (is this even possible?) could be possible from a deployment perspective. This would work for pages requiring the user’s identity but for resources not requiring authentication (WebResource.axd, ScriptResource.axd and some custom web services), allowing anonymous auth would be possible. I’ve looked at defining this on a per location basis in the web.config but the results were mixed (still a number of 401 responses).
I’d appreciate any guidance on a “best practice” for dealing with this situation. There are a lot of resources out there identifying the problem but none that I’ve found providing a feasible solution.
Thanks!
Edit: Resources not requiring authentication (i.e. web services used for cascading drop down lists) can be requested anonymously through adding a location entry to the web config but I'm yet to find an answer for authenticated resources.
Unfortunately this is an artifact of the HTTP NTLM authentication scheme.
In short, the browser (Internet Explorer or otherwise) doesn't know that it needs to authenticate at all until it gets bounced with a 401 response containing a WWW-Authenticate response header.
In the case of WWW-Authenticate: NTLM -- annoyingly enough -- it requires two 401 responses on a single persistent connection to complete, and this process must be repeated once the HTTP persistent connection is closed. So even if you were able to get the browser to initiate a request blindly attempting NTLM, at least one 401 response cannot be removed from the transaction.
I think your best bet would be to maximize the amount of time that persistent connections are left open when idle.
CSCRIPT.EXE c:\inetpub\adminscripts\ADSUTIL.VBS SET W3SVC/AuthPersistSingleRequest FALSE
Will reduce the amount of 401's significantly.
I believe you can convince Firefox to automatically send NTLM credentials to a whitelisted set of domains via "about:config" settings - use the "network.automatic-ntlm-auth.trusted-uris" setting. I haven't tried this myself though. I'm not sure there's any equivalent for Internet Explorer.
Unfortunately if you're using something else like Kerberos there does not seem to be a way to avoid the 401.
You may need to consider Forms Authentication if the 401-induced latency is too long. The users would have to explicitly log in, but just once. Then you could use a cookie or cookieless scheme and get a response on the first try.
I imagine that page load would be slow if you have cascading drop-downs and your initial page load populates one value that causes a POST to get the next list, set that value, another POST to get the next list again, and so on. If this is the situation, perhaps you need to populate all those drop-downs on the first round-trip rather than waiting for POST responses.
TL;DR I put HTTP header information in HTTP body
My example is in Angular, but any TypeScript/JavaScript (framework) might have the same issue.
When doing a HTTP post call to my backend API, which requires headers with the logged in user information, I added my HTTP headers where my HTTP body should be and the headers were empty.
PROBLEM
markInstructionAsCompleted(visitScheduleId: string, instructionId: number) {
return this.http.post(`${environment.apiUrl}/VisitInstructions/schedule/${visitScheduleId}/done/${instructionId}`, this.getHeaderWithAuthorization());
}
SOLUTION, notice that there's an added second argument to the HTTP post call, which is null
markInstructionAsCompleted(visitScheduleId: string, instructionId: number) {
return this.http.post(`${environment.apiUrl}/VisitInstructions/schedule/${visitScheduleId}/done/${instructionId}`, null, this.getHeaderWithAuthorization());
}

Why "Content-Length: 0" in POST requests?

A customer sometimes sends POST requests with Content-Length: 0 when submitting a form (10 to over 40 fields).
We tested it with different browsers and from different locations but couldn't reproduce the error. The customer is using Internet Explorer 7 and a proxy.
We asked them to let their system administrator see into the problem from their side. Running some tests without the proxy, etc..
In the meantime (half a year later and still no answer) I'm curious if somebody else knows of similar problems with a Content-Length: 0 request. Maybe from inside some Windows network with a special proxy for big companies.
Is there a known problem with Internet Explorer 7? With a proxy system? The Windows network itself?
Google only showed something in the context of NTLM (and such) authentication, but we aren't using this in the web application. Maybe it's in the way the proxy operates in the customer's network with Windows logins? (I'm no Windows expert. Just guessing.)
I have no further information about the infrastructure.
UPDATE: In December 2010 it was possible to inform one administrator about this, incl. links from the answers here. Contact was because of another problem which was caused by the proxy, too. No feedback since then. And the error messages are still there. I'm laughing to prevent me from crying.
UPDATE 2: This problem exists since mid 2008. Every few months the customer is annoyed and wants it to be fixed ASAP. We send them all the old e-mails again and ask them to contact their administrators to either fix it or run some further tests. In December 2010 we were able to send some information to 1 administrator. No feedback. Problem isn't fixed and we don't know if they even tried. And in May 2011 the customer writes again and wants this to be fixed. The same person who has all the information since 2008.
Thanks for all the answers. You helped a lot of people, as I can see from some comments here. Too bad the real world is this grotesque for me.
UPDATE 3: May 2012 and I was wondering why we hadn't received another demand to fix this (see UPDATE 2). Looked into the error protocol, which only reports this single error every time it happened (about 15 a day). It stopped end of January 2012. Nobody said anything. They must have done something with their network. Everything is OK now. From summer 2008 to January 2012. Too bad I can't tell you what they have done.
UPDATE 4: September 2015. The website had to collect some data and deliver it to the main website of the customer. There was an API with an account. Whenever there was a problem they contacted us, even if the problem was clearly on the other side. For a few weeks now we can't send them the data. The account isn't available anymore. They had a relaunch and I can't find the pages anymore that used the data of our site. The bug report isn't answered and nobody complaint. I guess they just ended this project.
UPDATE 5: March 2017. The API stopped working in the summer of 2015. The customer seems to continue paying for the site and is still accessing it in February 2017. I'm guessing they use it as an archive. They don't create or update any data anymore so this bug probably won't reemerge after the mysterious fix of January 2012. But this would be someone else's problem. I'm leaving.
Internet Explorer does not send form fields if they are posted from an authenticated site (NTLM) to a non-authenticated site (anonymous).
This is feature for challange-response situations (NTLM- or Kerberos- secured web sites) where IE can expect that the first POST request immediately leads to an HTTP 401 Authentication Required response (which includes a challenge), and only the second POST request (which includes the response to the challange) will actually be accepted. In these situations IE does not upload the possibly large request body with the first request for performance reasons. Thanks to EricLaw for posting that bit of information in the comments.
This behavior occurs every time an HTTP POST is made from a NTLM authenticated (i.e. Intranet) page to a non-authenticated (i.e. Internet) page, or if the non-authenticated page is part of a frameset, where the frameset page is authenticated.
The work-around is either to use a GET request as the form method, or to make sure the non-authenticated page is opened in a fresh tab/window (favorite/link target) without a partly authenticated frameset. As soon as the authentication model for the whole window is consistent, IE will start to send form contents again.
Definitely related: http://www.websina.com/bugzero/kb/browser-ie.html
Possibly related: KB923155
Full Explanation: IEInternals Blog – Challenge-Response Authentication and Zero-Length Posts
This is easy to reproduce with MS-IE and an NTLM authentication filter on server side. I have the same issue with JCIFS (1.2.), struts 1. and MS-IE 6/7 on XP-SP2. It was finally fixed. There are several workarounds to make it up.
change form method from POST (struts default setting) to GET.
For most pages with small sized forms, it works well. Unfortunately i have possibly more than 50 records to send in HTTP stream back to server side. IE has a GET URL limit 2038 Bytes (not parameter length, but the whole URL length). So this is a quick workaround but not applicable for me.
send a GET before POST action executing.
This was recommended in MS-KB. My project has many legacy procedures and i would not take the risk at the right time. I have never tried this because it still needs some extra authentication processing when GET is received by filter layer based on my understanding from MS-KB and I would not like to change the behavior with other browsers, e.g. Firefox, Opera.
detecting if POST was sent with zero content-length (you may get it from header properties hash structure with your framework).
If so, trigger an NTLM authentication cycle by get challenge code from DC or cache and expect an NTLM response.
When the NTLM type2 msg is received and the session is still valid, you don't really need to authenticate the user but just forward it to the expected action if POST content-length is not zero. BTW, this would increase the network traffics. So check your cache life time setting and SMB session soTimeOut configuration before applying the change plz.
Or, more simple, you may just send a 401-unauthorized status to MS-IE and the browser shall send back POST request with data in reply.
MS-KB has provided a hot-fix with KB-923155 (I could not post more than one link because of a low reputation number :{ ) , but it seems not working. Would someone post a workable hot-fix here? Thanks :) Here is a link for reference, http://www.websina.com/bugzero/kb/browser-ie.html
We have a customer on our system with exactly the same problem. We've pin pointed it down to the proxy/firewall. Microsoft's IAS. It's stripping the POST body and sending content-length: 0. Not a lot we can do to work around however, and down want to use GET requests as this exposes usernames/passwords etc on the URL string. There's nearly 7,000 users on our system and only one with the problem... also only one using Microsoft IAS, so it has to be this.
There's a good chance the problem is that the proxy server in between implements HTTP 1.0.
In HTTP 1.0 you must use the Content-Length header field: (See section 10.4 here)
A valid Content-Length is required on
all HTTP/1.0 POST requests. An
HTTP/1.0 server should respond with a
400 (bad request) message if it cannot
determine the length of the request
message's content.
The request going into the proxy is HTTP 1.1 and therefore does not need to use the Content-Length header field. The Content-Length header is usually used but not always. See the following excerpt from the HTTP 1.1 RFC S. 14.13.
Applications SHOULD use this field to
indicate the transfer-length of the
message-body, unless this is
prohibited by the rules in section
4.4.
Any Content-Length greater than or
equal to zero is a valid value.
Section 4.4 describes how to determine
the length of a message-body if a
Content-Length is not given.
So the proxy server does not see the Content-Length header, which it assumes is absolutely needed in HTTP 1.0 if there is a body. So it assumes 0 so that the request will eventually reach the server. Remember the proxy doesn't know the rules of the HTTP 1.1 spec, so it doesn't know how to handle the situation when there is no Content-Length header.
Are you 100% sure your request is specifying the Content-Length header? If it is using another means as defined in section 4.4 because it thinks the server is 1.1 (because it doesn't know about the 1.0 proxy in between) then you will have your described problem.
Perhaps you can use HTTP GET instead to bypass the problem.
This is a known problem for Internet explorer 6, but not for 7 that I know of. You can install this fix for the IE6 KB831167 fix.
You can read more about it here.
Some questions for you:
Do you know which type of proxy?
Do you know if there is an actual body sent in the request?
Does it happen consistently every time? Or only sometimes?
Is there any binary data sent in the request? Maybe the data starts with a \0 and the proxy has a bug with binary data.
If the user is going through an ISA proxy that uses NTLM authentication, then it sounds like this issue, which has a solution provided (a patch to the ISA proxy)
http://support.microsoft.com/kb/942638POST requests that do not have a POST body may be sent to a Web server that is published in ISA Server 2006
I also had a problem where requests from a customer's IE 11 browser had Content-Length: 0 and did not include the expected POST content. When the customer used Firefox, or Chrome the expected content was included in the request.
I worked out the cause was the customer was using a HTTP URL instead of a HTTPS URL (e.g. http://..., not https://...) and our application uses HSTS. It seems there might be a bug in IE 11 that when a request gets upgraded to HTTPS due to HSTS the request content gets lost.
Getting the customer to correct the URL to https://... resulted in the content being included in the POST request and resolved the problem.
I haven't investigated whether it is actually a bug in IE 11 any further at this stage.
Are you sure these requests are coming from a "customer"?
I've had this issue with bots before; they sometimes probe sites for "contact us" forms by sending blank POST requests based on the action URI in FORM tags they discover during crawling.
Presence and possible values of the ContentLength header in HTTP are described in the HTTP ( I assume 1/1) RFC:
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.13
In HTTP, it SHOULD be sent whenever the message's length can be determined prior to being transferred
See also:
If a message is received with both a
Transfer-Encoding header field and a Content-Length header field,
the latter MUST be ignored.
http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4
Maybe your message is carrying a Transfer-Encoding header?
Later edit: also please note "SHOULD" as used in the RFC is very important and not equivalent to "MUST":
3. SHOULD This word, or the adjective "RECOMMENDED", mean that there
may exist valid reasons in particular circumstances to ignore a
particular item, but the full implications must be understood and
carefully weighed before choosing a different course.
Ref: http://www.ietf.org/rfc/rfc2119.txt
We had a customer using same website in anonymous and NTLM mode (on different ports). We found out that in our case the 401 was related to Riverbed Steelhead application used for http optimization. The first signal pointing us into that direction was a X-RBT-Optimized-By header. The issue was the Gratuitous 401 feature:
This feature can be used with both per-request and per-connection
authentication but it‘s most effective when used with per-request
authentication. With per-request authentication, every request must be
authenticated against the server before the server would serve the
object to the client. However, most browsers do not cache the server‘s
response requiring authentication and hence it will waste one
round-trip for every GET request. With Gratuitous 401, the client-side
Steelhead appliance will cache the server response and when the client
sends the GET request without any authentication headers, it will
locally respond with a ―401 Unauthorized‖ message and therefore saving
a round trip. Note that the HTTP module does not participate in the
actual authentication itself. What the HTTP module does is to inform
the client that the server requires authentication without requiring
it to waste one round trip.
Google also shows this as an IE (some versions, anyway) bug after an https connection hits the keepalive timeout and reconnects to the server. The solution seems to be configuring the server to not use keepalive for IE under https.
Microsoft's hotfix for KB821814 can set Content-Length to 0:
The hotfix that this article describes implements a code change in Wininet.dll to:
Detect the RESET condition on a POST request.
Save the data that is to be posted.
Retry the POST request with the content length set to 0. This prevents the reset from occurring and permits the authentication process to complete.
Retry the original POST request.
curl sends PUT/POST requests with Content-Length: 0 when configured to use HTTP proxy. It's trick to overcome required buffering in case of first unauthorized PUT/POST request to proxy. In case of GET/HEAD requests curl simply repeats the query. The scheme for PUT/POST is like:
Send first PUT/POST request with Content-Length set to 0.
Get answer. HTTP status code of 407 means we have to use proxy
authorization. Prepare headers for proxy authentication for send request.
Send request again with filled headers for proxy authentication and real data to POST/PUT.

Resources