[cgiapp] Q: Authz, but only when user is Authenticated...

Lee Carmichael lecar_red at yahoo.com
Mon Mar 17 16:25:56 EDT 2008


Hello Graham,

I just ran into this same problem last week. I was just crafting an email about it but found it hard to explain. You did a great job :)

> So, I load up CAP::Authen and CAP::Authz in my App superclass and the prerun 
> hooks get invoked in order (authen first, then authz).  However... if they 
> both fail (user isn't logged in, so I obviously fail authz), CAP::Authz 
> calls "prerun_mode()" last and overrides the rm that was set by CAP::Authen 
> to trigger the login screen.

This is a problem with any prerun callbacks. The last one run will be the one that sets the 'prerun_mode'. 

I did find that one plugin (Dispatch I think) that was being aware and checking to make sure that prerun_mode wasn't set yet. I'm not sure this is a great choice since it assumes that plugin authors will be aware of this and code around it. It just seems wrong to me...

> I've got a few possible ideas for working around this, but wanted to find out 
> what others are doing...
> 
> 1) Load CAP::Authz first.  That way, even if Authz fails, CAP::Authen would be 
> the last one to call "prerun_mode()" and the user would get shown the login 
> page.  This works, but feels counter-intuitive; I'm always thinking that I 
> want Authen to run first so I load that plugin first.

I didn't like this one either.

> 2) Add a new "REQUIRES_AUTHEN" option to CAP::Authz, so that if its unable to 
> even figure out what the username is then it doesn't even bother doing an 
> Authz check.

I like this. 

> What are you guys doing when you want similar behaviour?

I needed a really quick solution, so I added the following to my code until a better long term solution could be determined:

(prerun_mode could have been $self->auth->username too)

package My::WebApp;

## ..snip...
my @protected_modes = qw( page1 page2 );

sub cgiapp_prerun {
    my $self = shift;

    if ( !$self->prerun_mode ) {
        ## validate user authz stuff
        $self->authz->authz_runmodes( map { $_ => 'pxdesk' }
                @protected_runmodes );

        ## this is a bit strange but has to due with calling stuff
        ## I would expect: $self->authz->prerun_callback too...
        $self->CGI::Application::Plugin::Authorization::prerun_callback();
    }
}

In my case, I need to have some other prerun code still run so I just excluded the authz code. 

Overall, I think CA should handle this a bit better, but I'm not sure how since that call_hook code is really well separated and has a clean design. It seems wrong to 'mess' it up for this one case.

Maybe it would be good to have the callback throw an exception that would tell CA to stop processing other callbacks? But I could envision situations where the app may want other callbacks to still be called anyway like mine above :) Today the callback code will just die if it sees an exception. Maybe 'prerun_mode' could only be set once inside the prerun callbacks, first one to set it gets it. 

Other ideas?

Take Care,

Lee









More information about the cgiapp mailing list