2012-02-21 6 views
4

Я пытаюсь подключиться к http://cmis.demo.nuxeo.org/nuxeo/atom/cmis/ с помощью NSURLConnection. Этот демонстрационный веб-сервис - documented, требующий аутентификации (логин: Administrator/password: Administrator).NSURLConnection не использует учетные данные по умолчанию

Редактировать: Этот веб-сервис теперь отправляет запрос на аутентификацию, это было не в то время, когда задавался вопрос.

Это веб-сервис не послать запрос аутентификации, поэтому я не могу использовать метод connection:didReceiveAuthenticationChallenge: делегата. Вместо этого я установил по умолчанию NSURLCredential в хранилище разделяемых учетных данных. К сожалению, этот учетный параметр по умолчанию не используется NSURLConnection.

Вот мой код (с использованием ARC, проверенное на прошивке 5):

@implementation ViewController 
{ 
    NSMutableData *responseData; 
} 

- (IBAction) connect:(id)sender 
{ 
    NSString *user = @"Administrator"; 
    NSString *password = @"Administrator"; 
    NSURL *nuxeoURL = [NSURL URLWithString:@"http://cmis.demo.nuxeo.org/nuxeo/atom/cmis/"]; 

    NSURLCredential *credential = [NSURLCredential credentialWithUser:user password:password persistence:NSURLCredentialPersistenceForSession]; 
    NSString *host = [nuxeoURL host]; 
    NSNumber *port = [nuxeoURL port]; 
    NSString *protocol = [nuxeoURL scheme]; 
    NSURLProtectionSpace *protectionSpace = [[NSURLProtectionSpace alloc] initWithHost:host port:[port integerValue] protocol:protocol realm:nil authenticationMethod:NSURLAuthenticationMethodHTTPBasic]; 
    [[NSURLCredentialStorage sharedCredentialStorage] setDefaultCredential:credential forProtectionSpace:protectionSpace]; 

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:nuxeoURL]; 
    BOOL manuallyAddAuthorizationHeader = NO; 
    if (manuallyAddAuthorizationHeader) 
    { 
     NSData *authoritazion = [[NSString stringWithFormat:@"%@:%@", user, password] dataUsingEncoding:NSUTF8StringEncoding]; 
     NSString *basic = [NSString stringWithFormat:@"Basic %@", [authoritazion performSelector:@selector(base64Encoding)]]; 
     [request setValue:basic forHTTPHeaderField:@"Authorization"]; 
    } 
    NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; 
    [connection start]; 
} 

- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response 
{ 
    responseData = [NSMutableData data]; 
} 

- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data 
{ 
    [responseData appendData:data]; 
} 

- (void) connectionDidFinishLoading:(NSURLConnection *)connection 
{ 
    NSLog(@"connectionDidFinishLoading:%@", connection); 
    NSLog(@"%@", [[NSString alloc] initWithData:responseData encoding:NSISOLatin1StringEncoding]); 
} 

- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error 
{ 
    NSLog(@"connection:%@ didFailWithError:%@", connection, error); 
} 

@end 

Поскольку учетные данные по умолчанию не используются, я получаю HTML (Войти страницы) вместо XML. Если я устанавливаю переменную manuallyAddAuthorizationHeader в YES, то авторизация работает, и я получаю xml.

Мой вопрос: почему NSURLConnection не автоматически использовать по умолчанию NSURLCredential?

ответ

8

Отправка учетных данных по умолчанию без запроса проверки подлинности считается небезопасной, особенно в случае, когда вы обмениваетесь обычным HTTP. Спецификация HTTP говорит, что вы можете отправить учетные данные проактивно, но вы обычно должны ждать проверки подлинности. И это поведение, которое Cocoa предоставляет по умолчанию.

Если вам нужно проактивно отправлять учетные данные, вам придется вручную добавлять заголовки самостоятельно. Вы можете просто основывают-64 закодировать его самостоятельно, или вы можете использовать CFHTTP функции, чтобы сделать это для вас, так как:

CFHTTPMessageRef dummyRequest = 
    CFHTTPMessageCreateRequest(
     kCFAllocatorDefault, 
     CFSTR("GET"), 
     (CFURLRef)[urlRequest URL], 
     kCFHTTPVersion1_1); 
CFHTTPMessageAddAuthentication(
    dummyRequest, 
    nil, 
    (CFStringRef)username, 
    (CFStringRef)password, 
    kCFHTTPAuthenticationSchemeBasic, 
    FALSE); 
authorizationString = 
    (NSString *)CFHTTPMessageCopyHeaderFieldValue(
     dummyRequest, 
     CFSTR("Authorization")); 
CFRelease(dummyRequest); 

Тогда просто установите authorizationString как Authorization колонтитула в NSURLRequest.

(Код скопирован явно из https://stackoverflow.com/a/509480/100478, хотя я написал подобный код сами много раз.)

3

В HTTP поддерживает различные методы аутентификации (Basic, Digest, Kerberos, и т.д.), NSURLConnection не может отправлять учетные данные, прежде чем он получает вызов аутентификации с сервера, потому что он не знает, как их отправить.

+0

Я явно создал «NSURLProtectionSpace» с 'authenticationMethod: NSURLAuthenticationMethodHTTPBasic', поэтому я подумал, что теперь будет использовать этот метод. – 0xced

0

Хотя ответ BJ может решить вашу проблему на стороне клиента, реальной проблемой является сервер. Внутренне NSURLConnection будет использовать собственный эквивалент метода делегирования connection:didReceiveAuthenticationChallenge: и других методов аутентификации. Здесь он ищет учетные данные, которые он может применять с NSURLCredentialStorage. В вашем случае это, похоже, не происходит. Для этих методов, которые должны быть вызваны, сервер должен предоставить не только код статуса 40x HTTP, но также должен включать заголовок WWW-Authenticate. Это говорит NSURLConnection, чтобы попытаться ответить на вызов аутентификации. Вероятно, ваш сервер не включает это, поэтому клиент не отправляет учетные данные.

Смежные вопросы