[cgiapp] CGI::Application status update from the maintainer

B. Estrade estrabd at gmail.com
Mon Sep 10 10:05:11 EDT 2012


Thank you, Mark.

I accept what you so at face value and will seek to educate myself
more. Below I address the questions you asked me.

On Sat, Sep 08, 2012 at 06:10:55PM -0400, Mark Stosberg wrote:
> 

snip..

> >
> > It would be really nice to merge in some bare bones Authentication and
> > Authorization support - maybe ever by more fully developing CAP's lifecycle.
> 
> More detailed suggestions would be welcome here, but I'm hestitent. Are
> there examples of other frames that do something here in a way that's
> appealing?

Not that I know of; I must admit I am a one trick pony wrt frameworks.
CAP is all I use and know.

> 
> I would generally plan to keep the core small, but would welcome more
> full-featured stacks to be shipped that were based on it, as Titanium
> did for CGI::Application.

My motivation for this is based on our needs. We use CAP to write not
just authenticated applications, but those with role based
authorization.  I have had moderate success using Authen and Authz,
but in order to do what was necessary to Authen before Authz or to
properly scale out the RBAC restrictions, I had to ditch both and
implement my own callbacks during the prerun stage.  I suppose both
plugins got be over the learning curve, and after I was able to
implement authentication and authorization without the plugins.

Anyway, my main reason for recommending these 2 in particular as
bona fide life cycle events is that the mirror Apache's life cycle. I
think this reflects the value of these two stages.  The first
(authentication) is simply for verifying to some degree that the actor
on the system is who they claim to be; the authorization is to ensure
that this authentication actor has authorized to execute the targeted
run mode. Both are prerun type of stages, but first classing them
would be nice. 

I am not sure I can persuade you to formalize these two stages in
particular, but I hope that you consider this. I believe that
authentication and RBAC style authorization is only going to become
more important, and if nothing these stages would provide a clue to
application programmers that CAP is very much suitable for industrial
strenght web applications.

> 
> One project that strikes me as interesting here is "Abilities".
> It addresses the problem space by using a "role". It is framework
> independent, but is intended to be used as part of web applications.
> 
>      https://metacpan.org/module/Abilities

Thank you.

> 
> This is an example of the kind of code I would like to make more easily
> available to CGI::App based projects.
> 
> > I am a recent addition to this community, and prefer CAP well over the
> > other alternatives.
> 
> That's good to hear, and welcome. Could you say more about why you
> prefer it and how you use it?

I prefer it because it provided me with a significant epiphany after
doing CGI the hard way for too long.  It's also more or less what we
standardize on internally at cPanel.

We use it to write internal applications and external facing APIs that
require both authentication and authorization. One of our primary
requirements is also raw speed, so even .05 seconds matters to us.
This is the basis for my distaste for any sort of MOP layer.  However,
I concede that in a persistent environment, start up times are
amortized over the long term and in this way any cost eventually goes
to 0. 

> 
> > 1. scalability - it is unnecessarily awkward to have more than 2
> > levels of subclassing currently.
> >
> > Direct subclass of CAP uses cgi_init; child of subclass uses setup;
> > anything else must call SUPER::setup.
> 
> Another option I use sometimes is to use the callback system:
> 
>     # Register an action to happen at the init stage.
>     __PACKAGE__->add_callback('init', sub {
> 
>     });

Nice.

> 
> Note that the Moose API also helps here as well, as it allows you to say
> this:
> 
>      # Add some additional functionality after 'setup' runs in the parent
>      after 'setup' => sub {
>          my $self = shift;
>      };
> 

Thank you. Yeah, that syntax makes me cring actually :).

However, this out of the box seems to provide the basis for a very
well structured plugin system.

>  
> https://metacpan.org/module/Moose::Manual::MethodModifiers#BEFORE-and-AFTER-modifiers
> 
> The Moose API also provides "BUILD", which like our callback system is
> called for every class in the inheritance hierarchy. So another way to
> add some "initialization" functionality would be to put this in your
> Moose/Mouse based child class:
> 
>      # Another way to add extra functionality when setting up classes.
>      sub BUILD {
>          my $self = shift;
>      }
> 
> > 2. a more fully developed lifecycle model - similar to the one that
> > Apache itself uses.  In particular, it would be really helpful to have
> > explicit  phases for state (e.g., Session munging), authentication,
> > and authorization.  I imagine those 3 in particular to be extremely
> > helpful for building things like role based access control or single
> > sign-on into your application.
> 
> I agree that session, authentication and authorization are all useful,
> but it's not clear to me what significant gains formal phase definitions
> here would bring us. Do you have examples where this design has been put
> to great use? Currently, our plugins in these areas use the calback
> system to hook in at the phases that are useful for them, and that seems
> to work well enough.

The one trouble I had with Authen and Authz is that while Authz will
call the Authen::username method if this plugin is being used, my
experiences lead me to believe that Authz will get called no matter if
there is an authenticated username or not - leading to having to
handle the case of username == undef. In otherwords, failure to
authenticate is not triggered before Authz is attempted (thus, this
has to be handled outside of Authen by Authz)...does this make sense?

I tried to order the plugins so that Authen failed before Authz was
attempted, but I couldn't figure out how to do this cleanly. I feel
like this is a serious problem.

> 
> > 3. a more fully developed plugin/event system; I think this goes along
> > with #2 (i.e., a few more hooks), but in addition to this I have
> > always thought it would be useful to have some sort of mechanism
> > through which plugins might be able to query one another.  A good
> > example (and actually the main motivation for #2 and #3) are the CAP
> > Authorization and Authentication plugins.  The short list of troubles
> > I have had with using these two are:
> >
> >   * when used together, Authorization is called before Authentication,
> >   making it awkward to handle authorization errors of unauthenticated
> >   guests (or maybe Authz assumes an authenticated session);
> >
> >   * default behavior of Authz is to query directly the Authorization
> >   plugin instance for a username; this works fine in that situation,
> >   but there is no clear way for plugin A to make information available
> >   to plugin B;
> >
> > That's just an example. I think that these improvements would go a
> > long way to encouraging the timeless benefits that you've outlined
> > about CAP above.
> 
> Regarding "more hooks", we already have an API to add custom hooks who
> folks who want more than the standard ones. Some plugins use this
> functionality to provide hooks that come part of their own published
> API.
> 
> Regarding "plugins querying each other", the Moose "Meta Object Protocol"
> provides functionality in this area that we could take advantage of.
> We can check to see if an object "does" a role, or check to
> see if the "original_package_name" matches the plugin we can expect.
> 
>    https://metacpan.org/module/Moose::Manual::Roles
>    https://metacpan.org/module/Class::MOP::Method

I think what I was thinking of for a "more developed" plugin system is
to provide a way to better manage when plugins are fired wrt hooks.

For example, have an "after" or "before" type of modifier when
registering a callback would be nice.  Even better would be a way to
easily manage the handler queue associated with each hook.  It's not
entirely clear to me how to ensure that handlerA will fire before
handlerB; I also know from reading the documentation that a class
level handler will fire before instance level handlers.  This might be
by design or just a consequence of the implementation; however being
able to control the handler execution order would be useful I believe.

> 
> > 4. more flexibility with the query object...err response object; I've
> > run into some hoops to jump through when I wanted to use CGI::Simple
> > and be able to upload capabilities on or off in a sub class.
> 
> You'll have be more specific here. The framework already allows you to
> use alternate query objects, and requires very few methods of it.

I think this has been addressed by others, so no real need to rehash
it.

> 
> Splitting the query object into response and request objects would
> immediately provide flexibility, as you could replace the objects
> independently. :)
> 
> Regarding turning uploads on and off independently, Plack::Request
> includes flexibility here, as upload handling is split off into it's own
> module, as Plack::Request::Upload. You could easily make an alternate
> class for uploads that behaved differently.
> 
> Perhaps want you want to do in your case is to reject "POST" requests as
> soon as possible. In that case, using a Plack "Middleware" may be best
> solution, as it can take action even before the content is prepared for
> processing by your application.

Thank you.

> 
> > 5. persistence - I would like to say that I'd like to learn more about
> > CAP and the ecosystem in persistent environments. It's my impression
> > that there are some corner cases or funny issues with it. I do not
> > claim this is true, but I think that we can all agree that while
> > persistent environments such as mod_perl are considered old fashioned,
> > I think that they will prove remain relevant amist the tide of
> > alternatives and "middleware" laden configurations. For me, the
> > ultimate goal would be to use CAP to create a responsive and
> > consistent daemon type application as served by Apache, defined
> > strictly through things like runmodes, plugins, etc. Is PSGI the path
> > to this? Maybe, maybe not.
> 
> I use CGI::Application almost exclusively under mod_perl 2 now, and am
> not aware of significant "gotchas" there. When I switch my large
> application over to PSGI (from vanilla mod_perl 2), it will still be
> running under mod_perl 2, only with a PSGI adapter.
> 
> I don't see Apache/mod_perl2 and "Middleware" as being at odds with each
> other. Sometimes they provide different solutions. Sometimes an Apache
> solution may perform better, sometimes a Middleware solution may be
> preferred for being hackable pure Perl.
> 
> I'm personal curious to evaluate replacing Apache with Starman as an app
> server, with Nginx in front of it serving static content and acting as a
> reverse-proxy. (I already use Nginx this way, but only with Apache on
> the backend).

Thank you.

> 
> > 6*. the last mile - in application frameworks, I am unsure of any that
> > take the finite state machine model to its logical max. This thought
> > may be way out there, but defining things like runmodes only takes you
> > so far. Going a step further, perhaps done through more feature dispatching
> > or routing, it'd be really nice to be able to define the application
> > runmodes in terms of a transition function (e.g., current runmode,
> > input, resulting runmode). In otherwords, support defining an
> > application to the fullest extent possible though some sort of runmode
> > dispatch table annotations.
> 
> I'll have to wait for the more specific proposal on this point. :)

Well, I think a proposal of this magnitude would be a pretty large
undertaking and be subverted by any use of a MOP (or maybe not); the
idea here is to do the opposite of Moose and have a step that takes an
application definition and generates some some fairly efficient/low
level Perl that is maximally explicit rather than maximally implicit
(as Moose provides); this would minize a lot of overhead. Custom code
would be provided through module hooks so that what you're generating
is the framework code and not the custom app code.  IDK, stay with me
because it's stull mulling around in my head.

Thanks, again,
Brett

> 
>      Mark
> 
> #####  CGI::Application community mailing list  ################
> ##                                                            ##
> ##  To unsubscribe, or change your message delivery options,  ##
> ##  visit:  http://lists.openlib.org/mailman/listinfo/cgiapp    ##
> ##                                                            ##
> ##  Web archive:   http://lists.openlib.org/pipermail/cgiapp/   ##
> ##  Wiki:          http://cgiapp.erlbaum.net/                 ##
> ##                                                            ##
> ################################################################
> 

-- 
Register Now for cPanel Conference
Oct 8-10, 2012, Houston, Texas
http://conference.cpanel.net/


More information about the cgiapp mailing list