Zend_ACL guest roles overide Adminstrator roles? - zend-framework

I have created Zend_ACL with three roles :'administrator, guest, *edito*r'. I want guest cannot access /album/index after login. Administrator, editor can access /album/index. All other pages are accessible by all.
I created the access list below with Acl.php in helper.
/library/My/Helper/Acl.php:
public function __construct() {
$this->acl = new Zend_Acl();
}
public function setRoles() {
$this->acl->addRole(new Zend_Acl_Role('guest'));
$this->acl->addRole(new Zend_Acl_Role('editor'));
$this->acl->addRole(new Zend_Acl_Role('administrator'));
}
public function setResource () {
$this->acl->add(new Zend_Acl_Resource('album::index'));
$this->acl->add(new Zend_Acl_Resource('album::add'));
$this->acl->add(new Zend_Acl_Resource('album::edit'));
$this->acl->add(new Zend_Acl_Resource('album::delete'));
$this->acl->add(new Zend_Acl_Resource('auth::index'));
$this->acl->add(new Zend_Acl_Resource('auth::logout'));
$this->acl->add(new Zend_Acl_Resource('error::error'));
}
public function setPrivilages() {
$allowEditorAdmin=array('administrator','editor');
$allowAll=array('administrator','guest','editor');
$this->acl->allow($allowEditorAdmin,'album::index');
$this->acl->allow($allowAll,'album::add');
$this->acl->allow($allowAll,'album::edit');
$this->acl->allow($allowAll,'album::delete');
$this->acl->allow($allowAll,'auth::index');
$this->acl->allow($allowAll,'auth::logout');
$this->acl->allow($allowAll,'error::error');
Then, I create a plugin Acl.php
public function preDispatch(Zend_Controller_Request_Abstract $request) {
$acl1 = new My_Controller_Helper_Acl();
$acl = Zend_Registry::get('acl');
$userNs = new Zend_Session_Namespace('members');
if($userNs->userType=='')
{
$roleName='guest';
}
else
$roleName=$userNs->userType;
if(!$acl->isAllowed($roleName,$request->getControllerName()."::".$request->getActionname()))
{
echo $request->getControllerName()."::".$request->getActionName();
$request->setControllerName('auth');
$request->setActionName('index');
}
else
echo "got authenticated";
}
The problem is my code "isallowed" not work correctly. The 'guest,editor,administrator' cannot access to /album/index after authenticate successfully. They redirect to /auth/index
if(!$acl->isAllowed($roleName,$request->getControllerName()."::".$request->getActionname()))
{
echo $request->getControllerName()."::".$request->getActionName();
$request->setControllerName('auth');
$request->setActionName('index');
}
else
echo "got authenticated";
}

As far as I can tell, You are using 2 different ACL instances, and never set up the appropriate ACL in the first place. I can share a bit of my own code, that does almost the same thing:
In Bootstrap.php
$this->_acl = new Model_AuthAcl();
//Check for access rights
$fc = Zend_Controller_Front::getInstance();
$fc->registerPlugin(new App_Plugin_AccessCheck($this->_acl));
In App_Plugin_AccessCheck
class App_Plugin_AccessCheck extends Zend_Controller_Plugin_Abstract
{
private $_acl = null;
public function __construct(Zend_Acl $acl)
{
$this->_acl = $acl;
}
public function preDispatch(Zend_Controller_Request_Abstract $request)
{
$module = $request->getModuleName();
$resource = $request->getControllerName();
$action = $request->getActionName();
try {
if (!$this->_acl->isAllowed(Zend_Registry::get('role'), $module . ':' . $resource, $action)) {
$request->setControllerName('authentication')->setModuleName('default')
->setActionName('login');
}
}
catch (Exception $ex) {
if (APPLICATION_ENV == "development") {
var_dump($ex->getMessage());
}
}
}
}
In Model_AuthAcl
class Model_AuthAcl extends Zend_Acl
{
/**
* Creates the resource, role trees
*/
public function __construct ()
{
//Create roles
$this->addRole(new Zend_Acl_Role('guest'));
$this->addRole(new Zend_Acl_Role('user'), 'guest');
$this->addRole(new Zend_Acl_Role('admin'), 'user');
//Create resources
//Default module
$this->addResource(new Zend_Acl_Resource('default'))
->addResource(new Zend_Acl_Resource('default:authentication'), 'default')
->addResource(new Zend_Acl_Resource('default:error'), 'default')
//Admin module
->addResource(new Zend_Acl_Resource('admin'))
->addResource(new Zend_Acl_Resource('admin:index'), 'admin')
//Guest permissions
$this->deny('guest')
->allow('guest', 'default:authentication', array('index', 'login', 'logout', 'email', 'forgot'))
->allow('guest', 'default:error', array('error'))
->allow('guest', 'api:authentication', array('index', 'get', 'head', 'post', 'put', 'delete'))
//Admin permissions
->deny('admin', 'admin:admins')
;
}
}
May not be the most OOP solution, bet it sure as hell works.
Hope this helps you set up your dream ACL :)

Related

It doesn't find my class even if it exists

This is the error:
Fatal error: Class 'Admin_Controller' not found in C:\xampp\htdocs\ci-blog-master\application\modules\admin\controllers\Settings.php on line 4
A PHP Error was encountered
Severity: Error
Message: Class 'Admin_Controller' not found
Filename: controllers/Settings.php
Line Number: 4
Backtrace:
And here is my code for :
Admin_controller.php
<?php defined('BASEPATH') OR exit('No direct script access allowed');
class Admin_Controller extends MY_Controller {
function __construct()
{
parent::__construct();
}
}
And here is my Settings.php
class Settings extends Admin_Controller {
public function __construct(){
parent::__construct();
$this->allow_group_access(array('admin'));
$this->load->model('Category');
$this->data['parent_menu'] = 'post';
}
public function index(){
$this->session->set_flashdata('message',message_box('Setting is the coming soon feature!','danger'));
redirect('admin/posts/index');
$config['base_url'] = site_url('admin/categories/index/');
$config['total_rows'] = count($this->Category->find());
$config['per_page'] = 10;
$config["uri_segment"] = 4;
$this->data['categories'] = $this->Category->find($config['per_page'], $this->uri->segment(4));
$this->data['pagination'] = $this->bootstrap_pagination($config);
$this->render('admin/categories/index');
}
public function add(){
$this->form_validation->set_rules('name', 'name', 'required|is_unique[categories.name]');
$this->form_validation->set_rules('status', 'status', 'required');
if($this->form_validation->run() == true){
$category = array(
'name' => $this->input->post('name'),
'status' => $this->input->post('status')
);
$this->Category->create($category);
$this->session->set_flashdata('message',message_box('Category has been saved','success'));
redirect('admin/categories/index');
}
$this->render('admin/categories/add');
}
public function edit($id = null){
if($id == null){
$id = $this->input->post('id');
}
$this->form_validation->set_rules('name', 'name', 'required');
$this->form_validation->set_rules('status', 'status', 'required');
if($this->form_validation->run() == true){
$category = array(
'name' => $this->input->post('name'),
'status' => $this->input->post('status')
);
$this->Category->update($category, $id);
$this->session->set_flashdata('message',message_box('Category has been saved','success'));
redirect('admin/categories/index');
}
$this->data['category'] = $this->Category->find_by_id($id);
$this->render('admin/categories/edit');
}
public function delete($id = null){
if(!empty($id)){
$this->Category->delete($id);
$this->session->set_flashdata('message',message_box('Category has been deleted','success'));
redirect('admin/categories/index');
}else{
$this->session->set_flashdata('message',message_box('Invalid id','danger'));
redirect('admin/categories/index');
}
}
public function update_multiple(){
#test commit
#test commit di branch sendiri
}
}
You can put more classes in MY_Controller.php file:
<?php defined('BASEPATH') OR exit('No direct script access allowed');
class MY_Controller extends CI_Controller
{
public function __construct()
{
parent::__construct();
}
public function some_mycontr_method()
{
// appropriate code here
}
}
class Admin_Controller extends MY_Controller
{
public function __construct()
{
parent::__construct();
}
public function some_admin_method()
{
// appropriate code here
}
}

Symfony2, Keep form data across redirect

How to use session for retrieving data during redirect? I am getting the error message: "exception 'Symfony\Component\Form\Exception\AlreadySubmittedException' with message 'You cannot change the data of a submitted form."
C:\Bitnami\wampstack-5.5.30-0\sym_prog\proj3_27\src\MeetingBundle\Controller\UserController.php
/**
* Creates a new User entity.
*
* #Route("/new", name="user_new")
* #Method({"GET", "POST"})
*/
public function newAction(Request $request)
{
$user = new User();
$form = $this->createForm(new UserType(), $user);
$form->handleRequest($request);
$session = $this->getRequest()->getSession();
$form->setData(unserialize($session->get('userFilter')));
if ( $form->isSubmitted() && $form->isValid() ) {
$session->set( 'userFilter', serialize($form->getData()) );
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();
return $this->redirectToRoute('user_edit', array('id' => $user->getId()));
}
return $this->render('MeetingBundle::user/new.html.twig', array(
'user' => $user,
'form' => $form->createView(),
));
} // public function newAction(Request $request)
C:\Bitnami\wampstack-5.5.30-0\sym_prog\proj3_27\src\MeetingBundle\EventListener\ExceptionListener.php
<?php
namespace MeetingBundle\EventListener;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Router;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
//every time the Kernel throws the kernel.exception event, the function onKernelException() is called.
/* also must create service :
meeting.exception_listener:
class: MeetingBundle\EventListener\ExceptionListener
arguments: [#templating, #kernel, #router]
tags:
- { name: kernel.event_listener, event: kernel.exception, method: onKernelException }
*/
class ExceptionListener
{
protected $templating;
protected $kernel;
protected $router;
public function __construct( EngineInterface $templating, $kernel, Router $router)
{
$this->templating = $templating;
$this->kernel = $kernel;
$this->router = $router;
}
public function onKernelException(GetResponseForExceptionEvent $event)
{
$exception = $event->getException();
$request=$event->getRequest();
$referer = $event->getRequest()->headers->get('referer');
$msg="";
$excStr=$exception->__toString(); // returns string finally!
$bdup=strpos( $excStr , 'Integrity constraint violation: 1062 Duplicate entry' );
if($bdup) {
$msg=" This username is already taken. Choose another username. ";
}
if(strlen($msg)!=0) {
// flash messsages are displayed in layout.html
$request->getSession()
->getFlashBag()
->add('Error', $msg);
}
$response = new RedirectResponse($referer); // redirect to the error page
if ($exception instanceof HttpExceptionInterface) {
$response->setStatusCode($exception->getStatusCode());
$response->headers->replace($exception->getHeaders());
} else {
$response->setStatusCode(Response::HTTP_INTERNAL_SERVER_ERROR);
}
$event->setResponse($response);
}
}

Call to a member function allow() on a non-object - authorization

I used this tutorial: http://book.cakephp.org/2.0/en/tutorials-and-examples/blog-auth-example/auth.html
To build my first form/create user app, but it fails with an error message:
Fatal error: Call to a member function allow() on a non-object in /home/public_html/cake/app/Controller/UsersController.php on line 18
This ius the 18 line:
$this->Auth->allow('add', 'logout');
The above line is a member of function:
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow('add', 'logout');
}
My whole UsersController.php:
<?php
class UsersController extends AppController {
public function login() {
if ($this->Auth->login()) {
$this->redirect($this->Auth->redirect());
} else {
$this->Session->setFlash(__('Invalid username or password, try again'));
}
}
public function logout() {
$this->redirect($this->Auth->logout());
}
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow('add', 'logout');
}
public function index() {
$this->User->recursive = 0;
$this->set('users', $this->paginate());
}
public function view($id = null) {
$this->User->id = $id;
if (!$this->User->exists()) {
throw new NotFoundException(__('Invalid user'));
}
$this->set('user', $this->User->read(null, $id));
}
public function add() {
if ($this->request->is('post')) {
$this->User->create();
if ($this->User->save($this->request->data)) {
$this->Session->setFlash(__('The user has been saved'));
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The user could not be saved. Please, try again.'));
}
}
}
public function edit($id = null) {
$this->User->id = $id;
if (!$this->User->exists()) {
throw new NotFoundException(__('Invalid user'));
}
if ($this->request->is('post') || $this->request->is('put')) {
if ($this->User->save($this->request->data)) {
$this->Session->setFlash(__('The user has been saved'));
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The user could not be saved. Please, try again.'));
}
} else {
$this->request->data = $this->User->read(null, $id);
unset($this->request->data['User']['password']);
}
}
public function delete($id = null) {
if (!$this->request->is('post')) {
throw new MethodNotAllowedException();
}
$this->User->id = $id;
if (!$this->User->exists()) {
throw new NotFoundException(__('Invalid user'));
}
if ($this->User->delete()) {
$this->Session->setFlash(__('User deleted'));
$this->redirect(array('action'=>'index'));
}
$this->Session->setFlash(__('User was not deleted'));
$this->redirect(array('action' => 'index'));
}
}
?>
Why does it happends?
Make sure the Auth compenent is actually called in your AppController. If you don't have an AppController create AppController.php in your Controllers directory with the following code:
<?php
class AppController extends Controller {
}
?>
The Auth component is called in a public variable in the AppController, so the controller would look like this:
<?php
class AppController extends Controller {
public $components = array('Auth');
}
?>
Auth is now available throughout your application. You could also call the AuthComponent in your UsersController, but that would make it only available to that particular controller. You probably want to use authentication in your entire application.

Having problems combining Zend_Acl and Zend_Navigation

I have a Federico_Plugin_Acl that extends Zend_Controller_Plugin_Abstract which looks like this:
class Federico_Plugin_Acl extends Zend_Controller_Plugin_Abstract {
private $_acl = null;
private $_auth = null;
const DEFAULT_ROLE = 'guest';
public function __construct($auth) {
$this->_auth = $auth;
$this->_acl = new Zend_Acl();
$this->_acl->addRole(new Zend_Acl_Role(self::DEFAULT_ROLE));
$this->_acl->addRole(new Zend_Acl_Role('user'), self::DEFAULT_ROLE);
$this->_acl->addRole(new Zend_Acl_Role('admin'), 'user');
$this->_acl->addResource(new Zend_Acl_Resource('index'));
$this->_acl->addResource(new Zend_Acl_Resource('users'));
$this->_acl->addResource(new Zend_Acl_Resource('about'));
$this->_acl->addResource(new Zend_Acl_Resource('gisele'));
$this->_acl->addResource(new Zend_Acl_Resource('admin'));
$this->_acl->allow('guest', 'index');
$this->_acl->allow('guest', 'about');
$this->_acl->deny('guest', 'gisele');
$this->_acl->deny('guest', 'users');
$this->_acl->allow('user', 'users', array('index'));
$this->_acl->allow('admin', 'users');
$this->_acl->allow('admin', 'gisele');
}
public function preDispatch(Zend_Controller_Request_Abstract $request) {
if ($this->_auth->hasIdentity()) {
$role = $this->_auth->getStorage()->read()->role;
} else {
$role = self::DEFAULT_ROLE;
}
$action = $request->getActionName();
$controller = $request->getControllerName();
if ($this->_acl->has($controller)) {
if (!$this->_acl->isAllowed($role, $controller, $action)) {
$request->setActionName('login');
$request->setControllerName('index');
}
}
}
}
And this method is in my bootstrap to make use of this class:
protected function _initNavigation()
{
$this->_auth = Zend_Auth::getInstance();
$this->_acl = new Federico_Plugin_Acl($this->_auth);
$this->bootstrap('view');
$view = $this->getResource('view');
$config = new Zend_Config_Xml(APPLICATION_PATH . '/configs/navigation.xml','nav');
$navigation = new Zend_Navigation($config);
$roleAuth = $this->_auth->getIdentity();
if(null == $roleAuth)
$role = 'guest';
else
$role = $roleAuth->role;
$view->navigation($navigation)->setAcl($this->_acl)->setRole($role);
}
With these configurations set like that, I get the following error:
Catchable fatal error: Argument 1 passed to Zend_View_Helper_Navigation_HelperAbstract::setAcl() must be an instance of Zend_Acl, instance of Federico_Plugin_Acl given, called in /home/fiodorovich/public_html/gisele/application/Bootstrap.php on line 118 and defined in /home/fiodorovich/library/ZendFramework/library/Zend/View/Helper/Navigation/HelperAbstract.php on line 333
Call Stack
Which is to be expected since Federico_Plugin_Acl is an instance of Zend_Controller_Plugin_Abstract...Still, if I extend Zend_Acl instead I get this error:
Fatal error: Zend_Acl_Role_Registry_Exception: Role 'guest' not found in /home/fiodorovich/library/ZendFramework/library/Zend/View/Helper/Navigation/HelperAbstract.php on line 522
So...I've been trying for a while to get this thing solved,... but don't seem to get this to work properly...Any ideas on what I'm missing here?
Zend_Controller_Plugin_Abstract and Zend_Acl are completelly different things. What you want to do is get the ACL object out of your plugin (which is now in private section) and pass it over to
$view->navigation($navigation)->setAcl(<here>);

is there a way to set up the acl roles that are allowed to access different parts of the site in my navigation.xml?

I have this in my bootstrap:
protected function _initAutoload()
{
$this->_auth = Zend_Auth::getInstance();
$this->_acl = new Federico_Plugin_Acl($this->_auth);
....
}
....
protected function _initNavigation()
{
$this->bootstrap('view');
$view = $this->getResource('view');
$config = new Zend_Config_Xml(APPLICATION_PATH . '/configs/navigation.xml','nav');
$navigation = new Zend_Navigation($config);
$view->navigation($navigation)->setAcl($this->_acl)
->setRole($this->_auth->getStorage()->read()->role);//I just added this
}
however the insert I just did generated this:
Catchable fatal error: Argument 1 passed to Zend_View_Helper_Navigation_HelperAbstract::setAcl() must be an instance of Zend_Acl, instance of Federico_Plugin_Acl given, called in /home/fiodorovich/public_html/gisele/application/Bootstrap.php on line 106 and defined in /home/fiodorovich/library/ZendFramework/library/Zend/View/Helper/Navigation/HelperAbstract.php on line 333
And this is what my navigation.xml looks like so far:
<configdata>
<nav>
<home>
<label>HOME</label>
<controller>index</controller>
<action>index</action>
</home>
<about>
<label>Nosotros</label>
<module>default</module>
<controller>about</controller>
<action>index</action>
</about>
<admin>
<label>Admin</label>
<uri>admin/index</uri>
<resource>admin</resource>
<pages>
<alta>
<active>0</active>
<label>Alta Usuario</label>
<controller>users</controller>
<action>create</action>
</alta>
</pages>
</admin>
</nav>
Right now, even the guests users can see that items in the nav, althogh they can't access since that's already set up in the Acl class... how do I pass the acl roles in here?
EDIT:
//my acl
class Federico_Plugin_Acl extends Zend_Controller_Plugin_Abstract
{
private $_acl = null;
private $_auth = null;
const DEFAULT_ROLE = 'guest';
public function __construct($auth)
{
$this->_auth = $auth;
$this->_acl = new Zend_Acl();
$this->_acl->addRole(new Zend_Acl_Role(self::DEFAULT_ROLE));
$this->_acl->addRole(new Zend_Acl_Role('user'), self::DEFAULT_ROLE);
$this->_acl->addRole(new Zend_Acl_Role('admin'), 'user');
$this->_acl->addResource(new Zend_Acl_Resource('index'));
$this->_acl->addResource(new Zend_Acl_Resource('users'));
$this->_acl->addResource(new Zend_Acl_Resource('about'));
$this->_acl->addResource(new Zend_Acl_Resource('gisele'));
$this->_acl->addResource(new Zend_Acl_Resource('admin'));
$this->_acl->allow('guest', 'index');
$this->_acl->allow('guest', 'about');
$this->_acl->deny('guest', 'gisele');
$this->_acl->deny('guest', 'users');
$this->_acl->allow('user', 'users', array('index'));
$this->_acl->allow('admin','users');
$this->_acl->allow('admin','gisele');
}
public function preDispatch (Zend_Controller_Request_Abstract $request)
{
if ($this->_auth->hasIdentity()) {
// user is logged in and we can get role
$role = $this->_auth->getStorage()->read()->role;
} else {
// guest
$role = self::DEFAULT_ROLE;
}
$action = $request->getActionName();
$controller = $request->getControllerName();
if($this->_acl->has($controller)) {
if(!$this->_acl->isAllowed($role, $controller, $action)) {
$request->setActionName('error');
$request->setControllerName('error');
}
}
}
}
Get the Zend_View instance (in your bootstrap, in an action helper, wherever it's easier for you) and then:
$view->navigation()
->setAcl(Zend_Acl $acl)
->setRole(Zend_Acl_Role $role);
Basically, the navigation view helper must explicitly be given knowledge about the ACL and current role.