ASIHTTPRequest setDomain -> NSURLRequest equivalent? - objective-c

I'm attempting to transition some old code for SOAP requests that relied heavily on the ASIHTTPRequest library, to instead use the standard NSMutableURLRequest instead. However, I'm running an issue: while with ASIHTTPRequest I had access to a setDomain function, I can't seem to find an equivalent with NSMutableURLRequest.
Does anyone know if there is an equivalent function? I've tried setting it as a header named "Domain", but that didn't seem to work.

Ended up following some advice from: iPhone - NTLM, Basic and other authorizations using async NSURLConnection
Turns out, you don't have to set the domain independently; you can set it by passing it as part of the username like so:
domain\\username
within an NSURLCredentials object. The exact code I ended up using was:
//takes care of HTTP Authentication
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
NSString* authMethod = [[challenge protectionSpace] authenticationMethod];
if ([authMethod isEqualToString:NSURLAuthenticationMethodNTLM]) {
NSURLCredential *credential = [NSURLCredential credentialWithUser:[NSString stringWithFormat:#"domain\\%#", self.userName]
password:self.password
persistence:NSURLCredentialPersistenceForSession];
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
}
}
This all assuming the class is an NSURLConnectionDeligate, of course.

Related

Two way SSL failed on WatchOS2.1, but same code works on iOS9.1

I was trying to communicate with a service with two way SSL.
I found the connection was cancelled immediately after the client (watch) provide the client certificate, by calling completeHandler(NSURLSessionAuthChallengeUseCredential, credential)
The error got is:
NSURLErrorDomain Code=-999 cancelled
But I've tried run the same piece of code on a phone, it did succeed.
Apart from that, other requests work fine on the watch.
Since, the frameworks on WatchOS and iOS are different, I am wondering if that might be an issue for WatchOS? Or is there anything specifically need to be configured for the watch?
Here is the code
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler
{
NSURLProtectionSpace *protectionSpace = [challenge protectionSpace];
NSString *authMethod = [protectionSpace authenticationMethod];
if (authMethod == NSURLAuthenticationMethodServerTrust) {
completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:serverTrust]);
} else if (authMethod == NSURLAuthenticationMethodClientCertificate) {
// cancelled immediately after calling the method below.
completionHandler(NSURLSessionAuthChallengeUseCredential, self.credential);
} else {
completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
}
}
Confirmed by Apple engineer.
It is an restriction of Watch OS. Two way SSL is not supported for now.

How can I check if my OS X application can connect to a specific server-- assuming there is internet connection?

I currently am using AFNetworking to determine if my application has network reachability.
NSNumber *s = notification.userInfo[AFNetworkingReachabilityNotificationStatusItem];
AFNetworkReachabilityStatus status = [s integerValue];
if (status == AFNetworkReachabilityStatusReachableViaWWAN || status == AFNetworkReachabilityStatusReachableViaWiFi) {
But, now I also need to know if my application can reach a specific server. More specifically, the server I am connecting to may be down and I need a way to determine if this is the case, from the client side, so I can notify my users appropriately.
It's a very tough google because all searches I do just point me to "How to determine network reachability". Has anybody dealt with this before, and have a solution in mind?
EDIT: #AvT recommended a promising looking solution, so I tried it like this:
self.testTSCReachabilityManager = [AFNetworkReachabilityManager managerForDomain:#"www.asdasfjsldfkjslefjslkjslfs.com"];
__weak MyObject *weakSelf = self;
[self.testReachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
if (weakSelf.testReachabilityManager.reachable) {
NSLog(#"YES");
}
else
{
NSLog(#"NO");
}
}];
But unfortunately, it is logging out "YES" for me, even after I have confirmed it is most definitely not reachable.
Instantiate AFNetworkReachabilityManager with class method
+ (instancetype)managerForDomain:(NSString *)domain;
and pass string with the required domain. AFNetworkReachabilityManager will check reachability of this domain.
If serverURL is an url of your server you should use it the following way:
[AFNetworkReachabilityManager managerForDomain:serverURL.host]
Update
Following code works as expected:
static AFNetworkReachabilityManager *testTSCReachabilityManager;
testTSCReachabilityManager = [AFNetworkReachabilityManager managerForDomain:#"www.asdasfjsldfkjslefjslkjslfs.com"];
[testTSCReachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
if (testTSCReachabilityManager.reachable) {
NSLog(#"YES");
}
else
{
NSLog(#"NO");
}
}];
[testTSCReachabilityManager startMonitoring];
Update: I actually ended up going w/ a different implementation than what Avt recommended, and did what matt recommended in the comments instead
I created an NSURLRequest and make a request to my server, then used the delegate callbacks to determine if the server was reachable. Works like a charm
-(void)checkConnectionToServers
{
NSMutableURLRequest* request = [NSMutableURLRequest new];
request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"www.myserver.com"] cachePolicy:0 timeoutInterval:(NSTimeInterval)5.0];
[request setHTTPMethod:#"GET"];
[NSURLConnection connectionWithRequest:request delegate:self];
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSLog(#"SUCCESS");
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"FAIL");
}

NSURLCredential-credentialForTrust vs username:password

I am new with iOS and https stuffs. I am a beginning software student. I want to write an app that extract the data (such as class number, announcements, etc) from my uni account and show me on my app.
Normally, I go to my uni student page, login with my username and password, and those information showed up on the browser.
I've tried using NSURLConnection and its delegate. please look at my code below. In the beginning, in the method connection:didReceviveAuthenticationChallenge, I created an NSURLCredential object by [NSURLCredential withUser:password:persistence]. And it was not working. Then I tried to do NSLog, then i just found out that the protectionSpace.authenticationMethod is NSURLAuthenticationMethodServerTrust.
Then, I tried to read Apple's document and some googled sources. But, I can't really get it, and then I edited my code as you seen below (it is my final edition, and its still not working).
The point that i don't really get is: I expect that the server should ask me for my username and password. Instead of that, it asked for credentialForTrust, which based on those documents I've read, they suggest me to evaluate the trust of NSURLConnection delegate against the server. However, the server never asked for username and password. so, how can the server know which account I am accessing.
So, i think it should be some relationship between that certificate(trust) with username and password. I don't really understand how these things work.
I think, my question might not be really clear or something, and it might be foolish. I accept this because I've never learned all these things.
So, please someones explain me of how these things work. You can assume that I have some basic understanding of what is https, SSL, NSURLConnection, NSURLCredential, etc. and please guide me to the solution.
I am appreciate for all your efforts.
Below is my code, (it's not working).
The NSLog() in connection:didReceiveAuthenticationChallenge, print out "NSURLAuthenticationMethodServerTrust"
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
{
return YES;
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
NSLog(#"authenticationMethod is: %#\n",challenge.protectionSpace.authenticationMethod);
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]){
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
}else{
NSURLCredential *creden = [[NSURLCredential alloc] initWithUser:myusername password:mypassword persistence:NSURLCredentialPersistenceForSession];
[[challenge sender] useCredential:creden forAuthenticationChallenge:challenge];
}
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError: %#\n %#\n",
[error localizedDescription],
[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[self.myData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[self.myData setLength:0];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSString *str = [[NSString alloc] initWithData:self.myData encoding:NSASCIIStringEncoding];
NSLog(#"Data in String %#", str);
}
NSURLAuthenticationMethodServerTrust challenges occur when the URL Loading system doesn't trust the server. If you want to avoid those calls, make sure that iOS trusts your server's cert (by installing it manually , or having a trusted root like Verisign sign it).

How to handle different requests using connectionDidFinishLoading in the same delegate?

Whenever I do a curl call using the below code:
NSURL *url = [NSURL URLWithString:requestURL];
NSURLRequest *request = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:30];
if (connectionInProgress) {
[connectionInProgress cancel];
}
connectionInProgress = [[NSURLConnection alloc]initWithRequest:request delegate:self startImmediately:YES];
connectionDidFinishLoading is my final destination where I can manipulate the response data and call my next methods to continue with the app . If I hard-code some specific tasks like
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:xmlData];
[parser setDelegate:self];
[parser parse];
[someLabel setText:parsedTextFromXMLData];
}
If I need to do another curl call to a different address, wouldn't someLabel setText always get re-set again? Is there a way to make this delegate function behave differently on each curl call? (btw, is connectionDidFinishLoading usually the right place to put the next step of codes?) If so then wouldn't it always get called again by the next curl call?
Have a look at this S.O. post for a recipe concerning NSURLConnection and multiple requests.The suggestion is doing something like this:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
if (connection == firstConnection) {
// do something
}
else if (connection == secondConnection) {
// do something else
}
}
EDIT: the idea here is that connectionDidFinishLoading is a method of your own delegate (so you write it). In the delegate, you store the address of each connection you create; then, when the connection comes back with the data, you tell which connection it is by comparing its address to the one you stored in the delegate. -END EDIT
Another option you have is using the ASIHTTPRequest framework, which offers a request-based (as opposed to connection-based) delegation mechanism, so each request has got a delegate object to handle the result; or, in other words, the delegate receives a reference to the request, so you can easily tell which request result you are handling.
ASIHTTPRequest offers a bunch of advantages over NSURLConnection. You can read about them in this S.O. post.
There're 2 options to do this:
you can implement a separate class, that will be responsible for handling NSURLConnection delegate stuff and create a separate instance for each request
you can use NSObject key-value methods on NSURLConnection instance for setting up some tag, that will be checked in connectionDidFinishLoading: method
For me, option 1 will be a better approach

How to set "CURLOPT_USERPWD" field of libcurl in NSURLConnection

I am trying to access a web service using NSURConnection, but i am not sure how to send password there because the example code given in php is setting CURLOPT_USERPWD field of libcurl, and there seems to be no such field in NSURLConnection/NSURLReqest.
Take the username and password, and concat them together with a colon. Take the resulting string and Base64 encode it. Take the Base64 encoded string, and prepend "Basic " (with the space). Now take that string (Basic [Base64 encoded value]) and set it as the "Authorization" header for your request.
Alternatively, if you're using the NSURLConnection delegate methods, you can implement one of them with something like:
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
NSURLCredential * credential = [NSURLCredential credentialWithUser:username password:password persistence:NSURLCredentialPersistenceForSession];
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
}
(warning: untested, typed in a browser. caveat implementor)