cakephp auth allow to specific actions of specific controllers - cakephp

I have admin authentication with the following beforeFilter() method in appController.php.
I am using cakePhp 2.4
public function beforeFilter() {
$this->Auth->allow(
array(
'controller'=>
'Services','Projects','News','Jobs','Messages',
'action'=>
'index','view'
)
);
}
I want to allow access to
1- index action of all controllers
2- view action of only Jobs controller
currently I have allowed access to index and view actions of all controllers.
how to fix?

Use $this-> Auth-> allow(array('index')) in appcontroller and$this-> Auth-> allow(array('index', 'view')) in JobsController.

It’s a common problem to CakePHP developer to auth allow to specific actions of a specific controller. See this article to solve it.
https://blog.sohelrana.me/cakephp-auth-allow-specific-actions-specific-controllers/

Related

How can CakePHP Authorization plugin authorize access to indexes?

I'm converting my app to CakePHP 3.6, and working now on using the new Authorization plugin. I'm not sure how to check authorization for things like indexes or other reports, where there is no "resource" to pass to the can() or authorize() functions.
For now, I've built a ControllerResolver, loosely copied from the ORMResolver, which accepts controller objects and finds policies based on the singularized controller name, so that they're named the same as the Entity policies I'm building. (That is, my UserPolicy can have canIndex and canEdit functions, the former found via the controller and the latter via the entity.)
This works fine in controller actions where I can call $this->Authorize->authorize($this);, but it doesn't work in views, where I'd like to be able to do things like:
if ($this->Identity->can('index', *something*)) {
echo $this->Html->link('List', ['action' => 'index']);
}
so as to only show links to people who are allowed to run those actions.
Anyone know if there's a reason why the system implicitly requires that the "resource" passed into authorization functions be an object? (For example, the plugin component calls get_class($resource) in the case of a failed authorization, without first checking that the provided resource is in fact an object.) Allowing a string (e.g. \App\Controller\UsersController::class) would make my life easy. Very happy to put together a PR for this if it's just an oversight.
But authorizing indexes seems like a pretty obvious function, so I wonder if I've missed something. Maybe I'm supposed to pass the table object, and split the authorization between an entity policy and a table policy? But using table objects in views just for this purpose seems like a violation of separation of concerns. Maybe uses of the plugin to date have been things where indexes are always public?
to do this you can use the authorizeModel, as stated in the documentation https://github.com/cakephp/authorization/blob/master/docs/Component.md#automatic-authorization-checks. Basically is adding the auhtorizeModel parameters when you load the component at AppController.php
$this->loadComponent('Authorization.Authorization', [
'skipAuthorization' => ['login','token'],
'authorizeModel' => ['index','add'],
]);
When you configure an action to be authorized by model the authorization service uses the TablePolicy, so if you want to authorize the index action for Books you need to create the BooksTablePolicy and implement the method
<?php
namespace App\Policy;
use App\Model\Table\BooksTable;
use Authorization\IdentityInterface;
/**
* Books policy
*/
class BooksTablePolicy
{
public function scopeIndex($user, $query)
{
return $query->where(['Books.user_id' => $user->id]);
}
public function canIndex(IdentityInterface $identity)
{
// here you can resolve true or false depending of the identity required characteristics
$identity['can_index']=true;
return $identity['can_index'];
}
}
This will be validated before the request reaches your controller so you do not need to authorize anything there. Nevertheless if you want to apply an scope policy as you can see in this example:
public function index()
{
$user = $this->request->getAttribute('identity');
$query = $user->applyScope('index', $this->Books->find()->contain('Users'));
$this->set('books', $this->paginate($query));
}

CakePHP : override BasicAuthenticate.php

I'm trying to override lib/Cake/Controller/Component/Auth/BasicAuthenticate.php,
because I need to change the unauthenticated() method.
So I copied and modified the file to app/Lib/Cake/Controller/Component/Auth/BasicAuthenticate.php (also tried without the 'Cake' folder), but the changes are not taken into account.
My edit works when modifying directly the core file but I'd rather not.
How should I do ?
I'm using Cake 2.5
Check if you really need to override a core class
To me this looks like you are on the wrong track, overriding the class shouldn't be neccesary unless for example you have no controler over where and how the basic authentication adapter is being used (for example in a plugin that doesn't offer configuration).
If you'd really need to overwrite the class, then the path should be
app/Lib/Controller/Component/Auth/BasicAuthenticate.php
and it should work just fine (it does for me, using CakePHP 2.5.6).
http://book.cakephp.org/2.0/en/core-utility-libraries/app.html#overriding-classes-in-cakephp
Use a custom authentication handler instead
If you have control over the adapter configuration, the I'd suggest that you extend the BasicAuthenticate class instead, and only override the unauthenticate() method, and finally make the auth component use the custom adapter.
Something like
app/Controller/Component/Auth/CustomBasicAuthenticate.php
App::uses('BasicAuthenticate', 'Controller/Component/Auth');
class CustomBasicAuthenticate extends BasicAuthenticate {
public function unauthenticated(CakeRequest $request, CakeResponse $response) {
// do something special
}
}
Controller
public $components = array(
'Auth' => array(
'authenticate' => array(
'CustomBasic'
)
)
);
See also the Creating Custom Authentication objects section in the Cookbook.

CakePHP Auth Module Tutorial--Why is it requesting user/login for these pages?

I have a custom routing setup (which might be cause of issue). As follows:
Router::connect('/o/*', array('controller' => 'open', 'action' => 'openinsert'));
Router::connect('/c/*', array('controller' => 'click', 'action' => 'clickinsert'));
Under UsersController, I have tried:
public function beforeFilter() {
parent::beforeFilter();
//$this->Auth->allow('add');
$this->Auth->allow('o/*');
$this->Auth->allow('clickinsert');
$this->Auth->allow('open');
}
clickinsert and openinsert are both apart of controller 'ClickController' and 'OpenController' respectively.
Nothing from above works. Is is possible to do what I'm wanting to do w/their default auth setup? Or will I need to make some major changes?
AuthComponent::allow
This method:
Takes a list of actions in the current controller for which authentication is not required, or no parameters to allow all actions.
It doesn't accept urls.
In particular this:
$this->Auth->allow('o/*');
Is neither the wildcard ( nothing or '*' depending on the version of CakePHP used) nor the name of an action, and this:
$this->Auth->allow('open');
Is apparently passing the name of a controller so neither of those method calls would do anything.
There's some confusion here
According to these two routes:
Router::connect('/o/*', array('controller' => 'open' <-
Router::connect('/c/*', array('controller' => 'click', <-
They point to two different controllers.
Under UsersController, I have tried:
Anything you put in your users controller is irrelevant for requests that don't use it. Either put the allow calls in the before filter for each controller - or put them in the beforeFilter for your App controller (which all controllers inherit from).

CakePHP administrator routing

I am having a hard time to understand this admin-routing of CakePHP. From the Cookbook:
"You can map the url /admin to your admin_index action of pages controller using following route:"
Router::connect('/admin', array('controller' => 'pages', 'action' => 'index', 'admin' => true));
What is not clear to me is the "'admin' = true". What is the purpose of this? When you call logout-function, do you pass the argument "'admin' = false" to redirect function in AppController?
When you have multiple prefixes in use, do you use "'manager' = true" if you want to enable manager-prefix?
admin=true in a route means your url is prefixed with /admin.
So in your example, your /admin route actually connects to: /admin/pages/index, and is serviced by the admin_index() action in your pages controller (as opposed to the non-prefixed index() action).
You can either ensure all links to logout are created with admin=false so they map to the standard Users::logout() action, or create a new action admin_logout() which handles admin logouts.
Adding manager=true to a url (along with the associated prefix setting) means the url with begin with /manager, and will map to manager_...() functions in the controller.
You can use both (or more!) prefixes, but not in the same url.
/pages/index maps to: PagesController:index();
/admin/pages/index maps to: PagesController:admin_index();
/manager/pages/index maps to: PagesController:manager_index();
Router Prefixes
In CakePHP 2.x prefixes changed a little.
You can have multiple prefixes now, but they have to be declared in the core.php file.
Configure::write('Routing.prefixes', array('admin','api','json'));
That would declare 3 prefixes, and there is no need to modify the routing tables to make them work. The word prefix means it's placed before the name of the action when dispatching to the controller.
For example;
class DocumentsController extends AppController
{
public index() { ... }
public admin_index() { ... }
public api_index() { ... }
public json_index() { ... }
}
CakePHP will call the correct action when one of these URLs are request.
http://example.com/documents/index
http://example.com/admin/documents/index
http://example.com/api/documents/index
http://example.com/json/documents/index
What you can not do is use more than one prefix at a time. The following will NOT work.
http://example.com/admin/json/documents/index
That would require custom routing, because CakePHP doesn't know which action to call.
When an action is called you can which for prefixes in the request params.
public function beforeFilter()
{
if(isset($this->request->params['admin']))
{
// an admin prefix call is being made
}
}

Turning off debug_kit within controller action, Cakephp

I am currently working on an export function in cakephp app and im doing a query that is getting around 10,000 rows each export which cake can handle but debug_kit seems to be using lot of memory and putting me over 128mb of memory used.
I have tried tried writing this in the top of the function but debugkit is still getting involved and using large amounts of memory.
Configure::write('debug',0);
HyperCas is correct in suggesting the beforeFilter() callback as an appropriate solution.
The code could look something like this in the controller where the action (ie, export) resides:
function beforeFilter() {
// filter actions which should not output debug messages
if(in_array($this->action, array('export'))) {
Configure::write('debug', 0);
}
}
You would adjust array('export') to include all the actions you want to prevent debug.
Just to improve Benjamin Pearson's answer. Unload the component instead of turning debugging off.
public function beforeFilter() {
parent::beforeFilter();
if(in_array($this->action, array('export'))) {
$this->Components->unload('DebugKit.Toolbar');
}
}
Use
Configure::write('debug',0);
in /app/config/core.php
Or use it in the beforeFilter() callback on the controller. That would stop the debugging for the entire controller if you don't check manually for the current action (in $this->params['action']).
If your model has multiple associations you should take a look at the containable behavior
http://book.cakephp.org/view/51/Controller-Attributes
you can also switch the debug level in the config.php to 0. this will disable the debug kit automaticaly + your application will use even less memory.
Disable debug_kit on the fly
class AppController extends Controller {
public function beforeFilter() {
Configure::write('debug', 0);
}
}
in cakephp3 open bootstrap.php file in config folder
comments or remove the DebugKit loading
if (Configure::read('debug')) {
// Plugin::load('DebugKit', ['bootstrap' => true]);
}
thats all .. it will unload the DebugKit from your application

Resources