I'm trying to make use of the Phalcon Acl in my application but I'm running into some very strange behavior. I'm using the Vokuro app as a guideline to persist Profiles (Acl Roles) to the database.
The following is my schema/data for a Role which is Identical to the Vokuro sample application
CREATE TABLE IF NOT EXISTS profiles (
id int(10) unsigned NOT NULL AUTO_INCREMENT,
name varchar(64) NOT NULL,
active char(1) NOT NULL,
PRIMARY KEY (id),
KEY active (active)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ;
INSERT INTO profiles (id, name, active) VALUES
(1, 'Administrators', 'Y'),
(2, 'Users', 'Y'),
(3, 'Read-Only', 'Y');
In my script, I fetch profiles and add them as roles (same as in the Acl for vokuro)
// Register roles
$profiles = Profiles::find('active = "Y"');
foreach ($profiles as $profile) {
$acl->addRole(new Role($profile->name));
}
Resources are defined as follows:
$acl->addResource(new Resource('index'), array('index'));
$acl->addResource(new Resource('user'), array('search', 'create'));
$acl->addResource(new Resource('admin'), array('create', 'update', 'delete'));
Once I have resources and roles added to the ACL, I try to set up some permissions, using the wildcard role first
EX1
$acl->allow('Read-Only', 'user', 'create'); // THIS WORKS
$acl->allow('*', 'index', 'index'); // allow everyone to access index/index THIS LINE CAUSES PROBLEMS
$acl->allow('Read-Only', 'user', 'search'); // FAILS HERE with error 'Role "Read-Only" does not exist in ACL'
The above code fails on the last line, where I try to set permissions on the Read-Only role, ONLY if I set a permission using '*' as the role before it (as in the example). It is strange because the first line executes fine, so the role Read-Only, exists at that point but doesn't exist after the 2nd line. So, the 2nd line is problematic.
A few things I noted about this issue is it only occurs for the very last role added to the ACL. In the above case, 'Read-Only' was last to be added to the ACL as a role.
The following code works fine
EX2
$acl->allow('Read-Only', 'user', 'create'); // THIS WORKS
$acl->allow('*', 'index', 'index'); // allow everyone to access index/index
$acl->allow('Users', 'user', 'search'); // THIS WORKS because 'Users' was not the last role added
Of course, If I don't use the wildcard role in line 2, I never have any problems for EX1.
If you use a wildcard role a second time, you get a different error
EX3
$acl->allow('Read-Only', 'user', 'create'); // THIS WORKS
$acl->allow('*', 'index', 'index'); // allow everyone to access index/index CAUSES PROBLEMS
$acl->allow('*', 'user', 'search'); // THIS FAILS
// ABOVE LINE PRODUCES THE Following stack trace
/*
PHP Fatal error: Uncaught exception 'Phalcon\Acl\Exception' with message 'Role "' in /www/project/scripts/acltest.php:130
Stack trace:
#0 [internal function]: Phalcon\Acl\Adapter\Memory->_allowOrDeny('\x00 \x00\x00\x00\x00\x00\x00y', 'user', 'search', 1)
#1 /www/project/scripts/acltest.php(130): Phalcon\Acl\Adapter\Memory->allow('*', 'user', 'search')
#
*/
The wildcard is clearly problematic.
Another strange thing I noticed is this behaviour doesn't occur if we hardcode the roles instead of retrieving from the db. For example if I define the above roles as follows:
// Hardcode the roles
$acl->addRole(new Role('Administrators'));
$acl->addRole(new Role('Users'));
// $profiles[2]->name == 'Read-Only' is true.
$acl->addRole(new Role('Read-Only')); // but we need to pass in a string literal
If I use this approach, EX1 gives me no issues
I realize that there are several work arounds for this. I could use role inheritance to avoid using a '*' role.
To confirm that my database environment is not at fault, I set up the vokuro app on the same mysql server, in the ACL rebuild method, I added code similar to EX1 and I get the exact same error. So that rules out the possibility my dabase setup is at fault.
I am fairly certain this is a bug, the $acl->allow() should not affect the collection of roles in the ACL. Has anyone else had this issue?
I'd really like for this behaviour to be fixed and work properly.