Nsurlconnection no usa la credencial predeterminada
-
28-10-2019 - |
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
?
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.