0

I have been googling this problem for hours now, and I can't seem to find a solution.

The last tutorial I followed was this tutorial explaining how I could send a JSON request over an untrusted SSL connection (in this case, a self-signed certificate).

In short, the code I have tried so far is this one:

This method checks if the token is valid with my web API:

-(BOOL)linked
{
    if([self token] == nil)
    {
        return NO;
    }else
    {
        NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@?token=%@&object=User&action=check_authorized", SPAtajosApiLink, [self token], nil]];
        NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
        [req setHTTPMethod:@"POST"];
        NSLog(@"%@", req);
        [req setHTTPBody: [mandatoryParameters dataUsingEncoding: NSUTF8StringEncoding]];

        NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:req delegate:self];
        [connection start];

        NSDictionary *validity = [NSJSONSerialization
                                  JSONObjectWithData:[NSURLConnection sendSynchronousRequest:req returningResponse:nil error:nil]
                                  options:NSJSONReadingMutableContainers
                                  error:nil];
        NSLog(@"RESPONSE LINKED %@ %@", validity[@"code"], validity[@"message"]);
    }
    return YES;
}

And I have implemented the NSURLConnectionDelegate methods as follows:

- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
{
    return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
}

- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
    {
        NSLog(@"API LINK %@", challenge.protectionSpace.host);
        if ([challenge.protectionSpace.host isEqualToString:SPAtajosApiLink])
        {
            [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
        }
    }

    [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}

Yet, my app always crashes with the following message:

2013-10-15 22:48:55.382 Atajos[733:60b] { URL: https://MY_API_URL/www/?token=657fd6c02b3ba439e69b060f7f7680cc&object=User&action=check_authorized } 2013-10-15 22:48:58.045 Atajos[733:3b17] NSURLConnection/CFURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813) 2013-10-15 22:48:58.049 Atajos[733:60b] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'data parameter is nil' * First throw call stack: (0x2ec2de8b 0x38f286c7 0x2ec2ddcd 0x2f5b5d77 0x5df9d 0x62395 0x31433025 0x3141e631 0x313b8be7 0x313b7edd 0x3141dca1 0x3389976d 0x33899357 0x2ebf877f 0x2ebf871b 0x2ebf6ee7 0x2eb61541 0x2eb61323 0x3141cf43 0x314181e5 0x62191 0x39421ab7) libc++abi.dylib: terminating with uncaught exception of type NSException

Okay, so NSData, presumably the parameter in NSJSONSerialization is NULL. The question, why?

Bizarrely enough I have a similar code that actually works with a UIWebView interacting with a website over untrusted SSL:

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    //Need to rebuild base URL. Otherwise I get the parameters which will always fail the check.
    NSURL *requestUrl = [request URL];
    NSString *basicPathString = [NSString stringWithFormat:@"%@://%@:%@%@", requestUrl.scheme, requestUrl.host, requestUrl.port, requestUrl.path];
    NSLog(@"%@", basicPathString);

    if([basicPathString isEqualToString:SPAtajosLoginLink])
    {

        __block NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfURL:request.URL.absoluteURL]
                                                                             options:NSJSONReadingMutableContainers
                                                                               error:nil];
        NSLog(@"Auth token is %@", jsonResponse[@"token"]);
        [self dismissViewControllerAnimated:YES completion:^{
            if([jsonResponse[@"code"] isEqualToNumber:[NSNumber numberWithInt:200]])
            {
                [[PDKeychainBindings sharedKeychainBindings] setObject:jsonResponse[@"token"]
                                                                forKey:@"com.shortcutpublicity.ios.atajos.userAccessToken"];
            }else
            {
                UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"No Se Pudo Autenticar", @"Error 500 title")
                message:NSLocalizedString(@"Se ha producido un error interno del servidor (500). Por favor, trata de nuevo más tarde.", @"Error describing error 500")
                delegate:nil
                cancelButtonTitle:NSLocalizedString(@"Aceptar", @"Accept") otherButtonTitles:nil];
                [alertView show];
            }
         }];
    }else {
    //--------------THIS IS THE RELEVANT PART------------
        BOOL result = _Authenticated;
        if (!_Authenticated)
        {
            _FailedRequest = request;
            NSURLConnection *trash = [[NSURLConnection alloc] initWithRequest:request delegate:self];
            if(trash)
            {
                NSLog(@"Allocated succesfully.");
            }
        }
        return result;
    }
    return YES;
}

-(void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
        NSURL* baseURL = [NSURL URLWithString:SPatajosAuthLink];
        if ([challenge.protectionSpace.host isEqualToString:baseURL.host]) {
            NSLog(@"trusting connection to host %@", challenge.protectionSpace.host);
            [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
        } else
            NSLog(@"Not trusting connection to host %@", challenge.protectionSpace.host);
    }
    [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}

-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)pResponse {
    _Authenticated = YES;
    [connection cancel];
    [_webView loadRequest:_FailedRequest];
}

I have tried to adapt this code that works with a WebView but I haven't had any luck adapting to use it with a NSURLConnection.

To be honest, I'm not quite sure I know how these workarounds work. I have been stealing and attempting to adapt other people's code to no avail. I have looked at NSURLConnection and NSURLRequest docs and I wasn't able to solve these problems. Please help me out.

Andy Ibanez
  • 12,104
  • 9
  • 65
  • 100
  • Have you set breakpoints in the delegate methods to make sure they are being called? – neilco Oct 16 '13 at 07:45
  • For whatever reason the delegate methods aren't being called... Well let's keep debugging. – Andy Ibanez Oct 16 '13 at 20:30
  • You are not using `NSURLConnection` delegate approach correctly! That is, you setup a delegate approach - but then invoking the synchronous convenient class method. This makes absolutely no sense. Furthermore, you should be aware that you are omitting server trust verification. This is OK only for testing. – CouchDeveloper Oct 17 '13 at 19:34

2 Answers2

1

We use this category in an #ifedf block for testing... make sure you DO NOT leave this in production:

#ifdef DEBUG
@interface NSURLRequest (IgnoreSSL)
   +(BOOL)allowsAnyHTTPSCertificateForHost:(NSString*)host;
@end
@implementation NSURLRequest (IgnoreSSL)
   +(BOOL)allowsAnyHTTPSCertificateForHost:(NSString*)host {return YES;}
@end
#endif
Cliff Ribaudo
  • 8,932
  • 2
  • 55
  • 78
0
try this Delegate method    




 - (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
    {



        //    SecTrustRef trustRef = [[challenge protectionSpace] serverTrust];
        //    SecTrustEvaluate(trustRef, NULL);
        //
        //    SecCertificateRef certRef = SecTrustGetCertificateAtIndex(trustRef, 0);
        //
        //    NSData *certificateData = (__bridge NSData *) SecCertificateCopyData(certRef);
        //    NSLog(@"Subject: %@", [[NSString alloc] initWithData:certificateData encoding:NSUTF8StringEncoding]);

        // [[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge];


        SecTrustRef trust = challenge.protectionSpace.serverTrust;
        NSURLCredential *cred;
        cred = [NSURLCredential credentialForTrust:trust];
        [challenge.sender useCredential:cred forAuthenticationChallenge:challenge];



    }
Muralikrishna
  • 1,044
  • 10
  • 17