Keeping Admin and Public Areas Separate Zend Framework - MVC - ACL versus .htaccess
This post started life as a question to Federico regarding his blog post (re-posted here to enable pre-formatting of the text) and also relates to this issue on the stack overflow site and Euragios’ question on sitepoint.
——-The Question——-
I’ve been looking for a way of seperating my admin control panel from the rest of the project.
I hardly ever see any acknowledgement of ‘an admin area’ in project structure examples that I’ve seen so far on the net (Although, I think i saw a mention on one of Federico’s posts somewhere).
The Concern
I’ve been skirting around the Zend Framework/Front Controller for ages now. Its the issue of ‘a safe admin realm’ that has been stopping me from deploying it to replace my existing, messy, site.
As I read the Zend Docs about routing I see that an URL (/:module/:controller/:action) gets routed, by default, to the appropriate Controller::Action()
This puts me right off the idea of having any ‘admin’ controllers within the same realm/include path of public controllers. My, paranoid, mind imagines so many possibilies for errors like :
//removeDefaultRoutes(); //I commented the line above //just wondering what this does ——–
Then, as i understand it, this would immediately set Zend to automatically map urls to Actions+Args:
This URL: http://example.com/customers/edit/delete/where/all
Would map to:
module -> customers
controller – > edit
action -> delete
Argkey1-> where
ArgValue1-> all
—–
See: http://framework.zend.com/manual/en/zend.controller.router.html#zend.controller.router.default-routes
I guess ACL can do stuff to protect objects. But i’d much prefer not to have to worry about it all.
*My sketchy idea for a solution*:
I was considering the idea of seperating the module’s Models into a stand-alone folder.
Then, “Admin Application Code”, and “Public Application Code” (Controllers+Views) into seperate folders or Realms.
This way, the public webroot “/index.php” can ensure that the ‘admin controllers’ are NEVER in the include path – hence avoiding any worries about an accidental change of code that causes Zend’s DefaultRoutes to flip into action.
So, I thought of a structure like:
App/Domains/ ——[holds model]
App/PublicRealm/ –[holds public controllers/UI/Configs] App/AdminRealm/—-[holds admin controllers/UI/Configs]
htdocs/ ———–[holds public bootstrap]
htdocs/admin/ —–[protected directory , holds admin bootstrap]
———— example:
app/ --Lib/ ----Zend/ ----MyLib/ --Domains/ ---- Modules/ ------default/ --------model/ ------customers/ --------model/ --PublicRealm/ ----bootstrap.php ----Modules/ ------default/ --------controllers/ --------views/ ------customers/ --------controllers/ ----------MemberLoginController.php --------views/ --AdminRealm/ ----bootstrap.php ----Modules/ ------default/ --------controllers/ --------views/ ------customers/ --------controllers/ ----------EditController.php--[solely used by admin] --------views/ --htdocs/ ----admin/ ------.htaccess [auth + mod rewrite] ------index.php [sets include path to AdminRealm , and then PublicRealm, Domains, Lib] --.htaccess [modrewrite] --index.php [setsinclude path to PublicRealm, Domains, Lib ONLY]———-
(For clarity, the above structure doesn’t mention the configs,caches,ini’s,versions etc)
This was something that i have come up with , because i just feel like the router is so complex and ‘automatic’ that i’d prefer to leave nothing to chance and keep the adminRealm seperate.
Does all this make sense?
I’m keen for your opinion
UPDATE
I’ve been doing some more research into this. Yeiniel added a comment, on a neat ‘build a blog tutorial series‘, to outline his methodology for the admin aspects of a Zend MVC Application. (Part 7 of the series exists, its the one that deals with the ACL, but it is not linked directly from Part 6).
Also here is an article that suggests that ACL should apply in the model as opposed to the controllers.
UPDATE
Half the battle, for me, is being clear about the whole routing and dispatch process. My over-cautious approach is a symptom of anxiety caused by “High importance of ensuring access control is fool-proof”+”Drive to ensure that I fully understand all Front Controller variations in implementation”. In my recent travels, I have found this diagram of the dispatch process which is a superb aid to such understanding.
Update
I have done some testing to investigate possibilities of have a subfolder in my controllers directory for admin/backend
Update - More research:Discussion
I’m reading through the discussion on the default app structure and making some notes of interesting comments that strike a chord:
- Everything’s a module
- Shared models
- ‘Gateways’ - some cross-over here with the Realms idea : comment-3867287
- Jason: “Modules as ‘a project inside a project’” : comment-5111819
- Michael: extending modules and sharing module libraries : comment-8945892
- Luiz: Module bootstraps : comment-9994405
- Glen: how would someone re-use your ‘default’ module? : comment-11927739
aah good point. (the idea of nested modules sounds a bit weird, though )
also ‘etc’ is a crappy name for a folder - Mathew : module directories would basically mimic the layout of [default /app] directory : comment-12353606
(confirmation of the controller subdirectories thang ‘_’)
DevZone
And a bit about new Autoloader: “This is particularly useful when grouping application code, where you may not want a rigid library hierarchy, and instead want to focus on grouping by responsibility. “:
http://devzone.zend.com/article/4525
After all this reading I have come to the conclusion that there is little agreement on the default way to structure an application. But, Zend Front Controller is capable of fitting in to almost any application’s requirements.
Update:
I’ve done some more searching…
- Here is an old discussion of the method for loading modules (another person who gets the heeby jeebies from the magic of the router).
- Here is a question on Nabble about how to manage “secret controllers” Solution was to extend the “Zend_Controller_Dispatcher_Standard”
Summary
Thoughts…after thinking about this for a few days I can summarise my problem:
I really want to be able to set the controller directories explicitly, and in one place, for each ‘front-end realm’ that shares the model, and shares some of the views and action controllers of an application - a hardcoded (not object-composed), whitelist approach. Primarily for maximum assurance that; “the controllers for an ‘admin realm’ are never accessible from a ‘public realm’ (but where the controllers for a ‘admin realm’ may access those of the ‘public realm’”. And, at the same time, avoiding repetition of code/modules. Whilst, following a documented standard, (a recommended ‘best practice’) in order to aid clear understanding within team members of this particular aspect of the architecture. And one that conforms with the direction in which the framework is evolving.
—
Perhaps I could use class property/method access naming rules for the controller directories; private, protected, public - (defaulting to private).
update- here’s an article about modular usage of zend application package :
http://monzee.wordpress.com/2009/06/08/modular-applications-in-zf-1-8/
UPDATE 25th july 2009
I’ve just noticed that it may not be possible to ‘protect’ a controller using .htaccess any way. I noticed this after experimenting with my first proper Zend 1.8 Application that i’m building:
Concept:
Developer uses folder structure to control access to a controller called “IMightBePrivilagedController”
—————
public_html/
–IMightBePrivilagedController/
—-.htaccess
—-…[virtual strucure of] privilaged actions…
_index_bootstrap.php
———
The user/hacker could then type URL
* example.com/_index_bootstrap.phpIMightBePrivilagedController
(note the target controller name is appended to bootstrap file name with no spaces)
As i see it, by default, this would tell the Zend router to route to:
[”controller”] -> “IMightBePrivilagedController”
Which the developer may have thought was only accessable via URLs like:
* example.com/_index_bootstrap.php/IMightBePrivilagedController
——-
furthermore…this hole is obvious to any user who sees the full error message on a 404
May 25th, 2009 at 12:04 am
note to self: this may be worth reading: http://devzone.zend.com/article/3509