I am completely and utterly lost on how to do this. I have 3 different roles : Admin, Staff and Donors. My problem is that It really gets confusing(for me anyway) with permissions and as well as appropriate redirections, should an unauthorized user tries to access an action from the URL.
In my UsersController I have the following actions
admin_index
admin_add
admin_edit
admin_view
admin_delete
non-prefixed actions
login
logout
view
add
edit
The admin should be allowed to access all admin-prefixed actions as well as login and logout, whilst the staff and donor
should only be able to access the latter 5. Also note that all users are using the same login form.
In my AppControlles's component I have the following :
'Auth' => array(
'loginRedirect' => array(
'controller' => 'donors',
'action' => 'index'
),
'logoutRedirect' => array(
'controller' => 'users',
'action' => 'login'
),
'authorize' => array('Controller')
)
However, In my login action I check for the user role to change the loginRedirect accordingly :
if($this->request->is('post')){
if($this->Auth->login()){
switch($this->Auth->user('role')){
case 'admin':
$this->Auth->loginRedirect = array('controller'=>'users','action'=>'admin_index','prefix'=>'admin','admin'=>true);
break;
case 'donor':
...
break;
case .....
}
}
}
Question 1
Now, if a current user with a role of donor is logged in, and tries to access localhost/sitename/admin/users/add he is redirected to admin/donors rather then just /donors . So how am I able to remove the admin prefix ?
Question 2
Also I do not fully understand hwo $this->Auth->allow(), works.. If In my donorsController I want to control the access to the controllers action according to roles, how can I do it? So for instance, If there is the 'delete' action in my donorsController, How will I be able to permit the staff user whilst denying the donor user to access the delete action. I believe the beforeFilter is the solution, but can't find how to do it! Any pointers ?
Thanks
1) In your login() action impelement a check for the user role, if the role is admin redirect to whatever controller/action and set the admin prefix. If hes not an admin redirect him to something else.
if ($this->Auth->login()) {
if ($this->Auth->user('role') === 'admin') {
$this->redirect(array(
'admin' => true,
'controller' => 'foo',
'action' => 'bar')));
} else {
// Do something else, another redirect or whatever
}
}
There is no need to remove the /admin from the URL as it should show the user hes not authorized when he tries to access an URL he is not allowed to.
2) If you want to grant access for different roles you can use the SimpleRbacAuth I've written. Check the tests for examples of how it works. You simply define a nested array structure and add the roles you want to an action or a whole controller or grant access to everyone by using *.
This may be a solution for you.
Go to the core.php file and uncomment if present/add if not present the below line.
Configure::write('Routing.prefixes', array('admin'));
Location: app/config/core.php
Put the below code inside the beforeFilter method of AppController.php (cake version 2.X) / app_controller.php (cake version < 2.X)
function beforeFilter(){
if($this->Auth->user('role') == 'admin'){
if(!in_array($this->params['action'],array('login','logout')) && (stristr($this->params['action'], 'admin_') === FALSE)){
$this->redirect(array("controller"=>$this->params['controller'],"action"=>'admin_'.$this->params['action'],"admin" => 1));
}
}else{
if(stristr($this->params['action'], 'admin_')){
$action = explode('_',$this->params['action']);
$this->redirect(array("controller"=>$this->params['controller'],"action"=>$action[1],"admin" => false));
}
}
}
Rest of the functionality you can manage by handling the custom error page.
You can refer to Customize error pae
Related
I have had installed and configured a new CakePHP 2.4 instance. Now I wanted to implement the AuthComponent. I have had implemented the component exactly as in recent projects, too. Now I have the problem that I get the error message Missing Controller: SteadinessController. But Steadiness is the project name. I'm confused haha.
The URL I want to open is http://localhost/steadiness/users/view/2 and I will be redirected to http://localhost/steadiness/steadiness/users/login. The controller and action invoked is correct but the second steadiness is false.
Thanks a lot for help.
Alex
Can you post the code where you try to direct the user to this url?
I'm guessing it's a redirect to do with the Auth component.
In your AppController when you set up Auth there should be something similar yo:
public $components = array(
'Session',
'Auth' => array(
'loginRedirect' => '/',
'logoutRedirect' => '/',
'authorize' => 'controller',
'unauthorizedRedirect' => '/'
)
);
The loginRedirect tells Cake where to send users after login who went directly to the login page (they didn't try to access a restricted link whilst not logged in).
The logoutRedirect tells Cake where to send users after logout.
The unauthorizedRedirect tells Cake where to send logged in users that try to access a link that they do not have the priveleges for (e.g. a non-admin tries to delete an account - only admins should be able to do that).
If one of these is not set then when Cake tries to use it you get redirected to '/{app-directory}' which is NOT the same as '/'.
This is most likely why your url has the domain appear twice - so Cake thinks it is looking for a controller with the same name as your domain.
I've implemented Authentication and Authorization in Cake, and mostly it works as needed.
However, if I hit log out from a page that requires particular credentials (say /admin) and log back in as another differently privileged user, I get redirected to /admin and an error message displayed.
Looking at the request headers in chrome, I notice that the Cookie CAKEPHP is still set even after log out.
public function login() {
...
if ($this->Auth->login()) {
$this->set('login_failed', false);
return $this->redirect($this->Auth->redirect());
} else {
...
}
}
public function logout() {
return $this->redirect($this->Auth->logout());
}
Any ideas about how I can troubleshoot this?
assign this to your AppController
public $components = array(
'Auth'=> array(
'logoutRedirect' => array('controller' => 'users', 'action'=>'login'),
'loginRedirect' => array('controller' => 'users', 'action' => 'login')
)
)
your logout function also is incorrect. You should do this:
public function logout(){
$this->Auth->logout();
$this->redirect($this->Auth->loginAction);
}
loginRedirect
logoutRedirect
Not sure which version of cake you are using, but you can try to unset the cookie and that should keep it from going to the last viewed page. You can add it to logout or to beforefilter().
It probably depends on the CakePHP version.
But you could try:
$this->Session->delete('Auth.redirect');
Which is working on CakePHP 2.x
Is admin a prefix? If so, try setting admin to false for the logout link in the admin view.
I recently upgraded from CakePHP 1.2 to CakePHP 1.3 and now I have some code that is trapping the user in a redirect loop. This is after the user has successfully logs in and decides to click on a link to manage emails.
I have some code in a controller where the index() method will check if the current user is an admin or not. If the user is not an admin it will do the following:
function index()
{
if ($this->Session->read('is_admin') < 1) {
$this->redirect(array('controller' => 'emails', 'action' => 'view', 'id' => $this->Session->read('username')));
}
//...more code...
}
This is intended to redirect the user to a view() method and display only their email and not everyone's email. What is happening when I debug this is the redirect keeps ending up in the index() method.
Is there something new in CakePHP that I'm missing? Is it a no-no to use the name "view" as an action in a controller?
* EDIT *
Okay, I was a little premature with this post. The code in the view($username) method is being reached. But the thing is the $username is not defined and I have some client code that is then redirecting back to the index() action if it is not defined.
I did check the original redirect and the $this->Session->read('username') is populated with the username but it is just not being passed in the view()'s $username argument.
Thanks!
It turns out the redirect signature changed from 1.2 to 1.3:
http://book.cakephp.org/view/1561/Migrating-from-CakePHP-1-2-to-1-3
Library Classes > Router
// CakePHP 1.2 way
$this->redirect(array('controller' => 'emails', 'action' => 'view', 'id' => $this->Session->read('username')));
// CakePHP 1.3 way
$this->redirect(array('controller' => 'emails', 'action' => 'view', $this->Session->read('username')));
I'm trying to wrap my head round how the auth component authenticates.
Currently my AppController looks something like this.
class AppController extends Controller
{
var $components = array('Auth', 'Session');
function beforeFilter()
{
$this->Auth->loginAction = array('controller' => 'users', 'action' => 'login');
$this->Auth->loginRedirect = array('controller' => 'users', 'action' => 'index');
$this->Auth->logoutRedirect = array('controller' => 'users', 'action' => 'login');
}
}
If I was to leave my login action completely empty, the auth component will still try to authenticate when the user reaches the login page.
Is this how it should be? Couldn't this be a problem if it's always trying to authenticate?
If the requested action is the action configured in AuthComponent::loginAction (UserController::login by default) and $this->data contains the fields configured in AuthComponent::userModel/AuthComponent::fields (User.username and User.password by default), the AuthComponent will try to authenticate the current user. It'll automatically try this after Controller::beforeFilter was executed but before the requested action is called. If the login was successful (and any additional restrictions you may have applied in the AuthComponent configuration have cleared), it'll redirect to where the user came from, otherwise it'll execute the requested action as usual.
So no, this won't pose a problem, since it'll only attempt authentication under these particular circumstances.
I implemented security according to the acl tutorial on the www.cakephp.org website. I'm trying to figure out which line of code is responsible for redirecting a user to the login page if they aren't already logged in. As a test, I commented out several lines from the beforefilter() function in app_controller.php so that it now looks like this:
function beforeFilter() {
//Configure AuthComponent
$this->Auth->authorize = 'actions';
$this->Auth->actionPath = 'controllers/';
// $this->Auth->loginAction = array('controller' => 'users', 'action' => 'login');
// $this->Auth->logoutRedirect = array('controller' => 'users', 'action' => 'login');
// $this->Auth->loginRedirect = array('controller' => 'alerts', 'action' => 'home');
// $this->Auth->loginRedirect = array('controller' => 'schedules', 'action' => 'index');
$this->Auth->allowedActions = array('display');
}
But I'm still being redirected to the login page.
The reason I'm asking about this is because my cakephp site is being served through a proxy server and I need to use relative url references, but the login redirect is using an absolute reference.
The actual redirection is done in AuthComponent::startup(). In there AuthComponent::isAuthorized() is called, and in your case (with Acl configured) Acl will be used to do the checking.
Changes to the settings in your beforeFilter() will no have any affect on the behavior. More than likely, you are failing the Acl->check() and being redirected on line 450.
See here - https://github.com/cakephp/cakephp/blob/master/cake/libs/controller/components/auth.php#L309, and https://github.com/cakephp/cakephp/blob/master/cake/libs/controller/components/auth.php#L450
To handle your redirect related issue, look at possibly overriding Helper::url(). Create an app/app_helper.php, define a class AppHelper that extends Helper... and provide a url method. Examine the passed arguments, return the appropriate url.