I'm handling the server trust authentication challenge in a custom way (comparing the public key from the server trust with a hashed local version) through the urlSessionDelegate, similarly to how it is done here:
How do I accept a self-signed SSL certificate using iOS 7's NSURLSession and its family of delegate methods for development purposes?
As described in the documentation, I need to cancel the challenge if I want to fail the server trust authentication myself. When doing this, my data task will complete with the NSURLErrorCancelled. I have some error handling classes which look at the resulting NSURLError returned by the datatask, and it would be a lot cleaner for me if I got NSURLErrorServerCertificateUntrusted instead.
Is there a way to achieve that? Or will those server errors only be forwarded when the authentication is handled automatically, without the delegate methods?
Would the normal handling of the certificate in question fail with that error?
If so, you could use NSURLSessionAuthChallengePerformDefaultHandling in that case.
If not, I think the only way would involve mucking around with the challenge sender, which is highly discouraged, though it might not be catastrophic if you call that and afterwards call the proper completion handler. There's a good chance you'd get two callbacks, though. I've never attempted this.
My advice would be to file a bug with Apple asking for a proper API to pass an NSError along with cancellation.
Related
It seems there are a couple choices within Xcode/iOS to communicate with my server, using simple HTTP requests or creating a full blown socket system. What vulnerabilities does each have? My main concern is that I can't allow someone to replicate a call that's not from my app, like you could spoof an AJAX call by examining a webpage's Javascript and getting the address for the call. Obv it wouldn't be so simple with a phone app, but I don't know what's possible for hackers.
Use HTTPS.
Override the TLS chain validation to fail if the public key doesn't match the one stored in your app.
In Apple's TLS validation doc below, start with "Listing 3 Overriding the trust object used by an NSURLConnection object", then add code so that if certificate evaluation succeeds, you check the key inside the challenge's protection space against a known-valid key (or keys) before allowing the connection to proceed.
I'm trying to handle Alamofire errors globally, similar to this: AFNetworking: Handle error globally and repeat request
One use case would be to detect a 400 status code error (unauthorized / expired API token) and present the login page. Is there a way to hook on something in the Alamofire core or should I create my own error handler and always call validate().response() manually each time?
Thanks
At the moment you will have to handle that logic in your own custom response implementation. We (the Alamofire TC) are currently working on ways that we can make this process easier, but it's very difficult to get right without complicating the rest of the APIs. We're still a ways off yet.
With that said, I built an OAuth 2.0 system that handles this process in a different non-open-source library. It is possible, it's just difficult to do. You will need to hook into the response closure for all requests that could 401. See my answer here for a full breakdown of how to do this.
Hopefully that helps shed some light. Cheers 🍻
I have an IOS6 app, that connects to a REST API to fetch some data.
I use NSURLConnection sendSynchronousRequest in my data fetcher class, and I call its methods by GCD async pattern with blocks from my controller classes. So far so good.
My problem, that I change the API endpoint to https, its certificate is self-signed (I know its secure problems etc, but it is out of question for now).
By using sendSynchronousRequest I can't bypass this problem, because to bypass it, I need to set delegate for NSURLConnection, but in case of sendSynchronousRequest I cant' set delegate, delegate methods just called in case of async calls.
I don't like async request calling, I adore this GCD/sync call pattern very much, it works like a charm, it simple and clear.
So how can I make calls to a https api endpoint by GCD and , NSURLConnection sendSynchronousRequest that bypasses untrusted certificate problem?
Thanks to all!
You answered your question already yourself:
By using sendSynchronousRequest I can't bypass this problem, because to bypass it, I need to set delegate for NSURLConnection, but in case of sendSynchronousRequest I cant' set delegate, delegate methods just called in case of async calls.
You should really get used to the asynchronous style. The approach with a synchronous call within a dispatch_async call is suboptimal to say the least.
The method sendSynchronousRequest is for beginners and toy apps. IMHO, Apple should really deprecate this method and remove it in the next iOSs.
The method sendAsynchronousRequest:queue:completionHandler: is for demonstration purposes, sample apps, prove of concept, and very simple requests not using authentication and https.
Finally, using the asynchronous style with implementing the delegates is for "serious" and release apps. Any serious app should use https when talking to a dedicated server, unless the server is public and does not support https.
Once your have switched to asynchronous style, there might be an answer to your actual question. However, there is no need to bypass a certificate - rather you will use the certificate as it is used in the release app.
I noticed that in a standard grails environment, a request is always executed to the end, even when the client connection is lost and the result can't be delivered anymore.
Is there a way to configure the environment in such a way that execution of a request is canceled as soon as the client connection is lost?
Update: Thanx fo the answers. Yes - most of the problems I am trying to avoid can be avoided by better coding:
caching can make nearly every page fast
a token can help to avoid submitting something twice
but there are some requests which still could consume some time. Let's take a map service as example. Calculating a route will take some time. One solution to avoid resubmitting the request could be a "calculationInProgress" flag together with a message to the user. But then it is still possible to create a lot of sessions and thus a lot of requests in order to do a DOS attack...
I am still curious: is there no way to configure the server to cancel the request? I used to develop on a system where the server behaved this way and it was great :-)
Probably there is no such way. And I'm sure grails (and your webcontainer) is designed to
accept incoming request
process it on server side
send response
if something happened during phase 2, i'll know about it only on send response phase. Actually you can send data to HttpSerlvetRespone by yourself, handle IOException, etc - but it will be too much low-level way, I think. And it will not help you with canceling your DB operations, while you're preparing data to send.
Btw, it's common pattern to use an web frontend, like nginx, that accepts incomming request and and handle all this problems with cancelled requests, slow requests (i guess it's the real problem?), etc.
According to your comment it is reload and multiple clicks that you are trying to avoid. The proper technique should be to use Grails support for handling multiple form submissions:
http://grails.org/doc/2.0.x/guide/theWebLayer.html#formtokens
I've just started to try out RestKit for an iOS app i'm building. I normally use ASIHttpRequest, but I want to test out RestKit mostly for its object mapping between JSON and CoreData. There are some great things about RestKit, but I've run into an issue that really makes it feel deficient, unless I'm doing something wrong or have missed something. I hope someone here can guide me on that.
I'm using RKObjectLoader to make async & sync calls to a REST API. My service is designed to send back proper HTTP status codes, along with some sort of description, a 401 being an example of when the API needs an authenticated user.
My problem is that RestKit stops acting normally if i get a 401 error back. The RKResponse object has a status code of 0, even though it has a payload in it. I'm pretty sure this comes down to NSURLConnection's poor handling of HTTP statuses, but I would expect RestKit to wrap around this somehow. Especially since the RKResponse class has quite a few wrapper functions to determine the status code of the response (isOK, isCreated, isForbidden, isUnauthorized, etc.).
In comparison, ASIHttpRequest doesn't use NSURLConnection, but instead uses the lower level CFNetwork code. ASIHttpRequest allows me to see exactly what came back over HTTP without sending out errors left & right.
Question is, am I doing something wrong, or is this the expected behavior out of RestKit? Has anyone successfully been able to make a calls to [RKResponse isAuthenticated]? Although its inconclusive to me, is there any difference between running in async and sync mode in this regard. I did read somewhere that NSURLConnection run in sync mode will act a bit differently, even though the underlying code is just calling the async operations. Does this have more to do with me using RKObjectLoader as opposed to just RKRequest? Perhaps the fact that the payload can't map to a model causes anger, but it seems that the code is breaking earlier within RKRequest.sendSynchronously, prior to when mapping actually takes place.
Bottom line is my code needs to be able to freely read HTTP status codes. Any guidance would be most appreciated.
Haider
The common way for RestKit 0.20.x is to subclass RKObjectRequestOperation.
I wrote a blog article about this problem which can be found here:
http://blog.higgsboson.tk/2013/09/03/global-request-management-with-restkit/
See http://groups.google.com/group/restkit/msg/839b84452f4b3e26
"... when authentication fails, the authentication challenge gets cancelled and that effectively voids the request."
UPDATE:
RestKit already includes a delegate method for this:
(void)request:(RKRequest *)request didFailAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
Triggers before
(void)objectLoader:(RKObjectLoader *)objectLoader didFailWithError:(NSError *)error
When HTTP Basic authentication fails, so we can use this instead.