We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

ACL BUG

Someone using the latest version of Phalcon can create an ACL that works following the example of INVO ???

Using Wamp Server latest version also, I have done tests on windows 8.1 64bit and Windows 7 32-bit and both simply I can not make it work, does anyone know tell if this is a bug?

I have lost more than a month trying to make it funcionard and all forms and could not functioning as it should, even including copying the code to ensure that there were no typos, but no use.

Does anyone have a response because I'm about to give up trying to use this framework, or is there any other efficient way to develop private areas on my system without using this ACL system.



33.8k

What error do you have? Blank page? Exception?

Does the error.log says something?

@phalcon

The pages are not private or public when they should, for example, I created a controller called open, it leaves this controller as an independent public I put it as private or not, it also leaves the public index controller others as it gets private, independent of the configuration that I do.

And even that it leaves open controller as standard public do not know why because I did not see it in the documentation, it's just the index action, the others are private as well.



33.8k

Did you create a session auth to check in every request if the user has access to that part of the app?

edited Jan '15

when the session there is no role should be defined as a guest and have access to areas defined as public but it does not.

$auth = $this->session->get('auth');

    if (!$auth){
        $role = 'Guests';
    } else {
        $role = 'Users';
    }


33.8k

Mmmm...

  1. Maybe you set the auth somewhere before in the code, so it is always Users.
  2. You haven't attached the events manager to the security plugin.

Else I think could be a bug as you say: Windows Phalcon has some problems, not like others OS, as I remember from reading.

SecurityPlugin.php

public function beforeDispatch(Event $event, Dispatcher $dispatcher)
{
    $auth = $this->session->get('auth');

    //Definindo Tipo User
    if (!$auth){
        $role = 'Guests';
    } else {
        $role = 'Users';
    }

    //$role = 'Users';

    $controller = $dispatcher->getControllerName();
    $action = $dispatcher->getActionName();
    $acl = $this->getAcl();

    $allowed = $acl->isAllowed($role, $controller, $action);

    if ($allowed != Acl::ALLOW) {
        $dispatcher->forward(array(
            'controller' => 'errors',
            'action'     => 'index'
        ));
        return false;
    }

services.php

$di->set('dispatcher', function() use ($di) {
$eventsManager = new EventsManager;
/**
 * Check if the user is allowed to access certain action using the SecurityPlugin
 */
$eventsManager->attach('dispatch:beforeDispatch', new SecurityPlugin);
/**
 * Handle exceptions and not-found exceptions using NotFoundPlugin
 */
//$eventsManager->attach('dispatch:beforeException', new NotFoundPlugin);
$dispatcher = new Dispatcher;
$dispatcher->setEventsManager($eventsManager);
return $dispatcher;
});

When I set the user as User to test it is as user, to enter the contest I created called Close is private, but it does not access the actions other than the index, and when the role is Guest he also does not access any action than the index, nor any other controller than the ones I created with the name of Open, Errors and the Index, any I create even being in the public list it does not release the access.

I have no idea why these three controllers are public by default, even if I will not declare, like Open for example.



33.8k
edited Jan '15

I've seen other things comparing with the INVO tutorial or with my code: I don't know if you don't have it in your code, or just skipped it here, but I'll tell you (also tips for your code).

services.php

$di->set('dispatcher', function() use ($di)
{
    $eventsManager = new EventsManager();
    $dispatcher    = new Dispatcher();

    /*
     * Check if the user is allowed to access certain action using the 'SecurityPlugin'.
     * Handle exceptions and not-found exceptions using 'NotFoundPlugin'.
     *
     * Tip: I would recomend creating a class only to pass the dispatcher's events.
     * From it, call the functions for security and error 404 from other classes.
     */
    $eventsManager->attach('dispatch:beforeExecuteRoute', new SecurityPlugin($di));
    // or $eventsManager->attach('dispatch', new SecurityPlugin($di));
    $eventsManager->attach('dispatch:beforeException', new NotFoundPlugin($di));
    // or $eventsManager->attach('dispatch', new NotFoundPlugin($di));

    /*
     * Set the events manager of the dispatcher and return it.
     */
    $dispatcher->setEventsManager($eventsManager);
    return $dispatcher;
});

SecurityPlugin.php

class SecurityPlugin extends Phalcon\Mvc\User\Plugin
{
    public function beforeExecuteRoute(Event $event, Dispatcher $dispatcher)
    {
        // Here I would only change (if you don't have need of) the forwarding by a redirect.
       $this->response->redirect('errors/index');
    }
}

I think this should do the trick.

I made the changes that u suggested but still resulting in the same, when I changed the "$eventsManager->attach('dispatch: beforeExecuteRoute', new SecurityPlugin ($ id));" al all pages are opened out, what should not happen, I tried other variations you also suggested did not work.

Note the controllers and actions in public and private areas, the controller 'Open' is an independent public to put it al in mapping or not, and the 'Close' is as a private in the same way, when I it below define the role as 'Users' I can access the controller 'Close', but can not access the action 'DOIS' that is contained in this controller, nor the Block controller that remains blocked, as well as other controllers with index of exception, open and errors, the actions 'LOGIN' and 'OPEN' are also not accessible to any role that are redirected to the error controller to be a guest user or...

Complete code

SecurityPlugin.php

class SecurityPlugin extends Plugin
{
/**
 * Returns an existing or new access control list
 *
 * @returns AclList
 */
public function getAcl()
{
    //throw new \Exception("something");
    if (!isset($this->persistent->acl)) {
        $acl = new AclList();
        $acl->setDefaultAction(Acl::DENY);

        //Register roles
        $roles = array(
            'users'  => new Role('Users'),
            'guests' => new Role('Guests')
        );
        foreach ($roles as $role) {
            $acl->addRole($role);
        }
        //Private area resources
        $privateResources = array(
            'close' => array('index', 'dois'),
            'block' => array('index')
        );
        foreach ($privateResources as $resource => $actions) {
            $acl->addResource(new Resource($resource), $actions);
        }
        //Public area resources
        $publicResources = array(
            'index'  => array('index', 'login'),
            'open'   => array('index', 'aberta'),
            'errors' => array('index'),
            'teste'  => array('index')
        );
        foreach ($publicResources as $resource => $actions) {
            $acl->addResource(new Resource($resource), $actions);
        }
        //Grant access to public areas to both users and guests
        foreach ($roles as $role) {
            foreach ($publicResources as $resource => $actions) {
                foreach ($actions as $action){
                    $acl->allow($role->getName(), $resource, $action);
                }
            }
        }

        //Grant acess to private area to role Users
        foreach ($privateResources as $resource => $actions) {
            foreach ($actions as $action){
                $acl->allow('Users', $resource, $action);
            }
        }
        //The acl is stored in session, APC would be useful here too
        $this->persistent->acl = $acl;
    }
    return $this->persistent->acl;
}
/**
 * This action is executed before execute any action in the application
 *
 * @param Event $event
 * @param Dispatcher $dispatcher
 */
public function beforeDispatch(Event $event, Dispatcher $dispatcher)
{
    $auth = $this->session->get('auth');

    //Definindo Tipo User
    /* if (!$auth){
        $role = 'Guests';
    } else {
        $role = 'Users';
    } */

    $role = 'Users';

    $controller = $dispatcher->getControllerName();
    $action = $dispatcher->getActionName();
    $acl = $this->getAcl();

    $allowed = $acl->isAllowed($role, $controller, $action);

    if ($allowed != Acl::ALLOW) {
        /* $dispatcher->forward(array(
            'controller' => 'errors',
            'action'     => 'index'
        )); */
        $this->response->redirect('errors/index');
        return false;
    }
}
}


33.8k

I made the changes that u suggested but still resulting in the same, when I changed the "$eventsManager->attach('dispatch: beforeExecuteRoute', new SecurityPlugin ($ id));" al all pages are opened out, what should not happen, I tried other variations you also suggested did not work

Did you changed the name method to beforeExecuteRoute?

Try not using a persistent ACL (just return $acl) and the conditional IF in getAcl(). Also comment the return false; if you do a redirect.

Did you changed the name method to beforeExecuteRoute?

yes, it was like he was not working for all controllers were open for all roles.



33.8k

Not working for all controllers? That cannot be, I use that event to restrict access, and I've 5 controllers with 2 to 8 actions inside.

And what about the second option? If that doesn't work, maybe it'll be a bug, 'cause I have no cards left in my deck.

Not working for all controllers? That cannot be, I use that event to restrict access, and I've 5 controllers with 2 to 8 actions inside.

And what about the second option? If that doesn't work, maybe it'll be a bug, 'cause I have no cards left in my deck.

What is your version of Phalcon and your OS and webserver?



33.8k

Phalcon 1.3.2, Ubuntu 12.04, apache2.4.10, PHP 5.5.17.

Yeah, I've older version, but I think that if is a bug it would had saw the light some time ago.

I would recomend changing to older version: as far as I know, Phalcon 2 is still in beta.

Phalcon 1.3.2, Ubuntu 12.04, apache2.4.10, PHP 5.5.17.

Yeah, I've older version, but I think that if is a bug it would had saw the light some time ago.

I would recomend changing to older version: as far as I know, Phalcon 2 is still in beta.

I will continue doing tests trying to figure out, honestly I believe I did everything right and is a bug, or this new version of Phalcon for windows or web server or both.

My Phalcon 1.3.4, so you have an idea in my pc the INVO project carries no page in addition to the index, pages are displayed in white, including About and Contact.



33.8k

I never did any tutorial pass the first one, so I cannot tell anything more with INVO. If you push the code to Github, maybe I would give it a try to see if it fails with my version.



5.7k
Accepted
answer

Maybe a quick and dirty tests independent of routing, something like this, this the gist of my ACL study code, I'm a little embarrassed, but what the hell:

    $acl = new \Phalcon\Acl\Adapter\Memory();
    $acl->setDefaultAction(\Phalcon\Acl::DENY);

    //Register roles
    $roles = array(
        'admin'  => new \Phalcon\Acl\Role('admin'),
        'guest' => new \Phalcon\Acl\Role('guest')
    );
    foreach ($roles as $role) {
        $acl->addRole($role);
    }

    //Private area resources
    $privateResources = array(
        'acl-protected'    => array('protected'),
    );
    foreach ($privateResources as $resource => $actions) {
        $acl->addResource(new \Phalcon\Acl\Resource($resource), $actions);
    }

    //Public area resources
    $publicResources = array(
        'index'   => array('index'),
        'acl-protected'   => array('index')
    );
    foreach ($publicResources as $resource => $actions) {
        $acl->addResource(new \Phalcon\Acl\Resource($resource), $actions);
    }

    //Grant access to public areas to both users and guests
    foreach ($roles as $role) {
        foreach ($publicResources as $resource => $actions) {
            $acl->allow('admin', $resource, '*'); // every controller's actions allowed, Carte blanche
            $acl->allow('guest', $resource, $actions); // A controller has both public and protected actions, only specified ones are allowed, instead of * (all)
        }
    }

    //Grant acess to private area to role admin
    foreach ($privateResources as $resource => $actions) {
        foreach ($actions as $action){
            //echo $resource,' ', $action.'<br>';
            $acl->allow('admin', $resource, $action);
        }
    }

    // eyeball test
    foreach ($roles as $role) {
        foreach ($publicResources as $resource => $actions) {
            foreach ($actions as $action){
                echo $role ,' - ', $resource, '/', $action,' [access: ';
                echo ($acl->isAllowed((string)$role, (string)$resource, $action) ? 'allowed' : 'false'),'] <br>';
            }
        }
        foreach ($privateResources as $resource => $actions) {
            foreach ($actions as $action){
                echo $role ,' - ', $resource, '/', $action,' [access: ';
                echo ($acl->isAllowed((string)$role, (string)$resource, $action) ? 'allowed' : 'false'),'] <br>';
            }
        }
        echo '<hr>';
    }
edited Jan '15

I installed an old version of WAMP who comes with version 5.3 of PHP and the first test I did the ACL worked perfectly, soon will be with time and will perform more tests in case of confirmation is a bug Phalcon with the latest version of WAMP with PHP 5.5+.

When performing the tests will post here to be corrected if someone perform these tests before please report here.

edited Jan '15

FYI I'm on PHP 5.6, Phalcon 1.3.3, I do have an actual test with dispatch working correctly, but have not tested with other versions or php/phalcon combo.

Result of testing your ACL, with one critical modification, I don't know what is $acl = new AclList(); and so replaced it with $acl = new \Phalcon\Acl\Adapter\Memory();. The results look correct.

Users - index/index[allow]
Users - index/login[allow]
Users - open/index[allow]
Users - open/aberta[allow]
Users - errors/index[allow]
Users - teste/index[allow]
Users - close/index[allow]
Users - close/dois[allow]
Users - block/index[allow]
------
Guests - index/index[allow]
Guests - index/login[allow]
Guests - open/index[allow]
Guests - open/aberta[allow]
Guests - errors/index[allow]
Guests - teste/index[allow]
Guests - close/index[not]
Guests - close/dois[not]
Guests - block/index[not]

If you've set up a serialized cache, obviously clear that before test, and kill $this->persistent->acl with this $this->session->destroy();, I do not know another way to kill persistent data.

Some ACL links:

It worked finally, all that was causing the problem was if the code where the function GETACL was inside.

if (!isset($this->persistent->acl))

Simply removing this snippet of code up as Edward Hew had recommended did all work perfectly in both PHP version I was testing.

I greatly appreciate the Edward Hew and RompePC the commitment to help solve this problem, is recorded here for if someone has the same problem in the future know how to troubleshoot quickly and easily.

Problem solved.