As i mentioned in my previous post, i was going to add AuthSub authentication for Ngeblog when people at Google Code team announced that Zend framework now has GData support.
After played around with it for hours, i finally got into a decision to use Zend Gdata for abstracting Ngeblog connection to Blogger. Unfortunately, Zend GData class library only supports AuthSub authentication, while Ngeblog already uses ClientLogin authentication and works fine so far.
So, to make it available for both type of authentication, i finally sat down and wrote some codes myself to add ClientLogin support for Zend GData. You can download the bundle in .zip here or in .tgz here which contains both original Zend_Gdata bundle and my Zend_Gdata_ClientLogin class for ClientLogin authentication.
How it works
To understand how this class works, you must first understand how Google account authentication works. Please read the manual for that. But i try to explain it anyway.
Authentication is required to access any of Google Services such as Google Calendar, Google Base or Blogger. To do that, first you must provide username and password to log into your Google account. And then once your login is authorized, Google will give you a token to identify yourself for accessing the desired Google Service.
Currently there are two kind of authentication that Google uses. AuthSub authentication and ClientLogin authentication. As the manual said, AuthSub is used for web application that offers a service to access Google Service. While ClientLogin is used for installed application, such as desktop or handheld application.
But that doesn’t mean you can’t use ClientLogin for web application. It’s just that with ClientLogin authentication you must handle the authentication programmatically yourself to get the token. While with AuthSub you only need to redirect your web users to log into Google Account web site and grab the token as the result once they authorized.
Now, let’s get to the business. To use this class, you must first include Zend.php
and load Zend_Gdata_ClientLogin
class, like this:
require_once 'Zend.php'; Zend::loadClass('Zend_Gdata_ClientLogin');
Then use getClientLoginAuth
method to get the token (authorization code), like this:
$username = 'yourusername'; $password = 'yourpassword'; $service = 'blogger'; $source = 'Ngoprekweb-Zend_Gdata-0.1.1'; // companyName-applicationName-versionID try { $resp = Zend_Gdata_ClientLogin::getClientLoginAuth($username,$password,$service,$source); print_r($resp); } catch ( Exception $e ) { echo $e->getMessage(); }
As you can see, there are four parameters required for this method: username, password, service and source. You can read about these parameters here.
The results of this method will be in three possibilities:
First
, if the authentication is success (authorized by Google), the output will be something like this,
Array ( [response] => authorized [auth] => DQAAAGgA...dk3fA5N )
Second, if the authentication is failed for some reasons, it throws exception. About the reason of this failure, the manual said:
Please note that ClientLogin does not differentiate between a failure due to an incorrect password or one due to an unrecognized user name (for example, if the user has not yet signed up for an account).
Third
, if Google requires you to solve CAPTCHA challenge, the output will be something like this,
Array ( [response] => captcha [captchatoken] => DQAAAGgA...dkI1LK9 [captchaurl] => http://www.google.com/login/captchaALD$ALSJ4.png )
About CAPTCHA challenge, the manual said,
ClientLogin uses standard security measures to protect user account information. To block bots and other entities from breaking user passwords, Google Accounts may add a visual CAPTCHA� to the authentication process when the server suspects an illegal intrusion, such as after too many incorrect login attempts. A CAPTCHA ensures that a real person is attempting login, and not a computer trying random strings (a dictionary attack).
Handling CAPTCHA Challenge
As i mentioned above, when Google requires you to answer CAPTCHA challenge (when she suspects you as an intruder :)), you’ll get both captchatoken for identifying which CAPTCHA image you received, and captchaurl that shows you the location of the image you have to answer (to tell miss Google you are human, not bot).
To answer that challenge, you use the same getClientLoginAuth
method, only now with two additional parameters: captchatoken and captchaanswer.
$username = 'yourusername'; $password = 'yourpassword'; $service = 'blogger'; $source = 'Ngoprekweb-Zend_Gdata-0.1.1'; // companyName-applicationName-versionID $captchatoken = 'DQAAAGgA...dkI1LK9'; $captchaanswer= 'brinmar'; try { $resp = Zend_Gdata_ClientLogin::getClientLoginAuth($username,$password,$service,$source,$captchatoken,$captchaanswer); print_r($resp); } catch ( Exception $e ) { echo $e->getMessage(); }
If you ARE really human, then most likely you’ll get something like this as the result,
Array ( [response] => authorized [auth] => DQAAAGgA...dk3fA5N )
which means you’re now authorized to use Google Service you requested, in this case is Blogger. Use $resp['auth']
as your token (authorization code) to do the rest of operation (query, add, edit or delete posts in your Blogger).
In Action: Reading Blogger
This far, some of you might said, “what in Google Earth is this guy talking about?!”. 🙂
Alright kids, grab your emacs or UltraEdit, here comes the example. What we’re going to do here is to get the entries of your Blogger, for comparing purpose with what Zend does using AuthSub (see my previous post here).
<?php /** * Testing Zend_Gdata_ClientLogin for getting list of Blogger entries * * written by: Eris Ristemena (http://www.ngoprekweb.com/tags/php) * */ set_include_path(dirname(__FILE__) . '/Zend_Gdata'); require_once 'Zend.php'; Zend::loadClass('Zend_Gdata_ClientLogin'); Zend::loadClass('Zend_Gdata'); Zend::loadClass('Zend_Feed'); $username = 'yourusername'; $password = 'yourpassword'; $service = 'blogger'; $source = 'Ngoprekweb-Zend_Gdata-0.1.1'; // companyName-applicationName-versionID $logintoken = $_GET['captchatoken']; $logincaptcha = $_GET['captchaanswer']; try { $resp = Zend_Gdata_ClientLogin::getClientLoginAuth($username,$password,$service,$source,$logintoken,$logincaptcha); if ( $resp['response']=='authorized' ) { $client = Zend_Gdata_ClientLogin::getHttpClient($resp['auth']); $gdata = new Zend_Gdata($client); $feed = $gdata->getFeed("http://www.blogger.com/feeds/default/blogs"); foreach ($feed as $item) { echo '<h3><a href="'.$item->link("alternate").'">' . $item->title() . '</a></h3>'; $_id = explode("/",(string) $item->id()); $blogid = $_id[count($_id)-1]; $feed1 = $gdata->getFeed("http://www.blogger.com/feeds/$blogid/posts/summary"); echo "<ul>"; foreach ($feed1 as $item1) { echo "<li>"; echo "<a href=\"{$item1->link('alternate')}\">{$item1->title()}</a><br />"; echo "{$item1->summary()}<br />"; echo "</li>"; } echo "</ul>"; } } elseif ( $resp['response']=='captcha' ) { echo 'Google requires you to solve this CAPTCHA image <br />'; echo '<img src="'.$resp['captchaurl'].'" /><br />'; echo '<form action="'.$_SERVER['PHP_SELF'].'" method="GET">'; echo 'Answer : <input type="text" name="captchaanswer" size="10" />'; echo '<input type="hidden" name="captchatoken" value="'.$resp['captchatoken'].'" />'; echo '<input type="submit" />'; echo '</form>'; exit; } else { // there is no way you can go here, some exceptions must have been thrown } } catch ( Exception $e ) { echo $e->getMessage(); } ?>
Have fun. And please be kind to drop some comments below or report any bugs you find to my email (eristemena at ngoprekweb dot you know what).
Out of interest, did you figure out a way to make google respond with a CAPTCHA request, as part of your testing? I’m developing an application on OS X, and need to test my handling of said response…
I’ve tested it like a hundred times with false login and yet they throw me Error: BadAuthentication instead of Error:CaptchaRequired.
I’ve reported this to google data api team, and this is what the google team said:
“Thanks for bringing this up. We are currently investigating this and will get back to you as soon as possible.”
So, i guess we have to wait for that. 🙂
Nice article about Zend GData ClientLogin Authentication.
Nice coding, Eris. I am using the modified classes to develop a Webmaster Tools API script. Your coding came in real handy, thanks.
Glad to hear my code helps 🙂
nice. Thanks
thank you but can do this with out zend?