Pregunta

Estoy tratando de conectarme con http://cmis.demo.nuxeo.org/nuxeo/atom/cmis/ con NSURLConnection. Este servicio web de demostración es documentado Para requerir autenticación (Iniciar sesión: Administrador / Contraseña: Administrador).

Editar: Este servicio web ahora envía un desafío de autenticación, no fue en el momento en que se hizo la pregunta.

Este servicio web no es Envíe un desafío de autenticación, para que no pueda usar el connection:didReceiveAuthenticationChallenge: Método delegado. En su lugar, establecí un predeterminado NSURLCredential En el almacenamiento de credenciales compartidas. Desafortunadamente, esta credencial predeterminada no es utilizada por NSURLConnection.

Aquí está mi código (usando ARC, probado en 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

Dado que no se usa la credencial predeterminada, recibo HTML (página de inicio de sesión) en lugar de XML. Si configuro el manuallyAddAuthorizationHeader variable a YES, entonces la autorización funciona y recibo XML.

Mi pregunta es: ¿Por qué lo hace? NSURLConnection no es automáticamente Utilice el valor predeterminado NSURLCredential?

¿Fue útil?

Solución

Enviar la credencial predeterminada sin un desafío de autenticación se considera inseguro, especialmente en el caso de que se esté comunicando sobre HTTP simple. La especificación de http dice que pueden Envíe credenciales de manera proactiva, pero que generalmente debe esperar un desafío de autenticación. Y ese es el comportamiento que el Cocoa proporciona de forma predeterminada.

Si necesita enviar de manera proactiva las credenciales, entonces tendrá que agregar manualmente los encabezados usted mismo. Puede simplemente base-64 codificarlo usted mismo, o puede usar el CFHTTP Funciones para hacerlo por ti, como así:

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

Entonces solo configure el authorizationString como el Authorization encabezado en tu NSURLRequest.

(Código copiado descaradamente de https://stackoverflow.com/a/509480/100478, aunque he escrito un código similar muchas veces).

Otros consejos

Como HTTP admite muchos métodos de autenticación diferentes (Basic, Digest, Kerberos, etc.), NSURLConnection No se puede enviar las credenciales antes de recibir el desafío de autenticación del servidor porque no sabe cómo enviarlas.

Si bien la respuesta de BJ puede resolver su problema en el lado del cliente, el problema real es el servidor. Internamente NsurlConnection utilizará su propio equivalente del método delegado connection:didReceiveAuthenticationChallenge: y los otros métodos de autenticación. Aquí es donde busca una credencial de la que puede aplicarse NSURLCredentialStorage . En su caso, esto no parece estar sucediendo. Para los métodos que se invocarán, el servidor no solo tiene que dar un código de estado HTTP 40x, sino que debe incluir un encabezado de autenticado www. Esto le dice a NSURLConnection que intente responder al desafío de autenticación. Es probable que su servidor no incluya esto, y es por eso que el cliente no está enviando credenciales.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top