CakePHP PSR7 Middleware Authentication

Introduction and background

Let’s start with some background story on this topic. One of the parts of the CakePHP framework I like the less is the authentication and authorization. There are a few reasons why. For example the authentication and authorization. Firstly both authentication and authorization have been married through the AuthComponent, secondly the component is an ugly monolith that is coupled to the controller layer of the MVC pattern.

While CakePHP 3 is an awesome framework it carries some of the older parts of the framework along to ensure backward compatibility which is, in my personal opinion, good. Software development should be an evolution and not a revolution. Also a soft migration path should be provided if possible. So the requirement for a new implementation was to stay backward compatible to some degree.

The new implementation

https://github.com/cakephp/authentication

I’ve been working from time to time late night to finish a new authentication system for the CakePHP 3 framework based on a PSR7 conform middleware. Which is the place where authentication should happen in my opinion. The request object should carry all information you need to identify an user. Also you want to identify an user or a service early in the stack.

The authentication has been completely refactored and was moved into a new namespace/authentication and the code‘s folder structure was reorganised as well. But the biggest change is probably the better split of the logic, a more fancy term is separation of concerns, of the authentication code. The code has been split into authenticators and identifiers. Basically the authenticator just looks for the credentials in the request and passes them to a collection of identifiers that will use the credentials to identify the identity against different sources. So for example you can check the same credentials against an users table using the CakePHP ORM and LDAP at the same time.

The configuration stays almost the same as it was before just that you have to split it for the authenticators and identifiers. Also hooking the authentication in your app is now happening in the middleware, no longer the controller. But these two things are the most dramatic changes on the surface you’ll be confronted with.

New features

Besides keeping the existing authenticators, HTTP Digest, HTTP Basic and Form there is now Token and Session as well. Token is a high level implementation that allows you to use a token from the requests query parameters or a HTTP header. Extending this to use JWT should be trivial.

Current status and roadmap

The current status of the plugin is that it is ready to be used – technically. What I expect from you, the community, is ideas for improvements and additions. And despite the good unit test coverage of more than 92% I expect bugs to be encountered as usual.

The roadmap for the plugin is to release 1.0.0 along with the official release of CakePHP 3.4. The plugin itself is right now in beta and will make it’s path to a final release depending on your feedback. So if everything goes well this means the plugin should be tagged 1.0.0 the latest by the end of January 2017.

The long term plan is that the plugin will be integrated into the framework itself. The goal is to get it into CakePHP 3.5 early to mid next year.

Where is the code? How do I install it?

Check the official repository of the plugin and install it via composer as usual.

Pay attention to the version constraints! Until CakePHP 3.4 is released it will require the 3.next branch!

The readme.md of the project contains some basic information on how to get started with the new implementation and provides information on how to migrate from the AuthComponent as well.

Using Robo to automatically trigger unit tests while developing

Robo is an excellent php task runner, similar to NodeJS Gulp. I was looking for a pure php alternative to Gulp for my php projects and I simply prefer to have a tool chain written in the same language if possible. Also I found the code to be a lot better manageable than using Gulp.

So here is one of my main use cases I have for it. I wanted to run the unit tests as soon as I modified a test case. The following code is for a CakePHP3 project.

You can adept the above script for other projects as well pretty easy. Also that should be required is to make sure that you change line 13 so that it fits the path and convention of your project.

Working with CakePHP 3.0 Entity objects vs CakePHP 2.0 arrays

CakePHP3 finds will now return a ResultSet object that contains entity objects, one per records. You’ll have to work with these objects now instead of arrays. This is the official description of them:

  • Cake\ORM\ResultSet – A collection of results that gives powerful tools for manipulating data in aggregate.
  • Cake\ORM\Entity – Represents a single row result. Makes accessing data and serializing to various formats a snap.

Further down on that page there is even more info about that. Take a look at the ResultSet API. You’ll see that it implements Iterator, you can use it like an array because of that but it’s an object.

Let’s start with the example UsersController.

The UsersTable, formerly known as a Model.

In your App/View/Products/index.ctp put this:

If you add a

in the loop it will show you the Entity object. I’m not pasting the whole long debug output here, skipping a few fields.

As you can see you’re getting an object back not an array any longer. To access the values or “fields” of your entity object just access it as a property of the object, the magic getter will get you the value of it from the protected _properties property of the Entity object.

Now try adding this into the foreach loop.

Output:

Not all fields were converted, fields that contain an object stay an object. Calling toArray() here will convert the object into an array in the case you really want to continue using arrays instead of object. I would not recommend to do so because your’re simply throwing the new features and possibilities objects make possible away!