Setting which pages can be accessed in CakePHP - php

I've put a considerable amount of digging into this but I haven't been able to figure out what the best method would be.
I have an employee management system where everyone who logs in is either an "employee", a "supervisor" or a "manager".
At the moment, I display different versions of pages just fine depending on what their rank is. However, regular "employees" can still get to pages they shouldn't if they manually enter the URL. According to CakePHP's documentation, it says all pages are restricted by default, and you have to grant access to each one. But I haven't granted access and it seems all the pages are accessible.
What is the best method for page access?
Thanks!
Edit: Here is the configuration of the AppController:
public $components = array(
'DebugKit.Toolbar',
'Session',
'Auth' => array(
'authenticate' => array(
'Form' => array(
'userModel' => 'Employee'
)
),
'loginAction' => array(
'controller' => 'employees',
'action' => 'login',
//'plugin' => 'users'
),
'loginRedirect' => array('controller' => 'employees', 'action' => 'dashboard'),
'logoutRedirect' => array('controller' => 'employees', 'action' => 'login'),
'authError' => 'You must be logged in to see that.'
)
);
And then there is the isAuthorized() method which always is set to return false:
public function isAuthorized($user = null) {
// Any registered user can access public functions
/*if (empty($this->request->params['admin'])) {
return true;
}*/
// Only admins can access admin functions
/*if (isset($this->request->params['admin'])) {
return (bool)($user['role'] === 'admin');
}*/
// Default deny
return false;
}

Crete two tables in database
resources (id, controller, action) (This will contain controller names and action names.)
permission (roll_id, resource_id)
In isAuthorized() function
If roll is admin, then return true.
Else Check the following.
using $this->request->controller Get current controller name.
using $this->request->action Get current action name.
Get resource_id from resources table for current controller and action.
Check record in permission table for resource_id and roll_id.
If record exist then return true.
Else at the end it is returning false by default.

Your code is missing this in the AppController.php
class AppController extends Controller {
public function isAuthorized($user) {
return true;
}
public function initialize() {
parent::initialize();
$this->loadComponent('RequestHandler');
$this->loadComponent('Flash');
$this->loadComponent('Auth', [
'authenticate' => [
'Form' => ['fields' => ['username' => 'email']]
],
'authorize' => ['Controller'],
]);
//some other code here
}

Related

Cakephp 3.6.14: redirect after action deny

I am trying to deny some actions for non-admin users in my controllers. So in the controllers I am using this code:
public $components = array('Auth');
public function beforeFilter(Event $event) {
parent::beforeFilter($event);
if($this->Auth->user('role_id')==1 or $this->Auth->user('role_id')==2){ //role: 1 admin, 2 project manager
$this->set('is_admin', true);
}
else
{
$this->Auth->deny(['index','delete']);
$this->set('is_admin', false);
}
$this->set('my_id', $this->Auth->user('id'));
}
So now anytime a user that is not admin or project manager tries to perform index or delete actions, is redirected to the "Method Not Allowed" error page. But I would like to return to the previous page with a message: "You are not authorized to perform this action".
I tried to set 'unauthorizedRedirect' => $this->referer() in the AppController:
$this->loadComponent('Auth', [
'authenticate' => [
'Form' => [
'fields' => [
'username' => 'email',
'password' => 'password'
]
]
],
'loginAction' => [
'controller' => 'Users',
'action' => 'login'
],
'unauthorizedRedirect' => $this->referer()
]);
But didn't work. The only way I managed to achieve that is by using this code in the beforeFilter function of the controller:
if(!($this->Auth->user('role_id')==1 && !$this->Auth->user('role_id')==2 && ($this->request->action === 'index' || $this->request->action === 'delete')){
$this->Flash->error(__('You are not authorized to perform this action'));
return $this->redirect(['controller' => 'Users', 'action' => 'index']);
}
But it doesn't seem the proper way to do this in all the controllers that I want to deny some actions. Is there another way?
Cakephp provides isAuthorized function for the same. You can take advantage of it.
Just define isAuthorized in your App controller or in separate controllers(if you want to put separate conditions for each controllers.)
public function isAuthorized($user)
{
$roleArray = [1, 2]; // your role ids array
if ( !in_array($user['role_id'], $roleArray) && in_array($this->request->getParam('action'), ['index', 'delete'])) { // put your conditions here
return false;
}
return true;
}
Cakephp -> Authentication and Authorization -> Authorization (who’s allowed to access what)

CakePHP 3 - Authorization for pages on PagesController

My admin hub page is currently situated in the PagesController (called admin). However, both non-logged in users as well as non-admin users are able to access this hub page, even if they can't access all the links from that hub.
Edit: I just realised that it's probably not working because "admin" isn't a function in the PagesController, but rather falls under "display".
My AppController is as follows:
public function initialize()
{
parent::initialize();
$this->loadComponent('RequestHandler');
$this->loadComponent('Flash');
$this->loadComponent('Auth',[
'authorize' => 'Controller',
]);
$this->Auth->allow(['display']);
}
public function beforeFilter(Event $event)
{
$this->Auth->deny(['admin']);
}
My PagesController is as follows:
public function initialize()
{
parent::initialize();
$this->Auth->deny(['admin']);
}
public function isAuthorized($user)
{
if (in_array($this->request->action,['admin'])) {
return (bool)($user['role_id'] === 1); //where role_id = 1 refers to an admin
}
return parent::isAuthorized($user);
}
The Auth->deny() function is to prevent unauthoried users from accessing actions. On the other hand the Auth->allow() function is to give the public access to specific(or all) actions.
Please read the documentation here: https://book.cakephp.org/3.0/en/controllers/components/authentication.html#making-actions-require-authorization
For the Auth component to work as you need it read the following: assuming you have a different admin users database table and you would like to ask visitors for credentials to access the restricted page, you can do the following:
in the AppController, when users visit the restricted page, or in your case when users access the PagesController, load the Auth component and ensure the admin users table is either defined in the Auth component or Cakephp conventions were followed when you named the table.
In AppController
public function initialize()
{
parent::initialize();
if ($this->request->params["controller"] == 'Pages') {
$this->loadComponent('Auth', [
'loginAction' => [
'controller' => 'Access',
'action' => 'admin_login',
'plugin' => 'Access'
],
'loginRedirect' => [
'controller' => 'Access',
'action' => 'admin_index',
'plugin' => 'Access'
],
'authenticate' => [
'Form' => [
'userModel' => 'your-admin-database-table'
]
]
]);
}
}
In PagesController then you need the following:
public function initialize()
{
parent::initialize();
}
loginAction - is used for admin login.
loginRedirect - is where to land the admin users after logging in.
authenticate - is used to define the form details such as database name and fields.
A very detailed documentation can be found here: https://book.cakephp.org/3.0/en/controllers/components/authentication.html
Edit: Please note that the code has not been tested
You're checking against the action, not the prefix. Documentation suggests that what you want is
if ($this->request->getParam('prefix') === 'admin')

Cakephp Auth Redirect

I just started trying to learn cakephp auth, i just copied and pasted the code, trying to understand it. I can't figure out what is directly the redirect
//app controller
//is empty i know in some cases you put it here, i'm just tested it in the user controller
//user controller
public $components = array('Paginator',
'Session',
'Auth' => array(
'loginAction' => array(
'controller' => 'users',
'action' => 'login',
'plugin' => 'users'
),
'authError' => 'Did you really think you are allowed to see that?',
'authenticate' => array(
'Form' => array(
'fields' => array('username' => 'email')
)
)
)
);
public function beforeFilter() {
$this->Auth->allow('index', 'view');
}
public function login() {
if ($this->request->is('post')) {
if ($this->Auth->login()) {
return $this->redirect($this->Auth->redirectUrl());
// Prior to 2.3 use
// `return $this->redirect($this->Auth->redirect());`
} else {
$this->Session->setFlash(
__('Username or password is incorrect'),
'default',
array(),
'auth'
);
}
}
}
I understand the before filter makes sense, it only allows index and view, i have another controller called admin which redirects to the login page if your not logged in
but for somme reason it keeps redirecting to users/users/login, i want it to go to users/login? How do i fix this?
you just have to put the controller wherever you go and the action
public function login() {
if ($this->request->is('post')) {
if ($this->Auth->login()) {
return $this->redirect(array('controller' => 'users', 'action' => 'login'));
}
} else {
$this->Session->setFlash(__('Invalido nombre de usuario o contraseña'));
}
}

Can't login using AuthComponent in Cake php

I guess this is a silly question but I'm having trouble logging in to the restricted sections of a site I'm building in Cake.
For starting I see that the password string in $this->request->data['Usuario']['clave'] is not the same as the hashed string using SimplePasswordHasher in the beforeSave function at the model. I should also say that the model is not the default Users model, because I'm writing the application for spanish language and I didn't want to use the default model, so my configuration of the component is:
class AppController extends Controller {
/*function beforeFilter() {
date_default_timezone_set('America/Mexico_City');
}*/
public $components = array(
'Session',
'Auth' => array(
'Form'=>array(
'userModel' => 'Usuario',
'unauthorizedRedirect' => false,
'loginRedirect' => array(
'controller' => 'ComplejosResidenciales',
'action' => 'index'
),
'logOutRedirect' => array(
'controller' => 'Usuarios',
'action' => 'index'
),
'fields' => array(
'username' => 'usuario',
'password' => 'clave'
),
'authorize' => 'Controller'
)
)
);
}
So I decided not to hash the password field, but still to no avail.
I wish anyone could lend me a hand on this because I'm newbie to CakePHP and don't know how to fix it.
I figure it must be something with the Auth->login() method because I'm not following conventions here, but I don't know how to configure the said method. Currently is like follows:
public function login() {
if($this->request->is('post')) {
if($this->Auth->login()) {
return $this->Auth->redirectUrl($this->Auth->redirectUrl());
}
else {
$this->Session->setFlash(__('Las credenciales proporcionadas no son correctas'), 'default', array(), 'auth');
}
As rrd pointed, my $components array was wrong, so I changed it to:
public $components = array(
'Session',
'Auth'=>array('loginRedirect'=>array('controller'=>'ComplejosResidenciales', 'action'=>'index'), 'logOutRedirect'=>array('controller'=>'Usuarios', 'action'=>'index'), 'loginAction'=>array('controller'=>'Usuarios', 'action'=>'login'), 'authenticate'=>array('Form'=>array('userModel'=>'Usuario', 'fields'=>array('username'=>'usuario', 'password'=>'clave')))));
Which is better, according to cakephp.org
Do not put other Auth configuration keys (like authError, loginAction etc) within the authenticate or Form element. They should be at the same level as the authenticate key.
But it isn't working.
Been struggling with it and I can't get the hang of it, I wish someone would point out what I'm doing wrong. In my AppController I have declared the component and the beforeFilter function like this:
public $components = array('Auth'=>array('loginRedirect'=>array('controller'=>'ComplejosResidenciales', 'action'=>'index'),
'logoutRedirect'=>array('controller'=>'Usuarios', 'action'=>'login'),
), 'Session');
public function beforeFilter(){
$this->Auth->authenticate = array(
AuthComponent::ALL => array('userModel' => 'Usuario', "fields" => array("username" => "usuario", "password" => "clave"), 'Form'));
}
And then I have the login function which goes (obviously I guess) in the UsuariosController, like this:
public function login() {
if($this->request->is('post')) {
if($this->Auth->login()) {
return $this->Auth->redirectUrl($this->Auth->loginRedirect);
}
else {
$this->Session->setFlash(__('Las credenciales proporcionadas no son correctas'), 'default', array(), 'auth');
}
}
}
But I just keep seeing the message "Las credenciales proporcionadas no son correctas". I don't know if I'm calling the method of Auth component correctly in the part $this->Auth->login() because apparently I have no result when calling it like that, without arguments, but I tried calling it with the argument $this->request->data and as a result it didn't mattered what I wrote in the username and password fields, anything would pass, which is bad, of course.
Now I see why coding $this->Auth->login($this->request->data) resulted in giving unrestricted access:
In 2.x $this->Auth->login($this->request->data) will log the user in with whatever data is posted, whereas in 1.3 $this->Auth->login($this->data) would try to identify the user first and only log in when successful.
According to cake's manual. I can't seem to read correctly any document about this. Anyway, I beg someone would help me because I'm in a hurry here. After reading some other documents I guess that Auth component should handle everything correctly, as long as I provide the right configuration, so I've ended up doing a beforeFilter() call in the AppController, like this:
var $components = array('Auth', 'Session');
public function beforeFilter() {
$this->Auth->loginAction = array('controller'=>'Usuarios', 'action'=>'login');
$this->Auth->redirectLogin = array('controller'=>'ComplejosResidenciales', 'action'=>'add');
$this->Auth->authenticate = array('Form'=>array('userModel'=>'Usuario', 'fields'=>array('username'=>'usuario', 'password'=>'clave')));
}
Then, in my "UsuariosController" I do:
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow('index', 'view', 'add', 'edit', 'delete');
}
And I have my login and logout functions, very simple, but it's not working, and it does not redirect me upon logging in nor does it let me access any other controller, it seems to do nothing. Please help!
/**
* login and logout functions
*
*/
public function login() {
}
public function logout() {
$this->redirect($this->Auth->logout());
}
You should change more things.
$components should be something like this:
public $components = array(
'Session',
'Auth' => array(
'authenticate' => array(
'Form' => array(
'fields' => array('username'=>'usuario', 'password'=>'clave')
)
)
)
);
I am not sure about userModel, check the manual.
Than you should implement isAuthorized
function isAuthorized($user){
if(in_array($this->action, array('view', 'edit')))
return true;
return false;
}
beforeFilter is not necessary for your case.
Your login method is something like this.
public function login() {
if ($this->request->is('post')) {
if ($this->Auth->login()) {
return $this->redirect($this->Auth->redirectUrl());
}
else {
$this->Session->setFlash(__('Username or password is incorrect'), 'default', array(), 'auth');
}
}
}
Again, I recommend you to read the manual or the book mentioned above. It has a free sample, I think You will get the main idea by that.

cakephp manage correctly permission in beforeFilter

I have a little problem isnisde my controller.
I want that a user can access only inside some pages an andmin user inside more pages.
I have a controller called UsersController
this is its beforeFilter method
public function beforeFilter () {
parent::beforeFilter(); // chiamo anche il callback beforeFilter dal parent per ottenere un'autorizzazione per l'utente loggato da tutte le viste $this->Auth->allow('index','view'); per tutti i Model
$views = array ('login','register','activate');
if ($this->Session->read('is_logged')) {
$views = array_merge ($views, array ('login','logout', 'change_password'));
if ($user_type == 'admin') {
$views = array_merge ($views, array ('add','delete','edit','create','index'));
}
}
$this->Auth->allow($views);
}
in this function guest can enter inside login, register and activate.
user logged can access inside login. logout and change_password, admin to the other pages more.
But this not works. For example a user logged can access inside the index view or add view.
Why this?
This is my beforeFilter inside appController:
public function beforeFilter () {
$this->setReleaseData();
$this->checkUserStatus();
$this->updateTimezone();
$this->setRedirect();
if($this->Session->read('is_logged')){
$auth_user = $this->Auth->user();
$this->set('user_type', $auth_user['group']);
}
}
How can I manage correctly permission to enter in pages?
Thanks
I see you are not using an Authorization Handler, thus you will have to manually deny the access to actions
$this->Auth->deny(array('index', 'add', 'edit', 'etc'));
EDIT
I would actually start by denying access to everything, in your beforeFilter (AppController)
$this->Auth->deny();
and then in the beforeFilter() of you specific controller
if ($user_type == 'admin') {
$this->Auth->allow('actionThatYouWantToGrantAccess');
}
I'd look into Auth Controller a little more. Try using Admin Routing (Turned on in App/Config/core.php) along with $this->Auth->allow() which can be set by default beforeFilter() in the AppController.php and then set with in each controller's beforeFilter as well.
/**
* #var mixed[mixed]
*/
public $components = array(
'Auth' => array(
'autoRedirect' => false,
'loginRedirect' => array(
'admin' => true,
'controller' => 'homes',
'action' => 'index',
),
'loginAction' => array(
'controller' => 'users',
'action' => 'login',
'admin' => false,
'plugin' => false,
),
'authenticate' => array(
'Form',
),
),
'Session',
'Cookie',
);
/**
* Before Filter callback
*/
public function beforeFilter() {
// Allow public views
$this->Auth->allow('index', 'view', 'display');
}

Categories