PHP, Zend Framework and Other Crazy Stuff
Openid and Yadis
PHP OpenID 2.0 library for PEAR: Updated source code
Jul 23rd
Just a quick update on the PHP OpenID 2.0 library being proposed to PEAR. The library is a PHP5 implementation of the OpenID 2.0 Authentication Specification. It’s currently only including a Consumer (so you can build OpenID authentication into websites) but a Server is already in the works for later.
Over the weekend, a set of changes were put through to patch some last instability issues:
- OpenID 1.1 support finalised
- Unencrypted associations (for those using SSL) now implemented
- HTML Discovery (required for OpenID 1.1 only servers) now implemented
- OpenID Extension support for SREG updated to patch a bug which malformed Extension keys
- All HTML parsing is now performed using DOMDocument, rather than ugly PCRE hacks!
- Data validation forms extended somewhat to cover edge cases, and also to support unencrypted response data
There are still a few more edge cases to work through, and error responses need to made more interactive (so users can access OpenID error messages from the Server), but nearly all the core pieces are finally coming together. If you are inclined to test out the alpha code, you can checkout the source from subversion at:
http://svn.astrumfutura.org/pear/trunk/
My last blog entry offered a quick example authentication script to get you started off. It also offers instructions for installing the related PEAR packages or source code required to support OpenID 2.0 (Services_Yadis, Crypt_DiffieHellman and Crypt_HMAC2).
A mailing list for those wishing to request support, or provide feedback/help is available from http://www.openidforphp.org, which will eventually offer OpenID library support and downloads of standalone packages. Of course the preferred install method will be PEAR! And the site will be supplementary to future PEAR/PEAR2 support options.
PHP OpenID 2.0 library for PEAR: Preview available from subversion
Jul 20th
So after a few days throwing around code in an IDE, a small amount of swearing, and an overdose of caffeine, I have committed initial OpenID PHP5 code in it’s shiny new PEARified form to subversion. What this means is that after a few more days of completion to work out major kinks, the PEAR-Dev mailing list will be notified of a new OpenID Consumer proposal
. A Server proposal will follow at a later date, i.e. when the dull ache in my forearms subsides.
http://svn.astrumfutura.org/pear/trunk/OpenID/
Feel free to checkout a copy from subversion for a preview. Just don’t shoot me if it’s not currently working; it needs at least two more days before it’s feature set is covering the main use cases. At present, I can only verify it works when authenticating against an OpenID 2.0 Server (i.e. no OpenID 1.1 servers just yet – try again tomorrow). The problem with specification coding is that after you’ve written around 95% of the source code required, nothing works – it’s always the last 5% that binds the entire thing into a functioning unit.
All I’m announcing here is that a public repository is open, and the code is for the first time available under an open source New BSD License. Up until this point there’s been no public code for anyone to read through. Now you can check it out, break it, complain to me, and explain how much of a steaming dogpile it all is
.
For those losing track of the plot, this is the exact same body of code (only in a much advanced state of refactoring) which was originally targeted for the Zend Framework since February 2007. When I was ready to publish proposals, I requested final feedback from the ZF mailing lists and received a reply within a few hours announcing that Zend had an in-house OpenID project and would be publishing their proposal during the week.
I was pretty critical of both the convenient timing of Zend’s urge to make an OpenID proposal, and the lack of awareness on anyone’s behalf of my pre-existing effort, and admittedly still find it mystifying. At the time I pulled my proposal completely, and well, here it is one month later heading to PEAR. Perhaps one day this code, and some of the related proposals I put back in place after some discussion with Dmitry Stogov, will still end up in the framework. I haven’t ruled that out, and I look forward to discussing OpenID with Dmitry in the future.
Now, where would code be without examples? I’ll be working on some documentation eventually, but here’s the quickie version to get anyone so inclined to use unstable, days from working perfectly, code started off.
Your first step should be to install three PEAR packages. These are previous PEAR proposal I made to support OpenID operations, and you can download the current packages from http://padraic.astrumfutura.com/pear/. To install, open up the command line and run the following PEAR command:
pear install Crypt_DiffieHellman-0.1.0a3.tgz
Do the same for the Crypt_HMAC2 and Services_Yadis packages. Services_Yadis should also get PEAR to install the Validate and HTTP_Request packages automatically since they are dependencies.
Next checkout the OpenID source code. I haven’t put this into a PEAR package yet since it still needs a spot of work before being ready for review, so you manually checkout/export using a Subversion client and copy to a location on your include_path.
Here’s a quick test authentication script to start you off. I’m 99.5% sure this currently works – so long as your OpenID is from an OpenID 2.0 toting Provider (1.1 authentication will be in place by tomorrow). MyOpenid.com for example supports 2.0 authentication. Note, if the response result matches the OpenID::OPENID_RESPONSE_SUCCESS constant value then authentication has succeeded.
[geshi lang=php]
require_once ‘OpenID/Consumer.php’;
require_once ‘OpenID/Store/File.php’;
$store = new OpenID_Store_File(dirname(__FILE__)); // use current working dir to cache association data used for verifying response signatures
$test = new OpenID_Consumer($store);
if (isset($_GET) && !empty($_GET)) {
$result = $test->finish($_GET);
if ($result->getResult() !== OpenID::OPENID_RESPONSE_SUCCESS) {
exit(‘Paddy\’s library screwed up or the Server did! Result was:’ . $result->getResult()); // “parse error” is often a library screw-up ; )
}
echo ‘Authenticated with User OpenID: ‘, $result->get(‘openid.claimed_id’), ‘ The OpenID Provider knows you as ‘, $result->get(‘openid.identity’), ‘
‘;
exit(0);
}
OpenID::setVersion(2.0);
$authRedirect = $test->start(‘padraic.myopenid.com’);
$authRedirect->redirect(‘http://localhost/path/to/this/file’, ‘http://localhost’); // last param only needs to be the base URI scheme and domain name
[/geshi]
Try not to break anything, ok?
Edit: OpenID 1.1 Authentication should now also work in most cases. The Sreg issue for OpenID 2.0 was resolved. Sreg for 1.1 is likely non-functional – this has a lower priority, and the reason is simple that Sreg has two versions, and I’m using the most recent one. Needs some logic to switch between the two.
OpenID for PEAR: Services_Yadis proposed
Jul 13th
The Services_Yadis package is now proposed to PEAR. This provides a PHP5 implementation of the Yadis Specification 1.0 a requirement of the OpenID Authentication 2.0 Specification. There are way too many specifications out there! The proposal is a reflection of February’s “Zend_Service_Yadis” proposal to the Zend Framework. The main differences (beside the PEARification) were fixing the main bugs the ZF sample code had.
Anyways, alongside Crypt_HMAC2 and Crypt_DiffieHellman (both of which passed voting this week – just waiting for a CVS account and finalisation by the PEAR group that it’s accepted) this will mark another milestone on the way to getting OpenID support into PEAR. Thanks to Christian Schmidt whose early comments on the PEAR Yadis proposal helped me tidy up and fix a few things yesterday.
Next up will be an OpenID Consumer proposal. Will likely propose this early next week – could be earlier if it keeps raining here in Ireland (it’s completely horrible outside now), and I’m stuck indoors over the weekend. It’s largely done – but some of the subtle OpenID 2.0 rules are omitted. I’ll layer these into the refactored code at a later date; the current version works fine for a typical OpenID 2.0 authentication process.
Released into the wild: Zend Framework 1.0.0
Jul 2nd
Today saw the much anticipated release of the first production release of the Zend Framework. I’ve been following the project keenly since last Summer, so congratulations to the developers, contributors and the ever omniscient Zenders for their hard work to date!
The Zend Framework has evolved into a loosely coupled, extremely flexible and easy to modify framework. Built across months of debate, hard work and the occasional emotional tirade (as I’ve been guilty of recently
) the 1.0.0 release now carries a stable API and an impressive array of features. Personally, I’m impressed on the insistence of obtaining a stable API by a fixed date at the cost of some completion concerns. It really is essential these days that adopters of a new technology are given the stability they need to get things done effectively now – not months down the line. I know from migrating several applications across 0.6, 0.7 to 0.9 that the lack of stability is a costly issue, much more costly than a few missing or incomplete features one can workaround for the moment.
I know most people will shout MVC a dozen times before collapsing into a state of ecstatic delirium, but there is a lot more to the Zend Framework than MVC. The MVC components are absolutely essential, but are not the sum total of the Framework.
Over the months I’ve come to appreciate the fixation on web services. Easy integration with web services is hugely important these days – from the simplicity of agregating RSS/Atom feeds to the complexity of building your own RESTful service. The Zend Framework is all geared up on web service steroids with support for RSS/Atom feeds, Google, StrikeIron (which is quite cool), Yahoo, Flickr, and the usual suspects. Not to mention the more general support offered by Zend_Rest and Zend_XmlRpc.
My other favourites are the i18n support offered by Zend_Locale, Zend_Date and Zend_Translate. For those who will use Zend_Validate classes, many of the character string validators attempt to use a Unicode mode so you’re not tied to the usual ASCII range. These components make it very easy to internationalise your application, support multibyte languages, and minimise the mountain of work a typical PHP application needs to go international correctly. Zend_Uri even has support for validating a number of Unicode IRIs (internationalised resource identifiers). Hopefully support for this improves over time given how many domain names are availing of IRI support – especially now that many of the popular browsers (incl. IE7) have built in the IDNA standard.
Finally, the Zend Framework website has seen a few changes. You can read the current future roadmap over at http://framework.zend.com/whyzf/future/. It’s interesting to see both OpenID (and to a lesser extent Vista’s CardSpace) mentioned along with support for the YAML format. I’ve worked with both extensively and have related proposals (Dmitry Stogov is leading the OpenID proposal, me the related Yadis Protocol one, as well as a Zend_Yaml proposal) on the ZF Developer’s Wiki. OpenID is a very interesting authentication service so spare the proposals a read if you have a chance
.
On a last unrelated note:
if you’ve read or intend reading my Acceptance Testing with PHPUnit/Selenium article on Devzone you should be aware that Sebastion Bergmann just announced the release of PHPUnit 3.1.0 which replaces the requirement for PEAR’s Testing_Selenium with an internal implementation. I’ll be testing later on to see if an article addendum is warranted.
Refactoring an OpenID Library
Jun 25th
Since I have a three track mind (but only one dedicated to PHP), I’m stuck with another OpenID post. Over the weekend, I managed to grab a few hours to dig around my OpenID library with the ultimate development tools: patience and experimentation. There are also a few integration tests as a safety net though
. So I will be sending a copy around to a few people including Dmitry who has posted a Zend Framework proposal for OpenID on the wiki (which is currently down, as usual, so I haven’t managed to add a comment on it yet – should be more stable in the near future I hear).
The refactored library changed a few aspects of the original code I wrote last Autumn. The original placed a lot of responsibilities in the Consumer class which meant it was very difficult to actually change things without knock on effects elsewhere. What I’ve refactored towards is a splitting of the OpenID process based on three categories: Request, Redirect, Response. The OpenID Specification is all about communication, and this type of splitting seems to have worked out very well. The other change was to centralise all values which are effectively constants to the top-level OpenID class. This class also manages the current version via a static public method – OpenID::setVersion().
So what does the library not include (always a good question!).
1. XRI Support is not complete. I need to add an interface to the Yadis object to extract an XRI’s Canonical ID which is the actual value used as an OpenID claimed identifier.
2. Stateless Mode is not supported. Also called Dumb Mode, it’s necessary when the server cannot store state between requests. Since PHP is perfectly stateful I omitted it for now.
3. Good session integration for frameworks. The library currently directly accesses $_SESSION under an “OPENID_SESSION” namespace. For the Zend Framework and others which have a Session class (e.g. Zend_Session_Namespace) this may not work well if sessions are being written to the database, or session expiry dates being set.
What does it support?
It supports almost the entire OpenID 2.0 Authentication Specification (draft 11 since it’s not finalised). It also transparently covers a few common edge cases such as OP Servers which do not always return an “ns” namespace value in responses. It also downgrades and tracks the association type when an OP cannot use SHA256 (e.g. a number of PHP4 based providers). It also supports OpenID Extensions – you can add extension types quickly to the current list (i.e. the Simple Registration Extension (sreg) for now).
Improvements over original library?
It now has wider support for Diffie-Hellman and HMAC using one of mhash or hash extensions (both crytographic algorithms are segregated to their own class also). Classes are now lowly coupled, so maintenance and individual class testing is simpler. Logic is more dispersed across smaller methods – again making it easier to maintain, test, and modify discrete chunks of logic. I’ve also centralised the constant values, and amended the API to be similar to that used by JanRain’s PHP4 library. There are of course differences from JanRain’s API but the flow is very similar.
Other stuff?
Except for some API improvements I should make, it includes a functional Yadis implementation. A task for later is allowing the OpenID library check whether an OP supports extensions like Sreg by checking the list of available Service types discovered by the Yadis protocol. This only needs a minor change – I first need to check whether a missing sreg service in an XRD document is a definitive sign it is not supported, or whether it’s entirely optional to show it as a service. (More spec reading this evening
).
Aside from an example to be passed to the Zend Framework proposal, the library in it’s refactored form will be proposed to PEAR. I think I’ll propose Services_Yadis first since it’s a component of the larger OpenID scheme.
