2

I am attempting to connect to an API using a self-signed certificate for testing.

  -(NSData*)getDataFromPostRequestWithHeaders:(NSDictionary*)headers      withPostData:(NSData*)postData fromURL:(NSString*)urlString
    {
    __block NSData* responseData;

    NSLog(@"URL is %@", urlString);
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]
                                                           cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                       timeoutInterval:10.0];
    [request setHTTPMethod:@"POST"];
    [request setHTTPBody:postData];
    [request setAllHTTPHeaderFields:headers];

    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
   // [config setHTTPAdditionalHeaders:headers];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];
    NSLog(@"%@", @"NSURLSession started successfully");
    // I.e. no I do not need to have a queue of sessions running in parallel currently.
   NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
                                                completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
                                            {
                                                NSLog(@"%@", @"completionHandler called successfully");
                                                    if (error) {
                                                        NSLog(@"Error whilst executing post request: %@", error);
                                                    } else {
                                                        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
                                                        NSLog(@"HTTP response from this request is %@", httpResponse);
                                                        responseData = data;
                                                    }
                                                }];
    [dataTask resume];

    return responseData;
}

This is my didReceiveChallenge() method:

-(void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler
{
    NSLog(@"%@", @"didReceiveChallenge method of NSURLSessionDelegate called successfully");
   if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
    {
        if ([challenge.protectionSpace.host isEqualToString:@"https://dongu.ravenlabs.co.uk"])
        {
            NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
            completionHandler(NSURLSessionAuthChallengeUseCredential, credential); // I.e. if it is this domain, then yes we can trust it.
        }
    }
}

The first one is called within a login method like so:

-(NSString*)loginUserAndRetrieveSessionID:(NSString*)userName withPassword:(NSString*)password
{
    __block NSDictionary *responseDict;
   NSDictionary *loginHeaders = @{ @"content-type": @"application/json",
                               @"accept": @"application/json",
                               @"cache-control": @"no-cache",
                               };
    NSDictionary *parameters = @{ @"login": userName,
                                  @"password": password };

    NSData *postData = [NSJSONSerialization dataWithJSONObject:parameters options:0 error:nil];
    NSString *urlString = [DONGU_API_BASE_URL stringByAppendingString:@"/session/"];
    NSData *responseData = [self getDataFromPostRequestWithHeaders:loginHeaders withPostData:postData fromURL:urlString];
    if (responseData)
    {
    responseDict = [self getDictionaryFromResponseData:responseData];
    }
    NSLog(@"%@", @"End of login method reached.");
    return [responseDict objectForKey:@"session-token"];

}

Whenever didReceiveChallenge is called, the app freezes completely. Is there a way around this? I've tried using GCD for calling the login method, and no joy. Is there any way around this?

Michael Dautermann
  • 88,797
  • 17
  • 166
  • 215
Michael Nares
  • 401
  • 4
  • 19

1 Answers1

0

You must call the provided completion handler every time that method is called, or else the connection will make no further progress. If you don't know what do do with a particular challenge, call it with ...PerformDefaultHandling.

Additionally, please be aware that the way you're disabling certificate validation is very, very unsafe. At a bare minimum, you should be comparing the provided public key with a known-valid public key stored in your app somewhere, and only if it matches should you tell the OS to use that credential. Otherwise, you run the risk of this code accidentally ending up in your shipping app, and losing all the benefits of TLS.

dgatwood
  • 10,129
  • 1
  • 28
  • 49