CakePHP 2.1 - custom authorization object not loaded/executed - php

I'm using CakePHP 2.1 RC + TinyAuthorize, the next way in AppController.php:
class AppController extends Controller {
public $components = array('Auth');
public function beforeFilter() {
$this->Auth->authorize = array('Tiny');
}
}
For some reason, Tiny doesn't get executed, thereby it's ACL rules not applied. Any ideas what could be wrong?

did you put it in app or tools plugin?
for the latter it is supposed to be
$this->Auth->authorize = array('Tools.Tiny');
see http://www.dereuromark.de/2011/12/18/tinyauth-the-fastest-and-easiest-authorization-for-cake2/ for details
After figuring out your problem I edit my answer:
This * (= any) placeholder for “roles” only refers to those users that are logged in. You must not declare your public actions this way! All those must be declared using $this->Auth->allow().
The reason is that Authenticate comes before Authorize. So without Authentication (logged in) there will never be any Authorization (check on roles).

Related

CakePHP - How to allow unauthenticated access to specific pages

I have created a CakePHP app where I have created a UsersController, which handles all about users.
When I try to browse www.mydomain.com, if I am logged in, it let's me see the index (app/View/Pages/home.ctp). Else, it redirects me to mydomain.com/users/login and persists to log in.
I have tried looking at AppController.php, PagesController.php or app/Config/core.php and app/Config/routes.php, but did not find anything. My UsersController.php, also, is not responsible for that, I think.
I do not remember and I cannot find how to disable this. Which file should be responsible for that?
EDIT:my CakePHP version is 2.3.
Generally you can make specific actions public using the auth components allow() method.
Making pages public may require a little more work in case you'd want to make only specific pages public, since the PagesController handles all pages in a single action (display()). If that is the case, then you could utilize request->params['pass'][0] which will hold the page name, test this against a list of allowed pages, and then allow the display action using Auth::allow.
Example, in the PagesController:
public function beforeFilter()
{
parent::beforeFilter();
$allowedPages = array('home', 'foo', 'bar');
if(isset($this->request->params['pass'][0]) &&
in_array($this->request->params['pass'][0], $allowedPages))
{
$this->Auth->allow('display');
}
}
This would allow the pages home, foo and bar to be viewed without being logged in.
If you'd wanted to make all pages public, then you could simply use Auth::allow without any conditions, ie:
public function beforeFilter()
{
parent::beforeFilter();
$this->Auth->allow('display');
}

Yii RESTful authentication

I am having trouble finding a method for authenticating API users in my application. I set out to initially build a system that users could access and authenticate through the web, but requirements have changed and I need to implement some additional actions that can be available in a RESTful manner using a POST API call.
I have created a class that extends CBehaviour and forced a redirect to the login page for all unauthenticated users (found on the yii framework forum here). Problem is that all API calls are forced through the same logic and any POST requests simply spit out the HTML to the login page.
class ApplicationBehavior extends CBehavior {
private $_owner;
public function events() {
return array(
'onBeginRequest' => 'forceGuestLogin',
);
}
public function forceGuestLogin() {
$owner = $this->getOwner();
if ($owner->user->getIsGuest())
$owner->catchAllRequest = array("site/login");
}
}
How would I go about separating the authentication of API users from the Web users?
I would follow this guide on creating a REST API in Yii. After modifying the config urlManager entries, all of your API requests will use the APIController. You can then place the following code in the beforeAction of your APIController to return nothing if the user is a guest (Or an error message)
protected function beforeAction($event) {
if (Yii::app()->user->isGuest) {
echo "Invalid credentials";
Yii::app()->end();
}
}
Note: The code above works for my purposes because all REST requests are sent via the same browser. (Which is already logged in and has a login cookie)
If you replace that behavior with a new base controller placed in protected/controllers to force login, it will only apply to your pages that require a login and not your APIController. Here is an example of mine:
//Make sure all Controllers which require a login inherit from this
class ControllerLoginRequired extends CController {
public function runAction($action) {
if (Yii::app()->user->isGuest && 'site' != $this->route) {
Yii::app()->user->returnUrl = $this->route;
parent::redirect(array('site/login'));
} else {
parent::runAction($action);
}
}
}
Everything explained will work for REST requests via the same browser in which the user has logged onto Yii. If you will have the need to expose your REST service to consumers that are not a browser logged into Yii, I believe you would have to come up with a custom authentication/token scheme.

Check if the user has access to post login pages in zend framework

In Zend Framework whats a better method to restrict user from accessing post login pages
if the user is not logged in.Without Zend I would have write a code to check if the
userid is set in session or not and put that code in common file(being used on all post
login pages).
In Zend Framework I can check that using hasIdentity method of zend_auth but I don't
want to check that inside all actions.The another method I am thinking is to create a
plugin and hook it to routeshutdown event,then after fetching controller and action
name from request object I can decide whether to redirect user or not.
Please suggest some good method to implement it in zend framework
You would normally write a Controller Plugin and add it to the front controller. This way you can intercept the dispatch and route process where you want and issue a redirect to an appropriate page.
class Your_Controller_Plugin_Authcheck extends Zend_Controller_Plugin_Abstract
{
}
In the Bootstrap class:
protected function _initFrontControllerPlugins()
{
$this->bootstrap(array('AuthcheckPlugin', 'FrontController'));
$front = $this->getResource('FrontController');
$front->registerPlugin($this->getResource('AuthcheckPlugin'));
}
protected function _initAuthcheckPlugin()
{
$plugin = new Your_Controller_Plugin_Authcheck();
return $plugin;
}
BTW: This is Zend Framework 1 - might work the same in 2, but I believe you might change things a bit there if you already use it.

Zend Framework MVC redirecting to different controller and action

i'm trying to work out how i can stop zend or redirect zend to go to a different zend controller and action if a check within the boot strap fails.
for example a get variable does not exist or more likely a session does not exist meaning the user must log in.
so the user had originally requested index/someaction
but i want them to go to login/index
within my boot strap i would place the condition and then change the controller action to view.
if i'm doing this in a way that is not standard can anyone direct me to documentation on the best practice ?
zend novice
From Zend documentation (Dispatcher)
// forward to an action in another controller:
// FooController::bazAction(),
// in the current module:
$this->_forward('baz', 'foo', null, array('baz' => 'bogus'));
I'd sugest you to do with plugins for access check on each page and for login create an authentication controller.
Here you'll find out how to do this http://alex-tech-adventures.com/development/zend-framework/61-zendauth-and-zendform.html
An example:
class Plugin_AccessCheck extends Zend_Controller_Plugin_Abstract
{
public function preDispatch(Zend_Controller_Request_Abstract $request)
{
// ...
if(!$auth->hasIdentity())
{
$request->setControllerName('authentication')
->setActionName('login');
}
}
}
I don't usually put authentication in the bootstrap, that should have it's own controller.
Create an AuthController() to set up your auth adapter and and set up your instance.
Then in a common view (for secure pages), just check your instance with something like:
$auth = Zend_Auth::getInstance();
if(!$auth->hasIdentity())
{
#re-direct to login page
}

How do I force a user to be logged in to view any page?

I am playing about with the Zend Framework at the moment and I have a written the authentication code using Zend_Auth. I am trying to find a way to ensure that the user is logged in before they can view anything but I don't want to do it on a per controller basis.
I am thinking a plugin, but all the books I have on it are pretty rubbish in this respect.
Zend_Auth::getInstance()->hasIdentity()
You can use this to determine if the user is logged in, and then use the redirector to redirect to the login page if not.
However, the easier way is to use a Redirector Zend Controller Action Helper.
A plugin is a good idea.
I answered to a similar question here:
How do i centralize code from my init functions in all controllers ?
Also check the documentation page Zend Controller Plugins
Look into Zend___Acl which can be used to define whether a user has access to certain resources. A resource can be pretty much anything, but in this context you can use the ACL to define your controllers and actions as resources. Each logged in user is then assigned a number of roles (we store them in a database). In a plugin you check the request for the Controller and Action, after routing is complete. Gather the roles of the user through the Zend_Auth and check them against the ACL. If the ACL says the user has permission to access the resource, do nothing, else you can forward/redirect to your error controller and print the error.
// Pseudo-code. You need to define the ACL and roles somehow.
class AclPlugin extends Zend_Controller_Plugin {
public function routeShutdown(Zend_Controller_Request_Abstract $request)
{
$controller = $request->getControllerName();
$action = $request->getActionName();
$roles = Zend_Auth::getInstance()->getRoles();
$acl = new MyAcl();
if($acl->hasAccess($roles, $controller, $action)) { return; }
// None of the user's roles gave her access to the requested
// controller/action, so re-write the request to the error controller
$request->setControllerName('error')
->setActionName('authorizationFailed')
->setParam('resource', array('controller' => $controller
'action' => $action));
}
}
class MyAcl extends Zend_Acl {
public function hasAccess($roles, $controller, $action) {
foreach($roles as $role) {
if($acl->isAllowed($role, $controller, $action)) {
return true; // Simplified. Here we say if one of the user roles can
// access a resource, that is good enough.
// Might want to do something a bit more complicated.
}
}
return false;
}
}
How about setting up a global controller that extends Zend_Controller_Action and then have your controllers extend from the global controller. Then your global controller puts the Zend_Auth::getInstance()->hasIdentity() in the init() or preDispatch?
I was pondering the same subject lately (ZF newbie), and thought about doing the authentication checks in the bootstrap (maybe with a list of "bypassed" controllers/actions).

Categories