Quantcast

Handling exceptions inside front controller plugins

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Handling exceptions inside front controller plugins

Karol Grecki
I use controller plugin for authentication and noticed that if an exception is thrown inside, the action is still executed (throwExceptions = false, my plugin works by redirecting user to a login page if they are not authenticated). The exception does trigger errorAction() in error controller so the user gets an error page as expected, but because the requested action is still executed (as I discovered by accident) he could POST some data and change application state bypassing the authentication and acl.
I tried putting all plugin logic into try-catch block and then modifying the request object to go directly to error controller but I had mixed results, it only seems to work with dispatchLoopStartup and is  there a way to pass thrown exception to error controller from another plugin?
I wonder if I'm doing something wrong, did anyone had similar problems and can provide some insight? How do you handle exceptions in something like an auth/acl plugin?

Thanks
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Handling exceptions inside front controller plugins

Ralph Schindler-2


> I use controller plugin for authentication and noticed that if an exception
> is thrown inside, the action is still executed (throwExceptions = false, my

It depends on what you are hooking into ultimately.
Authentication/Authorization stuff should generally happen in
preDispatch() since this is inside the dispatch loop, you have all the
control you need to set isDispatched() to false and handle either with
the errorHandler or your own plugin.

Exceptions should generally be reserved for exceptional behavior (like a
database not being present, or file cannot be accessed altered.)

Auth/Acl type stuff should be returning booleans when asked questions
like 'is there a user' or 'does he have access'.  In this case, you'd
want to (during preDispatch()), alter the request object to direct them
to the proper place, for example some kinda of NotAutorizedController.

> plugin works by redirecting user to a login page if they are not
> authenticated). The exception does trigger errorAction() in error controller
> so the user gets an error page as expected, but because the requested action
> is still executed (as I discovered by accident) he could POST some data and
> change application state bypassing the authentication and acl.

preDispatch() is where you can handle this.

ALSO, i would look into using ActionHelper preDispatch() hook as it
gives you per-controller access (as opposed to dispatch cycle only access)

> I tried putting all plugin logic into try-catch block and then modifying the
> request object to go directly to error controller but I had mixed results,
> it only seems to work with dispatchLoopStartup and is  there a way to pass
> thrown exception to error controller from another plugin?

try to avoid putting application logic inside dispatchLoopStartup- (like
  auth/acl)  the reason i say this b/c you have more control with the
dispatch loop, as opposed to the dispatchLoopStartup which can only
happen once regardless of what happens with regards to other plugins).

Also, the ErrorHandler is dispatched from within the loop.  So doing
checks in preDispatch() allows you to have control over when to forward
to the errorHandler.

> I wonder if I'm doing something wrong, did anyone had similar problems and
> can provide some insight? How do you handle exceptions in something like an
> auth/acl plugin?

If throwExceptions() is false, then you should be able to get all
exceptions throw during the dispatch loop inside your errorHandler /
ErrorController, and you can further do more "Exceptional logic" there.

-ralph
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Handling exceptions inside front controller plugins

Karol Grecki
>Exceptions should generally be reserved for exceptional behavior (like a
>database not being present, or file cannot be accessed altered.)

>Auth/Acl type stuff should be returning booleans when asked questions
>like 'is there a user' or 'does he have access'.  In this case, you'd
>want to (during preDispatch()), alter the request object to direct them
>to the proper place, for example some kinda of NotAutorizedController.

I actually noticed this behaviour because memcached server used for session storage
was inaccessible, that's pretty exceptional behaviour. Although it doesn't really matter
why the exception is thrown, because the effect is always the same.
I have to assume the code may fail, even if I don't explicitly throw anything.

>If throwExceptions() is false, then you should be able to get all
>exceptions throw during the dispatch loop inside your errorHandler /
>ErrorController, and you can further do more "Exceptional logic" there.

>-ralph

I can't really see any explanation or solution here, maybe I don't understand your point.
My current plugin looks a bit like this:

    public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request)
    {
        if (! Zend_Auth::getInstance()->hasIdentity()) {
            //redirect to login page
        }
        //get acl, check access to requested module/controller etc.
        throw new Exception('ups, something unexpected happened, database down, whatever');
        //redirect to not authorized page based on acl
    }

The result is an error page (from error controller) but the requested action
still gets executed regardless of the exception which could happen before
I had a chance to redirect user to another page.
If I change the hook to preDispatch() it doesn't even get to the error page,
it's thrown from Zend_Controller_Front->dispatch() while the action is still executed.

My current solution is to wrap all logic into try{} block and in catch{} do:
$request->setControllerName('error')->setActionName('error')->setDispatched(false);
This bypasses whatever action was requested and forwards user directly to the error controller.

This issue made me question the way I wrote my auth plugin, but I've seen it done
pretty much the same way by others. How would you do it?
Is there some recommended sample auth plugin anywhere that would be unaffected by this issue?

Thanks
Karol
Loading...