[cgiapp] Authentication/Authorization prerun interaction

Lyle Brooks brooks at deseret.com
Wed Jan 11 13:18:10 EST 2012


Quoting Cees Hek (ceeshek at gmail.com):
> On Wed, Jan 11, 2012 at 5:40 AM, Lyle Brooks <brooks at deseret.com> wrote:
> > I am attempting to use both
> >
> > CGI::Application::Plugin::Authentication
> > and
> > CGI::Application::Plugin::Authorization
> >
> > and when I attempt to restrict a runmode to require authorization (and
> > authentication), it produces a result I find counter-intuitive.
> >
> > I was wondering if anyone had similar experiences.
> >
> > The conditions occurs when I restrict a runmode to an authorized
> > group, and attempt to access it the first time (without authenticating).
> >
> > What I think "should" happen is that when I attempt to access the
> > runmode, I should be redirected to a login form to be authenticated.
> 
> The problem here is that Authorization does not necessarily have
> anything to do with Authentication.  You could authorize someone based
> on the IP address that they came from for instance.

Yes, I can understand that point.  However, I would "think" that the
case where Authorization is used in conjunction with Authentication
would often be a far more prevalent 'use case'.  No hard data to back
this up...just my gut feel.

> 
> > However, what actually occurs is that I get a "Forbidden" page.
> >
> > When I dug down into the code, it seems this is due to how the Plugin
> > modules interact with the prerun mode.
> >
> > When the request comes in, the prerun_callbacks that the Authentication
> > and Authorization registered are called before the requested runmode
> > code is executed....all good so far.
> >
> > The Authentication plugin will set the prerun_mode to "authen_login"
> > by default. ?The effect of this, as I understand it,
> > is to substitute the "authen_login" runmode for the requested runmode,
> > which effectively requires the user to authenticate. ?So far so good.
> >
> > Then the Authorization plugin callback is run. ?In this section
> > of code, it checks get_current_runmode() which returns the original
> > requested runmode....not the "authen_login" runmode set by the upstream
> > authentication plugin.
> >
> > And at this point, the authorization plugin judges the request to
> > be unauthorized, and it will then make a call to the "redirect_to_forbidding"
> > runmode which returns the "Forbidden" page I mentioned earlier.
> > So the Authorization plugin ends up taking action, before the prerun_mode
> > (set the the Authentication plugin) can be acted on ....later down the
> > request cycle.
> >
> > So if the login form (instead of a forbidden page) should be returned,
> > what should be the appropriate remedy?
> 
> The quick solution is to short circuit your code so that authorization
> checks are only executed when a user is authenticated.  You didn't
> provide any code so I can't be sure if that is easy or not...

There's not much code to provide.  I pretty much use the modules by
taking all the defaults.

For Authorization, I use the HTGroup driver.

For Authentication, I use the HTPasswd driver and the Session store.
I add a user_id to the group file like so...

admin: user1 user2

Then I have a very basic Application module with two runmodes, one that 
displays a form (the 'display' runmode) and another runmode that processes
the form data (the 'process' runmode)

In the Application's cgiapp_init() method I have two calls..

$self->authen->protected_runmodes( qw( display process ) );

$self->authorization->authz_runmodes(
    display => 'admin',
    process => 'admin',
);



> 
> > Should setting the prerun_mode() also set $self->{__CURRENT_RUNMODE}
> > inside of CGI::Application?
> 
> I am sure this is something that has been discussed in the past and
> was avoided for some reason that I can't remember...  Have a look
> through the archives.  I can't immediately see a problem with doing
> this and it makes a certain amount of sense, but I may be missing
> something.
> 
> >
> > or
> >
> > Should CGI::Application::Plugin::Authorization::prerun_callback be
> > modified to check the setting of prerun_mode() before get_current_runmode()?
> 
> This seems reasonable enough, but I am hesitant to just make that
> change without knowing what consequences that might have for existing
> users.
> 
> > I hope that is understandable. ?Any ideas other could share would
> > be appreciated.
> 
> My suggestion would be to try and handle this in your own code as I
> mentioned above.  If your authorization checks depend on someone being
> logged in, then only run the checks when someone is logged in.

Seems to me in this very basic case, that an unauthenticated user
should be given the opportunity to authenticate.  As it now stands,
the "Forbidden" page is returned...and the user (even one who would
be authorized to access the runmodes) is never the opportunity to
authenticate...and hence then be judged to be authorized).

This is why I argue that a change should be made to allow the
authentication (via the prerun mode) be given precedence over the
authorization's Forbidden response.

>From my reading of the CGI::Application's documention on the
use of prerun_mode(), its purpose is to allow for a new runmode
to supercede the requested runmode....in which case, it seems
like it should as a byproduct also set $self->{__CURRENT_RUNMODE}
In CGI::Application::prerun_mode() replace the line

$self->{__PRERUN_MODE} = $prerun_mode;

with 

$self->{__PRERUN_MODE} = $self->{__CURRENT_RUNMODE} = $prerun_mode;

(which I think would address my issue).

I don't what impact that would have on existing code written
for CGI::Application.

...

If that approach turned out to be inappropriate, then I would
in CGI::Application::Plugin::Authorization::prerun_callback()

the line 

if ($rule = $auth->is_authz_runmode($self->get_current_runmode)) {

be replaced with something like...


my $candidate_runmode = $self->prerun_mode() || $self->get_current_runmode();
if ($rule = $auth->is_authz_runmode($candidate_runmode)) {





More information about the cgiapp mailing list