I'm trying to connect to http://cmis.demo.nuxeo.org/nuxeo/atom/cmis/ with NSURLConnection
. This demo web service is documented to require authentication (login: Administrator / password: Administrator).
Edit: This web service now sends an authentication challenge, it was not at the time the question was asked.
This web service does not send an authentication challenge, so I can't use the connection:didReceiveAuthenticationChallenge:
delegate method. Instead I set a default NSURLCredential
in the shared credential storage. Unfortunately, this default credential is not used by NSURLConnection
.
Here is my code (using ARC, tested on 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
Since the default credential is not used, I receive html (login page) instead of xml. If I set the manuallyAddAuthorizationHeader
variable to YES
, then authorization works and I receive xml.
My question is: why does NSURLConnection
does not automatically use the default NSURLCredential
?
Sending the default credential without an authentication challenge is considered insecure, especially in the case where you're communicating over plain HTTP. The HTTP spec says that you can send credentials proactively, but that you should usually wait for an authentication challenge. And that's the behavior that Cocoa provides by default.
If you need to proactively send the credentials, then you'll have to manually add the headers yourself. You can just base-64 encode it yourself, or you can use the CFHTTP
functions to do it for you, like so:
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);
Then just set the authorizationString
as the Authorization
header in your NSURLRequest
.
(Code copied blatantly from https://stackoverflow.com/a/509480/100478, though I've written similar code myself many times.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With