2012-02-21 1 views
4

J'essaie de me connecter à http://cmis.demo.nuxeo.org/nuxeo/atom/cmis/ avec NSURLConnection. Ce service Web de démonstration est documented pour nécessiter une authentification (connexion: Administrateur/mot de passe: Administrateur).NSURLConnection n'utilise pas les informations d'identification par défaut

Modifier: Ce service Web envoie maintenant un défi d'authentification, il n'était pas au moment où la question a été posée.

Ce service Web n'a pas envoyer une demande d'authentification, je ne peux pas utiliser la méthode déléguée connection:didReceiveAuthenticationChallenge:. Au lieu de cela, j'ai défini une valeur par défaut NSURLCredential dans le stockage des informations d'identification partagées. Malheureusement, ce droit d'accès par défaut n'est pas utilisé par NSURLConnection.

Voici mon code (en utilisant ARC, testé sur iOS 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 

Depuis les informations d'identification par défaut n'est pas utilisé, je reçois html (page de connexion) au lieu de XML. Si je définis la variable manuallyAddAuthorizationHeader sur YES, l'autorisation fonctionne et je reçois le code XML.

Ma question est: pourquoi est-ce que NSURLConnection ne fonctionne pas automatiquement utilise la valeur par défaut NSURLCredential?

Répondre

8

L'envoi des informations d'identification par défaut sans authentification est considéré comme non sécurisé, en particulier dans le cas où vous communiquez via HTTP simple. La spécification HTTP indique que pouvez envoyer des informations d'identification de manière proactive, mais que vous devriez généralement attendre un défi d'authentification. Et c'est le comportement que Cocoa fournit par défaut.

Si vous devez envoyer les informations d'identification de manière proactive, vous devrez ajouter manuellement les en-têtes. Vous pouvez simplement Base64 encode vous-même, ou vous pouvez utiliser les fonctions CFHTTP de le faire pour vous, comme ceci:

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); 

Ensuite, positionner le authorizationString comme l'en-tête Authorization dans votre NSURLRequest.

(code Copié de manière flagrante de https://stackoverflow.com/a/509480/100478, bien que je l'ai moi-même écrit un code similaire à plusieurs reprises.)

3

Comme HTTP prend en charge plusieurs méthodes d'authentification (de base, Digest, Kerberos, etc.), NSURLConnection ne peut pas envoyer les informations d'identification avant il reçoit le challenge d'authentification du serveur car il ne sait pas comment les envoyer.

+0

J'ai explicitement créé un 'NSURLProtectionSpace' avec' authenticationMethod: NSURLAuthenticationMethodHTTPBasic', donc je pensais qu'il faudrait maintenant quelle méthode utiliser. – 0xced

0

Alors que la réponse de BJ peut résoudre votre problème côté client, le vrai problème est le serveur. En interne, NSURLConnection utilisera son propre équivalent de la méthode déléguée connection:didReceiveAuthenticationChallenge: et les autres méthodes d'authentification. C'est là qu'il cherche un justificatif d'identité qu'il peut appliquer à partir de NSURLCredentialStorage. Dans votre cas, cela ne semble pas se produire. Pour que ces méthodes soient invoquées, le serveur doit non seulement donner un code d'état HTTP 40x, mais il doit inclure un en-tête WWW-Authenticate. Cela indique à NSURLConnection de tenter de répondre au défi d'authentification. Il est probable que votre serveur n'inclue pas cela, et c'est pourquoi le client n'envoie pas d'informations d'identification.

Questions connexes