paulnug
paulnug

Reputation: 3

How to connect to a website that requires a username and password

I have a basic question and I am hoping there is a simple answer that I have missed. The basic premise is that I am going to connect to a website and download some JSON data. I am using the framework provided by Stig Brautaset and the tutorial worked really well.

My issue is that the website I am connecting to is in the format and the username and password are fixed for my app so the user will never be entering them.

curl -u username:password http://website.com/page

How do I pass in the url and password to a NSURLConnection?

It doesn't have to be an NSURLConnection, it just seems the best option.

I have looked at the AdvancedUrlConnections sample but it seems overly complex and is quite old. Searching on the web hasn't been much better. I am hoping that one of you guys can say just set these 2 properties, followed by suitable insults of course...

Upvotes: 0

Views: 1015

Answers (2)

Wayne Hartman
Wayne Hartman

Reputation: 18477

An NSURLConnection will work just fine. As pointed out in another answer, implementing the didReceiveAuthenticationChallenge callback is quite easy to do.

- (void) someMethod
{
    NSURLRequest* request = [[NSURLRequest alloc] 
         initWithURL:[NSURL urlWithString:@"someURL"]

    NSURLConnection* connection = [[NSURLConnection alloc] 
         initWithRequest:request delegate:self];

    [connection release];
    [request release];
}

This is all pretty straight forward. It's in the delegate methods of the NSURLConnection where all the magic happens:

This is where you handle the challenge for credentials. I have hardcoded a fake username and password to demonstrate how it works. I personally have a separate delegate object handle the challenge. Keep in mind that the connection will sit in an idle state until you respond to it or until the connection times out.

- (void) connection:(NSURLConnection *)connection 
      didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
    //  Make sure to use the appropriate authentication method for the server to
    //  which you are connecting.
    if ([[challenge protectionSpace] authenticationMethod] == 
             NSURLAuthenticationMethodBasicAuth)
    {
            //  This is very, very important to check.  Depending on how your 
            //  security policies are setup, you could lock your user out of his 
            //  or her account by trying to use the wrong credentials too many 
            //  times in a row.
        if ([challenge previousFailureCount] > 0)
        {
            [[challenge sender] cancelAuthenticationChallenge:challenge];

            UIAlertView* alert = [[UIAlertView alloc] 
                            initWithTitle:@"Invalid Credentials" 
                                  message:@"The credentials are invalid." 
                                 delegate:nil 
                        cancelButtonTitle:@"OK" 
                        otherButtonTitles:nil];
            [alert show];
            [alert release];      
        }
        else
        {
            [challenge useCredential:[NSURLCredential 
                   credentialWithUser:@"someUser" 
                             password:@"somePassword" 
                          persistence:NSURLCredentialPersistenceForSession 
           forAuthenticationChallenge:challenge]];
        }
    }
    else
    {
        //  Do whatever you want here, for educational purposes, 
            //  I'm just going to cancel the challenge
        [[challenge sender] cancelAuthenticationChallenge:challenge];
    }
}

You'll need to implement these other methods for an NSURLConnection, as well:

//  So you know when it's done downloading
- (void) connectionDidFinishLoading:(NSURLConnection *)connection;
//  In case of failure
- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;    
//  Gather the downloaded file data
- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;

Upvotes: 3

Tom Harrington
Tom Harrington

Reputation: 70946

There are a couple of possibilities.

If you use an asynchronous NSURLConnection, the method -connection:didReceiveAuthenticationChallenge:will be called on the connection's delegate. The docs for this method explain how to deal with it. It's what AdvancedUrlConnections uses and yeah, it's a little messy.

A simpler approach is to create an NSMutableURLRequest when creating the connection (instead of an immutable NSURLRequest). That allows you to add arbitrary HTTP headers. Constructing a basic auth header is simple-- something like

NSMutableURLRequest *request = .... // details omitted
NSString *username = // ....
NSString *password = // ....
NSData *authRawData = [[NSString stringWithFormat:@"%@:%@", username, password] dataUsingEncoding:NSUTF8StringEncoding];
NSString *authEncoded = [authRawData asBase64EncodedString];
[request setValue:[NSString stringWithFormat:@"Basic %@", authEncoded] forHTTPHeaderField:@"Authorization"];

The above uses the -asBase64EncodedString method included in TouchFoundation

Upvotes: 0

Related Questions