iOS 5 - connect to an HTTPS server - ios

I am trying to overcome the change done in iOS 5 regarding the NSURLConnection.
Basically the methods changed, so if you need to connect to a site that uses HTTPS and send credentials to authenticate, you cannot do it anymore, because many methods were deprecated.
Is there any place where I can get a working example of how should I write the code to use iOS5 compliant code? I've check the documentation and the headers but not a single source around show me how to make such connection with an example, that shows where the code goes in which file (assume that I just start from a standard template from Xcode, like the single view template or the tab bar template).
I would really appreciate any suggestion; Since my app will run on iOS 5 I would like to use the new procedure, but the lack of documentation and tutorials are making my task harder than what I thought.

You should use the NSURLCredentialStorage singleton. You need to add the credentials to the storage before using NSURLConnection by calling one of the NSURLCredentialStorage methods, for instance:
- (void)setCredential:(NSURLCredential *)credential forProtectionSpace:(NSURLProtectionSpace *)protectionSpace

I use this:
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:
(NSURLAuthenticationChallenge *)challenge {
if ([challenge previousFailureCount] <= maxRetryCount ) {
NSURLCredential *newCredential =
[NSURLCredential
credentialWithUser: userName
password:password
persistence:NSURLCredentialPersistenceForSession];
[[challenge sender]
useCredential:newCredential
forAuthenticationChallenge:challenge];
}
else
{
NSLog(#"Failure count %d",[challenge previousFailureCount]);
}
}
This works fine for me. However, it looks like self signed certificates are accepted too. I probably need to post a separate question about that.

Related

Basic Authentication failures with iOS 8

I have an iOS app that interacts with a server running Rails, and has been stable and reliable for 3 years. The server requires Basic and SSL certification, and this has been working perfectly fine right up to and including iOS 7.
However, I am now seeing authentication issues with devices running iOS 8. Devices / simulators running < iOS 8 continue to work fine.
On app initialization, there is a flurry of data requests to sync with the server that need to pass Basic authentication.
These result in the following delegate method being called,
willSendRequestForAuthenticationChallenge
...and the problem occurs because these are being challenged endlessly - the code deliberately fails on the second try when [challenge previousFailureCount] > 0 (the code path follows standard practice by calling cancelAuthenticationChallenge if the previousFailureCount > 0) - see below.
I've logged the challenge ids, and these are different across each challenge, even when the previousFailureCount > 0.
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodHTTPBasic])
{
if ([challenge previousFailureCount] == 0)
{
NSURLCredential *newCredential;
newCredential = [NSURLCredential credentialWithUser:MY_USERNAME
password:MY_PASSWORD
persistence:NSURLCredentialPersistenceForSession]; // Retain for rest of session
[[challenge sender] useCredential:newCredential forAuthenticationChallenge:challenge];
}
else
{
[[challenge sender] cancelAuthenticationChallenge:challenge];
// ...error will be handled by connection didFailWithError
}
}
}
If I knock out the call to check the previousFailureCount, there are endless invocations of the challenge method.
However, once this flurry of failures has failed, the subsequent and later 'individual' NSUrlRequests are successfully authenticated.
Again, this problem is specific to iOS 8. Any ideas why a 'fast' succession of authentication requests would fail in iOS 8, but work in iOS 7?
Thanks.
In case you are not handling the authentication method (NSURLAuthenticationMethodHTTPBasic) you must invoke one of these methods anyway:
useCredential:forAuthenticationChallenge:
continueWithoutCredentialForAuthenticationChallenge:
cancelAuthenticationChallenge:
performDefaultHandlingForAuthenticationChallenge:
rejectProtectionSpaceAndContinueWithChallenge:
If you want to ignore a certain authentication method you preferable might want to invoke performDefaultHandlingForAuthenticationChallenge:.
See also: connection:willSendRequestForAuthenticationChallenge:
I have the same issue, I deleted the if([challenge previousFailureCount] == 0) , and it works.
But I don't know why it fails in IOS 8.
The answer / update to this question also fixed the problem I was seeing.
NSURLConnection timing out on iOS8
Again, something changed in iOS 8, requiring this fix.

NSURLConnection Error code (-1202,1012)

I am using NSURLConnection for one field service type iOS appliation, so app is field service type there are more then 50 users and more then 50 users may use the application on same time that's why there are more then 50 or 60 request come to the server. Now my issue is I have received below two errors frequently means every single user can face this error more then 5 times in one day. so it become a challenge for me.
The Error Code:
-1202 NSURLErrorServerCertificateUntrusted
-1012 NSURLErrorUserCancelledAuthentication
I have searched a lot and i found that they are server related errors but still i don't have any solution for how to resolve this problem.
Please help me how can i solve this NSURLConnection error (-1202 NSURLErrorServerCertificateUntrusted and -1012 NSURLErrorUserCancelledAuthentication) problem.
Thanks in advance.
You need to use connectionWithRequest:delegate: to accept untrusted certificates.
You can implement these delegate methods
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
{
return YES;
}
- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection
{
return YES;
}

How get the status of a server without download the page content in IOS

I want to check if a web ressource is available without download any data. For exemple, if I do a NSURLConnection on a webPage, I can get the status code:
- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
int code = [httpResponse statusCode];//200 is ok
}
But all page datas are downloaded.
How can I get this code (or equivalent) without download this page ?
The status code comes along with the server answer, once you get the status code you will have the body as well.
Another option is maybe to check if the resource is reachable using the Reachability classes.
Check this example, it may help.
Update: borrrden pointed in the right direction here (use HEAD method instead of GET) check the comment on your anwser

How to check status of web server in iOS?

I need to check status of web server, specifically, the information if the web server returns proper status code 200. Is there any way to get the HTTP response code from web server in iOS?
This is well documented in the official docs, with no need to implement a 3rd party library (although if you're new to iOS coding, a Networking API can simplify the underlying function calls). Your class must be an NSURLConnection delegate, and after making the NSURLConnection you implement the delegate method something like this:
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse*)response
{
if ([response statusCode] == 200) {
// Handle valid response (You can probably just let the connection continue)
}
else {
// Other status code logic here (perhaps cancel the NSURLConnection and show error)
}
}
You should find the URL Loading Guide very useful reading for this and other networking functions on iOS.

How to make webservice pass errors through NSURLConnection's connection:didFailWithError:?

What does a web service need to do to cause NSURLConnection's delegate to receive the connection:didFailWithError: message?
For example:
iOS app passes a token to the web service, web service looks up the token, and then the web service needs to respond with an error saying "invalid token" or something of the like.
Currently, the data is received, and in "connectionDidFinishLoading:" is parsed for error messages. This means I'm error checking in two places, which I am trying to avoid.
I have both the iOS app and web service completely under my control.
In my experience (the three most dangerous words in programming), -connection:didFailWithError: is only called if the HTTP exchange failed. This is usually a network error or maybe an authentication error (I don't use authentication). If the HTTP message succeeds, no matter the response code, -connectionDidFinishLoading: is called.
My solution: call -connection:didFailWithError: when I detected an error. That way all my error handling code is in one place.
At the top of my -connectionDidFinishLoading:, I have:
NSError *error;
NSDictionary *result = [self parseResultWithData:self.connectionData error:&error];
if (!result) {
[self connection:connection didFailWithError:error];
return;
}
There are many conditions on which the delegate connection:didFailWithError: of NSUrlConnection may invoke.Here's a list of those errors or constants.I think an alertview would be better to show http errors in connection:didFailWithError:.
-(void) connection:(NSURLConnection *)connection didFailWithError: (NSError *)error
{
UIAlertView *errorAlert= [[UIAlertView alloc] initWithTitle: [error localizedDescription] message: [error localizedFailureReason] delegate:nil cancelButtonTitle:#"Done" otherButtonTitles:nil];
[errorAlert show];
[errorAlert release];
NSLog (#"Connection Failed");
}
While not directly related to your question, I would encourage you to move to a more high level library. I can heartily recommend AFNetworking, it is production ready and I have used it in many projects. This will allow you to inspect the response code of each request in the failure block. This project also abstracts away a lot of the low level handling that you would otherwise be required to write for network communication; I'm speaking here about parsing and creating XML / JSON strings to communicate with a service.
To give you a more focused answer to your question, I would call the cancel method of your NSURLConnection once you have noticed an error in connectionDidFinishLoading:. This will automatically cancel the request and call the failure method of the delegate object.
The documentation for NSURLConnection is pretty dry, and the failure method of the delegate does not specifically document the failure cases. You may be able to find more information in the URL Loading System Programming Guide.
I couldn't see the forrest for the trees.
I needed to step back from connection:didFailWithError: and look at a different delegate method connection:didReceiveResponse:!!
With the web service fully under my control, the endpoint could respond with a 500 status code, which gets picked up in connection:didReceiveResponse, and pass along some JSON further explaining the situation, which gets picked up and processed in connection:didReceiveData:.
The NSURLConnection delegate hangs onto a couple more bits of state throughout the process, but it has the best code smell I've found so far.
Jeffery's answer was by far most correct: the connection:didFailWithError: callback is only in relation to the network failing, any response from the web service means the connection didn't fail!

Resources