HTTP Basic authentification and cappuccino

Setting up a test environment

Settings for Apache and php

If you search the net for information on HTTP Basic authentification you discover that the http server will have to send a header "WWW-Authenticate" and indicate the method "Basic" and the realm.

WWW-Authenticate: Basic realm="WallyWorld"

Suppose that you have granted access to user "Aladdin" with password "open sesame". You have to encode with the Base64 algorithm the string "Aladdin:open sesame". This is, as you have already calculated, the string "QWxhZGRpbjpvcGVuIHNlc2FtZQ==". So you have to reply to the server with the header "Authorization" and indicate the method "Basic" and the password (almost in clear). Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

We will setup a test environment for a Macintosh running Mac OS 10.5. We will use the installed Apache web server and php (5.2.6). Start by reading the documentation about Apache authentification. We first have to create a "passwords" file.

$ cd ~ $ htpasswd -c /Users/philippe/passwords Aladdin # htpasswd /Users/philippe/passwords JohnDoe $ cat passwords Aladdin:pEjVFOpSqdFcY

Go to your web folder (named "Sites" in your home folder). Create a directory "Private" that will be protected by a "Basic" authentification. $ cd ~/Sites $ mkdir Private

Create a file named ".htaccess" in the "Private" folder with the content described below.

$ cd Private $ cat .htaccess AuthType Basic AuthName "WallyWorld" AuthUserFile /Users/philippe/passwords Require user Aladdin JohnDoe

You will have to modify your Apache settings in the "/etc/apache2" directory.

$ cd /etc/apache2 $ ls extra mime.types other httpd.conf magic original users $ cd users/ $ ls philippe.conf

First enable support for php with Apache. You have to edit your file "httpd.conf" and remove the "#" character in front of the line below. You need to have admin access to the file so you may use the command "sudo emacs httpd.conf".

LoadModule php5_module libexec/apache2/libphp5.so

You also have to indicate Apache that you want to allow override the authentification configuration in the directory "/Users/philippe/Sites/" with files ".htaccess". On Mac OS 10.5, you will to change "AllowOverride None" to "AllowOverride AuthConfig" in the file /etc/apache2/users/philippe.conf. Where "philippe.conf" should be changed to your user account.

$ cd /etc/apache2/users $ more philippe.conf Options Indexes MultiViews AllowOverride AuthConfig Order allow,deny Allow from all

To force the Apache web server to read your configuration, you can open your system preferences and click on the button to disable "Web Sharing". Enable "Web Sharing" again to have your preferences taken into account.

Creating the php scripts to read/write JSON messages

Create a file named "get_json.php" in the "~/Sites" folder.

$ cat get_json.php <?php $picture1 = array('url'=>'Photos/PLL_0018_550_368.jpg'); $picture2 = array('url'=>'Photos/PLL_0033_550_368.jpg'); $picture3 = array('url'=>'Photos/DSC6881_550_368.jpg'); $arr = array($picture1, $picture2, $picture3); echo json_encode($arr); ?>

You can test that php will send you a JSON string.

$ php get_json.php [{"url":"Photos\/PLL_0018_550_368.jpg"},{"url":"Photos\/PLL_0033_550_368.jpg"},{"url":"Photos\/DSC6881_550_368.jpg"}]

Create a file named "post_json.php" in the "~/Sites/Private" folder.

$ cat post_json.php <?php if ( $_SERVER['REQUEST_METHOD'] === 'POST' ) { // Read the input from stdin (max 100 kb) $postText = trim( file_get_contents('php://input', FILE_TEXT, NULL, 0, 102400) ); $received = json_decode($postText, true); /* Uncomment this and allows write access to the directory to dump the request // Check the received data $myFile = "/Users/philippe/Sites/dump.txt"; $fh = fopen($myFile, 'a') or die("can't open file"); fwrite($fh, $postText . "\n"); fclose($fh); */ // For tutorial, we dump the same JSON but we could send a real response encoded as a JSON string echo $postText; } ?>

Using JSON and cappuccino

This small category will increase behaviour of the CPString class.

@implementation CPString (JSON) // Returns a string representing the supplied JavaScript object encoded as JSON. + (CPString)JSONFromObject:(JSObject)anObject { return CPJSObjectCreateJSON(anObject); } // Returns a JavaScript object decoded from the string's JSON representation. - (JSObject)objectFromJSON { return CPJSObjectCreateWithJSON(self); }

We can now create a JSON message (using the category above) for our php web service.

// Create a javascript object from scratch var myFirstJSONObject = { "action" : "Login", "user" : "John", "password" : "Doe"}; // Get the JSON representation of the object var content = [CPString JSONFromObject:myFirstJSONObject]; var contentLength = [[CPString alloc] initWithFormat:@"%d", [content length]];

Using Base64 with cappuccino

Support for Base64 encoding and decoding is present in cappuccino 0.7b but since we want to use release 0.6, we have to create the file "Utilities.j" with the same Base64 code. I have created a small category for this tutorial that will increase the behaviour of the CPString class.

@implementation CPString (base64) // Returns a base64 encoded string. - (CPString)encodeBase64 { return base64_encode_string(self); } // Returns a string decoded from its base64 representation. - (CPString)decodeBase64 { return base64_decode_to_string(self); }

We can now use the Base64 category to create the proper header.

var request = [[CPURLRequest alloc] initWithURL:@"http://macbookpro.local/~philippe/Private/post_json.php"]; [request setHTTPMethod:@"POST"]; [request setHTTPBody:content]; [request setValue:contentLength forHTTPHeaderField:@"Content-Length"]; [request setValue:"text/plain;charset=UTF-8" forHTTPHeaderField:@"Content-Type"]; if (useIndentifier) { var user = @"Aladdin"; var password = @"open sesame"; var secret = [[CPString stringWithFormat:@"%@:%@", user, password] encodeBase64]; var authorization = [CPString stringWithFormat:@"Basic %@", secret]; [request setValue:authorization forHTTPHeaderField:@"Authorization"]; }

Once you have build your request, you can send it as usual.

var request = [self createRequestWithIdentifier:YES]; postConnection = [CPURLConnection connectionWithRequest:request delegate:self];

References

If you'd like to see the complete code listing from the tutorial, you can download it all in a single file: Tutorial-Login-Step1.zip. The web application is available online: Tutorial-Login-Step1

Copyright © 2009 - Philippe Laval. Cappuccino and Objective-J are registered Trademarks of 280 North.