Wednesday, May 5, 2010

Zoho Creator

So I found a company that provides basically the exact same functionality that I hope to provide with Wax. I knew there had to be someone out there with similar ideas, I just can't believe it took this long to find them. The company is called Zoho and their product is called Zoho Creator. It's basically designed to be an online database builder that lets you build custom applications around the database. So, if you want to see the long term aspirations for this project, check out http://www.zoho.com/creator/platform-features.html

Wax 0.11 and a Tutorial

So I finally managed to get a release together in time for this poster session. There are some things that I had hoped to have working that I just didn't have time for. The greatest contributor to this is that I did a rewrite on most of the blocks used by Wax after changing the routing methods.

Features Supported, but are probably still pretty buggy

  • Scaffolding (Create/Read/Update/Delete)
  • Dynamic Model (Modify/Add Attribute/Remove Attribute/Remove Model)
    • Fully implemented in DDS
    • Partially Implemented by WaxPDO (implements the DDM directly in SQL using ALTER TABLE)-- NOT RECOMMENDED
  • Context wrappers (similar to controllers, but not really), and Role Methods
  • Views
  • Layouts
  • Wax Querystring Routing (/Object/_id/method/arg/arg/...)

Things that kindof work, but aren't documented and are full of bugs

See the previous post for more details about these.
  • Login System (Requires creation of extra views and custom session management code)
  • ACL (Front-ends aren't done, Still very buggy)

Things that don't work / not implemented / TODO

  • Ajax support
  • Recursive Models (IE: auto-detect parents and children when fetching data)
  • Advanced Attributes (facebook-style)
  • Hidden Attributes (for the AntiSpam attribute, mostly)
  • Custom Forms (more on this once it's implemented)
  • Multiple layouts/output formats (ie: HTML, Ajax, RSS, etc.)
  • CouchDB interactivity with the Dynamic Model *high priority*
Documentation is still pretty rough, but any feedback is welcome. There's also quite a few security flaws that I haven't quite sorted out yet. You can check out the tutorial at The Getting Started wiki page and grab the downloads from The Google Code Page or from the sidebar on the right.

Monday, May 3, 2010

Users, Permissions, and the ACL

With frameworks inevitably comes the need to authenticate users and control permissions. In Wax, this need must be very carefully planned out, since the dynamic nature of the system allows for (almost) any object to have permissions on almost any other object. Let's consider a simple example: We have a Users object and a Tickets object. Regular users can view a list of tickets, while Administrators can CRUD the tickets. We want to make sure that these are the permissions applied in the system.

Creating a Model that has Permissions

As much as I would love to say that there is no coding involved in the creation of a login system, there are a few things that need to be done to make the system work properly.

Creating an Object with rLoginIdentifier and rPermissionHolder

The Wax DDM (Dynamic Data Model) provides two roles, rLoginIdentifier and rPermissionHolder which give regular old dumb objects the ability to act as smarter, permission having objects. First, an object must be created in the DDM. The object must contain a 'Username' field and a 'Password' field. Besides that you could store user information, last login information, etc., but 'Username' and 'Password' are all that are required. Secondly, the object must implement rLoginIdentifier and rPermissionHolder:
class Users extends DDM implements rLoginIdentifier, rPermissionHolder {}

That's pretty much it for the Login system

Implementing the rLoginIdentifier also gives the Users object the 'login' action, which actives the resource: /Users/login - which is the front-end to the login system. The Login system allows you to turn a regular dumb object into something useful with only 1 line of code (the Users class definition). Normally, the DDM handles all actions directed at a dynamic model, but in this case, we've overridden the basic DDM and given the Users object all of the dynamic functionality but added some additional functions as well.

Using the ACL

Using the ACL is just as simple as setting up a login system. In fact, half of setting up the login system is actually setting up the ACL. The rPermissionHolder role exposes 3 methods which interface with the Dynamic Data Model which allow for Getting/Setting permissions on resources.

Getting a User's Permissions

The User information is stored in the PHP $_SESSION object, which allows you to access the actual user information very easily ($_SESSION['User']). Using this information, an actual model can be instantiated:
$user = new Users($_SESSION['User']);
The permissions of any resource can then be checked with IsAllowed or GetPermissions.
if ($user->IsAllowed("SomeModel/modify")) {    
    // success
}
else {    
    // InvalidPermissionsException
}
$permissions = $user->GetPermissions();
/**
* Permissions would be something like:
* Array(
*    [SomeModel/] => 1,        // User has access to all function of SomeModel
*    [SomeModel/delete] => 0   // But there is also an explicit DENY to SomeModel/delete
* )
*/
By default, all permissions are denied for all users. Each ACL entry represents an ALLOW permission for some resource. As shown above, explicit DENYs can also exist, which is useful when you want to grant all permissions EXCEPT for some action-- in the above case, Deleting the objects is not allowed.

Sunday, May 2, 2010

Login- A good example of customizing the dynamic model

With the Dynamic Data Model rewritten in the new routing format, it was relatively easy to get the Login roles working. The next step is to make the ACL work. The login system is implemented in 3 different pieces:
  • The Users object
  • The rLoginIdentifier roles
  • The UsersLoginCtx context
Each of these pieces serves a different purpose, explained below.

The Users Object

The Users object contains the basic object that extends DDM. Additionally, it implements the rLoginIdentifier which provides the Authenticate() and session management methods. This object also provides the target for the actual request-- as in the URL for accessing the login function is:
/Users/login

rLoginIdentifier

The rLoginIdentifier role provides methods that Authenticate the user against the dynamic model. It makes use of the PasswordAttribute class and the rPasswordHasher role to hash the password using a User-specified hash function. The LoginIdentifier role also provides access to 2 session management methods:
  • SetSession($var, $value)
  • DestroySession()
Where SetSession can set and unset session variables, while DestroySession can destroy a session for logout purposes.

UsersLoginCtx

This is the class that actually handles the Login request. Requests are handled either by a corresponding context name (ie: UsersLoginCtx) or role method (Users->Login). In this case, the context is used since each application's Login method will be different and as such, should not be coded as a role method. Since the Authenticate role only returns the result of the actual Authentication, this context is responsible for handling the result of the Authenticate function. It takes the result and stores it in the session, then redirects the User to the home page. This context must be coded specifically for each application. It allows for the basic Authentication module to be very dynamic (providing a list of different hash functions), while allowing the actual session management to be completely custom.

More To Come...

This is just this first example of the model of programming that Wax and the IWH package are built on. The roles will provide commonly used functionality (scaffolding, the dynamic data model, login/sessions, etc.), while the contexts provide a way to set up these function calls around custom application functionality.