CakePHP: How to require admin role for a specific page? - php

We are using the Auth component. We are currently able to prevent non-logged in users from visiting our "admin" page (adminhome.ctp). But we can't figure out how to make isAuthorized() prevent non-admins from visiting the page also.
Inside the AppController:
public function beforeFilter() {
$this->Auth->allow('index', 'view', 'login', 'logout', 'display');
$this->Auth->authorize = array('Controller');
//$this->Auth->autoRedirect = false;
}
public function isAuthorized($user_id) {
$this->loadModel('User');
$user = $this->User->findById($this->Auth->user());
if ( $user['User']['role'] === 'admin') {
$this->Session->setFlash('isAuthorized');
return true;
}
$this->Session->setFlash('!isAuthorized');
return false;
}
Here the beforeFilter() in PagesController:
function beforeFilter() {
$this->Auth->deny('adminhome');
}
What are we doing wrong?

I have just used Aryan answer however I have made some minor changes which could be helpful for others:
if($this->Session->read('Auth.User.role') != 'admin')
{
$this->Session->setFlash('You are not authorized to visit this page');
$this->redirect('/');
}

I believe that your way it doesn't work because you should use Auth->deny() to restrict access to methods, and adminhome is not a method in the PagesController. Try this:
# in app/controller/PagesController.php
public function display() {
$page = empty($this->request->params['pass'][0]) ? null : $this->request->params['pass'][0];
if($page == 'adminhome' || $this->User->isAuthorized()) {
$this->render($page);
} else {
# redirect the user somewhere else
}
}
I hope this helps

You'll have role field in user table. In particular action add this line
if($this->Session->read('Auht.User.role') != 'admin') {
...............................
}
If you want only admin can see every actions in some controller like admincontroller
you can add this code in that controller in beforeRender action
if($this->Session->read('Auth.User.role') != 'admin')
{
$this->Session->setFlash(You are not authorized to visit this page,'flash',array('alert'=>'info'));
$this->redirect('/');
}

Related

How to allow controller action in CakePhp 3.x if temporary password in url passes verification?

I have set up a forget password scenario where the user submits email address, gets a temporary password sent to them, and the user clicks link to be sent to a user's edit function to change password to something they can remember. I am passing the temp pass in the url.
I debugged what I could and it seems to checkout, but still won't allow a non-logged in user to access the edit method. It seems to only authorize against logged in users (you can see my problem if they forgot their password and thus cannot login).
So how would you allow access to the controller method if the temp pass matches the id param of the url?
isAuthorized function:
public function isAuthorized($user = null)
{
if (isset($user['role']) && $user['role'] === 1 ) {
return true;
}
if ( $this->request->action === 'edit' ) {
$paramId = (int)$this->request->pass;
$logged_out_user = $this->Users->get($paramId);
if ( password_verify($this->request->query('pass'), $logged_out_user->password) === true ) {
return true;
} else {
return $this->redirect($this->Auth->redirectUrl());
}
}
return parent::isAuthorized($user);
}
sample link address: http://localhost/site/users/edit/1?pass=o1eNbs5l7GlHlqvPAmU.
I just figured it out. I added the 'edit' action to my beforefilter so that anyone could access it whether logged in or not, then in the edit function I just added the checks, pretty simple really, but for some reason I wasn't able to think of it.
inside edit function:
if ($this->request->session()->read('Auth.User')) {
if ( $user->id === $this->request->session()->read('Auth.User.id') || $this->request->session()->read('Auth.User.role') === 1 ) {
$this->Auth->allow();
} else {
$this->Flash->error(__('You do not have access to that page.'));
return $this->redirect(['action' => 'login']);
}
} elseif ( !empty($this->request->query('pass')) && password_verify($this->request->query('pass'), $user->password) === true ) {
$this->Auth->setUser($user->toArray());
} else {
$this->Flash->error(__('You do not have access to that page.'));
return $this->redirect(['action' => 'login']);
}
if ( !empty($this->request->query('pass')) && password_verify($this->request->query('pass'), $user->password) === true ) {
$user->old_password = $this->request->query('pass');
}
I think ideally you would make it two separate actions in the controller, so that you can make your edit page only for actual user editing and your reset password page only for resetting the password.
Then just do (in your controller)...
public function initialize()
{
parent::initialize();
$this->Auth->allow(['reset_password']);
}
This assumes you'd make your controller reset password action like this...
public function reset_password($pass = false) {
if (password_verify($pass)) {
// show password reset form
} else {
$this->redirect(['action' => 'key_required_or_expired']);
}
}

Yii: Getting the role of logged in users and showing content according to role

I want to get the roles of the registered users and show the content to the registered users according to their roles.
I have two users right now.
admin
user(authenticated)
The thing i am trying to do is that when the admin logs in via "webapp/user/login" a sidebarwidget which i have already made should be shown upon login and when the user(authenticated) gets logged in, the user(authenticated) should only be able to see the index.php page.
I am using Yii users and rights. I have looked around and found this piece of code which is for getting the role of the logged in user but I dont know where to place this piece of code to get the output.
Below are two pieces of codes, please do tell me which one will be more useful.
if($user = Users::model()->findAll()) {
foreach($user as $id => $user) {
if(!$user->checkAccess('Authenticated')) {
unset($user[$id]);
}
}
$users = array_values($user); // to reset indices (optional)
}
and this is another piece of code which i have found.
$command = Yii::app()->db->createCommand("SELECT * FROM `authassignment` WHERE userid={$user->id}");
$results = $command->queryAll();
$roles = array();
foreach ($results as $result)
{
$roles[] = $result['itemname'];
}
$this->setState('roles', $roles);
From what I have done following tutorials, here is a proposal.
The authentication can take place in file protected/components/UserIdentity.php :
public function authenticate($native=false){
$record=User::model()->findByAttributes(array('username'=>$this->username));
//can provide function "same" if needed - found it here:
//http://codereview.stackexchange.com/questions/13512
if($record!==null&&$this->same($record->password,crypt($this->password,$record->password)){
$authRoleName=Role::model()->findByAttributes(array('id'=>$record->role_id))->name;
$this->setState('role_name', $authRoleName);
$this->errorCode = self::ERROR_NONE;
}else{
$this->errorCode=self::ERROR_UNKNOWN_IDENTITY;
}
return !$this->errorCode;
}
In this case the several roles (admin, mobile, user, etc) are stored in db (table roles) and each user model has a role_id.
I assume the SiteController does the login (file protected/controllers/SiteController.php):
public function actionLogin()
{
$model=new LoginForm;
// if it is ajax validation request
if(isset($_POST['ajax']) && $_POST['ajax']==='login-form')
{
echo CActiveForm::validate($model);
Yii::app()->end();
}
// collect user input data
if(isset($_POST['LoginForm']))
{
$model->attributes=$_POST['LoginForm'];
// validate user input and redirect to the previous page if valid
if($model->validate() && $model->login()){
$this->redirect(Yii::app()->user->returnUrl);
}
}
// display the login form
$this->render('login',array('model'=>$model));
}
File protected/models/LoginForm.php:
class LoginForm extends CFormModel
public $username;
public $password;
public $rememberMe;
private $_identity;
public function authenticate($attribute,$params)
{
if(!$this->hasErrors())
{
$this->_identity=new UserIdentity($this->username,$this->password);
if(!$this->_identity->authenticate())
$this->addError('password','False username or password.');
}
}
public function login()
{
if($this->_identity===null)
{
$this->_identity=new UserIdentity($this->username,$this->password);
$this->_identity->authenticate();
}
if($this->_identity->errorCode===UserIdentity::ERROR_NONE)
{
$duration=$this->rememberMe ? 3600*24*30 : 0; // 30 days
Yii::app()->user->login($this->_identity, duration);
return true;
}
else
return false;
}
In view you could do a role based decision making, like the example below in file protected/views/site/index.php :
<?php
$userModel =User::model()->findByAttributes(array('id'=>Yii::app()->user->getId()));
if($userModel){
if(Yii::app()->user->getState('role_name') == 'admin'){
$this->renderPartial(
//...
);
}else{
//...
}
}
Moreover, if RBAC is on your mind, and you manage to have a proper protected/data/auth.php (there are ways for this, I use command "./protected/yiic rbac" after creating file protected/commands/RbacCommand.php - I can post this latter file if needed) then in any place in your code you simply:
if(Yii::app()->user->checkAccess('admin')){
//staff for admins
}
Also, in this case, you could set the rights of whole actions in controller's function accessRules() by issuing roles instead of usernames:
public function accessRules()
{
return array{
array('allow',
'actions'=>array('index', 'index2', 'view','create','update','getRecordDetails', 'getTotalCount'),
'roles'=>array('admin'),
),
);
}

How to redirect a user to users page and admin to admin page in single login form laravel

I have this in my database
|username|password|type|
------------------------
|foo |12345 |1 |
|asd |adsdsd |0 |
Here 1 means that the user is an admin, 0 a normal user.
How can I redirect the admin to the admin page and the normal user to normal user page??
if($attempt)
{
$id = User::find($attempt);
$user = $id->type;
if($user === 0)
{
return Redirect::action('LoginUsersController#profile');
}
else
{
return Redirect::to('adminpage');
}
}
I created this in my UsersController page I don’t know if this is the proper way to do this, and my code is not working.
Are you using normal Laravel Authentication?
You will get Object Auth::user(), this will return current user Object.
It should look like this.
Controller (SessionsController#store)
public function store() {
$input = Input::all();
$attempt = Auth::attempt([
'username' => $input['username'],
'password' => $input['password']
]);
if($attempt) {
if(Auth::user()->type == 1) {
return Redirect::admin(); // If admin, redirect to admin
} else {
return Redirect::profile(); // Else, redirect to user profile
}
}
}
Route
Route::resource('sessions', 'SessionsController', ['only' => ['create','store','destroy']]);
Route::get('admin', 'AdminController#dashboard')->before('adminAuth');
Route::get('profile/{id}', 'UsersController#showProfile')->before('auth');
First of all you have to add a new field in your users table to check against, for example 'rank'. If rank for a user is '1' so he is an Admin,
else he is a normal user.
Then define all required routes in your routes file like this:
Route::get('login', 'adminController#login');
Route::post('login', 'adminController#checkuser');
Route::group(array('before' => 'auth'), function() {
Route::resource('admin', 'adminController');
Route::resource('normaluser', 'normaluserController');
} );
Then in your controller you have to define all actions:
public function login()
{
return View::make('loginview');
}
public function checkuser()
{
if (Auth::attempt(array('username'=>Input::get('username'), 'password'=>Input::get('password'))))
{
$user_data = Auth::getUser();
if ($user_data->rank == 1) //if true, so this user is an admin
{return Redirect::to('admin');} //go to adminController index action
else //if not, so he is a normal user
{return Redirect::to('normaluser');} // go to normaluserController index action
}
else
{
//return 'wrong user name or password';
Session::flash('mismatch', "Username and Password mismatch");
return Redirect::to('login'); // go again to login form to relogin
}
}
if any thing is not clear, don't hesitate to ask.
in the if statement use:
if($attempt)
{
$id = User::find($attempt);
$user = $id->type;
if($user === 0)
{
return Redirect::action('LoginUsersController#profile');
header('Location: http://www.example.com/userpahe.php');
}
else
{
return Redirect::to('adminpage');
header('Location: http://www.example.com/admin-page.php');
}
}

Laravel 4 redirect issue with login page

I am using laravel 4 and here is my AdminController file :
class AdminController extends BaseController {
protected $layout = "admin.layout";
public function __construct() {
// security for the forms and access
$this->beforeFilter('csrf', array('on'=>'post'));
$this->beforeFilter('auth.admin' , array('except' =>array('getIndex','postSignin')));
// using this one to display user value if login and is admin
if (Auth::check() && Auth::user()->isAdmin()){
$this->user = Auth::getUser();
View::share('user', $this->user);
}
}
// main admin page
public function getIndex(){
$this->layout->content = View::make('admin.login');
}
// get the dashboard page
public function getDashboard() {
$this->layout->content = View::make('admin.dashboard');
}
// missing pages all redirect to dashboard if user is logged in.
public function missingMethod($parameters = array()){
if (Auth::check() && Auth::user()->isAdmin())
$this->getDashboard();
else
$this->getIndex();
}
Here is my filters.php file :
Route::filter('auth.admin', function()
{
if(!Auth::check() && !(Auth::user()->isAdmin())){
return Redirect::guest('admin');
}
});
in my routes.php file I am doing this:
Route::controller('admin', 'AdminController');
here is what I want if you could help me :_
1) . I want to clean up my code where there is not that much checking for if user is logged and isAdmin.
2). right now if you are logged in and you go to "admin/" , it will show you the login page ? how could I fix it in an effective way.
3). also if you are not logged in and you go to "admin/dashboard" it will show you dashboard content ? how to fix
Thank you in advance for all your help :)
You can use route groups and use a single filter to validate them
Check the docs
http://laravel.com/docs/routing#route-groups
Add this in your routes.php file:
Route::group(array('before' => 'auth.admin'), function() {
Route::controller('admin', 'AdminController');
})
Declare filter in filters.php file:
Route::filter('auth.admin', function(){
// Assumed you have a '/login' url
if (Auth::guest() || (Auth::check() && !Auth::user()->isAdmin())) {
return Redirect::guest('login');
}
});
Also make sure you have the user()->isAdmin() method in your User model that you are using and it checks whether the user is an admin or not and returns a Boolean value, TRUE if the user is an admin otherwise FALSE.

cakephp limit access to login screen when logged in

I don't want my users to be able to go to the login page if they are logged in. They have to log out first to be able to login. It seems simple enough, am i not understanding something correctly
class UsersController extends AppController {
public function isAuthorized($user) {
if( $this->Auth->login() ){
return false;
} else {
return true;
}
}
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');
}
}
}
There are also actions like register or lost password etc.
Basically you just check on blacklisted controller/actions and redirect to your home screen or login redirect accordingly
// Do not allow access to these public actions when already logged in
$allowed = array('Account' => array('login', 'lost_password', 'register'));
foreach ($allowed as $controller => $actions) {
if ($this->name === $controller && in_array($this->request->action, $actions)) {
$this->Common->flashMessage('The page you tried to access is not relevant if you are already logged in. Redirected to main page.', 'info');
return $this->redirect($this->Auth->loginRedirect);
}
}
See
https://github.com/dereuromark/cakefest/blob/master/Controller/AppController.php#L66
I use laravel, and in situations like that, my login route is filtered like this.
Route::get('login', array('before' => 'guest', "uses" => "SessionController#create"));
guest is the name of a filter, defined as return !Auth::check();
For CakePHP, I'd imagine it'd be pretty similar. Look for a way that you can filter your routes, based on if your current user is authenticated.

Categories