A use case of Zend_Auth and Zend_Acl with DB and LDAP
Posted: April 11th, 2011 | Author: enrico | Filed under: Zend Framework | Tags: acl, auth, database, ldap | 52 Comments »During one of my recent consultancy I helped a customer to implement an authentication and authorization mechanism for a Zend Framework application. Because this scenario is quite common in PHP business applications I decided to write this post to present a possible solution.
The requirements of the web application were:
- implement a login page to access the web application;
- authorize the usage of the application based on user’s groups;
- management of the MVC architecture of ZF using modules;
- implement an access control list (ACL) to authorize specific modules, controllers and actions for user’s groups;
- implement a LDAP authentication or a database authentication (based on the user profile);
- use of a database to manage the user’s groups and the relative authorizations;
- good performance (the ACL can be big).
In this implementation we used the Zend_Auth class to authenticate the users and Zend_Acl to implement an access control list based on ZF modules, controllers and actions. We used a FrontController plugin to insert the authentication and the authorization check using the preDispatch() method. We used the Zend_Auth_Adapter_DbTable and Zend_Auth_Adapter_Ldap to implement the authentication using a DB and a LDAP server.
The implementation follow the common criteria of a ZF application. In my opinion, one of the most interesting part is the permission definition for the resources with the user’s groups. We used a special syntax using the following structure: “module/controller/action” where module, controller, and action are the names of the specific components. We decided to implement a way to specify multiples components using the * character. That means you can use resources like: “module/*/*” to enable or disable the access to all the controllers and actions of a specific module.
Using this mechanism you can provide complex rules with few definitions, for instance to enable the access of generic controllers and deny the access for some specific actions you will need only two resources.
The idea is to enable or disable the access of specific resources based on the permission starting from the more general until the more specific, using a top-down approach:
- */*/*
- module/*/*
- module/controller/*
- module/controller/action
A specific rule wins against the general one. Unless otherwise specified all resources are disabled by default.
We used the following MySQL database to implement the data structure of the authentication and authorization system:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | CREATE TABLE 'permissions' ( 'id' INT(11) NOT NULL AUTO_INCREMENT, 'id_role' INT(11) NOT NULL, 'id_resource' INT(11) NOT NULL, 'permission' enum('allow','deny') NOT NULL, PRIMARY KEY (`id`) ); CREATE TABLE 'resources' ( 'id' INT(11) NOT NULL AUTO_INCREMENT, 'resource' VARCHAR(128) NOT NULL, PRIMARY KEY ('id') ); CREATE TABLE 'roles' ( 'id' INT(11) NOT NULL AUTO_INCREMENT, 'role' VARCHAR(40) NOT NULL, 'id_parent' INT(11) NOT NULL, PRIMARY KEY (`id`) ); CREATE TABLE 'users' ( 'username' VARCHAR(40) NOT NULL, 'password' VARCHAR(40) NOT NULL, 'id_role' INT(11) NOT NULL, 'ldap' tinyint(1) NOT NULL DEFAULT '0', PRIMARY KEY USING BTREE (`username`) ); |
We have 4 tables: users, roles, resources and permissions. In the table users we store the user’s profile with the role of each user and the authentication mechanism, using an LDAP server (ldap=1) or a database (ldap=0).
In the role table we provide a generic solution to inheritance privileges from a parent group (using the id_parent field). In the permissions we insert a field (permission) that can be used to allow or deny the access of a resource for a specific user’s group.
For the performance requirement we used a caching system for the ACL object. That means the system caches the Zend Acl object based on the user’s role and reuse it for different requests. In this way the access to the MYSQL database for the ACL is done only once, for each user’s group. The lifetime of the cache can be very long, because generally speaking the ACL is done rarerly, and it’s related to the update time of the ACL in the database. We used the APC backends to cache the access control list.
Notes about the example
Here you can download the implementation: download the source code.
We created a ZF application that has two modules: login and home. In the login module we inserted all the logic of authentication and authorization. This solution is quite good because you can just reuse it in different ZF applications without big changes.
In the home module we insert only 2 static pages: index and menu. This just to provide an example of different permissions. In the database provided with the example we have two users: admin and enrico (with passwords ‘admin‘ and ‘enrico‘). Admin can access all the modules, controllers, actions of the application (using the resource syntax ‘*/*/*’). Enrico can access all the resources in the home module, except for the action menu of the index controller (this is specified with the two following rules: allow ‘home/*/*’, deny ‘home/index/menu’).
Try to access with admin, and request the url /home/index/menu. After logout and login with enrico to try again to access the url /home/index/menu, you will see that the application will redirect you on the login page because enrico doesn’t have the right to access that url.
The most interesting part of the implementaion is the Login_Plugin_SecurityCheck class that is the front controller plugin. Here is specified the logic of the user authorization in the _isAllowed() private method (lines 73-90).
Below id reported the source code of this plugin:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | class Login_Plugin_SecurityCheck extends Zend_Controller_Plugin_Abstract { const MODULE_NO_AUTH='login'; private $_controller; private $_module; private $_action; private $_role; /** * preDispatch * * @param Zend_Controller_Request_Abstract $request */ public function preDispatch (Zend_Controller_Request_Abstract $request) { $this->_controller = $this->getRequest()->getControllerName(); $this->_module= $this->getRequest()->getModuleName(); $this->_action= $this->getRequest()->getActionName(); $auth= Zend_Auth::getInstance(); $redirect=true; if ($this->_module != self::MODULE_NO_AUTH) { if ($this->_isAuth($auth)) { $user= $auth->getStorage()->read(); $this->_role= $user['id_role']; $bootstrap = Zend_Controller_Front::getInstance() ->getParam('bootstrap'); $db= $bootstrap->getResource('db'); $manager = $bootstrap->getResource('cachemanager'); $cache = $manager->getCache('acl'); if (($acl= $cache->load('ACL_'.$this->_role))===false) { $acl= new Login_Acl($db,$this->_role); $cache->save($acl,'ACL_'.$this->_role); } if ($this->_isAllowed($auth,$acl)) { $redirect=false; } } } else { $redirect=false; } if ($redirect) { $request->setModuleName('login'); $request->setControllerName('index'); $request->setActionName('index'); } } /** * Check user identity using Zend_Auth * * @param Zend_Auth $auth * @return boolean */ private function _isAuth (Zend_Auth $auth) { if (!empty($auth) && ($auth instanceof Zend_Auth)) { return $auth->hasIdentity(); } return false; } /** * Check permission using Zend_Auth and Zend_Acl * * @param Zend_Auth $auth * @param Zend_Acl $acl * @return boolean */ private function _isAllowed(Zend_Auth $auth, Zend_Acl $acl) { if (empty($auth) || empty($acl) || !($auth instanceof Zend_Auth) || !($acl instanceof Zend_Acl)) { return false; } $resources= array ( '*/*/*', $this->_module.'/*/*', $this->_module.'/'.$this->_controller.'/*', $this->_module.'/'.$this->_controller.'/'.$this->_action ); $result=false; foreach ($resources as $res) { if ($acl->has($res)) { $result= $acl->isAllowed($this->_role,$res); } } return $result; } } |









Hi,
this is a very quality and good coding example.
Keep up your good work
I’m going to implement it within my CMS!
best regards
René
I’m using a similar approach for ACLs, with key differences that the permissions/roles/resources are not in a database but in a simple array (no requirement to change them from say an admin panel) and that I have implemented groups also. Groups allow me to say, for example:
– group-unregistered has access to the home page, login page and register page.
– group-registered has access to the myprofile page (both regular users and site administrators)
– and finally to say administrators can access the administration page
instead of explicitly saying users have access to the myprofile page and administrators have access to the myprofile page.
Hi,
The above looks good, I have a small question/comment regarding the way isAllowed is being dealt with.
I see that for each request you are checking permissions from the most open to the most restricted – ie from ‘*/*/*’ .all the way to down to a specific ‘module/controller/action’.
In Zend Acl, (plz correct me if I’m wrong
), if a role doesnt have allowed() set for a particular resource it will be denied access?
Therefore if you assign module:controller:* to a role, but don’t then assign a specific module:controller:action, the foreach loop will return false.
I can see that you are using has() to check that the resource exists in the ACL, which I guess prevents you from having to specify every module:controller:action in the database. However, does this mean the following scenario is not possible :
Two roles : ROLE A & ROLE B
Two resources : moduleX:controllerY:actionZ & moduleX:controllerY:*
Permissions
ROLE A has : moduleX:controllerY:actionZ
ROLE B has : moduleX:controllerY:*
Would ROLE B be denied access?
I may be missing something obvious, but I’m implementing Zend ACL currently and running into all sorts of issues!
Cheers
Rob
Hi Rob,
the Zend_Acl denies access, by default, for every resources, if you don’t allow explicitly a resource.
In your example the ROLE B has access to all the actions of the controllerY, moduleX.
The ROLE A has access only on the actionZ, controllerY, moduleX.
All the others resources means modules, controllers, and actions are denied.
Hi Enrico,
Thanks for your reply!
Could I just ask you to clarify this point…
“In your example the ROLE B has access to all the actions of the controllerY, moduleX”
Based on my understanding – Role B has access to a “resource” called controllerY:moduleX:*, which to me semantically means it has access to all the actions within that controller. However, given the way isAllowed is being called:
foreach ($resources as $res) {
if ($acl->has($res)) {
$result= $acl->isAllowed($this->_role,$res);
}
}
return $result;
For any given action, isAllowed will only return true if the role has been assigned the specific resource “module:contr:action”. True will not be returned if the role is just assigned the wildcard version.
Do you agree with this deduction?
If so, could you plz outline what use the wildcard resources have, as it appears to me I would always need the most specific versions for each action assigned to a role anyway.
Thanks for your time
rob
Hi Rob,
your deduction is not correct because you are missing the logic of my implementation of the rules from general (*/*/*) to specific (module/controller/action). I suggest to have a look at the _is Allowed method of the plugin Login_Plugin_SecurityCheck. The permission is defined against 4 checking (lines 92-96). If a role has the rule we check if the resources is allowed or not. That means if you are checking a specific action and you have the rule that allow on ‘module/controller/*’ the $result will be true. Notice that the $result variable is overwritten with a more specific rule, if it exists.
Hey Enrico,
Thanks for your reply.
Are you saying that if a role is assigned a resource for example module:controller:*” it doesn’t need to be assigned the more specific resource module:controller:action to be granted access to that action?
I’m afraid I cant see how this would work as the final run of the foreach loop (line 85 above) would always return false given that the role isnt actually assigned the “resource module:controller:action”.
Based on my understanding the only way I could see this working would be if you were using inheritance in your resource structure.
Don’t want to take up too much of your time, but would like to bottom this out.
Thanks
Rob
Hi Enrico,
The nice craftsmanship of Zend ACL.
In early days, i really scared of zend ACL. But this tutorial has helped me a lot to make my hand dirty to play with zend ACL.
Well, I’m using your code but what I’m facing a problem is I cant take an advantage of roles inheritance
(i.e. guest->member->admin->super admin).
This is because of ,Login_ACL loads only those resources which have permission defined in “permission” table for a specific role.
So here I need to specify each and every possible permission(allow or deny) for each role.
If i want to take a benefits of roles inheritance then i guess, I need to load resources and permission of all the ancestors of this role.
Can you please correct me whether am I interpreting it correctly ?
And my app is based on zend framwork and ajax so can you help me how to deal with ACL for ajax based request.
I’m thinking to abort the ajax request from the client side only instead giving a load to server.
Thanks,
Sachin
Hi Sachin,
you are right the inheritance implementation was not correct in my example.
I changed it to load all the resources and the permissions of the inheritances of a role.
I updated the source code on Github, the main change is in the Login_Acl class.
Regarding the Ajax call and ACL i think is a good idea to disable the call for performance but it’s also very important to implement the ACL checking in the server side, for security reason.
Thanks for your comment.
Hi Rob,
i just updated the source code based on the comment of Sachin.
There was a problem regarding the inheritance implementation.
Regarding your question the idea is to use the has() method to check previously if the resource is assigned to that request, if not I don’t check it using isAllow(). That means it will win the previous check using the 4 resources: */*/*, module/*/*, module/controller/*. module/controller/*.
Btw, thanks for your comments i’m double checking my code
Hi Enrico,
Great discussion, finding this very useful.
Ive checked your code and I still believe there is an issue.
Let me run through an example with the sql you have in your github.
Admin Role has the following role : */*/*.
This is the ouput of each step in the foreach loop (85 above) as I see it.
Say you’ve made a request for module: home, controller: index, action : menu
and the user has the role ‘Admin’
Step 1. $res = ‘*/*/*’, – $result will be true as admin has this role.
Step 2. $res = ‘home/*/*’ – $result will be false as admin does not have this role
Step 3. $res = ‘home/index/*’ – $result will be false as admin does not have this role
Step 4. $res = ‘home/index/menu’ – $result will be false as admin does not have this role
$result will be returned as false as step 4 returns false
The only way this implementation will work is if you use inheritance in your resources.
See Zend_Acl : line 282 (framework version : 1.11.3)
public function addResource($resource, $parent = null)
You could think about breaking out of the your foreach loop if true is returned, but this would still not accommodate the role being denied a more specific version of the resource.
What do you think?
Hi Rob,
i don’t see the issue regarding your scenario.
In my db example the role admin has only the allowed resource ‘*/*/*’ (that means every modules, controllers and actions, from a semantic point of view).
In the lines 92-96 of the SecurityCheck plugin only the first loop will be executed, because of has().
The trick is the usage of the method has() to check if the resource exists for that specific role (admin).
In the Zend_Acl instance I inserted only the resources related with admin and his inheritances.
That means the $result will be true at the end of the loop.
Thanks Enrico!
I totally missed the fact that you are only loading resources that are assigned to the role that the current user has.
That way as you say, has() is working to authenticate that resource, as opposed to just checking if is in the ACL.
Great stuff.
Thanks for your time
Rob.
Hi Enrico,
Thanks for making change in older copy to support inheritance. I will download the fresh copy soon.
I’m curious to know about the performance stuff to add role and resource using addRole(new Zend_Acl_Role($role->id) and $this->addResource(new Zend_Acl_Resource($res['resource'])); respectively in conjuction with foreach loop when permission list is too long.
I mean, is it the right practice to create the numerous objects using loop ?
yes,I have checked that you have used zend _cache to cache the ACL object, so once it is compiled for first time , the later/sub-sequent request would be served from cache.
Thanks for the reply,
Sachin
Hi Enrico,
today, i have had chance to look into the updated version of ACL.
Two things I found are
1) Login_Model_Roles :: getParentRole($role) method
suggestion:
We dont need the mysql self join to “roles” table.
As the parentID of $role itself is an ID of parent role.
We can use sql like “select parentID from roles where ID=$role ”
2) Login_Acl :: loadResources($db,$role) method
suggestion:
We need to check whether the resource we are going to add is already in registry or not. If it is not there then we should not allow to add resource.
Actually, the problem is because now it supports the role inheritance. So there might be case when one role (A) has access to resource R1 and now if role B is inherited from A then it is possible that we set deny permission for Role B to access R1.
if(!$this->has($res['resource']))
$this->addResource(new Zend_Acl_Resource($res['resource']));
Correct me if I’m wrong….
Cheers,
Sachin
Hi Sachin,
thanks a lot for your suggestions!
I don’t know why I used the join in the query to get the parent_id, just to complicate the solution
Regarding the performance I don’t think is a problem because I used a caching system.
For the problem of load the same resources more times, in case of inheritance, you are right, i fixed it.
I already updated the source code in github with your suggestions.
Thanks again.
Hi, Enrico
I want your little help in zend framwork.
Actually, i want to add ACL to zend navigation that i’m using to draw the html navigation menu.
So here what I’m doing is, I initialize the navigation in my bootstrap (which extends Zend_Application_Bootstrap_Bootstrap) using _initNavigation() that construct Zend_Navigation() object by loading one xml file.
Now, I’m initialized Zend_Acl() which loads the necessary roles,resources and permissions from database. This is written inside same function call _initNavigation().
Actually, I have taken one model that extends Zend_Acl to construct app ACL object.
So what exception I’m getting is ” No adapter found for Default_Model_DbTable_Roles”
What I’m predicting to cause this error is, ZF is not able to initialize the zend db object at the time when I construct ACL object for my app from _initNavigation().
protected _initNavigation()
{
$aclObj = new my_model_for_ACL(); //this extends Zend_Acl
$navigation = new Zend_Navigation($navConfig);
$view->navigation($navigation)->setAcl($aclObj)
->setRole($userRole);
}
I guess, there may be a hook to initialize the database adapter from bootstrap file itself.(application.ini already contains all the necessary parameters for resources.db.XXXXX)
Will you please help to fix this ?
Have a nice day,
Thanks,
Sachin
Hi Sachin,
the error “No adapter found for…” is general related to the DB adapter used by Zend_Db_Table. Did you tried to specify the resources.db.isDefaultTableAdapter = true in your application.ini?
regarding your request to initialize the db resource of Zend_Application you can use the following code:
$bootstrap->bootstrap(‘db’);
$dbAdapter = $bootstrap->getResource(‘db’);
to get the Adapter of your DB (where $bootstrap is the instance of the Zend_Application).
Curious as to how this handles scenarios like only your one-to-many relationships. I can understand a one-to-one where it is /user/profile/edit and a user has only one profile but if a user has multiple then isAllowed needs to take into account more information such as /content/comment/edit where a user might have 20 comments but can edit only his posts. Let me know if I’m missing something as this is why I’ve stayed away from Zend_Auth / Zend_Acl. thx
This is just an example to manage an access control list using Zend_Acl based on modules/controllers/actions. If you need to manage authorization based on other criteria you have to insert the condition in your code. Btw, you can do even with this implementation, you can add resources for some role and check it in your code.
Don’t forget that Zend_Acl is very general and is not related to any specific resource. A resource is only a string for Zend_Acl, the developer gives the meaning of what a resources is, as I did in the implementation reported in this post.
hi. i ran your code and the acl extension crashed apache. i get this error:
[Thu May 12 18:49:08 2011] [apc-error] Cannot redeclare class zend_loader_autoloader
[Thu May 12 18:49:13 2011] [crit] Parent: child process exited with status 2 — Aborting.
any suggestions?
I’m using a much more simpler approach with each user is defined as a particular “user type” and I keep an intermediate table between all possible actions and rights allowed to each “user type”.
Everything is very easy modifiable from a custom interface I put in place, applied immediately as there is no cache applied to this security approach and on top I can extract report with current right to any audit by user(s) / application(s) / action(s). Any modification to such structure leaves a trace in a shadow table, all managed with MySQL triggers (identifiers, old, new value, date/time and modifying user).
Maybe the only downside of my approach would be that would become hard to maintain if # of “user type” is medium or high but for the location I’m working in works perfectly.
Hi Chrisv,
did you check if your include_path is set twice?
I’m not sure maybe is a problem of session close, check this: http://www.readmespot.com/question/o/1364750/opcode–apc-xcache—zend–doctrine–and-autoloaders
What version of APC, PHP and Zend Framework are you using? I will check your environment on my laptop.
Hello Enrico,
Very nice use case.
Do you have any suggestions on extending this ACL plugin so it’s optional to also add user restrictions on a user_id instead of role_id only. So that a person can get a exception on a predefined role?
Kind regards,
Erwin
Hi Erwin,
the simplest way to manage authorizations for a single user is to create a special role for the user. This role must be assigned only to the user.
In this way you can continue to work with the same architecture without change the PHP code of the web application.
Hi Enrico,
I have tried to implement this in my module based app but cannot get things working. The Zend loader doesn’t find Login_Plugin_SecurityCheck.
Here’s the first error:
Warning: include_once(Login/Plugin/SecurityCheck.php) [function.include-once]: failed to open stream: No such file or directory in /path/to/my/vhost/htdocs/Library/Zend/Loader.php on line 146
I believe I made the proper changes to my application.php and ini files.
My ini does use this:
resources.frontController.defaultModule = “default”
instead of your setting of “login”
Any help would be greatly appreciated.
Jeff
Hi Jeff,
if you changed the modules of the project you have to change the namespace of the Login_Plugin_SecurityCheck in Default_Plugin_SecurityCheck, where Default is the module name that you used. Moreover you have to change the configuration of the application.ini according with the new module name.
I realize that in trying to be concise, I probably wasn’t very clear about what I had going on.
I decided to set up a new vhost using your application only and then figure out how to find out the issue with my existing zf app from there.
Unfortunately, I couldn’t get that to work…
I can now see the log in screen but when I submit the form, I get a 404 (The requested URL /login/index/login was not found on this server.)
This is set up from your download with only my db credentials added to the .ini
Again, any help would be greatly appreciated.
Jeff
Hi Jeff,
the 404 error means that the routing of the application is not working.
Did you enable the rewrite module of Apache for the .htaccess?
Did you create a virtual host to point to the public folder of the project?
Hi Enrico,
I kept assuming that I had the rewrite conditions proper because I had copied the host configuration from another vhost. That’s where the problem was.
Thank you for the article and for the help.
Jeff
Hi Enrico,
The problem was with my rewrite conditions. I assumed they were fine since I copied the vhost config.
Thank you for the article and your help
Jeff
Hi Enrico,
Hope you’re doing good…
I back again..!!!!
Just want to know how to distinguished errors 404 and not allowed(access denied) when using your ACL code.
Thanks,
Sachin
Hey, many thanks for sharing.
It helped me a lot while implementing ACl for my project.
Thanks again.
-Prasad
Hi Enrico,
I am having difficulties using your setup with the zend_navigation plugin.
Do you have any ideas how to use your setup with it? The problem is that the Zend_Navigation is based on the standard validation and not on the */*/* idea you have used.
Do you have any tips.
Kind regards,
Erwin
I am trying to implement this using the GitHub example – https://github.com/ezimuel/Authentication-and-authorization-with-ZF
..but i can’t seem to get past this error:
Fatal error: Class ‘Login_Plugins_SecurityCheck’ not found in /Library/WebServer/Documents/myProject/library/Zend/Application/Resource/Frontcontroller.php on line 117
My SecurityCheck.php file is located – /application/modules/login/plugins/
My application.ini file looks like:
resources.frontController.defaultModule = “login”
resources.frontController.params.prefixDefaultModule = “1″
resources.modules[]=
resources.frontController.moduleDirectory = APPLICATION_PATH “/modules”
resources.frontController.plugins[] = “Login_Plugins_SecurityCheck”
Any help with this would be great!
hi men thanks for share in GPL your code. i try to experiment to use zend framework more expecificly zend_auth & zend_acl, i try to use your code. and give to me an error;
Resource id ‘home/index/menu’ already exists in the ACL
#0 /var/www/jaime/autentificacion/application/modules/login/library/Login/Acl.php(64): Zend_Acl->addResource(Object(Zend_Acl_Resource))
#1 /var/www/jaime/autentificacion/application/modules/login/library/Login/Acl.php(22): Login_Acl->loadResources(Object(Zend_Db_Adapter_Pdo_Pgsql), Object(Zend_Db_Table_Row))
#2 /var/www/jaime/autentificacion/application/modules/login/plugins/SecurityCheck.php(45): Login_Acl->__construct(Object(Zend_Db_Adapter_Pdo_Pgsql), 2)
#3 /var/www/jaime/autentificacion/library/Zend/Controller/Plugin/Broker.php(309): Login_Plugin_SecurityCheck->preDispatch(Object(Zend_Controller_Request_Http))
#4 /var/www/jaime/autentificacion/library/Zend/Controller/Front.php(941): Zend_Controller_Plugin_Broker->preDispatch(Object(Zend_Controller_Request_Http))
#5 /var/www/jaime/autentificacion/library/Zend/Application/Bootstrap/Bootstrap.php(97): Zend_Controller_Front->dispatch()
#6 /var/www/jaime/autentificacion/library/Zend/Application.php(366): Zend_Application_Bootstrap_Bootstrap->run()
#7 /var/www/jaime/autentificacion/public/index.php(29): Zend_Application->run()
#8 {main}
i try so much to make work the code… i don’t know if i am the idiot or what jajaja.
scuce me my bad english
thanks
hello enrico,
thanks you for your tutorial,
I downlaod your zend project but I have got an error when I connect to the application :
Exception information:
Message: The apc extension must be loaded for using this backend !
Stack trace:
#0 C:\wamp\www\acl_test\library\Zend\Cache\Backend\Apc.php(59): Zend_Cache::throwException(‘The apc extensi…’)
#1 C:\wamp\www\acl_test\library\Zend\Cache.php(153): Zend_Cache_Backend_Apc->__construct(Array)
#2 C:\wamp\www\acl_test\library\Zend\Cache.php(94): Zend_Cache::_makeBackend(‘Apc’, Array, ”, ”)
#3 C:\wamp\www\acl_test\library\Zend\Cache\Manager.php(173): Zend_Cache::factory(‘Core’, ‘Apc’, Array, Array, ”, ”, ”)
#4 C:\wamp\www\acl_test\application\modules\login\plugins\SecurityCheck.php(37): Zend_Cache_Manager->getCache(‘acl’)
#5 C:\wamp\www\acl_test\library\Zend\Controller\Plugin\Broker.php(309): Login_Plugin_SecurityCheck->preDispatch(Object(Zend_Controller_Request_Http))
#6 C:\wamp\www\acl_test\library\Zend\Controller\Front.php(941): Zend_Controller_Plugin_Broker->preDispatch(Object(Zend_Controller_Request_Http))
#7 C:\wamp\www\acl_test\library\Zend\Application\Bootstrap\Bootstrap.php(97): Zend_Controller_Front->dispatch()
#8 C:\wamp\www\acl_test\library\Zend\Application.php(366): Zend_Application_Bootstrap_Bootstrap->run()
#9 C:\wamp\www\acl_test\public\index.php(26): Zend_Application->run()
#10 {main}
Request Parameters:
array (
‘module’ => ‘home’,
‘controller’ => ‘index’,
‘action’ => ‘index’,
)
Do you have any idea ?
Thanks you for your answer
Hi mamadou,
this example project use the APC backend as caching system to store the Zend_Acl objects.
You must install APC to run this example. You can find how to install APC in your system here:
http://www.php.net/manual/en/apc.installation.php
If you cannot install APC you can change the resources.cachemanager in the application/configs/application.ini.
For instance, you can choose the File as cache backend:
resources.cachemanager.acl.backend.name = File
resources.cachemanager.acl.backend.options.cache_dir = “/path/to/cache”
Thanks you Enrico it work fine,
I choose the configuration of the ini File
I replacethe path with C:/wamp/www/acl_test/application/cache
I will install APC because I read in your presentation that APC is more speed than the others caching technic (file, memcache…)
Hello Enrico,
I have another question,
I have updated the table permisions, I add some permission to the guest. In order to give permision to personnes who do not have an account in the site, but the acces is still locked
I add the permision for the register controller.
Thanks for your answer
Great article! Thanks a lot for it.
Is it also possible to present each role it’s own welcome message? What is the best way to achieve this?
Thanks in advance.
Hi Tim, my suggestion is don’t implement it in the ACL tables. I think you should create a welcome table and select the message according to the logged user.
Thank you for great code! I developed some small database with your script on local windows machine and permissions works great. Then I moved it to linux(red hat) machine and I have little problem. When I try make login as “enrico” (per your example), then in link row in firefox is http://…./home, but page stay on login page. It looks that page was not redirected due permissions. (But permissions are same as on local machine). I am afraid that can be due server setup. Thank you
Hello Enrico,
thank you very much for your example, it works fine!!! I’m new in ZF and I have a question and i hope, you can help me.
In my bootstrap i load my menu with:
$config = new Zend_Config($this->getMainMenu());
$container = new Zend_Navigation();
$container->addPages($config);
$this->view->navigation($container);
it works fine but it works at the moment without ACL. I would like use the menu with your ACL and use this:
$this->view->navigation()->setAcl(Zend_Registry::get(‘Zend_Acl’));
$this->view->navigation()->setRole(‘admin’);
But then i become the following message:
Fatal error: Uncaught exception ‘Zend_Exception’ with message ‘No entry is registered for key ‘Login_Acl”
Do you know where is the problem?
And the second questions. How can I load all privileges for a user in a control to allow or deny special funtions (can delete or edit…)?
Best regards
Joe
It was an error in my last example – here is the right one.
$this->view->navigation()->setAcl(Zend_Registry::get(‘Zend_Acl’));
$this->view->navigation()->setRole(‘admin’);
But then i become the following message:
Fatal error: Uncaught exception ‘Zend_Exception’ with message ‘No entry is registered for key ‘Zend_Acl”
Best regards
Joe
The navigator doesn’t…
Just out of curiosity, how do you manage the Zend_Navigator? (If you use it).
I’m trying to apply your acl in my structure but that seems impossible. In my Navigation structure I’ve many resources and before to render the menu I do this:
$this->_view->navigation ()->setAcl ( $acl )->setRole ( $role );
So.. every resource contained in the navigator must be defined otherwise we’ll obtain an error…
In my ACL I’m defining four roles:
- superadmin (*/*/*),
- admin (admin/*/*),
- staff (admin/mydata/*),
- guest(home/*/*).
Your algorithm consider only to define resources/privileges for parents. This means that if for example I’ve a resource like admin/*/* allowed to ‘admin’ user, the superadmin can get in said resource because of the priority on resource */*/* but if I want to work with navigator I’ve to define the permissions and resources regarding admin also. How can we solve this problem?
I see two solution(but if you have another don’t hesitate to write here!!!):
- create a navigator container specific for each user(one file per each role);
- modify your algo in a way to load resource/permission for childs(but in this case we lose the benefit you proposed)…
I hope to be clear and tell me if I understood well…
Thank you in advance,
Claudio
Very good article, I have two doubts:
How can I pass a parameter to the view the username of the logged in User.
2 is a left module without authentication for users not logged in visitors?
(Thiago Crispin) Brazil.
Hi,
I have downloaded ur project. I am trying to execute it. In DB, u inserted password values as SALT value. How to use login page while entering username and password? That is, I want to know the original password of admin and enrico. I am new to ZF. Pls help me.
The password is stored in the database using SHA1(salt . password) and the salt is stored in configs/application.ini file. The password of admin is ‘admin’ and the password of enrico is ‘enrico’ (as reported in the README file).
Hi,
Is anybody knows how to implement this with “guest” or “public” module in which auth and acl are not required? So people can browse the web site and if want – then create account and login?
Thanks
Aelx
Hi Aelx,
if you want to remove a module under authentication you can easly add that module in the condition (line 22) of the Login_Plugin_SecurityCheck class of my example code.
For instance you can write something like:
if (!in_array($this->_module, $this->_noAuthModules)) {
where $this->_noAuthModules = array(‘login’,'public’); and login, public are the modules without authentication.
Hello Enrico,
First of all thank you, this tut has helped a lot, but just a noob question. in your last answer you state how to remove the auth of another module, but what if I just wanted to remove the auth on a controller of another module and not the entire module…how is that done here?
thanks
chris