Синхронная обработка SSL-сертификата на iPhone - PullRequest
3 голосов
/ 26 августа 2010

Мне было интересно, может ли кто-нибудь помочь мне понять, как добавить обработку SSL-сертификата в синхронный подключения к службе https.

Я знаю, как это сделать с асинхронными подключениями, но не синхронно.

                NSString *URLpath = @"https://mydomain.com/";
    NSURL *myURL = [[NSURL alloc] initWithString:URLpath];
    NSMutableURLRequest *myURLRequest = [NSMutableURLRequest requestWithURL:myURL cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:60];
    [myURL release];
    [myURLRequest setHTTPMethod:@"POST"];

    NSString *httpBodystr = @"setting1=1";
    [myURLRequest setHTTPBody:[httpBodystr dataUsingEncoding:NSUTF8StringEncoding]];

    NSHTTPURLResponse* myURLResponse; 
    NSError* myError;
    NSData* myDataResult = [NSURLConnection sendSynchronousRequest:myURLRequest returningResponse:&myURLResponse error:&myError];

            //I guess I am meant to put some SSL handling code here

Спасибо.

Ответы [ 3 ]

7 голосов
/ 17 сентября 2013

Использование статической функции sendSynchronousRequest невозможно, но я нашел альтернативу.

Прежде всего NSURLConnectionDataDelegate объект, подобный этому

FailCertificateDelegate.h

@interface FailCertificateDelegate : NSObject <NSURLConnectionDataDelegate>
   @property(atomic,retain)NSCondition *downloaded;
   @property(nonatomic,retain)NSData *dataDownloaded;
   -(NSData *)getData;
@end

FailCertificateDelegate.m

#import "FailCertificateDelegate.h"

@implementation FailCertificateDelegate
@synthesize dataDownloaded,downloaded;
-(id)init{
    self = [super init];
    if (self){
        dataDownloaded=nil;
        downloaded=[[NSCondition alloc] init];   
    }
    return self;
}


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


- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:    (NSURLAuthenticationChallenge *)challenge {
     NSLog(@"didReceiveAuthenticationChallenge:");
    [challenge.sender useCredential:[NSURLCredential     credentialForTrust:challenge.protectionSpace.serverTrust]     forAuthenticationChallenge:challenge];
}


- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    [downloaded signal]; 
    [downloaded unlock];
    self.hasFinnishLoading = YES; 
} 
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
    [dataDownloaded appendData:data];
    [downloaded lock]; 
} 

-(NSData *)getData{
    if (!self.hasFinnishLoading){
        [downloaded lock]; 
        [downloaded wait]; 
        [downloaded unlock]; 
    } 

    return dataDownloaded; 
}

@end

А для использования это

FailCertificateDelegate *fcd=[[FailCertificateDelegate alloc] init];
NSURLConnection *c=[[NSURLConnection alloc] initWithRequest:request delegate:fcd startImmediately:NO];
[c setDelegateQueue:[[NSOperationQueue alloc] init]];
[c start];    
NSData *d=[fcd getData];

Теперь у вас будут все преимущества асинхронного использования nsurlconnection и преимущества простого соединения синхронизации. Поток будет заблокирован до тех пор, пока вы не загрузите все данные делегата, но вы можете улучшить его, добавив некоторую защиту от ошибок в классе FailCertificateDelegate

РЕДАКТИРОВАТЬ: исправить для больших данных. по комментарию Николая Д.С. Большое спасибо

0 голосов
/ 22 февраля 2011

У меня была похожая проблема. В моем случае у меня было a-синхронное соединение, работающее с ssl, как требуется, с использованием двух методов делегата, которые позволили мне принять любой сертификат:

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

- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
}

Но я застрял на том же синхронном режиме. Я искал в Интернете, пока не нашел ваше сообщение и, к сожалению, еще одно сообщение stackoverflow , где намекнули, что вы не можете выполнять синхронизирующие вызовы NSURLConnection и работать с ssl (из-за отсутствия делегата для обработки процесса аутентификации ssl ). В итоге я получил ASIHTTPRequest и использовал его. Это было безболезненно, и мне потребовалось около часа, чтобы все настроить. вот как я это использую.

+ (NSString *) getSynchronously:(NSDictionary *)parameters {
    NSURL *url = [NSURL URLWithString:@"https://localhost:8443/MyApp/";
    ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
    NSString *parameterJSONString = [parameters JSONRepresentation];
    [request appendPostString:parameterJSONString];
    [request addRequestHeader:@"User-Agent" value:@"MyAgent"];
    request.timeOutSeconds = CONNECTION_TIME_OUT_INTERVAL;
    [request setValidatesSecureCertificate:NO];
    [request startSynchronous];

    NSString *responseString = [request responseString];
    if (request.error) {
        NSLog(@"Server connection failed: %@", [request.error localizedDescription]);
    } else {
        NSLog(@"Server response: %@", responseString);
    }

    return responseString;
}

Важной частью, конечно же, является

[request setValidatesSecureCertificate:NO];

Другая альтернатива для вас - обработать загрузку в другом потоке с подключением a-synch, используя два вышеописанных метода, и заблокировать поток, из которого вы хотите, подключение синхронизации до тех пор, пока запрос не будет завершен

0 голосов
/ 28 августа 2010

Я близок к тому, чтобы найти решение для этого с кодом ниже.Это работает, но часто происходит сбой, вероятно, потому, что я делаю что-то не так в коде, а у меня нет четкого понимания используемых методов.Но если у кого-то есть какие-либо предложения о том, как улучшить это, пожалуйста, напишите.

Сразу после строки:

NSError* myError;

и непосредственно перед строкой:

NSData* myDataResult = [NSURLConnection sendSynchronousRequest:myURLRequest       
returningResponse:&myURLResponse error:&myError];

добавить:

    int failureCount = 0;
    NSURLProtectionSpace *protectionSpace = [[NSURLProtectionSpace alloc]      
    initWithHost:@"mydomain.com" port:443 protocol:@"https"  realm:nil  
    authenticationMethod:NSURLAuthenticationMethodServerTrust];

    NSURLResponse *response = [[NSURLResponse alloc] initWithURL:myURL MIMEType:@"text/html" 
    expectedContentLength:-1 textEncodingName:nil]; 

    NSURLAuthenticationChallenge *challange = [[NSURLAuthenticationChallenge alloc] 
    initWithProtectionSpace:protectionSpace proposedCredential:[NSURLCredential 
    credentialForTrust:protectionSpace.serverTrust] previousFailureCount:failureCount 
    failureResponse:response error:myError sender:nil];
...