NSURLCredential madness

Mikuro

Crotchety UI Nitpicker
I'm trying to write a program in Cocoa that accesses a password-protected web page (specifically, my gmail account atom feed). I'm basing my routine on Apple's sample code.

My problem is that I can't for the life of me figure out how to isolate my program's credentials from other Cocoa programs (e.g., Safari's). If I'm logged in to a gmail account in Safari, my app uses Safari's credentials, no matter what I do! This is bad, because I don't necessary want to access the same account in Safari and my program.

So, let's say that in Safari, I'm logged in as myName@gmail.com. Now how can I access myOtherName@gmail.com in my other program? I've tried putting the login info right into the URL (https://myOtherName:myOtherPassword@mail.google.com/mail/feed/atom), but this will still return the feed for myName, not myOtherName.

I've also wrestled with NSURLCredentialStorage, to no avail. I've tried adding credentials to mimic what Safari seems to have made, hoping to override it. Here's a snippet to show what I mean:
Code:
NSURLCredential *newCredential =[NSURLCredential credentialWithUser:@"myOtherName" password:@"myOtherPassword" persistence:NSURLCredentialPersistenceForSession];
NSURLProtectionSpace *space;

space = [[NSURLProtectionSpace alloc] initWithHost:@"mail.google.com" port:0 protocol:@"https" realm:nil authenticationMethod:NSURLAuthenticationMethodDefault];
[store setCredential:newCredential forProtectionSpace:space];

space = [[NSURLProtectionSpace alloc] initWithHost:@"gmail.google.com" port:0 protocol:@"https" realm:@"New mail feed" authenticationMethod:NSURLAuthenticationMethodDefault];
[store setCredential:newCredential forProtectionSpace:space];

space = [[NSURLProtectionSpace alloc] initWithHost:@"https://mail.google.com/mail/feed/atom" port:80 protocol:@"https" realm:nil authenticationMethod:NSURLAuthenticationMethodDefault];
[store setCredential:newCredential forProtectionSpace:space];
And I've tried that snippet using both setCredential and setDefaultCredential. Either way, I still get the feed for myName, not myOtherName. GAAH!


What am I missing? I'm running out of ideas here. Any help would be greatly appreciated!
 
Turns out I was a little wrong, and my program was NOT getting its login data from Safari, but rather from Keychain. I'm not sure how that data got into Keychain to begin with, since Safari doesn't give me the option to save my login data to Keychain, but anyway...

I tried deleting all all the entries programmatically with removeCredential, and now they're gone for good all across the system, and my program works fine, and independently.

But the question remains: How can I isolate my program from credentials specified by other programs? I can't guarantee my users will not have gmail account info in their Keychains, and I certainly can't go deleting Keychain data willy-nilly.

Is there any way to use an NSURLCredentialStorage that's not shared?

I assume there is, since while the data was in Keychain, I could access other accounts in Safari.
 
It seems to me that NSURLConnection's connection:didReceiveAuthenticationChallenge: delegate method can be implemented to authenticate using credentials supplied by the application if the host requires authentication. If the method is not implemented, the NSURLCredentialStorage is automatically used.

NSURLCredentialStorage probably works as a Keychain wrapper and uses the same Keychain data as Safari/WebKit.

http://developer.apple.com/document...connection:didReceiveAuthenticationChallenge:
 
Thanks for the reply. I did override connection:didReceiveAuthenticationChallenge: (I copied the whole protocol implementation from Apple's own sample code), but the problem was that it didn't even call it; it just went straight to the account info from Safari without even asking.

As I said before, it turned out that the items I found in NSURLCredentialStorage were not from Safari, but rather from Keychain. I deleted them all, and for a while it worked exactly as it should....for a while. Now it's using Safari's active login for some reason, even though I can't see that data in NSURLCredentialStorage at all! Confusing!

I think I might need to subclass NSURLConnection and override useCredential:forAuthenticationChallenge:. I assume it's getting called behind the scenes at some point, so if I can intercept the authentication there, I can replace it with my own data. I haven't tried to implement this yet, though, because.....well, because I have a short attention span and have not been working on that project for a week or so. ;)
 
Back
Top