Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

CGI::Application::Authentication and Static Pages

by digger (Friar)
on Jan 15, 2008 at 22:11 UTC ( [id://662571]=perlquestion: print w/replies, xml ) Need Help??

digger has asked for the wisdom of the Perl Monks concerning the following question:

I am currently using CGI::Application as my framework of choice in a shared hosting environment. C::A and its associated plugins are a lifesaver.

The only problem I have is that my sites are made up of a combination of dynamic and static pages, in directories protected by a .htaccess file. Protecting those static pages is a bit of a hassle, because right now, I am just getting $ENV{PATH_INFO}, opening the requested file and serving it back from my app. I also have to make sure there is no query string so that I don't intercept calls to runmodes within my application.

My question is - Is there a better way to handle this? I have Googled and researched, and haven't found anything yet.

Thanks for sharing your wisdom, digger

  • Comment on CGI::Application::Authentication and Static Pages

Replies are listed 'Best First'.
Re: CGI::Application::Authentication and Static Pages
by leocharre (Priest) on Jan 15, 2008 at 22:59 UTC
    Sounds a little vague.. Can you describe your problem a little more? What are you protecting? Sensitive information? Subsctiption content? Why are you so worried about calls to runmodes? Your cgiapp should be expecting to get bogus data. In fact you should code a cgiapp as if 99.99% is going to be bogus and malicious data. Use CGI::Application::Plugin::Session, if youdon't already. You can use that to check a level of authentication you have put on someone, perhaps. With my cgiapps that are interfaces to sensitive material, i check and recheck every single tiny little call to the server. I assume at ALL states of my application, in ALL runmodes, that I am getting bad data, bogus data, malicious data, etc. You can have things like..
    # uses CGI::Application::Plugin::Forward and Authen.. etc # you must know these by now.. sub break_a_leg : Runmode { my $self = shift; $self->__check or return $self->forward('error'); # ... do whatever... } sub __check { my $self = shift; $self->authen or die('no way.'); $self->_my_sub_check_user_input() or return 0; return 1; }
    And you can call check in every runmode. Furthermore, you are aware that with CGI::Application::Plugin::Authentication, you can block ALL runmodes NOT matching whatever.. such as..
    #more incomplete code.. sub _authen_config { my $self = shift; # authenticate $self->authen->config( DRIVER => [ 'Generic', sub { return $self->_verify_credentials(@_); }, ], LOGIN_SESSION_TIMEOUT => '45m', # TODO change to 35m for release CREDENTIALS => ['authen_username','authen_password','authen_captcha'], STORE => 'Session', LOGIN_RUNMODE => 'login', ); $self->authen->protected_runmodes(qr/^(?!login)/); return 1; }
      I hate to write (ok it's a macro - but still) even the my $self = shift; part in each runmode - and you have the check in each one?

      I've came up with this before Authen plugin was written ...

      == this is the "base module shared by all - I use base *it* instead of + CGI::App directly. package YPTP::App; use strict; use base 'CGI::Application'; use base 'YPTP::DataBase'; use base 'YPTP::Email'; use CGI::Application::Plugin::TT; # TemplateToolkit use CGI::Application::Plugin::Session; # CGI::Session use CGI::Application::Plugin::AutoRunmode; sub cgiapp_init { my $self = shift; .... ussual setup stuff ... } # In case most of pages are public - if not I set it to return 0 sub authorize { my $self = shift; return 1; } sub cgiapp_prerun { my ($self, $run_mode) = @_; # CGI::APP doesn't alow you to change runmode at init stage - say +if there is an error with # DB connection ... So I set it there and catch it here. if( $self->param('error') ){ $self->prerun_mode('ERROR'); } # Maybe only some runmodes need to be protected - so we send the r +unmode name to decide unless( $self->authorize($run_mode) ){ # Error $self->prerun_mode('NOT_AUTHORIZED'); } } === some module containing runmodes connected logically package YPTP::Runmodes::Admin; use strict; use base 'YPTP::App'; sub authorize { my $self = shift; my $runmode = shift; my $type = $self->session->param('type'); return 1 if($type eq 'admin'); # admin can do anything return 0; # everyone else can't do a thing }
      I'm obviously using CGI::Application::Dispatch to decide which file/module to call. So for each file containing runmodes you can override the default authorize method and even check auth based on runmode to be called.
      sub authorize { my $self = shift; my $runmode = shift; my $tip = $self->session->param('tip'); return 1 if($tip eq 'admin'); # Admin moze sve ! :) my $auth = { 'index' => 1, # everyone profil_forma => $tip eq 'poslodavac', profil_obrada => $tip eq 'poslodavac', '_default' => $tip eq 'poslodavac' }; if(defined $auth->{$runmode}) { return $auth->{$runmode}; } else { return $auth->{_default}; } }

      Have you tried freelancing? Check out Scriptlance - I work there. For more info about Scriptlance and freelancing in general check out my home node.
Re: CGI::Application::Authentication and Static Pages
by Youdaman (Acolyte) on Jan 16, 2008 at 00:51 UTC
    Perhaps CGI::Application::Dispatch is what you're after? Have a look at the "Simple Apache Example" on its CPAN page for an example of how to serve files or directories directly, but route other requests to your dispatcher/cgiapp.

      I looked at using mod_rewrite rules to solve the problem, but I still need to use C::A::Plugin::Authentication to authenticate users, even for the ststic pages.

      Thanks for the pointer to that sample. It is a great example of using mod_rewrite.

Re: CGI::Application::Authentication and Static Pages
by digger (Friar) on Jan 16, 2008 at 14:37 UTC

    I see how my question seems a little vague so I'll give a more concrete example. I have an admin script for the website that is its own application.

    Package Site::Admin;
    use base 'CGI::Application';
    ...
    
    ---.htaccess-----
    Action admin	/cgi-bin/siteadmin.pl
    AddHandler	admin .html
    -----------------------

    So now, any html file requested in this directory will be have its request redirected to my admin app. The static pages here are simple pages like a list of admin options that don't require any code to generate. I don't want just any Joe Lookyloo getting access to these pages, so I want to make sure that the user is authenticated before accessing the page.

    If I do a simple redirect after verifying authentication, I end up back at the login page instead of the static page because all requests for html files have to pass through my app. It looks like the only solution is to open the file for the static page and effectively serve the page from my app.

    I am wondering if there is a better way of solving the problem of serving static pages using this method. I know that if I had some additional Apache modules and mod_perl, this would not be an issue, but the shared hosting limits my options.

      IMHO, anything you don't want everyone to see- should not physically reside in webshare- period.

      On one hand this is a general rule for me- on the other- it sounds like you're doing some fun stuff. It seems your admin will either be an editor of the content- or your html files are HTML::Template files, that are prefed by admin app- very witty..

      So, these *are* or are not "static web pages" or are they templates that are fed by admin??

      (Still, I say nothing in webshare that you don't want everyone to see..

      For example with shared hosting, or whenever you're at the mercy of root..
      What if they disable some apache directives that now make your .htaccess files worthless? Then your content is free for the viewing. Yes, this is a wild and whacky rare possibility. What if cgi stopped working? Is your content unprotected? If your cgi serves content not normally accessible via http, then if things break, nothing is lost. )

      That junk said..
      It seems like your ap is *not* using authentication? Is that correct? I mean, authentication *inside itself* ...

      Maybe you're not familiar with CGI::Application::Plugin::Authentication, it took me a little while to figure out how to use it, it was frustrating at first- but it sets some sort of a standard for doing authen. You can use .htpassw files even if you want, i think...

      The idea is that every runmode (run, state, screen) of your cgi app requires a check. And if you don't store files in webshare, you don't have to worry about the rest.

        These really are static pages. One page is just a list of links to admin options, and another is an upload page. There is a templates folder inside the admin directory that holds my H::T templates for the application, but the templates are completely separate from the static pages I want to use in this case.

        Please pardon my ignorance, but I am a little confused about moving these kinds of pages outside the web accessible directory structure. If I do that, don't I get stuck still opening and serving these pages directly within my app? And if I don't use .htaccess to redirect requests for files to my app, how do I require authentication to access the directory contents? I don't want to use .htpasswd, I want to use the same authentication method as the rest of my app. I may be missing something, so I am more than willing to learn a new way of doing things if it is more efficient/effective.

        I am using C::A::P::Authentication to handle auth for my application. All of my run modes are protected and it works great serving dynamic content. With static content, I have 2 options. One - try to redirect after authentication and two, manually serve dynamic pages. If I do a redirect, I get stuck in a loop because each request ends up passed to my app, which redirects to the page which sends the request to my app...... So it looks to me like the only option is to manually open the static html files and return them from my app. I was wondering if there was a way to serve the static content without opening an delivering the files that way.

        Thanks for taking the time to answer my questions,
        digger

Re: CGI::Application::Authentication and Static Pages
by misc (Friar) on Jan 17, 2008 at 11:13 UTC
      I've used perlhandlers and they're pretty slick. But its probably tough to get mod_perl running on shared hosting...
Re: CGI::Application::Authentication and Static Pages
by Ryszard (Priest) on Jan 17, 2008 at 10:10 UTC
    i think others have it right when they say, anything you dont want accessed directly via a url, keep outside your web root, and have your C::A pick it up from another part of the filesystem and serve it up.

    i'm about to do something pretty much the same with user photos. i dont any old user getting a hold of other users photos, so i will store them outside the webroot where they are not accessable directly via a url, but accessible by the web server user

Re: CGI::Application::Authentication and Static Pages
by sundialsvc4 (Abbot) on Jan 18, 2008 at 03:42 UTC

    I suggest that you arrange things so that, even if some or most of your content actually comes from “static files,” your CGI::Application is consistently “how it happens.”

    In other words, you use mod_rewrite, which pretty much every shared-hosting client will support. You send ordinary static stuff like CSS and image-directories directly to the files, which really are static, but the rest of it ... all the rest of it ... you direct to your application. Even if the only thing that the application actually does is to determine the location of a straight-HTML file, grab it up and serve it (perhaps through a suitable template...), the application does it.

    The URI's presented by the web-user have no direct or obvious relation to the actual files from which the content may come. Those files are accessible to the Perl script, but not directly to Apache.

    What this does for you is to eliminate Apache's need to make any meaningful distinction, with respect to “actual content.” As far as Apache is concerned, it's either an image, or a stylesheet, or ... something that should be handled by Perl. Apache hands the request-URI to Perl, and Perl serves up the content. So, in the end there is only one way for “content” to be served. Not two.

    These days, I'm running quite a few sites in which most of the content is static. Dynamic content is the rare exception, not the rule. Yet it is impossible for you, the web-site user, to know the difference. Apache certainly doesn't know the difference.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://662571]
Approved by kyle
Front-paged by andyford
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (5)
As of 2024-04-25 14:56 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found